1

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]
Ash Hekmat
  • 31
  • 4

1 Answers1

1

I think the issue was due to my opaque_pixeldata tuples containing alpha, but my using putdata() to add them to an image with mode set to RGB. Changing the mode of paletted to 'RGBA' seems to have done the trick and the dominant colour I get for image 2 is now [243, 39, 36] as expected

Ash Hekmat
  • 31
  • 4