image tono - Fórmula para determinar el brillo del color RGB.




saturacion luminosidad (16)

Estoy buscando algún tipo de fórmula o algoritmo para determinar el brillo de un color dados los valores RGB. Sé que no puede ser tan simple como sumar los valores RGB y tener sumas más altas sea más brillante, pero no sé por dónde empezar.


Answers

La 'V' de HSV es probablemente lo que estás buscando. MATLAB tiene una función rgb2hsv y el artículo de wikipedia previamente citado está lleno de pseudocódigo. Si una conversión RGB2HSV no es factible, un modelo menos preciso sería la versión en escala de grises de la imagen.


A continuación se muestra el único algoritmo CORRECTO para convertir imágenes sRGB, como se usa en navegadores, etc., a escala de grises.

Es necesario aplicar una inversa de la función gamma para el espacio de color antes de calcular el producto interno. Luego aplicas la función gamma al valor reducido. Si no se incorpora la función gamma, se pueden producir errores de hasta el 20%.

Para cosas típicas de la computadora, el espacio de color es sRGB. Los números correctos para sRGB son aprox. 0,21, 0,72, 0,07. Gamma para sRGB es una función compuesta que se aproxima a la exponenciación en 1 / (2.2). Aquí está todo en C ++.

// sRGB luminance(Y) values
const double rY = 0.212655;
const double gY = 0.715158;
const double bY = 0.072187;

// Inverse of sRGB "gamma" function. (approx 2.2)
double inv_gam_sRGB(int ic) {
    double c = ic/255.0;
    if ( c <= 0.04045 )
        return c/12.92;
    else 
        return pow(((c+0.055)/(1.055)),2.4);
}

// sRGB "gamma" function (approx 2.2)
int gam_sRGB(double v) {
    if(v<=0.0031308)
        v *= 12.92;
    else 
        v = 1.055*pow(v,1.0/2.4)-0.055;
    return int(v*255+0.5); // This is correct in C++. Other languages may not
                           // require +0.5
}

// GRAY VALUE ("brightness")
int gray(int r, int g, int b) {
    return gam_sRGB(
            rY*inv_gam_sRGB(r) +
            gY*inv_gam_sRGB(g) +
            bY*inv_gam_sRGB(b)
    );
}

El espacio de colores de HSV debería hacer el truco; consulte el artículo de wikipedia de acuerdo con el idioma en el que está trabajando; puede obtener una conversión de biblioteca.

H es el tono que es un valor numérico para el color (es decir, rojo, verde ...)

S es la saturación del color, es decir, cuán 'intenso' es

V es el 'brillo' del color.


Por favor define el brillo. Si está buscando qué tan cerca del blanco está el color, puede usar la Distancia euclidiana desde (255, 255, 255)


Para determinar el brillo de un color con R, convierto el color del sistema RGB al color del sistema HSV.

En mi script, uso el código del sistema HEX antes por otra razón, pero también puede comenzar con el código del sistema RGB con rgb2hsv {grDevices} . La documentación está here .

Aquí está esta parte de mi código:

 sample <- c("#010101", "#303030", "#A6A4A4", "#020202", "#010100")
 hsvc <-rgb2hsv(col2rgb(sample)) # convert HEX to HSV
 value <- as.data.frame(hsvc) # create data.frame
 value <- value[3,] # extract the information of brightness
 order(value) # ordrer the color by brightness

Valor de luminancia RGB = 0.3 R + 0.59 G + 0.11 B

http://www.scantips.com/lumin.html

Si está buscando qué tan cerca del blanco está el color, puede usar la Distancia euclidiana desde (255, 255, 255)

Creo que el espacio de color RGB es perceptivamente no uniforme con respecto a la distancia euclidiana L2. Los espacios uniformes incluyen CIE LAB y LUV.



Creo que lo que está buscando es la fórmula de conversión RGB -> Luma .

Fotométrica / digital ITU BT.709 :

Y = 0.2126 R + 0.7152 G + 0.0722 B

Digital ITU BT.601 (le da más peso a los componentes R y B):

Y = 0.299 R + 0.587 G + 0.114 B

