使RGB获得最接近的颜色算法更准确

时间:2014-09-02 10:07:05

标签: java algorithm math colors rgb

我已经创建了一个包含名称和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;
        }
    }

3 个答案:

答案 0 :(得分:2)

我不知道你如何提出你的距离功能,但它有点尴尬。让我解释一下:

您使用颜色的比例而不是差异,如:

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)

。{/ 1}

好吧,假设col2col3距离col1等于:

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提到的那样,并不是最夸张的结果。 使用像欧几里得这样的距离函数。

答案 1 :(得分:1)

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

你做

之类的事情要好得多

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

getClose中的

答案 2 :(得分:0)

为了定义&#34;亲密度&#34;的衡量标准,您需要调整人眼的颜色感知以及可能的显示设备。

首先,一个通道中的X的距离比两个通道中的X / 2的距离差(色调的变化比可比较的亮度变化更明显)。单个通道距离越大,相似的&#34;相似的&#34;颜色是。简单地添加差异并不符合这一点。

实现距离的简单方法是通道之间的差异平方

 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;

这应该提供合理的亲密度功能。只需选择颜色距离最小的颜色即可。