Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to "round" a Color object to the nearest Color Constant?

Tags:

java

pixel

colors

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?

like image 371
Stormbreaker Avatar asked Jun 13 '11 18:06

Stormbreaker


People also ask

How do you find the distance between colors?

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*₂)².

What is the nearest color to red?

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.

How do you compare two colors in Java?

To compare two Color objects you can use the equals() method : Color « 2D Graphics « Java Tutorial. 16.10. 1.


2 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.

like image 65
Ted Hopp Avatar answered Oct 22 '22 05:10

Ted Hopp


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.

like image 3
Jonah Avatar answered Oct 22 '22 07:10

Jonah