use*_*nan 3 algorithm rgb colors
我想找到颜色名称,给出它的 RGB 值。
RGB 值示例为:(237, 65, 83)
预定义值
数组(11, '红色', '#FF0000', '255,0,0'),
array(3, '棕色', '#A52A2A', '165,42,42')
如果我使用这种方法距离计算
我得到的颜色是棕色的。
但如果我们在这里测试 RGB 值,实际颜色是红色
已编辑 1
<?php
$colors = array(
array(1, 'Black', '#000000', '0,0,0'),
array(2, 'Blue', '#0000FF', '0,0,255'),
array(3, 'Brown', '#A52A2A', '165,42,42'),
array(4, 'Cream', '#FFFFCC', '255,255,204'),
array(5, 'Green', '#008000', '0,128,0'),
array(6, 'Grey', '#808080', '128,128,128'),
array(7, 'Yellow', '#FFFF00', '255,255,0'),
array(8, 'Orange', '#FFA500', '255,165,0'),
array(9, 'Pink', '#FFC0CB', '255,192,203'),
array(11, 'Red', '#FF0000', '255,0,0'),
array(10, 'Purple', '#800080', '128,0,128'),
array(12, 'Tan', '#d2b48c', '210,180,140'),
array(13, 'Turquoise', '#40E0D0', '64,224,208'),
array(14, 'White', '#FFFFFF', '255,255,255')
);
$miDist = 99999999999999999 ;
$loc = 0 ;
$findColor = RGBtoHSV(72, 70, 68);
for( $i = 0 ; $i < 14 ; $i++){
$string = $colors[$i][3];
$pieces = explode(',' , $string);
$r0 = $pieces[0];
$g0 = $pieces[1];
$b0 = $pieces[2];
$storedColor = RGBtoHSV($r0,$g0,$b0);
echo $storedColor[0] ."-" . $storedColor[1] ;
// distance between colors (regardless of intensity)
$d = sqrt( ($storedColor[0]-$findColor[0])
*($storedColor[0]-$findColor[0])
+
($storedColor[1]-$findColor[1])
*($storedColor[1]-$findColor[1])
);
echo $colors[$i][1] ."=" .$d;
//echo $d ;
if( $miDist >= $d )
{
$miDist = $d;
$loc = $i ;
}
echo "<br>" ;
}
echo $colors[$loc][1];
function RGBtoHSV($R, $G, $B) // RGB values: 0-255, 0-255, 0-255
{ // HSV values: 0-360, 0-100, 0-100
// Convert the RGB byte-values to percentages
$R = ($R / 255);
$G = ($G / 255);
$B = ($B / 255);
// Calculate a few basic values, the maximum value of R,G,B, the
// minimum value, and the difference of the two (chroma).
$maxRGB = max($R, $G, $B);
$minRGB = min($R, $G, $B);
$chroma = $maxRGB - $minRGB;
// Value (also called Brightness) is the easiest component to calculate,
// and is simply the highest value among the R,G,B components.
// We multiply by 100 to turn the decimal into a readable percent value.
$computedV = 100 * $maxRGB;
// Special case if hueless (equal parts RGB make black, white, or grays)
// Note that Hue is technically undefined when chroma is zero, as
// attempting to calculate it would cause division by zero (see
// below), so most applications simply substitute a Hue of zero.
// Saturation will always be zero in this case, see below for details.
if ($chroma == 0)
return array(0, 0, $computedV);
// Saturation is also simple to compute, and is simply the chroma
// over the Value (or Brightness)
// Again, multiplied by 100 to get a percentage.
$computedS = 100 * ($chroma / $maxRGB);
// Calculate Hue component
// Hue is calculated on the "chromacity plane", which is represented
// as a 2D hexagon, divided into six 60-degree sectors. We calculate
// the bisecting angle as a value 0 <= x < 6, that represents which
// portion of which sector the line falls on.
if ($R == $minRGB)
$h = 3 - (($G - $B) / $chroma);
elseif ($B == $minRGB)
$h = 1 - (($R - $G) / $chroma);
else // $G == $minRGB
$h = 5 - (($B - $R) / $chroma);
// After we have the sector position, we multiply it by the size of
// each sector's arc (60 degrees) to obtain the angle in degrees.
$computedH = 60 * $h;
return array($computedH, $computedS, $computedV);
}
?>
Run Code Online (Sandbox Code Playgroud)
因此,如果您想要两种颜色之间的距离(r0,g0,b0)并(r1,g1,b1)检测最接近的颜色,无论其强度如何(这就是本例中基色的含义),您应该
// variables
int r0,g0,b0,c0;
int r1,g1,b1,c1,d;
// color sizes
c0=sqrt(r0*r0+g0*g0+b0*b0);
c1=sqrt(r1*r1+g1*g1+b1*b1);
// distance between normalized colors
d = sqrt((r0*c1-r1*c0)^2 + (g0*c1-g1*c0)^2 + (b0*c1-b1*c0)^2) / (c0*c1);
Run Code Online (Sandbox Code Playgroud)
比较深色时,这种方法会变得不稳定,因此您可以添加简单的条件,例如
if (c0<treshold) color is dark
Run Code Online (Sandbox Code Playgroud)
并且仅将这种颜色与灰色阴影进行比较或返回未知颜色。我们的视觉工作原理类似,我们无法安全地识别深色......
无论如何,HSV 颜色空间更适合颜色比较,因为它更类似于人类颜色识别。因此,转换RGB -> HSV和计算距离忽略V颜色强度值......
在HSV中,您需要将其处理H为周期性整圆值,因此变化只能是圆大的一半。S告诉您它是颜色还是灰度,必须单独处理,并且V是强度。
if (c0<treshold) color is dark
Run Code Online (Sandbox Code Playgroud)
有些事情需要比较...
您应该对源进行目视检查,以实际了解发生了什么,否则您将原地踏步而没有任何结果。例如,我刚刚在C++/VCL/mine 图像类中编写了这个代码:
// variables
int h0,s0,v0;
int h1,s1,v1,d,q;
q=h1-h0;
if (q<-128) q+=256; // use shorter angle
if (q>+128) q-=256; // use shorter angle
q*=q; d =q;
q=s1-s0; q*=q; d+=q;
if (s0<32) // grayscales
{
d=0; // ignore H,S
if (s1>=32) continue; // compare only to gray-scales so ignore this color
}
q=v1-v0; q*=q; d+=q;
Run Code Online (Sandbox Code Playgroud)
您可以忽略这些pic0内容,它只是对图像的像素访问。我在 RGB 距离方程中添加了一些怪癖来移动子结果,使它们适合 32 位,int以避免溢出。我使用这张图片作为输入:
然后对于每个像素,从LUT中找到相应的基色。这是结果:
左边是源图像,然后是朴素的RGB比较,然后是标准化RGB比较(无法区分相同的色调),右边是HSV比较。
对于标准化RGB,找到的颜色始终是LUT中颜色相同但强度不同的第一个颜色。比较仅选择较暗的颜色,因为它们位于LUT中的第一个。
正如我之前提到的,深色和灰度颜色是有问题的,应该单独处理。如果您得到类似的结果但检测仍然错误,那么您需要添加更多的基色来弥补差距。如果您根本没有类似的结果,那么您很可能遇到以下问题:
<0,255>溢出某处
当数字相乘时,所使用的位被相加!所以
8bit * 8bit * 8bit * 8bit = 32bit
Run Code Online (Sandbox Code Playgroud)
如果数字有符号,你就有麻烦了......如果像我在上面的例子中一样使用 32 位变量,那么你需要稍微改变范围或在间隔上使用FPU<0.0,1.0>。
为了确保万一您遇到问题,我还添加了我的HSV/RGB转换。
这里是原始 HSV 生成的转换: