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?
In order to measure the difference between two colors, the difference is assigned to a distance within the color space. In an equidistant-method color space, the color difference ∆E can be determined from the distance between the color places: ΔE = √ (L*₁-L*₂)² + (a*₁-a*₂)² + (b*₁-b*₂)².
Scarlet is best described as a very bright red with a hint of orange. It is the closest to pure red of all the tones represented here, and the distinction may not be obvious, but as can be seen from the colour code, there is a small tint of green light incorporated.
To compare two Color objects you can use the equals() method : Color « 2D Graphics « Java Tutorial. 16.10. 1.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With