8

I want to call a method with argument color. But there are a lot of colors which differ only by a shade. How can I find the colors which differ from my color only by little, for example AntiqueWhite and Bisque. Here's the color palette.

Bitmap LogoImg = new Bitmap("file1.jpeg");//the extension can be some other
System.Drawing.Color x = LogoImg.GetPixel(LogoImg.Width-1, LogoImg.Height-1);
LogoImg.MakeTransparent(x);
image1.Source = GetBitmapSource(LogoImg);
petko_stankoski
  • 10,459
  • 41
  • 127
  • 231

6 Answers6

16

Could you use a method like this:

 public bool AreColorsSimilar(Color c1, Color c2, int tolerance)
 {
     return Math.Abs(c1.R - c2.R) < tolerance &&
            Math.Abs(c1.G - c2.G) < tolerance &&
            Math.Abs(c1.B - c2.B) < tolerance;
 }

This method takes two colours and a tolerance and returns whether those two colours are close or not based on their RGB values. I think that should do the trick but you may need to extend to include brightness and saturation.

Kevin Holditch
  • 5,165
  • 3
  • 19
  • 35
7

I found this routine here:

Color nearest_color = Color.Empty;
foreach (object o in WebColors)
{
    // compute the Euclidean distance between the two colors
    // note, that the alpha-component is not used in this example
    dbl_test_red = Math.Pow(Convert.ToDouble(((Color)o).R) - dbl_input_red, 2.0);
    dbl_test_green = Math.Pow(Convert.ToDouble
        (((Color)o).G) - dbl_input_green, 2.0);
    dbl_test_blue = Math.Pow(Convert.ToDouble
        (((Color)o).B) - dbl_input_blue, 2.0);

    temp = Math.Sqrt(dbl_test_blue + dbl_test_green + dbl_test_red);
    // explore the result and store the nearest color
    if(temp == 0.0)
    {
        nearest_color = (Color)o;
        break;
    }
    else if (temp < distance)
    {
        distance = temp;
        nearest_color = (Color)o;
    }
}
Marco
  • 56,740
  • 14
  • 129
  • 152
  • It's a colors palette. Take a look [here](http://pietschsoft.com/post/2006/06/29/C-NET-Convert-SystemDrawingColor-to-HTML-color.aspx) to convert it to something different – Marco Oct 21 '11 at 07:50
  • There's no real reason to take the square root, though. the closest value will be the closest value, even without adding that CPU-heavy operation. – Nyerguds Apr 23 '17 at 20:44
4

You can get the closest color from the KnownColors enum.

// A color very close to Rosy Brown
var color = Color.FromArgb(188, 143, 142);

var colors = Enum.GetValues(typeof (KnownColor))
                .Cast<KnownColor>()
                .Select(Color.FromKnownColor);

var closest = colors.Aggregate(Color.Black, 
                (accu, curr) =>
                ColorDiff(color, curr) < ColorDiff(color, accu) ? curr : accu);

And the support method

private int ColorDiff(Color color, Color curr)
{
    return Math.Abs(color.R - curr.R) + Math.Abs(color.G - curr.G) + Math.Abs(color.B - curr.B);
}
Jonas Elfström
  • 30,834
  • 6
  • 70
  • 106
2

I used Keven Holditch's answer below. But I modified it for my own purposes. This version uses exclusive-or so that only one value can be off by the tolerance and still return true. (Tolerance is also <= instead of just <.)

private bool AreColorsSimilar(Color c1, Color c2, int tolerance)
{
    return Math.Abs(c1.R - c2.R) <= tolerance ^
           Math.Abs(c1.G - c2.G) <= tolerance ^
           Math.Abs(c1.B - c2.B) <= tolerance;
}
NielW
  • 3,626
  • 1
  • 30
  • 38
2

Analyze this example Find the Nearest Color with C#. Hope gives you an idea.

enter image description here

Color nearest_color = Color.Empty;
foreach (object o in WebColors)
{
    // compute the Euclidean distance between the two colors
    // note, that the alpha-component is not used in this example
    dbl_test_red = Math.Pow(Convert.ToDouble(((Color)o).R) - dbl_input_red, 2.0);
    dbl_test_green = Math.Pow(Convert.ToDouble
        (((Color)o).G) - dbl_input_green, 2.0);
    dbl_test_blue = Math.Pow(Convert.ToDouble
        (((Color)o).B) - dbl_input_blue, 2.0);
    // it is not necessary to compute the square root
    // it should be sufficient to use:
    // temp = dbl_test_blue + dbl_test_green + dbl_test_red;
    // if you plan to do so, the distance should be initialized by 250000.0
    temp = Math.Sqrt(dbl_test_blue + dbl_test_green + dbl_test_red);
    // explore the result and store the nearest color
    if(temp == 0.0)
    {
        // the lowest possible distance is - of course - zero
        // so I can break the loop (thanks to Willie Deutschmann)
        // here I could return the input_color itself
        // but in this example I am using a list with named colors
        // and I want to return the Name-property too
        nearest_color = (Color)o;
        break;
    }
    else if (temp < distance)
    {
        distance = temp;
        nearest_color = (Color)o;
    }
}
Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
2

I think to find similar colors you should take a look at the HSL or HSB color space instead of the RGB one, cause with this it is a lot easier to find similar colors.

Within .Net you can call the GetHue(), GetSaturation() and GetBrightness() method to get these values from a given color and compare these values to find similar ones.

If you need the way back from an HSB value to a color you can also use this method.

Community
  • 1
  • 1
Oliver
  • 43,366
  • 8
  • 94
  • 151