将Color对象“舍入”到最接近的颜色常量的最佳方法是什么?

时间:2011-06-13 18:06:38

标签: java colors pixel

我将检索像素的确切颜色,并希望将该确切颜色与Color.blue之类的常量相关联。有没有一种简单的方法可以“舍入”到最近的颜色常数?另外,有没有办法定义自己的颜色常数?

3 个答案:

答案 0 :(得分:18)

基本方法是通过简单地将样本与每个样本进行比较,找到最接近样本的标准颜色。当然,问题在于定义“最接近的”。最明显的是使用RGB空间中的欧几里德距离。问题是这个距离与我们对“最接近的颜色”的感知感很不一致。可以在this paper中找到对此问题的讨论,以及一个很好的(易于计算的)度量(包括伪代码!)。

编辑:以防万一到那篇论文的链接已经死了(或者如果你很懒,并且愿意使用代码而不理解它的作用),这里是我的Java版本的“色距函数”推荐距离函数的“低成本近似”(RGB空间中的加权欧氏距离):

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));
}

请注意,如果您只想对颜色距离进行排名,则可以省去对Math.sqrt()的调用,从而节省一些计算成本。

答案 1 :(得分:3)

可能最好的方法是循环每个常量,并比较各自的RGB通道(getRedgetGreengetBlue)。跟踪最接近的那个。

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;
    }
}

不,你不能在类中添加颜色常量,但你可以创建一个自己的类来保存常量。

class MyColors {
    public static final Color heliotrope = new Color(...);
}

修改:添加差异算法,感谢@ Ted的链接。

答案 2 :(得分:1)

您可以使用Java的内置颜色转换,其中IndexColorModel包含可能颜色的调色板。在内部,该类使用颜色分量上的欧几里德距离来确定最接近的颜色。

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];
    }
}