【问题标题】:finding similar colors programmatically以编程方式查找相似的颜色
【发布时间】:2010-12-16 01:54:43
【问题描述】:

我在 java 中有一个缓冲图像,我想根据颜色值记录每个像素与另一个像素的相似程度。因此具有“相似”颜色的像素将具有更高的相似度值。例如,红色和粉色的相似度值为 1000,但红色和蓝色的相似度值为 300 或更少。

我该怎么做。当我从缓冲的图像像素中获取 RGB 时,它返回一个负整数,我不确定如何用它来实现。

【问题讨论】:

    标签: java colors


    【解决方案1】:

    首先,你是如何得到整数值的?

    获得 RGB 值后,您可以尝试

    ((r2 - r1)2 + (g2 - g1)2 + (b2 - b1)2)1 /2

    这将为您提供与两个点在 3D 空间中的距离,每个点由 (r1,g1,b1) 和 (r2,g2,b2) 指定。

    或者有更复杂的方法使用颜色的 HSV 值。

    【讨论】:

    • 我认为你在 (b2-b1); 之后遗漏了 ^2;无论如何,+1 因为我正要发布相同的内容
    • 这真的是您在 3D 空间中测量距离的方式吗?我会认为它会在某处涉及平方根?如果这行得通,那么它可以在 2d 空间中使用,而且你已经超越了毕达哥拉斯。
    • 他在取立方根,这是不正确的;它应该是平方根。但是不需要求根,因为您可以像比较距离本身一样容易地比较距离的平方,并且可以节省求根的时间。
    • 这个可以用来解决Robot.getPixelColor(int x, int y)的OSX颜色匹配差异的问题。
    【解决方案2】:

    最简单的方法是将两种颜色都转换为 HSV 值并找出 H 值的差异。最小的变化意味着颜色相似。不过,您可以自行定义阈值。

    【讨论】:

      【解决方案3】:

      您可能在每个像素上调用 getRGB(),它以 4 个 8 位字节返回颜色,高字节 alpha,下一个字节为红色,下一个字节为绿色,下一个字节为蓝色。您需要分离出通道。即使这样,RGB 空间中的颜色相似性也不是那么好——使用 HSL 或 HSV 空间可能会得到更好的结果。转换代码见here

      换句话说:

      int a = (argb >> 24) & 0xff;
      int r = (argb >> 16) & 0xff;
      int g = (argb >> 8) & 0xff;
      int b = argb & 0xff;
      

      我不知道java缓冲图像中具体的字节顺序,但我认为是对的。

      【讨论】:

      • -1 用于推荐 HSL 或 HSV。这些是临时转换,在现实世界中没有任何意义。它们是为早期的图形程序发明的。 Lab 空间中的距离是基于数百次真实眼睛和真实颜色实验的测量结果。
      【解决方案4】:

      您可以按如下方式获取单独的字节:

      int rgb = bufferedImage.getRGB(x, y); // Returns by default ARGB.
      int alpha = (rgb >>> 24) & 0xFF;
      int red = (rgb >>> 16) & 0xFF;
      int green = (rgb >>> 8) & 0xFF;
      int blue = (rgb >>> 0) & 0xFF;
      

      【讨论】:

        【解决方案5】:

        我建议你从这里开始阅读

        Color difference formulas 如果您想正确执行此操作。它解释了用于计算色差的ΔE*abΔE*94ΔE*00ΔE*CMC 公式。

        【讨论】:

          【解决方案6】:

          我发现 HSL 值更容易理解。 HSL Color 解释了它们的工作原理并提供了转换例程。与其他答案一样,您需要确定类似对您意味着什么。

          【讨论】:

            【解决方案7】:

            HSL 是一个糟糕的举动。 L*a*b 是一个色彩空间,旨在表示颜色的实际感知方式,它基于数百个实验的数据,这些实验涉及用真眼观察不同颜色并说“我能分辨出这两种颜色的人。但不是那两个”。

            L*a*b 空间中的距离表示根据这些实验得出的预测实际感知到的距离。

            转换为 L*a*b 后,您只需在 3D 空间中测量线性距离。

            【讨论】:

              【解决方案8】:

              这是一个与#1634206类似的问题。

              如果您正在寻找 RGB 空间中的距离,则欧几里得距离将起作用,假设您平等对待红色、绿色和蓝色值。

              如果您想对它们进行不同的加权,就像在将颜色/RGB 转换为灰度时通常所做的那样,您需要按不同的量加权每个组件。例如,使用流行的从 RGB 转换为 30% 红色 + 59% 绿色 + 11% 蓝色的灰度:

              d2 = (30*(r1-r2))**2 + (59*(g1-g2))**2 + (11*(b1-b2))**2;
              

              d2的值越小,(r1,g1,b1)(r2,g2,b2)的颜色越接近。

              但除了 RGB 之外,还有其他颜色空间可供选择,这可能更适合您的问题。

              【讨论】:

              • 这里的权重是伽马校正权重。虽然蓝色 (11) 对人类对亮度的感知没有太大贡献,但它们实际上在人类确定颜色距离方面做出了很大的区分。 compuphase.com/cmetric.htm 权重 2,4,3 更适合所述目的。我通过颜色距离 (2^24 * 2^24) 的每个排列运行 LAB (delta E) 并对它们进行平均。并且权重 22、43、35 更好(使用 LAB 作为人眼的替代物)。另外,我已经实现了加权欧几里得算法,太烂了!
              【解决方案9】:

              我试过了。 HSL/HSV 值绝对没有用。例如:

              • 所有 L=0 的颜色都是“黑色”(RGB 000000),尽管它们的 HSL 差异可能意味着颜色距离较大。

              • 所有 S=0 的颜色都是“灰色”阴影,尽管它们的 HSL 差异可能暗示色距较大。

              • H(色调)范围以“红色”阴影开始和结束,因此 H=0 和 H=[max](360° 或 100% 或 240,取决于应用程序)都是红色并且相互比较相似,但欧几里得HSL距离接近最大值。

              所以我的建议是使用没有根的欧几里得 RGB 距离 (r2-r1)² + (g2-g1)² + (b2-b1)²。 1000 的(主观)阈值适用于相似的颜色。差异大于 1000 的颜色很容易被人眼分辨。此外,对组件进行不同的加权也会很有帮助(参见上一篇文章)。

              【讨论】:

              • 色调是一个角度。你不能把它扔进欧几里得距离方程。您需要将其绘制为某种形状(圆柱体、圆锥体)内的空间位置,然后找到该形状内这些位置之间的距离。当您尝试这样做时,您会发现 HSV(360°, 1, 1) 和 HSV(0°, 1, 1) 完全不同,而实际上它们是完全相同的颜色(纯红色)。跨度>
              【解决方案10】:

              如果您要使用 HSV,您需要意识到 HSV 不是三维空间中的点,而是圆锥的角度、大小和距顶部的距离。要计算 HSV 值的距离,您需要通过变换确定 3d 空间中的点。

              X = Cos(H)*S*V

              Y = Sin(H)*S*V

              Z = V

              对于两个点,然后取它们之间的欧几里得距离:

              Sqrt((X0 - X1)*(X0 - X1) + (Y0 - Y1)*(Y0 - Y1) + (Z0 - Z1)*(Z0 - Z1))
              

              成本为 2 Cos、2 Sin 和平方根。

              或者,如果您愿意,实际上可以更容易地计算距离,方法是意识到当展平到 2D 空间时,您只需从原点有两个向量,并应用 cosign 定律来找到 XY 空间中的距离:

              C² = A² + B² + 2*A*B*Cos(Theta)
              

              其中 A = S*V 的第一个值,B = S*V 的第二个和 cosign 是差值 theta 或 H0-H1

              然后考虑 Z,将 2D 空间扩展到 3D 空间。

              A = S0*V0
              B = S1*V1
              dTheta = H1-H0
              dZ = V0-V1
              distance = sqrt(dZ*dZ + A*A + B*B + 2*A*B*Cos(dTheta);
              

              请注意,因为余符号定理给了我们 C²,所以我们只需将其与 Z 的变化一起插入其中。这需要 1 Cos 和 1 Sqrt。 HSV 非常有用,您只需要知道它所描述的色彩空间类型。您不能只是将它们打造成欧几里得函数并从中得到连贯的东西。

              【讨论】:

                【解决方案11】:

                关于这个问题有一篇有趣的论文:

                用于基于内容的图像和视频检索的具有相关颜色相似度度量的新感知均匀颜色空间 M. Sarifuddin 和 Rokia Missaoui

                您可以使用 Google 或特别是 [Google Scholar.][1] 轻松找到此内容。

                总而言之,一些颜色空间(例如 RGB、HSV、Lab)和距离度量(例如几何平均值和欧几里得距离)比其他颜色空间更能代表人类对颜色相似性的感知。该论文讨论了一种新的色彩空间,它比其他的更好,但它也提供了对常见的现有色彩空间和距离度量的很好的比较。定性*,使用常用颜色空间测量感知距离的最佳方法似乎是:HSV 颜色空间和圆柱距离测量。

                *至少,根据参考论文中的图 15。

                圆柱距离度量是(在 Latex 表示法中):

                D_{cyl} = \sqrt{\Delta V^{2}+S_1^{2}+S_2^{2}-2S_1S_2cos(\Delta H)}

                【讨论】:

                • 已经阅读了论文并实现了算法。基本上都是废话。这并不可怕,但它真的不比 HSV 好。 C 和 L 变量的推导很好,论文错误地列出了色调(如果您使用给定的绿色=红色的值)。图 15 如此接近是由于方法有缺陷。它拒绝颜色,直到它有足够的颜色来填充该区域。因此,任何色彩空间都根据其被给予的拒绝阈值进行分级,并且 NOT 它能够正确反映普通人将衡量为最不同颜色的内容。这甚至还不是所有的错误。
                【解决方案12】:
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-13
                • 2011-12-12
                • 2011-12-16
                • 2015-12-06
                • 2021-03-31
                • 1970-01-01
                相关资源
                最近更新 更多