关于算法:如何比较两种颜色的相似度/差异 |
您所在的位置:网站首页 › 怎么对比两个图片 › 关于算法:如何比较两种颜色的相似度/差异 |
我想设计一个程序,可以帮助我评估5种预定义颜色之间的哪种颜色更类似于可变颜色,以及以什么百分比进行评估。 问题是我不知道如何一步一步地手动进行操作。 因此,想一个程序就更加困难了。 更多详细信息:颜色来自带有不同颜色的凝胶管的照片。 我有5个颜色不同的试管,每个试管代表5个级别中的1个。 我想拍摄其他样本的照片,然后在计算机上通过比较颜色来评估该样本属于哪个级别,我也想知道它的近似百分比。 我想要一个执行以下操作的程序:http://www.colortools.net/color_matcher.html 如果您可以告诉我要采取什么步骤,即使这些是我自己要手动思考和执行的事情。 这将非常有帮助。 相关讨论 我对文本进行了较小的更改,将葡萄牙语单词更改为我认为正确的英语等效单词...如果我犯了错误,请将其改回。 有一篇有关颜色差异的维基百科文章:en.wikipedia.org/wiki/Color_difference 这应该很有趣:stevehanov.ca/blog/index.php?id=116它探索计算三种不同颜色模型中的差异。 嘿@OcasoProtal,那真是个很棒的链接,感谢您的分享。对于OP,有趣的问题。 尽量减少任何潜在的照片变异性...更多详细信息,请参见下面的答案。 颜色逻辑算法的可能重复项 这并不是真正的编程逻辑解决方案,因此我不会将其标记为答案,但是该功能已经可以通过Adobe Kuler API获得。 learn.adobe.com/wiki/display/kulerdev/C.+样本-这是根据图像选择博客背景颜色的样本之一-gondaba.com-我怀疑为给定的颜色选择了相应的颜色难。当然,这会将您的程序耦合到您可能不需要的第三方API。 一些不错的颜色对比度检测算法:splitbrain.org/blog/2008-09/ 也许Lea verous游戏可能会有所帮助。 这个问题和近乎重复的数量有力地证明了标签色差别名为色差的情况有关正确的线索,请参见Wikipedia上有关色差的文章。 基本上,您想在某些多维色彩空间中计算距离度量。 但是RGB并不是"感知上均匀的",因此Vadim建议的欧几里得RGB距离度量将与人类感知的颜色之间的距离不匹配。首先,Lab *旨在成为可感知的统一色彩空间,并且通常使用deltaE度量。但是,还有更多精致的色彩空间和更多精致的deltaE公式更接近于匹配人类的感知。 您必须学习有关色空间和光源的更多信息才能进行转换。但是,要使用比欧几里得RGB度量更好的快速公式,只需执行以下操作:假设您的RGB值在sRGB色彩空间中,找到sRGB到Lab *的转换公式,将sRGB色彩转换为Lab *,然后计算之间的DeltaE您的两个Lab *值。它在计算上并不昂贵,它只是一些非线性公式以及一些乘加运算。 相关讨论 +1是" deltaE",这是最标准化的比较方法,并且deltaE公式适用于不同的用例。 您可以在此处找到转换公式:brucelindbloom.com/index.html?Equations.html 或者,如果您使用Ruby,请查看color gem,它在其他颜色操作中实现了deltaE。 这是上述Javascript实现的要点gist.github.com/ryancat/9972419b2a78f329ce3aebb7f1a09152只是我首先想到的一个想法(对不起,如果很愚蠢)。 颜色的三个分量可以假定为点的3D坐标,然后可以计算点之间的距离。 F.E. 12Point1 has R1 G1 B1 Point2 has R2 G2 B2颜色之间的距离为 1d=sqrt((r2-r1)^2+(g2-g1)^2+(b2-b1)^2)百分比为 1p=d/sqrt((255)^2+(255)^2+(255)^2) 相关讨论 如果使用RGB色彩空间,则2种颜色之间的差异与人类对差异的感知并不相同。但是是的,基本思想在任何地方都是相同的-只需要将其映射到另一个颜色空间中(实验室ID认为) @Voo:我同意,对于基于距离的相似度匹配,HSV / HSL / LAB比(s)RGB的色彩空间要好得多。 这是告诉您两种颜色的区别的好方法,但是告诉您两种颜色的区别却做得不好。人眼远非完美:对绿色比对红色或蓝色更敏感,我们对亮度的感知是对数的,等等。但请参阅此处,了解专门为人类视觉量身定制的算法。 +这也是我的第一个想法。 这里的另一个问题是255,0,0与0,255,0的距离相同,因为它是0,0,255。 我认为(1-p)* 100为相似百分比 天才的主意!我还没有想到。实际上,几个月前我走了同样的路。这个问题没有完美的答案(在这里被问了几次),但是有一个比sqrt(r-r)等答案更复杂的问题,并且更容易直接使用RGB,而无需移至所有其他可替换的色彩空间。我在这里找到了这个公式,它是相当复杂的真实公式的低成本近似值(通过CIE(即颜色的W3C),因为这不是一项尚未完成的任务,因此您可以在其中找到更旧,更简单的色差方程式。 祝好运 编辑:为了后代,这是相关的C代码: 123456789101112typedef struct { unsigned char r, g, b; } RGB; double ColourDistance(RGB e1, RGB e2) { long rmean = ( (long)e1.r + (long)e2.r ) / 2; long r = (long)e1.r - (long)e2.r; long g = (long)e1.g - (long)e2.g; long b = (long)e1.b - (long)e2.b; return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8)); } 相关讨论 这种方法对我有用。它帮助我从颜色名称列表中找到最接近的颜色。颜色值具有多个维度,因此没有比较两种颜色的内在方法。您必须为用例确定颜色的含义,从而确定如何最好地比较它们。 您最有可能希望比较与红色/绿色/蓝色分量相对的颜色的色相,饱和度和/或亮度属性。如果您在弄清楚如何比较它们时遇到困难,请获取一些成对的示例颜色并进行心理比较,然后尝试向自己证明/解释为什么它们相似/不同。 一旦知道要比较的颜色的哪些属性/成分,就需要弄清楚如何从颜色中提取该信息。 您很可能只需要将颜色从常见的RedGreenBlue表示形式转换为HueSaturationLightness,然后计算类似 12avghue = (color1.hue + color2.hue)/2 distance = abs(color1.hue-avghue)本示例将为您提供一个简单的标量值,该值指示颜色的渐变/色相彼此之间的距离。 请参阅Wikipedia上的HSL和HSV。 相关讨论 从我记得在讲这些东西的讲义中,我会将图像转换为Lab色彩空间,而不是HSV / HSL。选那个有什么理由吗? 不。我最熟悉RGB和HSL,因此我选择HSL只是为了强调"默认" RGB不是唯一的选择的想法-它实际上取决于应用程序。感谢您告知我有关Lab颜色空间的信息。 无论如何,我给了+1,因为这里的基本原理是"正确"的答案(在色彩空间中进行转换以统一处理感知到的差异,然后进行比较)。我不确定哪个空间是最好的-所有这些不同的颜色空间都让我感到困惑,imo;)如果您有两个Color对象c1和c2,则可以将c1中的每个RGB值与c2的每个RGB值进行比较。 123int diffRed = Math.abs(c1.getRed() - c2.getRed()); int diffGreen = Math.abs(c1.getGreen() - c2.getGreen()); int diffBlue = Math.abs(c1.getBlue() - c2.getBlue());您可以将这些值除以差异饱和度的数量(255),然后得到两者之间的差异。 123float pctDiffRed = (float)diffRed / 255; float pctDiffGreen = (float)diffGreen / 255; float pctDiffBlue = (float)diffBlue / 255;之后,您可以找到百分比的平均色差。 1(pctDiffRed + pctDiffGreen + pctDiffBlue) / 3 * 100这将使您在c1和c2之间的百分比有所不同。 相关讨论 还有2件事:1 pctDiffRed = diffRed 255;将给您0,除非您在某个地方使用浮点数。 2您需要在某处乘以100才能得到一个百分比。 这可能不会产生最佳的"可见"差异,因为人眼对颜色的感知不同。话虽如此,我猜测这正是她所寻找的,因为她可能正在寻找一个可量化的差异而不是一个预期的差异。只是想在这里将其标识为需要考虑的事情。通过人类感知比较两种颜色的最佳方法之一是CIE76。差异称为Delta-E。小于1时,人眼无法识别差异。 有很棒的颜色实用程序类ColorUtils(下面的代码),其中包括CIE76比较方法。它由苏黎世大学的Daniel Strebel撰写。 在ColorUtils.class中,我使用以下方法: 1static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)r1,g1,b1-第一种颜色的RGB值 r2,g2,b2-RGB值是您要比较的第二种颜色 如果您使用的是Android,则可以这样获得以下值: r1 = Color.red(pixel); g1 = Color.green(pixel); b1 = Color.blue(pixel); 苏黎世大学Daniel Strebel撰写的ColorUtils.class: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107import android.graphics.Color; public class ColorUtil { public static int argb(int R, int G, int B) { return argb(Byte.MAX_VALUE, R, G, B); } public static int argb(int A, int R, int G, int B) { byte[] colorByteArr = {(byte) A, (byte) R, (byte) G, (byte) B}; return byteArrToInt(colorByteArr); } public static int[] rgb(int argb) { return new int[]{(argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF}; } public static int byteArrToInt(byte[] colorByteArr) { return (colorByteArr[0] 0.04045){ blue2 = (blue2+0.055)/1.055; blue2 = Math.pow(blue2,2.4); } else{ blue2 = blue2/12.92; } red2 = (red2*100); green2 = (green2*100); blue2 = (blue2*100); var x = (red2 * 0.4124) + (green2 * 0.3576) + (blue2 * 0.1805); var y = (red2 * 0.2126) + (green2 * 0.7152) + (blue2 * 0.0722); var z = (red2 * 0.0193) + (green2 * 0.1192) + (blue2 * 0.9505); var xyzresult = new Array(); xyzresult[0] = x; xyzresult[1] = y; xyzresult[2] = z; return(xyzresult); } //end of rgb_to_xyz function function xyztolab(xyz){ //a convertor from xyz to lab model var x = xyz[0]; var y = xyz[1]; var z = xyz[2]; var x2 = x/95.047; var y2 = y/100; var z2 = z/108.883; if(x2>0.008856){ x2 = Math.pow(x2,1/3); } else{ x2 = (7.787*x2) + (16/116); } if(y2>0.008856){ y2 = Math.pow(y2,1/3); } else{ y2 = (7.787*y2) + (16/116); } if(z2>0.008856){ z2 = Math.pow(z2,1/3); } else{ z2 = (7.787*z2) + (16/116); } var l= 116*y2 - 16; var a= 500*(x2-y2); var b= 200*(y2-z2); var labresult = new Array(); labresult[0] = l; labresult[1] = a; labresult[2] = b; return(labresult);} 123456789101112131415161718192021222324 var canvas = document.getElementById('myCanvas'); var context = canvas.getContext('2d'); var imageX = 0; var imageY = 0; context.drawImage(imageObj1, imageX, imageY, 240, 140); var imageData = context.getImageData(0, 0, 240, 140); var data = imageData.data; var n = data.length; // iterate over all pixels var m = 0; for (var i = 0; i < n; i += 4) { var red = data[i]; var green = data[i + 1]; var blue = data[i + 2]; var xyzcolor = new Array(); xyzcolor = rgbtoxyz(red,green,blue); var lab = new Array(); lab = xyztolab(xyzcolor); constants.colorMap.push(lab); //fill up the colormap array with lab colors. } }// ------------------------------------------------ -------------------------------------------------- --- 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 function colorize(pixqty) { function deltae94(lab1,lab2){ //calculating Delta E 1994 var c1 = Math.sqrt((lab1[1]*lab1[1])+(lab1[2]*lab1[2])); var c2 = Math.sqrt((lab2[1]*lab2[1])+(lab2[2]*lab2[2])); var dc = c1-c2; var dl = lab1[0]-lab2[0]; var da = lab1[1]-lab2[1]; var db = lab1[2]-lab2[2]; var dh = Math.sqrt((da*da)+(db*db)-(dc*dc)); var first = dl; var second = dc/(1+(0.045*c1)); var third = dh/(1+(0.015*c1)); var deresult = Math.sqrt((first*first)+(second*second)+(third*third)); return(deresult); } // end of deltae94 function var lab11 = new Array("80","-4","21"); var lab12 = new Array(); var k2=0; var canvas = document.getElementById('myCanvas'); var context = canvas.getContext('2d'); var imageData = context.getImageData(0, 0, 240, 140); var data = imageData.data; for (var i=0; i 24), (argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF }; } public static int[] ColorToLab(int R, int G, int B) { // http://www.brucelindbloom.com double r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr; double Ls, fas, fbs; double eps = 216.0f / 24389.0f; double k = 24389.0f / 27.0f; double Xr = 0.964221f; // reference white D50 double Yr = 1.0f; double Zr = 0.825211f; // RGB to XYZ r = R / 255.0f; //R 0..1 g = G / 255.0f; //G 0..1 b = B / 255.0f; //B 0..1 // assuming sRGB (D65) if (r eps) fz = (float)Math.Pow(zr, 1 / 3.0); else fz = (float)((k * zr + 16.0) / 116); Ls = (116 * fy) - 16; fas = 500 * (fx - fy); fbs = 200 * (fy - fz); int[] lab = new int[3]; lab[0] = (int)(2.55 * Ls + 0.5); lab[1] = (int)(fas + 0.5); lab[2] = (int)(fbs + 0.5); return lab; } }一种仅使用RGB的简单方法是 12345cR=R1-R2 cG=G1-G2 cB=B1-B2 uR=R1+R2 distance=cR*cR*(2+uR/256) + cG*cG*4 + cB*cB*(2+(255-uR)/256)我已经使用了一段时间,它在大多数情况下都能正常工作。 相关讨论 使用以上公式,距离值的范围是多少 这与欧几里得色差近似非常接近。 我猜测它正在跳过根组件以加快计算速度,因此其范围是0到100 ^ 3。 如果要归一化为100,请距离13的幂我在我的android系统中使用了它,虽然不建议使用RGB空间,但似乎令人满意: 1234567891011 public double colourDistance(int red1,int green1, int blue1, int red2, int green2, int blue2) { double rmean = ( red1 + red2 )/2; int r = red1 - red2; int g = green1 - green2; int b = blue1 - blue2; double weightR = 2 + rmean/256; double weightG = 4.0; double weightB = 2 + (255-rmean)/256; return Math.sqrt(weightR*r*r + weightG*g*g + weightB*b*b); }然后,我使用以下代码获取相似性百分比: 123double maxColDist = 764.8339663572415; double d1 = colourDistance(red1,green1,blue1,red2,green2,blue2); String s1 = (int) Math.round(((maxColDist-d1)/maxColDist)*100) +"% match";它运作良好。 我希望您最后想分析整个图像,不是吗?因此,您可以检查与标识颜色矩阵的最小/最大差异。 大多数用于处理图形的数学运算都使用矩阵,因为使用它们的可能算法通常比经典的逐点距离和比较计算更快。 (例如,用于使用DirectX,OpenGL等的操作) 所以我认为您应该从这里开始: http://en.wikipedia.org/wiki/Identity_matrix http://en.wikipedia.org/wiki/Matrix_difference_equation ...并且正如Beska在上面已经评论的那样: This may not give the best"visible" difference... 这也意味着,如果要处理图像,算法将取决于您对"类似"的定义。 Kotlin版本,您要匹配多少百分比。 具有百分比可选参数的方法调用 1isMatchingColor(intColor1, intColor2, 95) // should match color if 95% similar方法主体 1234567891011121314151617181920212223242526private fun isMatchingColor(intColor1: Int, intColor2: Int, percent: Int = 90): Boolean { val threadSold = 255 - (255 / 100f * percent) val diffAlpha = abs(Color.alpha(intColor1) - Color.alpha(intColor2)) val diffRed = abs(Color.red(intColor1) - Color.red(intColor2)) val diffGreen = abs(Color.green(intColor1) - Color.green(intColor2)) val diffBlue = abs(Color.blue(intColor1) - Color.blue(intColor2)) if (diffAlpha > threadSold) { return false } if (diffRed > threadSold) { return false } if (diffGreen > threadSold) { return false } if (diffBlue > threadSold) { return false } return true }比较颜色的唯一"正确"方法是在CIELab或CIELuv中使用deltaE进行比较。 但是对于许多应用程序,我认为这是一个足够好的近似值: distance = 3 * |dR| + 4 * |dG| + 3 * |dB| 我认为加权曼哈顿距离在比较颜色时更有意义。请记住,原色只在我们的脑海中。它们没有任何物理意义。 CIELab和CIELuv是根据我们对颜色的感知进行统计建模的。 为了快速而肮脏,您可以 123456789import java.awt.Color; private Color dropPrecision(Color c,int threshold){ return new Color((c.getRed()/threshold), (c.getGreen()/threshold), (c.getBlue()/threshold)); } public boolean inThreshold(Color _1,Color _2,int threshold){ return dropPrecision(_1,threshold)==dropPrecision(_2,threshold); }利用整数除法量化颜色。 我尝试了各种方法,例如LAB色彩空间,HSV比较,并且发现光度可以很好地达到此目的。 这是Python版本 1234567891011121314151617181920212223242526def lum(c): def factor(component): component = component / 255; if (component |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |