Nombre del color base del valor RGB

Quiero encontrar el nombre del color, dado su valor rgb.

El valor de RGB de ejemplo es: (237, 65, 83)

Valores predefinidos

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

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

Si uso este método cálculo de distancia

Me da color como marrón.

Pero el color real es rojo si probamos ese valor rgb aquí

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

Entonces, si quiere distancia entre 2 colores (r0,g0,b0) y (r1,g1,b1) para detectar el color más cercano independientemente de su intensidad (eso es lo que significa el color base en este caso), debería

  1. Normalice los vectores de color al tamaño común
  2. Calcular la distancia
  3. Escalar el resultado
 // 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); 

Este enfoque se volverá inestable al comparar colores oscuros para que pueda agregar condiciones simples como

 if (c0 

Y compare ese color solo contra los tonos grises o devuelva un color desconocido. Nuestra visión funciona de manera similar, no podemos reconocer con seguridad los colores oscuros ...

De todos modos, el espacio de color HSV es mucho mejor para la comparación del color, ya que se asemeja mejor al reconocimiento del color humano. así que convierta RGB -> HSV y calcule la distancia ignorando el valor V que es la intensidad del color ...

En HSV necesita manejar H como un valor de círculo completo periódico para que el cambio solo sea la mitad del círculo grande. S le dice si es color o escala de grises lo que debe manejarse por separado y V es la intensidad.

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

Algunas cosas para comparar ...

Deberías hacer una comprobación visual de tu fuente para ver realmente lo que está sucediendo, de lo contrario irás en círculos sin ningún resultado. Por ejemplo, ahora codifiqué esto en C ++ / VCL / mine image class :

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

Puedes ignorar las cosas de pic0 , es solo el acceso de píxeles a la imagen. Agregué algunos caprichos en la ecuación de distancia RGB para cambiar los sub-resultados para que quepan dentro de 32 bit int s para evitar desbordamientos. Como entrada, uso esta imagen:

en

Y para cada píxel, se encuentra el color base correspondiente de la LUT encontrada. Este es el resultado:

fuera

A la izquierda está la imagen de origen, luego la comparación RGB ingenua, luego la comparación RGB normalizada (no se puede distinguir entre las mismas sombras de color) y a la derecha la comparación HSV .

Para el RGB normalizado, los colores encontrados siempre son los primeros en el LUT del mismo color pero con diferentes intensidades. La comparación selecciona el más oscuro solo porque están primero en el LUT .

Como mencioné anteriormente, los colores oscuros y en escala de grises son un problema con esto y deben manejarse por separado. Si obtuviste resultados similares y aún tienes una detección incorrecta, entonces necesitas agregar más colores base para cubrir los huecos. Si no tiene resultados similares, es probable que tenga un problema con:

  1. los rangos HSV o RGB incorrectos míos son <0,255> para cada canal
  2. rebosar en algún lado

    al multiplicar los números, los bits utilizados se sumn. Asi que

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

    y si los números están firmados estás en problemas ... si en las variables de 32 bits igual que yo en el ejemplo anterior, entonces necesitas cambiar el rango un poco o usar FPU en intervalos <0.0,1.0> .

Solo para asegurarme de haber agregado también las conversiones HSV / RGB en caso de que haya algún problema allí.

Y aquí la conversión original generada HSV:

fuera