I'm trying to find the dominant colour in an image that has some transparent pixels. My ideal pre-requisite is to avoid needing any other modules beyond PIL. I like solution2 from Pithikos suggested here: Python - Find dominant/most common color in an image
Instead of building an array, it reduces the colours in the image down to a palette then selects the colour from the palette that occurs most frequently.
But the issue is that when the image is converted to 'P', transparent pixels (0,0,0,0) are converted to black, then that often becomes the most dominant colour if there is a lot of transparency.
So I tried to add a step to remove transparent pixels, then use the palette method. It works fine for image 1, outputting (250, 235, 167) as the dominant colour, but image 2 returns (255, 255, 255) instead of some sort of red, which is what I was expecting.
Image 1: Image 1 Image 2: Image 2
Have I gone wrong somewhere?
My code is here, apologies, I'm very new to Python/programming in general and mainly trying to adapt what I've been able to find from others:
def _return_dominant_color(self, image, key):
# Resize image to speed up processing
width, height = 75, 30
image.thumbnail((width, height))
# Remove transparent pixels
pixeldata = image.getcolors(width * height)
sorted_pixeldata = sorted(pixeldata, key=lambda t: t[0], reverse=True)
opaque_pixeldata = [pixeldata for pixeldata in sorted_pixeldata if pixeldata[-1][-1] == 255]
opaque_pixels = []
for position, pixeldata in enumerate(opaque_pixeldata):
for count in range(pixeldata[0]):
opaque_pixels.append(pixeldata[1])
# Reduce colors to palette
paletted = Image.new('RGB', (len(opaque_pixels), 1))
paletted.putdata(opaque_pixels)
paletted = paletted.convert(
'P', palette=Image.ADAPTIVE, colors=32)
# Find color that occurs most often
palette = paletted.getpalette()
color_counts = sorted(paletted.getcolors(), reverse=True)
palette_index = color_counts[0][1]
# Calculate luminosity of dominant colour and convert to RGB
dominant = palette[palette_index*3:palette_index*3+3]
luminosity = self._return_luminosity(dominant)
luminosity = int(luminosity * 1000)
dominant = self._rgb_to_hex(dominant)
return (dominant, luminosity)
And this is the output I see for each stage:
Image 1:
palette: [255, 241, 172, 255, 240, 171, 254, 239, 170, 253, 238, 170, 253, 238, 169, 252, 237, 169, 252, 237, 168, 251, 237, 168, 251, 236, 168, 250, 236, 168, 250, 235, 167, 249, 235, 167, 249, 234, 167, 248, 234, 166, 248, 233, 166, 247, 233, 166, 247, 232, 165, 246, 232, 165, 246, 231, 165, 245, 230, 164, 244, 229, 163, 243, 229, 163, 243, 228, 163, 242, 228, 162, 241, 227, 161, 241, 226, 161, 240, 226, 161, 240, 225, 160, 239, 225, 160, 238, 224, 159, 237, 223, 159, 236, 222, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
colour_counts: [(10, 10), (9, 16), (9, 14), (9, 12), (9, 8), (8, 5), (7, 30), (7, 29), (7, 20), (6, 28), (6, 19), (6, 18), (6, 1), (5, 26), (5, 23), (5, 4), (5, 2), (4, 31), (4, 25), (4, 21), (4, 15), (4, 3), (4, 0), (3, 24), (3, 22), (3, 17), (3, 13), (3, 6), (2, 27), (2, 11), (2, 9), (2, 7)]
palette_index: 10
dominant: [250, 235, 167]
Image 2:
opaque_pixeldata: [(21, (255, 255, 255, 255)), (17, (255, 42, 39, 255)), (17, (253, 41, 38, 255)), (17, (245, 40, 37, 255)), (15, (239, 39, 36, 255)), (13, (252, 41, 38, 255)), (12, (238, 39, 36, 255)), (11, (244, 40, 37, 255)), (10, (246, 40, 37, 255)), (9, (247, 40, 37, 255)), (9, (243, 40, 37, 255)), (7, (249, 41, 38, 255)), (6, (250, 41, 38, 255)), (5, (255, 43, 39, 255)), (5, (240, 39, 36, 255)), (5, (251, 41, 38, 255)), (4, (242, 40, 37, 255)), (4, (255, 42, 38, 255)), (4, (248, 41, 37, 255)), (3, (249, 41, 37, 255)), (3, (248, 41, 38, 255)), (3, (255, 41, 38, 255)), (3, (247, 41, 37, 255)), (3, (248, 40, 37, 255)), (3, (241, 39, 36, 255)), (2, (254, 42, 38, 255)), (2, (255, 44, 40, 255)), (2, (255, 43, 40, 255)), (2, (242, 40, 36, 255)), (2, (241, 40, 37, 255)), (1, (254, 42, 39, 255)), (1, (253, 42, 38, 255)), (1, (246, 41, 37, 255)), (1, (242, 39, 36, 255)), (1, (249, 40, 37, 255)), (1, (247, 41, 38, 255)), (1, (239, 40, 36, 255))]
palette: [255, 255, 255, 255, 44, 40, 255, 43, 40, 255, 43, 39, 255, 42, 39, 255, 42, 38, 254, 42, 38, 255, 41, 38, 253, 41, 38, 252, 41, 38, 251, 41, 38, 250, 41, 38, 249, 41, 38, 249, 41, 37, 248, 41, 38, 248, 41, 37, 247, 41, 37, 246, 41, 37, 248, 40, 37, 247, 40, 37, 246, 40, 37, 245, 40, 37, 244, 40, 37, 243, 40, 37, 242, 40, 37, 242, 40, 36, 241, 40, 37, 241, 39, 36, 240, 39, 36, 239, 40, 36, 239, 39, 36, 238, 39, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
color_counts: [(22, 0), (18, 21), (18, 8), (18, 4), (16, 30), (14, 9), (13, 31), (12, 22), (11, 20), (10, 23), (10, 19), (8, 12), (7, 11), (7, 6), (6, 28), (6, 27), (6, 18), (6, 16), (6, 10), (6, 3), (5, 24), (5, 15), (5, 5), (4, 14), (4, 13), (4, 7), (3, 26), (3, 25), (3, 2), (3, 1), (2, 29), (2, 17)]
palette_index: 0
dominant: [255, 255, 255]