Sign in to follow this  
ginkeq

Rounding to nearest color?

Recommended Posts

How do you implement something like rounding to the nearest color, given a RGB value? There are clearly lots of cases if i wanted to use a bunch of if statements, is there a standard way to round to a given color(or a way in C#)? For instance, how do you know if a color is yellow, or red, etc.

Share this post


Link to post
Share on other sites
I'm not sure if this is technically correct, but it feels intuitive and works well in a program I wrote to convert an image to a paricular hard-coded palette.

The trick is to work out the "distance" between your colour and the possible matches, then to take the match that is the shortest distance away. To calculate the distance, I simply used Pythagoras's theorem. That is:
static int GetDistanceBetweenColours(Color a, Color b) {
int dR = a.R - b.R, dG = a.G - b.G, dB = a.B - b.B;
return dR * dR + dG * dG + dB * dB;
}

As we'll be just comparing the distances against other distances, you can ignore taking the square root (so this actually calculates the distance squared). You could then use it in a method like this:
static Color GetClosestColour(Color source, IEnumerable<Color> palette) {

// Store the current closest distance and colour:
int CurrentClosestDistance = int.MaxValue;
Color CurrentClosestColour = Color.Black;

// Iterate over the possible matches, and check the distance each time.
foreach (Color c in palette) {
int d = GetDistanceBetweenColours(source, c);
if (d < CurrentClosestDistance) {
CurrentClosestDistance = d;
CurrentClosestColour = c;
}
}

// Return the closest colour!
return CurrentClosestColour;
}

Share this post


Link to post
Share on other sites
I would suggest benryves method, except for determining the distance I would suggest weighting each channel by its perceptual significance (instead of straight Euclidean distance), just use the NTSC conversion weights which I think are {0.299, 0.587, 0.114}

Share this post


Link to post
Share on other sites
I've written a C# method to do this that finds the closest color match from an array of color swatches. Pretty much the same thing as benryves's solution.

private Color GetColorMatch(Color col)
{
Color ColorMatch = Color.Empty;

int LeastDistance = int.MaxValue;

int Alpha = col.A;
int Red = col.R;
int Green = col.G;
int Blue = col.B;

for(int i=0; i<SwatchArray.Length; i++)
{
Color PaletteColor = SwatchArray[i];

int AlphaDistance = PaletteColor.A - Alpha;
int RedDistance = PaletteColor.R - Red;
int GreenDistance = PaletteColor.G - Green;
int BlueDistance = PaletteColor.B - Blue;

int Distance = ( AlphaDistance * AlphaDistance ) +
( RedDistance * RedDistance ) +
( GreenDistance * GreenDistance ) +
( BlueDistance * BlueDistance );

if(Distance < LeastDistance)
{
ColorMatch = PaletteColor;
LeastDistance = Distance;

if(Distance == 0)
return PaletteColor;
}
}

return ColorMatch;
}


Share this post


Link to post
Share on other sites
Quote:
Original post by ginkeq
How do you implement something like rounding to the nearest color, given a RGB value?

There are clearly lots of cases if i wanted to use a bunch of if statements, is there a standard way to round to a given color(or a way in C#)?

For instance, how do you know if a color is yellow, or red, etc.


What is "a color" for the purpose of your rounding? Every RGB value describes a particular colour.

Anyway, to pick a "nearest" colour, you must also define the "distance" between two colours. There are a few different ways to do this.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this