C++ – Color detection algorithm – How should I do this

algorithmccolorsdetection

I'm a bit stuck on designing a color detection system – I can't quite figure out a way to do it easily.

Basically, I have a library of images, that I want to sort by color. So if the user specifies 'sort by blue', then the most blue images will appear at the top of the results, with the least blue appearing at the bottom.

The problem is that the images aren't all one color, so it is doing two things at the same time:

1 – finding the bluest part of the image
2 – ranking this blue color (based on color hue and amount of this color).

I've tried about 3 or 4 different approaches, with varying results – none work well though, and 2 of these were quite mathematical algorithms (which all work much better on paper than in practice haha).

What different ways could I go about the whole process? I'm probably missing some really obvious ways it could work – any help or ideas would be much appreciated 🙂

EDIT: Thanks for all the responses – here's what I've tried so far:

  • getting the average rgb value for the whole image and comparing it to blue. Comparing was done using normalised rgb 3 space vectors and finding distances between them. This works the least well, an image with no blue could easily appear above an image with partial very strong blue.

  • finding the dominant color and comparing it to blue (again using 3 space vector distances). This didn't work as there might have been a large blue section of the image that wasn't the most (or in the top couple) of dominant color sections.

  • finding pixels that are close to blue, averaging all of these and comparing the answer to actual blue.

  • finding all the pixels that are close to blue, incrementing a count and finding a percentage based on count/total pixels.

Best Answer

Two thoughts come to mind:

Cheap version: convert images to HSV color space, and for each pixel compute cos(H - target_hue) or a reasonable approximation (for blue, target_hue would be 240 degrees), multiply by saturation, and average that quantity over all of the pixels in the image. High values are best. Note that colors that are closer to yellow than to blue have "negative blueness", and that black, white, and pure gray have equally "zero blueness". Note that you really want HSV, not HSL, in this situation, because the "S" in HSL doesn't map well to perceptual saturation. For example, the color #f8f8ff (RGB 248, 248, 255) has a saturation of 100% in HSL (i.e. a pure blue), but it looks nearly white. The same color in HSV has an "S" coordinate of only 3%, which is reasonable.

Less cheap version: convert images to CIELAB color space, discard L, and compute the distance in a*b* space between each pixel and the target color, then average or RMS over each pixel. Low values are best.