1

In my application I have loaded a picture and I want to be able to detect similar colors. So if I select a color I want the application to be able to find all pixels with that same (or almost the same) color. This is what I wrote for a detection system that looks in a vertical direction between the point of the mouse click and the end of the bitmap.

for (int y = mouseY; y < m_bitmap.Height; y++)
        {
            Color pixel = m_bitmap.GetPixel(mouseX, y);
            //check if there is another color
            if ((pixel.R > curcolor.R + treshold || pixel.R < curcolor.R - treshold) ||
                (pixel.G > curcolor.G + treshold || pixel.G < curcolor.G - treshold) ||
                (pixel.B > curcolor.B + treshold || pixel.B < curcolor.B - treshold))
            { //YESSSSS!
                if ((y - ytop > minheight)&&(curcolor != Color.White)) //no white, at least 15px height
                {
                    colorlayers.Add(new ColorLayer(curcolor, y - 1, ytop));
                }
                curcolor = pixel;
                ytop = y;
            } 
        }

Would this be the best way? Somehow it looks like it doesn't work too good with yellowish colors.

dcaswell
  • 3,137
  • 2
  • 26
  • 25
BreinBaas
  • 391
  • 3
  • 11
  • Please explain `I want to be able to detect similair colors`? How what would be your desired output like? Are you just asking to help you correcting your `if statement logic`? And are you wishing to look it down from mouse click position? you mean horizontally your colors do not change? You might have answered all these already.. but at least i could not see these things clear in your question. – Sami Oct 17 '13 at 13:34

3 Answers3

2

RGB is a 3D space.

A color far away threshold in all directions is not so similar to original one (and what is similar according to numbers may not be so similar to human beings eyes).

I would make a check using HSL (for example) where hue value as a finite 1D range, just for example:

for (int y = mouseY; y < m_bitmap.Height; y++)
{
    Color pixel = m_bitmap.GetPixel(mouseX, y);
    if (Math.Abs(color.GetHue() - curcolor.GetHue()) <= threshold)
    {
        // ...
    }
}

Moreover please note that using bitmaps in this way (GetPixel() is terribly slow, take a look to this post to see a - much - faster alternative).

Community
  • 1
  • 1
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
0

The reason why yellow colors give a problem might be that RGB is not a perceptually uniform colorspace. This means that, given a distance between two points/colors in the colorspace, the perception of this color distance/difference will in general not be the same.

That said, you might want to use another color space, like HSL as suggested by Adriano, or perhaps Lab.

If you want to stick to RGB, I would suggest to calculate the euclidian distance, like this (I think it's simpler):

float distance = Math.sqrt((pixel.R-curcolor.R)^2 + (pixel.G-curcolor.G)^2 + (pixel.B-curcolor.B)^2);

if(distance < threshold)
{
    // Do what you have to. 
}
juFo
  • 17,849
  • 10
  • 105
  • 142
elnigno
  • 1,751
  • 14
  • 37
0

It might be interesting to look at how the magic wand tool in Paint.NET works.

This is how they compare 2 colors:

private static bool CheckColor(ColorBgra a, ColorBgra b, int tolerance)
{
  int sum = 0;
  int diff;
  diff = a.R - b.R;
  sum += (1 + diff * diff) * a.A / 256;
  diff = a.G - b.G;
  sum += (1 + diff * diff) * a.A / 256;
  diff = a.B - b.B;
  sum += (1 + diff * diff) * a.A / 256;
  diff = a.A - b.A;
  sum += diff * diff;
  return (sum <= tolerance * tolerance * 4);
}

Source

Reda
  • 2,289
  • 17
  • 19