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 8,026 Nov-06-2017, 12:38 AM
Last Post: Redoudou

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020