【Unity】计算颜色色差,近似颜色识别,实现油漆桶工具

想要做一个工具,自动化把贴图中的所有主色调区域区分开,以便逐步为各个主色调区域单独上色。所以需要将贴图中颜色近似的区域区分开,看似非常简单,其实不然。常用的RGB或HSV颜色模型,由三个变量共同控制着颜色,如何合并成一个因子呢?经过查阅资料最终选用了一个效率和准确度相对平衡的算法。

最简单的方式就是转化为颜色空间的距离,即:distance² = (R2 - R1)² + (G2 - G1)² + (B2 - B1)²

但是人类的眼睛对于红、绿、蓝的敏感度也是不同的,这就可能造成数值上distance很小,但肉眼识别颜色感觉色差很大。因此就引入了一个RGB权重的问题,人眼越敏感的颜色权重值越大。麻烦的是在不同的色值下人类对RGB的敏感权重不同,比如R < 128 和 R ≥ 128时的敏感权重就不同:

取两个颜色R的平均值,计为averageR:

averageR = (R1 + R2) / 2

averageR < 128时:distance² = 2 * (R2 - R1)² + 4 * (G2 - G1)² + 3 * (B2 - B1)²

averageR ≥ 128时:distance² = 3 * (R2 - R1)² + 4 * (G2 - G1)² + 2 * (B2 - B1)²

还可以把两种情况的权重平滑过度,变成一个公式:

distance² = (2 + averageR / 255f) * (R2 - R1)² + 4 * (G2 - G1)² + (2 + (255 - averageR) / 255f) * (B2 - B1)²

最后最终的结果distance归一化到0-1

下面是C#实现,需要做后处理可以照搬shader中实现:

    public class ColorExt
    {
        public static float Difference(Color c1, Color c2)
        {
            c1 *= 255; c2 *= 255;
            var averageR = (c1.r + c2.r) * 0.5f;
            return Mathf.Sqrt((2 + averageR / 255f) * Mathf.Pow(c1.r - c2.r, 2) + 4 * Mathf.Pow(c1.g - c2.g, 2) + (2 + (255 - averageR) / 255f) * Mathf.Pow(c1.b - c2.b, 2)) / (3 * 255f);
        }
    }

返回值为色差,取值范围0-1。颜色越近似返回值越小,比如相同颜色返回值为0,白色与黑色返回值为1.

算法参考:

https://en.wikipedia.org/wiki/Color_difference

猜你喜欢

转载自blog.csdn.net/final5788/article/details/117374481