1

In this answer about detecting the color of an image olooney said that "loop over the histogram and take the average of pixel color weighed by the pixel count".

I ran the histogram like this:

class ImageResize(webapp.RequestHandler):
    def get(self):
        q = HomePage.all()
        q.filter("firm_name", "noise")
        qTable = q.get()
        id = qTable.key().id()
        if id:
            homepage = HomePage.get_by_id(id)
            if homepage:
                img = images.Image(homepage.thumbnail)
                hist = img.histogram()

then in IDLE, for each color of the histogram hist2, I tried to get the average and divided by pixel count, but I get the same number. What am I doing wrong?

>>> average_red = float(sum(hist2[0]))/len(hist2[0])
>>> average_red
789.2578125
>>> average_green = float(sum(hist2[1]))/len(hist2[1])
>>> average_green
789.2578125
>>> average_blue = float(sum(hist2[2]))/len(hist2[2])
>>> average_blue
789.2578125
>>>

Update

Thanks to Saxon Druce for the answer. Here's the code I used:

>>> def hist_weighed_average(hist):
    red_hist = hist[0]
    green_hist = hist[1]
    blue_hist = hist[2]

    red_weighed_sum = float(sum(i * red_hist[i] for i in range(len(red_hist))))
    green_weighed_sum = float(sum(i * green_hist[i] for i in range(len(green_hist))))
    blue_weighed_sum = float(sum(i * blue_hist[i] for i in range(len(blue_hist))))

    red_num_pixels = float(sum(red_hist))
    green_num_pixels = float(sum(green_hist))
    blue_num_pixels = float(sum(blue_hist))

    red_weighed_average = red_weighed_sum / num_pixels
    green_weighed_average = green_weighed_sum / num_pixels
    blue_weighed_average = blue_weighed_sum / num_pixels
    return red_weighed_average, green_weighed_average, blue_weighed_average
>>> hist = hist3
>>> hist_weighed_average(hist)
(4.4292897797574859, 4.8236723583271468, 5.2772779015095272)
>>> hist = hist2
>>> hist_weighed_average(hist)
(213.11471417965851, 220.01047265528334, 214.12880475129919)
>>> 
Community
  • 1
  • 1
Zeynel
  • 13,145
  • 31
  • 100
  • 145
  • 1
    is it a grayscale image? – mpenkov Sep 27 '11 at 05:44
  • @Zeynel: Note that red_num_pixels, green_num_pixels and blue_num_pixels will all be the same, so you don't need to calculate it three times. Even faster would be to just use the `width * height` of the image. – Saxon Druce Sep 28 '11 at 01:07

1 Answers1

3

Assuming hist2[0] is the histogram of the red pixels, then it is a histogram of pixel counts indexed by the red component. That means that sum(hist2[0]) is always going to be the number of pixels in the image, and len(hist2[0]) is always going to be 256. This will always give you the same answer, for all three of red, green and blue.

You need to multiply the pixel counts (the values in the histogram) by the pixel values (the index in the list), then add them, to get a weighted sum. Then divide by the number of pixels to get the weighted average. Maybe something like this:

red_hist = hist2[0]
weighted_sum = sum(i * red_hist[i] for i in range(len(red_hist)))
num_pixels = sum(red_hist)
weighted_average = weighted_sum / num_pixels
Saxon Druce
  • 17,406
  • 5
  • 50
  • 71
  • Saxon Druce: Many thanks for the answer; I added the code to my question. How do I order pictures according to colors, any suggestions? Thanks again. – Zeynel Sep 27 '11 at 13:37
  • @Zeynel: It will depend on what your images are like. You could try converting the RGB values to HSV, and then sorting by the H. However this will only look sensible if the S and V values are roughly similar. For example those two colours in your sample code are slightly blue and slightly green, so would be sorted with other blues and greens respectively, but in reality they look like black and light grey, and so would look out of place. You could also try converting from RGB to YUV or YCbCr, and then using the Y (which is like a greyscale), which may work if your images are shades of grey. – Saxon Druce Sep 28 '11 at 01:05
  • SaxonDruce: I tried a couple of others methods including reducing the image to 1 pixel and sorting by the hue none of them really worked. The best appears to be ordering my query first by red then by green and then by blue: http://ting-1.appspot.com/displayimage?sort_by=red_green_and_blue. Although it may be a coincidence. I want to achieve this effect: http://www.readwriteweb.com/archives/search_flickr_images_by_color_with_multicolr_search_lab.php but it seems that not possible at this level of programming. Thanks again. – Zeynel Sep 28 '11 at 03:47