Here's a step by step guide on using PIL to find the 3 most common colors in an image and create a grayscale image that highlights only these colors.
Start by importing PIL and returning a list of the RBG codes
from PIL import Image
def get_pixels(image):then you'll need to find the most common colours
im = Image.open(image)
pixels = []
pix = im.load()
width,height = im.size
img_width, img_height = 0,0
for _ in range(width * height):
if img_width == width:
img_height += 1
img_width = 0
pixels.append(pix[img_width, img_height])
img_width += 1
return pixels
def pixel_index(pixels):
pix_index = {}
for pixel in pixels:
if pixel in pix_index.keys():
pix_index[pixel] += 1
else:
pix_index[pixel] = 1
return pix_index
and from there get the top 3 from the result
def sort_pixels(pixels, n=3, offset_range=50): #return top n pixels outside the offset_range deviationOkay now with this we can start creating the new image, I've put each functionality into a separate function so it's easier to explain and replace logic later on. Note that the task of finding the top colours using "pixel_index" is slow because it iterates over every pixel while creating a dictionary. It should be far more quicker if you create a new function with picked rbg codes you want to keep.
pixel_copy = copy.deepcopy(pixels)
result = []
result.append(max(pixel_copy, key=lambda key: pixel_copy[key]))
while len(result) < n:
find_max = max(pixel_copy, key=lambda key: pixel_copy[key])
for val in result:
off_1 = abs(find_max[0] - val[0])
off_2 = abs(find_max[1] - val[1])
off_3 = abs(find_max[2] - val[2])
if off_1 > offset_range or off_2 > offset_range or off_3 > offset_range and find_max not in result:
result.append(find_max)
del pixel_copy[find_max]
return result
def pixels_check(top_pixels, pixel):
for pix in top_pixels:
result = valid_check(pix, pixel)
if result == True:
return True
return False
def valid_check(first_color, second_color, offset=10):
off_1 = abs(first_color[0] - second_color[0])
off_2 = abs(first_color[1] - second_color[1])
off_3 = abs(first_color[2] - second_color[2])
if off_1 < offset and off_2 < offset and off_3 < offset:
return True
return False
pixels_check will use the result of list of top colors and return True if the color is almost close to one in the top colors.
Finally the main function will get a string of the color name and create the new file. Remember to create a folder "colored" where your testing.
def colourfest(image):
image_name = image
pix = pixels = get_pixels(image)
pix = pixel_index(pix)
top_pixels = sort_pixels(pix)
image = Image.open(image)
pix_load = image.load()
width,height = image.size
new_image = Image.new(image.mode, image.size)
img_width, img_height = 0,0
for _ in range(width * height):
if img_width == width: #checks if width exceeded and jumps to next row
img_height += 1
img_width = 0
pixel = pix_load[img_width, img_height]
top_pix = pixels_check(top_pixels, pixel)
if top_pix == True:
new_image.putpixel([img_width, img_height],pixel)
else:
gray = (pixel[0] + pixel[1] + pixel[2])/3
new_image.putpixel([img_width, img_height], (gray, gray, gray))
img_width += 1
new_image.save('colored/'+image_name)
Now you can run this code and get your colourfest image
In [1]: from colorfest import *
In [2]: colourfest('58c7814d7857c.jpeg')
Here are some results from running this
You can find the code on github
No comments:
Post a Comment