RGB 值基础颜色名称

3

我想找到一种颜色的名称,给定它的RGB值。

例如,RGB值为:(237,65,83)

预定义值

array(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);
 }

 ?>

否则,我将把它转换为十六进制,并找到最接近的匹配,那么我会得到正确的输出吗? - usernan
将注释移动到答案中。 - Spektre
你可以使用这个挑战中的代码。 - justhalf
你可以查看以下链接:https://github.com/mattfordham/Name-That-Color---Sublime-Plugin/blob/master/name_that_color.py - albttx
1个回答

5

如果你想要获取两个颜色之间的距离(r0,g0,b0)(r1,g1,b1),以便无论其强度如何都可以检测最接近的颜色(在这种情况下,基础颜色是什么意思),你应该:

  1. 将颜色向量归一化到相同的大小
  2. 计算距离
  3. 将结果缩放回去
// 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);

这种方法在比较深色时会变得不稳定,因此您可以添加简单的条件,例如:
if (c0<treshold)  color is dark 

只有将颜色与灰色阴影进行比较,或者返回未知颜色。我们的视觉工作方式类似,我们无法安全地识别暗色。
无论如何,HSV颜色空间更适合颜色比较,因为它更好地类似于人类的颜色识别。所以将RGB转换为HSV并计算距离,忽略颜色强度(V)...
在HSV中,需要将H处理为周期性的完整圆值,因此变化只能是半个圆。S告诉您它是彩色还是灰度图像,这需要分别处理,而V则是强度。
// 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;

一些需要比较的事情...

你应该对源代码进行视觉检查,以实际看到发生了什么,否则你将会在循环中打转而无法得到任何结果。例如,我刚刚在C++/VCL/我的图像类中编写了以下代码:

union color
    {
    DWORD dd; WORD dw[2]; byte db[4];
    int i; short int ii[2];
    color(){}; color(color& a){ *this=a; }; ~color(){}; color* operator = (const color *a) { dd=a->dd; return this; }; /*color* operator = (const color &a) { ...copy... return this; };*/
    };

    enum{ // this is inside my picture:: class
        _x=0,   // dw
        _y=1,

        _b=0,   // db
        _g=1,
        _r=2,
        _a=3,

        _v=0,   // db
        _s=1,
        _h=2,
        };

void rgb2hsv(color &c)
    {
    double r,g,b,min,max,del,h,s,v,dr,dg,db;
    r=c.db[picture::_r]; r/=255.0;
    g=c.db[picture::_g]; g/=255.0;
    b=c.db[picture::_b]; b/=255.0;
    min=r; if (min>g) min=g; if(min>b) min=b;
    max=r; if (max<g) max=g; if(max<b) max=b;
    del=max-min;
    v=max;
    if (del<=1e-10) { h=0; s=0; }   // grayscale
    else{
        s=del/max;
        dr=(((max-r)/6.0)+(del/2.0))/del;
        dg=(((max-g)/6.0)+(del/2.0))/del;
        db=(((max-b)/6.0)+(del/2.0))/del;
        if      (fabs(r-max)<1e-10) h=db-dg;
        else if (fabs(g-max)<1e-10) h=(1.0/3.0)+dr-db;
        else if (fabs(b-max)<1e-10) h=(2.0/3.0)+dg-dr;
        if (h<0.0) h+=1.0;
        if (h>1.0) h-=1.0;
        }
    c.db[picture::_h]=h*255.0;
    c.db[picture::_s]=s*255.0;
    c.db[picture::_v]=v*255.0;
    }

void hsv2rgb(color &c)
    {
    int i;
    double r,g,b,h,s,v,vh,v1,v2,v3,f;
    h=c.db[picture::_h]; h/=255.0;
    s=c.db[picture::_s]; s/=255.0;
    v=c.db[picture::_v]; v/=255.0;
    if (s<=1e-10) { r=v; g=v; b=v; }    // grayscale
    else{
        vh=h*6.0;
        if (vh>=6.0) vh=0.0;
        f=floor(vh); i=f;
        v1=v*(1.0-s);
        v2=v*(1.0-s*(    vh-f));
        v3=v*(1.0-s*(1.0-vh+f));
             if (i==0) { r=v ; g=v3; b=v1; }
        else if (i==1) { r=v2; g=v ; b=v1; }
        else if (i==2) { r=v1; g=v ; b=v3; }
        else if (i==3) { r=v1; g=v2; b=v ; }
        else if (i==4) { r=v3; g=v1; b=v ; }
        else           { r=v ; g=v1; b=v2; }
        }
    c.db[picture::_r]=r*255.0;
    c.db[picture::_g]=g*255.0;
    c.db[picture::_b]=b*255.0;
    }

struct _base_color
    {
    DWORD rgb,hsv;
    const char *nam;
    _base_color(DWORD _rgb,const char *_nam){ nam=_nam; rgb=_rgb; color c; c.dd=rgb; rgb2hsv(c); hsv=c.dd; }

    _base_color(){};
    _base_color(_base_color& a){};
    ~_base_color(){};
    _base_color* operator = (const _base_color *a){};
    //_base_color* operator = (const _base_color &a);
    };
const _base_color base_color[]=
    {
    //          0x00RRGGBB
    _base_color(0x00000000,"Black"),
    _base_color(0x00808080,"Gray"),
    _base_color(0x00C0C0C0,"Silver"),
    _base_color(0x00FFFFFF,"White"),
    _base_color(0x00800000,"Maroon"),
    _base_color(0x00FF0000,"Red"),
    _base_color(0x00808000,"Olive"),
    _base_color(0x00FFFF00,"Yellow"),
    _base_color(0x00008000,"Green"),
    _base_color(0x0000FF00,"Lime"),
    _base_color(0x00008080,"Teal"),
    _base_color(0x0000FFFF,"Aqua"),
    _base_color(0x00000080,"Navy"),
    _base_color(0x000000FF,"Blue"),
    _base_color(0x00800080,"Purple"),
    _base_color(0x00FF00FF,"Fuchsia"),
    _base_color(0x00000000,"")
    };

void compare_colors()
    {
    picture pic0;
    int h0,s0,v0,h1,s1,v1,x,y,i,d,i0,d0;
    int r0,g0,b0,r1,g1,b1,c0,c1,q,xx;
    color c;
    pic0.resize(256*4,256);
    pic0.pf=_pf_rgba;
    for (y=0;y<256;y++)
     for (x=0;x<256;x++)
        {
        // get color from image
        c=pic0.p[y][x];
        xx=x;
        r0=c.db[picture::_r];
        g0=c.db[picture::_g];
        b0=c.db[picture::_b];
        rgb2hsv(c);
        h0=c.db[picture::_h];
        s0=c.db[picture::_s];
        v0=c.db[picture::_v];
        // naive RGB
        xx+=256;
        for (i0=-1,d0=-1,i=0;base_color[i].nam[0];i++)
            {
            // compute distance
            c.dd=base_color[i].rgb;
            r1=c.db[picture::_r];
            g1=c.db[picture::_g];
            b1=c.db[picture::_b];
            // no need for sqrt
            d=((r1-r0)*(r1-r0))+((g1-g0)*(g1-g0))+((b1-b0)*(b1-b0));
            // remember closest match
            if ((d0<0)||(d0>d)) { d0=d; i0=i; }
            }
        pic0.p[y][xx].dd=base_color[i0].rgb;
        // normalized RGB
        xx+=256;
        c0=sqrt((r0*r0)+(g0*g0)+(b0*b0));
        if (!c0) i0=0; else
         for (i0=-1,d0=-1,i=1;base_color[i].nam[0];i++)
            {
            // compute distance
            c.dd=base_color[i].rgb;
            r1=c.db[picture::_r];
            g1=c.db[picture::_g];
            b1=c.db[picture::_b];
            c1=sqrt((r1*r1)+(g1*g1)+(b1*b1));
            // no need for sqrt
            q=((r0*c1)-(r1*c0))/4; q*=q; d =q;
            q=((g0*c1)-(g1*c0))/4; q*=q; d+=q;
            q=((b0*c1)-(b1*c0))/4; q*=q; d+=q;
            d/=c1*c0; d<<=16; d/=c1*c0;
            // remember closest match
            if ((d0<0)||(d0>d)) { d0=d; i0=i; }
            }
        pic0.p[y][xx].dd=base_color[i0].rgb;
        // HSV
        xx+=256;
        for (i0=-1,d0=-1,i=0;base_color[i].nam[0];i++)
            {
            // compute distance
            c.dd=base_color[i].hsv;
            h1=c.db[picture::_h];
            s1=c.db[picture::_s];
            v1=c.db[picture::_v];
            // no need for sqrt
            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 grayscales
                }
            q=v1-v0; q*=q; d+=q;
            // remember closest match
            if ((d0<0)||(d0>d)) { d0=d; i0=i; }
            }
        pic0.p[y][xx].dd=base_color[i0].rgb;
        }
    pic0.bmp->Canvas->Brush->Style=bsClear;
    pic0.bmp->Canvas->Font->Color=clBlack;
    x =256; pic0.bmp->Canvas->TextOutA(5+x,5,"Naive RGB");
    x+=256; pic0.bmp->Canvas->TextOutA(5+x,5,"Normalized RGB");
    x+=256; pic0.bmp->Canvas->TextOutA(5+x,5,"HSV");
    pic0.bmp->Canvas->Brush->Style=bsSolid;
    //pic0.save("colors.png");
    }

您可以忽略 `pic0` 部分,它只是针对像素访问图片的。我在 RGB 距离公式中添加了一些特别之处,以便将子结果移动,以使其适合 32 位 `int` 中,以避免溢出。作为输入,我使用了这张图片:

in

然后为每个像素找到相应的基准颜色,从 LUT 中找到。这是结果:

out

左边是源图像,接下来是天真的 RGB 比较,然后是规范化的 RGB 比较(无法区分相同颜色的阴影),右边是 HSV 比较。 对于规范化的 RGB,所找到的颜色始终是来自于同一颜色但不同强度的第一个 LUT。比较只选了较暗的颜色,因为它们是 LUT 中的第一个。 如我之前所提到的,深色和灰度颜色是此问题的难点,应该分别处理。如果您得到类似的结果但仍然出现错误检测,则需要添加更多基础颜色以覆盖空缺。如果您根本没有类似的结果,则很可能存在以下问题:
  1. wrong HSV or RGB ranges mine are <0,255> for each channel
  2. overflow somewhere

    when multiplying numbers the bits used are summed !!! So

    8bit * 8bit * 8bit * 8bit = 32bit
    

    and if the numbers are signed you re in trouble ... if on 32bit variables just like me in the example above so you need to shift the range a bit or use FPU on <0.0,1.0> intervals.

为确保您没有问题,我也添加了我的HSV/RGB转换。

以下是原始的HSV生成转换:

out


你将如何对HSV进行比较? - usernan
@usernan 使用相同的欧几里得距离,但仅在二维中忽略“值V”,因为它是颜色强度(亮度)。我添加了示例,还可以参考HSV直方图获取更多信息。 - Spektre
唯一的问题是我正在使用 Python 中的 rgb_to_hsv,它的输出为 (0.16666666666666666, 0, 142),而不是 RGB 值 (132, 142, 113) 对应的 (82 度,20%,56%)。 - usernan
@usernan 看起来这是所有组件的标准 <0.0,1.0> 范围。它应该按预期工作。 - Spektre
让我们在聊天中继续这个讨论 - usernan
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接