【问题标题】:What's the best way to "round" a Color object to the nearest Color Constant?将颜色对象“四舍五入”到最接近的颜色常数的最佳方法是什么?
【发布时间】:2011-09-14 03:03:14
【问题描述】:

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

【问题讨论】:

    标签: java colors pixel


    【解决方案1】:

    基本方法是通过简单地将样品与每种颜色进行比较来找到与您的样品最接近的标准颜色。当然,问题在于定义“最接近”。最明显的是在 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() 的调用,从而节省一些计算成本。

    【讨论】:

    • 那篇论文提出了一个有趣的观点,我必须承认我以前从未考虑过,可能没有客观的答案来回答这样的问题,“这些颜色中的哪一个与这个最相似一?”我们可以发明一个可以客观应用的规则——比如差的平方和——但这并不意味着这个规则是“真的”。 (例如,我可以将“最佳总统候选人”定义为最高的人,这很容易衡量。但可衡量并不能成为一个好的规则。)
    • 如果调用函数时使用了两种相同的颜色(实际上是相同的颜色)——例如 colorDistance(0x123456, 0x123456),函数是否保证返回 0?只有在这种情况下它才会返回 0?
    • @Jamrelian - 是的,如果两种颜色相同,我发布的代码和链接论文中的完整公式都将返回 0。此外,两个公式都将为两种不同的颜色返回非零结果。
    【解决方案2】:

    可能最好的方法是循环遍历每个常量,并比较它们各自的 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 的链接。

    【讨论】:

    • 另外,您可以让 MyColor 扩展 Color 类以保留旧常量和您的常量。
    • 您无法像比较 RGB 组件那样真正比较 Alpha 通道。
    • @Jay:好点,反正没有一个常量是透明的。
    • 乔纳,非常感谢您的帮助。您最初的回答让我想起了一个我稍微考虑过的模糊想法。泰德的论文给了我更多的思考。再次感谢您的帮助 - 我可能会创建自己的类来定义更具体的常量。
    • 小点:为了效率,我不会费心取平方根。这不会影响排序 - 如果 x>y 然后 sqrt(x)>sqrt(y) - 只是需要更多时间来计算。
    【解决方案3】:

    您可以将 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];
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-05-02
      • 2016-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-21
      相关资源
      最近更新 更多