Si está dispuesto a intercambiar precisión por desempeño, hay dos fórmulas de aproximación para esta:

Y = 0.33 R + 0.5 G + 0.16 B

Y = 0.375 R + 0.5 G + 0.125 B

Estos pueden ser calculados rápidamente como

Y = (R+R+B+G+G+G)/6

Y = (R+R+R+B+G+G+G+G)>>3

Encontré este código (escrito en C #) que hace un excelente trabajo de cálculo del "brillo" de un color. En este escenario, el código está tratando de determinar si se debe colocar texto blanco o negro sobre el color.


He hecho la comparación de los tres algoritmos en la respuesta aceptada. Generé colores en el ciclo donde solo se usaba cada 400 colores. Cada color está representado por 2x2 píxeles, los colores se ordenan de más oscuro a más claro (de izquierda a derecha, de arriba a abajo).

1ª imagen - [1]

0.2126 * R + 0.7152 * G + 0.0722 * B

2da imagen - [2]

0.299 * R + 0.587 * G + 0.114 * B

3ª imagen - [3]

sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2)

Cuarta imagen: WCAG 2.0 SC 1.4.3 fórmula de relación de luminancia relativa y contraste (consulte @Synchro's respuesta de @Synchro's )

El patrón puede verse a veces en la 1ra y 2da imagen dependiendo del número de colores en una fila. Nunca vi ningún patrón en la imagen del tercer o cuarto algoritmo.

Si tuviera que elegir iría con el algoritmo número 3, ya que es mucho más fácil de implementar y es un 33% más rápido que el 4º.


¿Te refieres al brillo? ¿Brillo percibido? Luminancia?

  • Luminancia (estándar para ciertos espacios de color): (0.2126*R + 0.7152*G + 0.0722*B) [1]
  • Luminancia (opción percibida 1): (0.299*R + 0.587*G + 0.114*B) [2]
  • Luminancia (opción percibida 2, más lenta de calcular): sqrt( 0.241*R^2 + 0.691*G^2 + 0.068*B^2 )sqrt( 0.299*R^2 + 0.587*G^2 + 0.114*B^2 ) (gracias a @MatthewHerbst ) [3]

La fórmula de gamma inversa de Jive Dadson debe tener eliminado el medio ajuste cuando se implementa en Javascript, es decir, el retorno de la función gam_sRGB debe devolverse int (v * 255); no devuelve int (v * 255 + .5); La mitad del ajuste se redondea, y esto puede causar un valor demasiado alto en R = G = B, es decir, tríada de color gris. La conversión a escala de grises en una tríada R = G = B debe producir un valor igual a R; Es una prueba de que la fórmula es válida. Consulte Nine Shades of Greyscale para ver la fórmula en acción (sin el medio ajuste).


Me pregunto cómo se determinaron esos coeficientes rgb. Yo mismo hice un experimento y terminé con lo siguiente:

Y = 0.267 R + 0.642 G + 0.091 B

Cerca, pero obviamente diferente de los coeficientes ITU establecidos hace mucho tiempo. Me pregunto si esos coeficientes podrían ser diferentes para cada observador, porque todos podemos tener una cantidad diferente de conos y bastones en la retina en nuestros ojos, y especialmente la relación entre los diferentes tipos de conos puede diferir.

Para referencia:

ITU BT.709:

Y = 0.2126 R + 0.7152 G + 0.0722 B

ITU BT.601:

Y = 0.299 R + 0.587 G + 0.114 B

Hice la prueba moviendo rápidamente una pequeña barra gris sobre un fondo rojo brillante, verde brillante y azul brillante, y ajustando el gris hasta que se integrara lo más posible. También repetí esa prueba con otros tonos. Repetí la prueba en diferentes pantallas, incluso una con un factor de gamma fijo de 3.0, pero para mí todo me parece igual. Además, los coeficientes de la UIT están literalmente equivocados para mis ojos.

Y sí, presumiblemente tengo una visión de color normal.


Aquí hay un poco de código C que debe calcular correctamente la luminancia percibida.

