【发布时间】:2011-09-14 03:03:14
【问题描述】:
我将检索像素的确切颜色,并希望将该确切颜色与Color.blue 等常量相关联。有没有一种简单的方法可以“四舍五入”到最近的颜色常数?另外,有没有办法定义你自己的颜色常数?
【问题讨论】:
我将检索像素的确切颜色,并希望将该确切颜色与Color.blue 等常量相关联。有没有一种简单的方法可以“四舍五入”到最近的颜色常数?另外,有没有办法定义你自己的颜色常数?
【问题讨论】:
基本方法是通过简单地将样品与每种颜色进行比较来找到与您的样品最接近的标准颜色。当然,问题在于定义“最接近”。最明显的是在 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() 的调用,从而节省一些计算成本。
【讨论】:
可能最好的方法是循环遍历每个常量,并比较它们各自的 RGB 通道(getRed、getGreen、getBlue)。跟踪最近的那个。
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 的链接。
【讨论】:
MyColor 扩展 Color 类以保留旧常量和您的常量。
您可以将 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];
}
}
【讨论】: