Nome da cor base do valor RGB

Eu quero encontrar o nome da cor, dado o seu valor de rgb.

Exemplo de valor RGB é: (237, 65, 83)

Valores predefinidos

array (11, ‘Vermelho’, ‘# FF0000’, ‘255,0,0’),

array (3, ‘Brown’, ‘# A52A2A’, ‘165,42,42’)

Se eu usar este cálculo de distância de método

Eu estou ficando cor marrom.

Mas a cor real é vermelha se testarmos esse valor de rgb aqui

Editado 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 = $d ) { $miDist = $d; $loc = $i ; } echo "
" ; } 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

Então, se você quer uma distância entre 2 colors (r0,g0,b0) e (r1,g1,b1) para detectar a cor mais próxima, independentemente de sua intensidade (isso é o que significa cor de base, neste caso) você deve

  1. Normalize os vetores de cor para tamanho comum
  2. Distância de computação
  3. Escale o resultado de volta
 // 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); 

Esta abordagem ficará instável comparando colors escuras para que você possa adicionar condições simples como

 if (c0 

E compare essa cor apenas contra os tons de cinza ou retornar cor desconhecida. Nossa visão funciona de forma semelhante, não podemos reconhecer com segurança as colors escuras ...

De qualquer forma, o espaço de cor do HSV é muito melhor para comparação de colors, porque se assemelha melhor ao reconhecimento de colors humanas. então converta RGB -> HSV e calcule a distância ignorando o valor V que é a intensidade da cor ...

No HSV, você precisa manipular H como um valor de círculo completo periódico para que a alteração possa ser apenas metade do círculo grande. S informa se é colorido ou em escala de cinza, que deve ser tratado separadamente e V é a intensidade.

 // 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; 

Algumas coisas para comparar ...

Você deve fazer uma verificação visual da sua fonte para realmente ver o que está acontecendo, caso contrário você entrará em círculos sem nenhum resultado. Por exemplo, acabei de codificar isso em C ++ / VCL / minha class de imagem :

 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 (max1.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"); } 

Você pode ignorar o material pic0 , é apenas o access de pixels para a imagem. Eu adicionei algumas peculiaridades na equação de distância RGB para deslocar os sub-resultados para que eles se encaixem dentro de 32 bits int para evitar overflows. Como input, utilizo esta imagem:

dentro

E para cada pixel é, então, a cor base correspondente da LUT encontrada. Este é o resultado:

Fora

À esquerda está a imagem de origem, a comparação de RGB ingênua, a comparação de RGB normalizada (não é possível distinguir entre os mesmos tons de colors) e à direita a comparação de HSV .

Para o RGB normalizado, as colors encontradas são sempre as primeiras na LUT da mesma cor, mas com intensidades diferentes. A comparação seleciona o mais escuro apenas porque eles são os primeiros no LUT .

Como mencionei anteriormente, as colors escuras e em tons de cinza são um problema com isso e devem ser tratadas separadamente. Se você obteve resultados semelhantes e ainda detecção incorreta, é necessário adicionar mais colors de base para cobrir as lacunas. Se você não tem resultados semelhantes, então você provavelmente terá um problema com:

  1. os intervalos errados de HSV ou RGB são meus <0,255> para cada canal
  2. transbordar em algum lugar

    ao multiplicar números, os bits usados ​​são sumdos !!! assim

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

    e se os números são assinados, você está com problemas ... se em variables ​​de 32 bits como eu no exemplo acima, então você precisa mudar o intervalo um pouco ou usar FPU em intervalos de <0.0,1.0> .

Só para ter certeza eu adicionei também as minhas conversões HSV / RGB no caso de você ter algum problema lá.

E aqui a conversão gerada pelo HSV original:

Fora