Python Forum
Image Color Analyzer
Thread Rating:
  • 1 Vote(s) - 3 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Image Color Analyzer
#1
Photo 
Hey ! I wrote a simple script to return the color used in an image.

Requirements
  1. Install the PIL module
  2. Configure Init values
Return options
  • Beautiful pie chart Heart
  • Colored images named with the percentage
  • Json file
Other useful options Dance
  • Process only colors with a minimum percentage
  • Allow transparent pixels process
  • Multiple return color format available

Feel free to suggest improvements, and please tell me if it's working with Python 3 Blush

#!/usr/bin/env python #-*- coding: utf-8 -*- import os import json from PIL import Image from PIL import ImageDraw # Init file = '/path/to/your/file.png' results_dir = '/path/to/results/dir' min_percentage = 0.5 # min percentage of color in the file to be added alpha_pixels = True # use transparent pixels circle_size = 500 # circle file size (pixels) color_files = True # get results with image files results_file = True # get json results results_color_format = 'hex' # hex / rgb / rgba results_ext = '.json' PIL_file = Image.open(file) all_pixels = PIL_file.size[0] * PIL_file.size[1] colors_hm = {} sorted_colors = [] if not os.path.isdir(results_dir):	os.makedirs(results_dir) for rgba_pixel in PIL_file.getdata():	if rgba_pixel[3] == 0:	if alpha_pixels == True:	rgba_pixel = (0, 0, 0, 0)	else:	all_pixels -= 1	continue	try:	nb = colors_hm[rgba_pixel]['nb']	colors_hm[rgba_pixel] = {'nb':nb + 1}	except:	colors_hm[rgba_pixel] = {'nb':1} for color in colors_hm:	color_percentage = colors_hm[color]['nb'] * 100 / float(all_pixels)	if color_percentage >= min_percentage:	rgba_pixel = eval(str(color))	if color_files == True:	img = Image.new('RGBA', (100, 100), (rgba_pixel[0],rgba_pixel[1],rgba_pixel[2],rgba_pixel[3]))	file_name = '%03.4f %%.png' % color_percentage	img.save(os.path.join(results_dir,file_name),format="png")	sorted_colors.append({'color':rgba_pixel,'num':color_percentage}) sorted_colors.sort(key=lambda k: k['num'],reverse=True) circle = Image.new('RGBA', (circle_size,circle_size), (0,0,0,0)) current_deg = 0 for x in sorted_colors:	rgba_pixel = eval(str(x['color']))	pieslice_deg = x['num'] * 3.6	ImageDraw.Draw(circle).pieslice([10, 10, circle_size-10, circle_size-10], current_deg, current_deg + pieslice_deg, fill=(rgba_pixel[0],rgba_pixel[1],rgba_pixel[2],rgba_pixel[3]))	current_deg += pieslice_deg	if results_file == True:	if results_color_format == 'hex':	x['color'] = '#%02x%02x%02x' % (rgba_pixel[0],rgba_pixel[1],rgba_pixel[2])	elif results_color_format == 'rgb':	x['color'] = (rgba_pixel[0],rgba_pixel[1],rgba_pixel[2]) circle.save(os.path.join(results_dir,"circle.png"),format="png") if results_file == True:	with open(os.path.join(results_dir,"results"+results_ext), 'w') as outfile:	json.dump(sorted_colors, outfile) print "Done."
Reply
#2
(Aug-27-2017, 10:48 PM)Aerosmite Wrote: Feel free to suggest improvements, and please tell me if it's working with Python 3 Blush


Line 81: print "Done."
That would throw an error in python3. 