// reverses the rgb gamma
#define inverseGamma(t) (((t) <= 0.0404482362771076) ? ((t)/12.92) : pow(((t) + 0.055)/1.055, 2.4))

//CIE L*a*b* f function (used to convert XYZ to L*a*b*)  http://en.wikipedia.org/wiki/Lab_color_space
#define LABF(t) ((t >= 8.85645167903563082e-3) ? powf(t,0.333333333333333) : (841.0/108.0)*(t) + (4.0/29.0))


float
rgbToCIEL(PIXEL p)
{
   float y;
   float r=p.r/255.0;
   float g=p.g/255.0;
   float b=p.b/255.0;

   r=inverseGamma(r);
   g=inverseGamma(g);
   b=inverseGamma(b);

   //Observer = 2°, Illuminant = D65 
   y = 0.2125862307855955516*r + 0.7151703037034108499*g + 0.07220049864333622685*b;

   // At this point we've done RGBtoXYZ now do XYZ to Lab

   // y /= WHITEPOINT_Y; The white point for y in D65 is 1.0

    y = LABF(y);

   /* This is the "normal conversion which produces values scaled to 100
    Lab.L = 116.0*y - 16.0;
   */
   return(1.16*y - 0.16); // return values for 0.0 >=L <=1.0
}

En lugar de perderse entre la selección aleatoria de fórmulas que se mencionan aquí, le sugiero que busque la fórmula recomendada por los estándares de W3C.

Aquí hay una implementación PHP simple pero exacta de las fórmulas de relación de luminancia relativa y contraste WCAG 2.0 SC 1.4.3 . Produce valores que son apropiados para evaluar las relaciones requeridas para el cumplimiento de WCAG, como en esta página , y como tal, es adecuado y apropiado para cualquier aplicación web. Esto es trivial para portar a otros idiomas.

/**
 * Calculate relative luminance in sRGB colour space for use in WCAG 2.0 compliance
 * @link http://www.w3.org/TR/WCAG20/#relativeluminancedef
 * @param string $col A 3 or 6-digit hex colour string
 * @return float
 * @author Marcus Bointon <[email protected]>
 */
function relativeluminance($col) {
    //Remove any leading #
    $col = trim($col, '#');
    //Convert 3-digit to 6-digit
    if (strlen($col) == 3) {
        $col = $col[0] . $col[0] . $col[1] . $col[1] . $col[2] . $col[2];
    }
    //Convert hex to 0-1 scale
    $components = array(
        'r' => hexdec(substr($col, 0, 2)) / 255,
        'g' => hexdec(substr($col, 2, 2)) / 255,
        'b' => hexdec(substr($col, 4, 2)) / 255
    );
    //Correct for sRGB
    foreach($components as $c => $v) {
        if ($v <= 0.03928) {
            $components[$c] = $v / 12.92;
        } else {
            $components[$c] = pow((($v + 0.055) / 1.055), 2.4);
        }
    }
    //Calculate relative luminance using ITU-R BT. 709 coefficients
    return ($components['r'] * 0.2126) + ($components['g'] * 0.7152) + ($components['b'] * 0.0722);
}

/**
 * Calculate contrast ratio acording to WCAG 2.0 formula
 * Will return a value between 1 (no contrast) and 21 (max contrast)
 * @link http://www.w3.org/TR/WCAG20/#contrast-ratiodef
 * @param string $c1 A 3 or 6-digit hex colour string
 * @param string $c2 A 3 or 6-digit hex colour string
 * @return float
 * @author Marcus Bointon <[email protected]>
 */
function contrastratio($c1, $c2) {
    $y1 = relativeluminance($c1);
    $y2 = relativeluminance($c2);
    //Arrange so $y1 is lightest
    if ($y1 < $y2) {
        $y3 = $y1;
        $y1 = $y2;
        $y2 = $y3;
    }
    return ($y1 + 0.05) / ($y2 + 0.05);
}

La notación hexadecimal en color es como la siguiente: #AARRGGBB

  • A: alfa
  • R: rojo
  • G: verde
  • B: azul

Primero debes ver cómo funciona el hexadecimal . Puedes escribir a lo sumo FF.





image colors rgb