[英]Make a Sim Hash (Locality Sensitive Hashing) Algorithm more accurate?
[英]Making an RGB get closest colour algorithm more accurate
我创建了一个包含名称和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;
}
}
我不知道您是如何提出距离功能的,但是有点尴尬。 让我解释:
您使用颜色的比例,而不是像这样的差异:
float lastColorCloseness = (getClose(red, lastColor.red) + getClose(green, lastColor.green) + getClose(blue, lastColor.blue)) / 3f;
这具有奇怪的效果,即不相等地应用于相等距离的颜色。 例如比较col1(100, 50, 200)
col2(50, 100, 150)
col1(100, 50, 200)
与col2(50, 100, 150)
col3(150, 100, 250)
col2(50, 100, 150)
和col3(150, 100, 250)
。
好吧,假设col2
和col3
与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所说,这并不是最夸张的结果。 请改用欧几里得距离函数。
发生这种情况是因为您的getClose
方法做得不好。 如果两个数字都非常小,则它们之间的距离会大大放大。
做类似这样的事情会更好
1 /(1 +(firstNumber-secondNumber)*(firstNumber-secondNumber))
在getClose
。
为了定义“紧密度”的量度,您需要调整人眼的色彩感知能力,可能还需要调整显示设备。
首先,一个通道中的X距离比两个通道中的X / 2距离差(色调变化比亮度的可比变化更明显)。 单通道距离越大,颜色越“相似”。 简单地添加差异并不能解决这个问题。
一种简单的距离测量方法是通道之间的平方差:
int deltaR = red1 - red2;
int deltaG = green1 - green2;
int deltaB = blue1 - blue2;
int distance = (deltaR * deltaR) + (deltaG * deltaG) + (deltaB * deltaB);
人眼对每个颜色通道的敏感度都不相同。 因此,您可能需要为此调整加权颜色通道。 可以从RGB到灰度级加权( 将RGB转换为灰度/强度 )得出简单的权重
修改权重的距离函数可以得出:
float distance = (deltaR * deltaR) * 0.2989F
+ (deltaG * deltaG) * 0.5870F
+ (deltaB * deltaB) * 0.1140F;
那应该提供一个合理的关闭功能。 只需选择颜色距离最小的颜色即可。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.