【问题标题】:Making an RGB get closest colour algorithm more accurate使 RGB 最接近颜色算法更准确
【发布时间】:2014-10-26 13:37:57
【问题描述】:

我已经创建了一个包含名称和 RGB 值的巨大颜色列表(花了很长时间)现在我创建了一个算法,可以将相应的颜色获取到最接近的值。

它似乎工作得很好,但有时当有一个完全没有的奇数值时,它会得到错误的颜色。

示例输出

Log: InputRGB: R:7.1009636 | G:83.84344 | B:2.5013387
Log: ColorToCompare: Ball Blue (R13.0,G67.0,B80.0) CLOSE:0.4588677 | CurrentColor: Acid Green CLOSE: 0.41585693
Log: ColorToCompare: Bitter Lemon (R79.0,G88.0,B5.0) CLOSE:0.5143066 | CurrentColor: Ball Blue CLOSE: 0.4588677
Log: ColorToCompare: Citrine (R89.0,G82.0,B4.0) CLOSE:0.5610447 | CurrentColor: Bitter Lemon CLOSE: 0.5143066
Log: ColorToCompare: Smoky Black (R6.0,G5.0,B3.0) CLOSE:0.57945675 | CurrentColor: Citrine CLOSE: 0.5610447
Log: ColorName:Smoky Black
Log: End Color: R:6.0 G:5.0 B:3.0
Log: InputRGB:    R:7.1009636 | G:83.84344 | B:2.5013387

我为计算这个而创建的代码:

   public String getClosetColor(float red, float green, float blue){

        Functions.log("InputRGB: R:" + red + " | G:" + green + " | B:" + blue);

        Color lastColor = null;
        for(Color eachColor : this.colors)
        {
            if(lastColor == null){
                lastColor = eachColor;
            }

            float lastColorCloseness = (getClose(red, lastColor.red) + getClose(green, lastColor.green) + getClose(blue, lastColor.blue)) / 3f;
            float thisColorCloseness = (getClose(red, eachColor.red) + getClose(green, eachColor.green) + getClose(blue, eachColor.blue)) / 3f;

            if(Float.isFinite(thisColorCloseness) && Float.isFinite(lastColorCloseness))
            {
                //If they are the same, choose a random one.
                if(lastColorCloseness == thisColorCloseness){
                    if(MathUtils.random() > 0.5f){
                        lastColor = eachColor;
                    }
                }
                //If this one is greater then set it.
                else if(thisColorCloseness > lastColorCloseness){
                    Functions.log(
                            "ColorToCompare: " + eachColor.nameOfColor + " (R" + eachColor.red + ",G" + eachColor.green + ",B" + eachColor.blue + ") CLOSE:" + thisColorCloseness +
                                    " | CurrentColor: " + lastColor.nameOfColor + " CLOSE: " + lastColorCloseness
                    );

                    lastColor = eachColor;
                }
            }
        }

        Functions.log("ColorName:" + lastColor.nameOfColor);
        Functions.log("End Color: R:" + lastColor.red + " G:" + lastColor.green + " B:" + lastColor.blue);
        Functions.log("InputRGB:    R:" + red + " | G:" + green + " | B:" + blue);

        return "";
    }

    //Basically if one is higher than the other then devide by it.
    private float getClose(float firstNumber, float secondNumber){
        if(firstNumber < secondNumber){
            return firstNumber / secondNumber;
        }
        else{
            return secondNumber / firstNumber;
        }
    }

【问题讨论】:

标签: java algorithm math colors rgb


【解决方案1】:

我不知道你是怎么想出你的距离函数的,但这有点尴尬。让我解释一下:

你使用颜色的比例而不是像这样的差异:

float lastColorCloseness = (getClose(red, lastColor.red) + getClose(green, lastColor.green) + getClose(blue, lastColor.blue)) / 3f;

这有一个奇怪的效果,即不能同等地应用于等距离的颜色。例如比较 col1(100, 50, 200)col2(50, 100, 150)col3(150, 100, 250)

好吧,假设col2col3col1 的距离等于:

abs(100-50)+abs(50-100)+abs(200-150)=150
abs(100-150)+abs(50-100)+abs(200-250)=150

你的距离函数给出了不同的结果:

(50/100+50/100+150/250)/3=0.53
(50/100+50/100+200/250)/3=0.6

正如@David Wallace 所说,这并不是最夸张的结果。 改用欧几里得之类的距离函数。

【讨论】:

    【解决方案2】:

    发生这种情况是因为您的 getClose 方法做得不好。如果两个数字都非常小,那么它们之间的差距就被大大夸大了。

    你最好做一些类似的事情

    1 / ( 1 + ( firstNumber - secondNumber ) * ( firstNumber - secondNumber ))

    getClose.

    【讨论】:

      【解决方案3】:

      为了定义“接近度”的衡量标准,您需要根据人眼的颜色感知以及可能的显示设备进行调整。

      首先,一个通道中 X 的距离比两个通道中 X/2 的距离差(色调变化比亮度变化更明显)。单通道距离越大,颜色就越不“相似”。简单地添加差异并不适用。

      一个简单的距离度量是通道之间的差异平方

       int deltaR = red1 - red2;
       int deltaG = green1 - green2;
       int deltaB = blue1 - blue2;
       int distance = (deltaR * deltaR) + (deltaG * deltaG) + (deltaB * deltaB);
      

      人眼对每个颜色通道的敏感度不同。因此,您可能需要为此调整加权颜色通道。一个简单的加权可以从 RGB 导出到灰度加权 (Converting RGB to grayscale/intensity)

      修改权重的距离函数给出:

       float distance = (deltaR * deltaR) * 0.2989F
                      + (deltaG * deltaG) * 0.5870F
                      + (deltaB * deltaB) * 0.1140F;
      

      这应该提供一个合理的接近函数。只需选择色距最小的颜色即可。

      【讨论】:

        猜你喜欢
        • 2019-07-02
        • 1970-01-01
        • 2019-08-17
        • 2011-05-27
        • 2011-05-09
        • 2016-11-13
        • 1970-01-01
        相关资源
        最近更新 更多