I didn't read through all of it, but it's a cool idea :)
Do you have a sample image, and what the output would be (for those of us that want to see what's up without needing to run it)?
Reply
#3
(Aug-28-2017, 04:47 PM)nilamo Wrote: Do you have a sample image, and what the output would be (for those of us that want to see what's up without needing to run it)?

Good idea Wink

INPUT

Input image
[Image: fond_salle_3.png]

Init values
# Init file = '/Users/mathieu/Desktop/Fond Salle/fond salle 3.png' results_dir = '/Users/mathieu/Desktop/Fond Salle/final' min_percentage = 0.5 # min percentage of color in the file to be added alpha_pixels = False # I don't want to process the transparent background circle_size = 200 # circle file size (pixels) color_files = True # results with image files results_file = True # json results results_color_format = 'hex' # hex color format results_ext = '.json'

OUTPUT

Results preview Cool
[Image: Capture_d_cran_2017_08_28_23_28_22.png]

Pie chart
[Image: circle.png]

Json file
[{"color": "#eff8ff", "num": 27.855486948809506}, {"color": "#ffb009", "num": 17.40053298739901}, {"color": "#3b2802", "num": 13.558536465017378}, {"color": "#0affe8", "num": 9.815141346250764}, {"color": "#efcc8f", "num": 4.208820734803976}, {"color": "#f74a00", "num": 3.6577831216158483}, {"color": "#000000", "num": 2.9170917393700897}, {"color": "#ffdda1", "num": 2.2327861897305246}, {"color": "#f7e0ba", "num": 2.0723164118198536}, {"color": "#ef4c20", "num": 1.5319486682273635}, {"color": "#668eaf", "num": 1.2689553607238304}, {"color": "#08ccba", "num": 1.2210042076398797}, {"color": "#b0d4ff", "num": 1.1766799667504932}, {"color": "#f9f212", "num": 0.9418584888512515}, {"color": "#87aacc", "num": 0.8144526546677727}, {"color": "#c49257", "num": 0.6270762490811471}, {"color": "#058074", "num": 0.5094968165410814}]


(Aug-28-2017, 04:47 PM)nilamo Wrote: Line 81: print "Done."
That would throw an error in python3.

Thanks! New code:

#!/usr/bin/env python #-*- coding: utf-8 -*- import os import json from PIL import Image from PIL import ImageDraw # Init file = '/path/to/your/file.png' results_dir = '/path/to/results/dir' min_percentage = 0.5 # min percentage of color in the file to be added alpha_pixels = True # use transparent pixels circle_size = 500 # circle file size (pixels) color_files = True # get results with image files results_file = True # get json results results_color_format = 'hex' # hex / rgb / rgba results_ext = '.json' PIL_file = Image.open(file) all_pixels = PIL_file.size[0] * PIL_file.size[1] colors_hm = {} sorted_colors = [] if not os.path.isdir(results_dir): os.makedirs(results_dir) for rgba_pixel in PIL_file.getdata(): if rgba_pixel[3] == 0: if alpha_pixels == True: rgba_pixel = (0, 0, 0, 0) else: all_pixels -= 1 continue try: nb = colors_hm[rgba_pixel]['nb'] colors_hm[rgba_pixel] = {'nb':nb + 1} except: colors_hm[rgba_pixel] = {'nb':1} for color in colors_hm: color_percentage = colors_hm[color]['nb'] * 100 / float(all_pixels) if color_percentage >= min_percentage: rgba_pixel = eval(str(color)) if color_files == True: img = Image.new('RGBA', (100, 100), (rgba_pixel[0],rgba_pixel[1],rgba_pixel[2],rgba_pixel[3])) file_name = '%03.4f %%.png' % color_percentage img.save(os.path.join(results_dir,file_name),format="png") sorted_colors.append({'color':rgba_pixel,'num':color_percentage}) sorted_colors.sort(key=lambda k: k['num'],reverse=True) circle = Image.new('RGBA', (circle_size,circle_size), (0,0,0,0)) current_deg = 0 for x in sorted_colors: rgba_pixel = eval(str(x['color'])) pieslice_deg = x['num'] * 3.6 ImageDraw.Draw(circle).pieslice([10, 10, circle_size-10, circle_size-10], current_deg, current_deg + pieslice_deg, fill=(rgba_pixel[0],rgba_pixel[1],rgba_pixel[2],rgba_pixel[3])) current_deg += pieslice_deg if results_file == True: if results_color_format == 'hex': x['color'] = '#%02x%02x%02x' % (rgba_pixel[0],rgba_pixel[1],rgba_pixel[2]) elif results_color_format == 'rgb': x['color'] = (rgba_pixel[0],rgba_pixel[1],rgba_pixel[2]) circle.save(os.path.join(results_dir,"circle.png"),format="png") if results_file == True: with open(os.path.join(results_dir,"results"+results_ext), 'w') as outfile: json.dump(sorted_colors, outfile) print("Done.")
Reply
#4
Are you skipping black or something?  That looks like it should be the #1 color, instead of the cloud/off-white.

Also, what's the goal of these lines?
Quote:
rgba_pixel = eval(str(color))

Unless I'm reading it wrong, color is already a tuple of int, so converting it to a string and calling eval() on it will result with... exactly the same thing you started with.
Reply
#5
(Aug-28-2017, 09:58 PM)nilamo Wrote: Are you skipping black or something?  That looks like it should be the #1 color, instead of the cloud/off-white.
My image hosting convert transparent pixels to black and since alpha_pixels = False, it's skipping them.

(Aug-28-2017, 09:58 PM)nilamo Wrote: Unless I'm reading it wrong, color is already a tuple of int, so converting it to a string and calling eval() on it will result with... exactly the same thing you started with.
You right thanks it was an old test.
Also do you know which is the better ? Use an hash map to store the color (key) and it's image number...
for rgba_pixel in PIL_file.getdata():	if rgba_pixel[3] == 0:	if alpha_pixels == True:	rgba_pixel = (0, 0, 0, 0)	else:	all_pixels -= 1	continue	try:	nb = colors_hm[rgba_pixel]['nb']	colors_hm[rgba_pixel] = {'nb':nb + 1}	except:	colors_hm[rgba_pixel] = {'nb':1}
and then add only colors under the min_percentage into a list and sort it.
Or use only a list, makes severals test to update theses values like the hash map, delete colors below min_percentage and just sort it after ? Is it worth it ?

Current new code:
#!/usr/bin/env python #-*- coding: utf-8 -*- import os import json from PIL import Image from PIL import ImageDraw # Init file = '/path/to/your/file.png' results_dir = '/path/to/results/dir' min_percentage = 0.5 # min percentage of color in the file to be added alpha_pixels = True # use transparent pixels circle_size = 500 # circle file size (pixels) color_files = True # get results with image files results_file = True # get json results results_color_format = 'hex' # hex / rgb / rgba results_ext = '.json' PIL_file = Image.open(file) all_pixels = PIL_file.size[0] * PIL_file.size[1] colors_hm = {} sorted_colors = [] if not os.path.isdir(results_dir): os.makedirs(results_dir) for rgba_pixel in PIL_file.getdata(): if rgba_pixel[3] == 0: if alpha_pixels == True: rgba_pixel = (0, 0, 0, 0) else: all_pixels -= 1 continue try: nb = colors_hm[rgba_pixel]['nb'] colors_hm[rgba_pixel] = {'nb':nb + 1} except: colors_hm[rgba_pixel] = {'nb':1} for color in colors_hm:	color_percentage = colors_hm[color]['nb'] * 100 / float(all_pixels)	if color_percentage >= min_percentage:	if color_files == True:	img = Image.new('RGBA', (100, 100), (color[0],color[1],color[2],color[3]))	file_name = '%03.4f %%.png' % color_percentage	img.save(os.path.join(results_dir,file_name),format="png")	sorted_colors.append({'color':color,'num':color_percentage}) sorted_colors.sort(key=lambda k: k['num'],reverse=True) circle = Image.new('RGBA', (circle_size,circle_size), (0,0,0,0)) current_deg = 0 for x in sorted_colors:	pieslice_deg = x['num'] * 3.6	ImageDraw.Draw(circle).pieslice([10, 10, circle_size-10, circle_size-10], current_deg, current_deg + pieslice_deg, fill=(x['color'][0],x['color'][1],x['color'][2],x['color'][3]))	current_deg += pieslice_deg	if results_file == True:	if results_color_format == 'hex':	x['color'] = '#%02x%02x%02x' % (x['color'][0],x['color'][1],x['color'][2])	elif results_color_format == 'rgb':	x['color'] = (x['color'][0],x['color'][1],x['color'][2]) circle.save(os.path.join(results_dir,"circle.png"),format="png") if results_file == True:	with open(os.path.join(results_dir,"results"+results_ext), 'w') as outfile:	json.dump(sorted_colors, outfile) print("Done.")
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Youtube Watched History Analyzer Aerosmite 4 11,124 Nov-06-2017, 12:38 AM
Last Post: Redoudou

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020
This forum uses Lukasz Tkacz MyBB addons.
Forum use Krzysztof "Supryk" Supryczynski addons.