views:

493

answers:

3

I'm using Python and PIL.

I have images in RGB and I would like to know those who contain only one color (say #FF0000 for example) or a few very close colors (#FF0000 and #FF0001).

I was thinking about using the histogram but it is very hard to figure out something with the 3 color bands, so I'm looking for a more clever algorithm.

Any ideas?

ImageStat module is THE answer! Thanks Aaron. I use ImageStat.var to get the variance and it works perfectly.

Here is my piece of code:

from PIL import Image, ImageStat

MONOCHROMATIC_MAX_VARIANCE = 0.005

def is_monochromatic_image(src):
    v = ImageStat.Stat(Image.open(src)).var
    return reduce(lambda x, y: x and y < MONOCHROMATIC_MAX_VARIANCE, v, True)
A: 

First, you should define a distance between two colors. Then you just have to verify for each pixel that it's distance to your color is small enough.

SmuK
Computing the Euclidian distance between each pixel in the 3 dimensions RGB space is theoreticaly fine, but I think it won't work with multi million pixels images... (at least in Python)
Grégoire Cachet
Why Euclidian distance? You can imagine something else depending on what you want.
SmuK
The problem is not in the type of distance, but in the fact that the algorithm is O(N^2), N being the number of pixels in the image (I have cases with N=10,000,000)
Grégoire Cachet
Perhaps i misunderstood your question.If you have to check that each pixel is close enough to a given color, it's linear time.
SmuK
@Smuk: I don't think it's a given color -- the color they are all closest to could be anything, specific to each image, right?
Doug Kavendek
@Doug: that's right
Grégoire Cachet
+2  A: 

Try the ImageStat module. If the values returned by extrema are the same, you have only a single color in the image.

Aaron Digulla
A: 

Here's a little snippet you could make use of :


import Image

im = Image.open("path_to_image")
width,height = im.size

for w in range(0,width):
  for h in range(0,height):
     # this will hold the value of all the channels
     color_tuple = im.getpixel((w,h))
     # do something with the colors here

Maybe use a hash and store the tuples as the key and it's number of appearances as value?

Geo