I will be retrieving the exact color of a pixel and would like to relate that exact color to a constant like Color.blue
. Is there an easy way to "round" to the nearest Color Constant? Additionally, is there a way to define your own Color Constants?

- 133
- 1
- 5
3 Answers
The basic approach is to find the closest standard color to your sample by simply comparing the sample to each of them. The problem, of course, is in defining "closest." The most obvious would be use the Euclidean distance in RGB space. The problem is that this distance does not correspond very well with our perceptual sense of "closest color". A discussion of this problem, along with a nice (easily computed) metric (including pseudocode!) can be found in this paper.
EDIT: Just in case the link to that paper goes dead (or if you're lazy and are willing to use code without understanding what it does), here's my Java version of the "color distance function" the paper suggests as a "low-cost approximation" to their recommended distance function (a weighted Euclidean distance in RGB space):
double colorDistance(Color c1, Color c2)
{
int red1 = c1.getRed();
int red2 = c2.getRed();
int rmean = (red1 + red2) >> 1;
int r = red1 - red2;
int g = c1.getGreen() - c2.getGreen();
int b = c1.getBlue() - c2.getBlue();
return Math.sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}
Note that if you're just going to rank color distances, you can dispense with the call to Math.sqrt()
, saving some computation costs.

- 232,168
- 48
- 399
- 521
-
1That paper brings up the interesting point, which I must admit I've never previously considered, that there may not be an objective answer to a question like, "Which of these colors is most similar to this one?" We can invent a rule that can be objectively applied -- like sum of the squares of the differences -- but that doesn't mean that the rule is "true". (Like, I could define the "best candidate for president" as the one who is tallest, which is easily measurable. But being measurable doesn't make it a good rule.) – Jay Jun 13 '11 at 20:54
-
If the function is called with two equal colors (actually the same color) - e.g colorDistance(0x123456, 0x123456), is the function guaranteed to return 0? And only in this case it will return 0? – TechAurelian Jul 16 '15 at 13:12
-
1@Jamrelian - Yes, both the code I posted and the full formula in the linked paper will return 0 if the two colors are identical. Also, both formulas will return a non-zero result for two different colors. – Ted Hopp Jul 16 '15 at 15:39
Probably the best way would be to loop over every constant, and comparing their respective RGB channels (getRed
, getGreen
, getBlue
). Keep track of the one that is closest.
Color color = new Color(...);
Color[] constantColors = new Color[] { Color.black, Color.blue, Color.cyan, Color.darkGray, Color.gray, Color.green, Color.lightGray, Color.magenta, Color.orange, Color.pink, Color.red, Color.white, Color.yellow };
Color nearestColor = null;
Integer nearestDistance = new Integer(Integer.MAX_VALUE);
for (Color constantColor : constantColors) {
if (nearestDistance > Math.sqrt(
Math.pow(color.getRed() - constantColor.getRed(), 2)
- Math.pow(color.getGreen() - constantColor.getGreen(), 2)
- Math.pow(color.getBlue() - constantColor.getBlue(), 2)
)
) {
nearestColor = color;
}
}
No, you can't add color constants to the class, but you can create a class of your own to hold constants.
class MyColors {
public static final Color heliotrope = new Color(...);
}
Edit: added difference algorithm, thanks to @Ted's link.
-
1Also, you could have `MyColor` extend the `Color` class to preserve the old constants along with yours. – Anko - inactive in protest Jun 13 '11 at 18:16
-
You can't really compare an alpha channel in the same way you compre RGB components. – Jay Jun 13 '11 at 18:25
-
-
Jonah, thank you very much for your help. Your original answer reminded me of a vague idea I had given a little thought to. Ted's paper has given me even more to think about. Thanks again for your help - I'll probably make my own class to define more specific constants. – Stormbreaker Jun 13 '11 at 18:47
-
2Small point: For efficiency, I wouldn't bother taking the square root. That doesn't affect the ordering -- if x>y then sqrt(x)>sqrt(y) -- and it just takes more time to compute. – Jay Jun 13 '11 at 20:56
-
You can use Java's built-in color conversion with an IndexColorModel
containing the palette of possible colors. Internally, the class uses Euclidean distance over the color components to determine the closest color.
import java.awt.Color;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
public class ColorConverter {
private final Color[] colors;
private final IndexColorModel colorModel;
public ColorConverter(Color[] colors) {
this.colors = colors;
this.colorModel = createColorModel(colors);
}
private static IndexColorModel createColorModel(Color[] colors) {
final int[] cmap = new int[colors.length];
for (int i = 0; i<colors.length; i++) {
cmap[i] = colors[i].getRGB();
}
final int bits = (int) Math.ceil(Math.log(cmap.length)/Math.log(2));
return new IndexColorModel(bits, cmap.length, cmap, 0, false, -1, DataBuffer.TYPE_BYTE);
}
public Color nearestColor(Color color) {
final byte index = ((byte[])colorModel.getDataElements(color.getRGB(), null))[0];
return colors[index];
}
}

- 12,081
- 6
- 50
- 65