Pregunta

Estoy buscando algún tipo de fórmula o algoritmo para determinar el brillo de un color dado los valores RGB. Sé que no puede ser tan simple como agregar los valores de RGB juntos y tener sumas más altas es más brillante, pero tengo una pérdida de dónde comenzar.

¿Fue útil?

Solución

¿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 para 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]

Otros consejos

Creo que lo que estás buscando es el RGB -> Luma Fórmula de conversión.

Fotométrico/digital ITU Bt.709:

Y = 0.2126 R + 0.7152 G + 0.0722 B

Digital ITU BT.601 (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 la precisión por rendimiento, 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 se pueden calcular rápidamente como

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

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

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

Primera imagen - Luminancia (pariente)

0.2126 * R + 0.7152 * G + 0.0722 * B

2da imagen - http://www.w3.org/tr/aert#color-contrast

0.299 * R + 0.587 * G + 0.114 * B

Tercera imagen - Modelo de color HSP

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

4ta imagen - WCAG 2.0 SC 1.4.3 luminancia relativa y relación de contraste Fórmula (ver @Synchro's responder aquí)

El patrón a veces se puede ver en la primera y segunda imagen dependiendo del número de colores en una fila. Nunca vi ningún patrón en la imagen del tercer o 4º 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 aproximadamente un 33% más rápido que el cuarto.

Perceived brightness algorithm comparison

A continuación se muestra el único algoritmo correcto para convertir las imágenes SRGB, como se usa en los 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 aplica la función gamma al valor reducido. No incorporar la función gamma puede dar lugar a errores de hasta 20%.

Para las cosas de computadora típicas, 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 exponencia 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)
    );
}

Curiosamente, esta formulación para rgb => hsv Solo usa V = Max3 (R, G, B). En otras palabras, puedes usar el máximo de (r, g, b) como la v en hsv.

Revisé y en la página 575 de Hearn & Baker Así es como calculan el "valor" también.

From Hearn&Baker pg 319

encontré este código (Escrito en C#) que hace un excelente trabajo al calcular el "brillo" de un color. En este escenario, el código está tratando de determinar si poner texto blanco o negro sobre el color.

Para agregar lo que dijeron todos los demás:

Todas estas ecuaciones funcionan un poco bien en la práctica, pero si necesita ser muy preciso, primero debe convertir el color en espacio de color lineal (aplicar gamma de imagen inversa), haga el promedio de peso de los colores primarios y, si desea Muestre el color: vuelva a llevar la luminancia al monitor gamma.

La diferencia de luminancia entre el gamma gamma y hacer gamma adecuado es de hasta un 20% en los grises oscuros.

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

Aquí hay una implementación de PHP directa pero exacta del WCAG 2.0 SC 1.4.3 luminancia relativa y relación de contraste Fórmulas. 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 el puerto 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 <marcus@synchromedia.co.uk>
 */
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 <marcus@synchromedia.co.uk>
 */
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 respuesta "aceptada" es incorrecta e incompleta

Las únicas respuestas que son precisas son el @Jive-Dadson y @Eddingtonsmonkey Respuestas y en apoyo @nils-pipenbrinck. Las otras respuestas (incluido el aceptado) están vinculando o citando fuentes que son incorrectas, irrelevantes, obsoletas o rotas.

Brevemente:

  • SRGB debe ser Linealizado antes de aplicar los coeficientes.
  • La luminancia (L o Y) es lineal como es ligera.
  • La ligereza percibida (L*) no es lineal al igual que la percepción humana.
  • HSV y HSL ni siquiera son remotamente precisos en términos de percepción.
  • El estándar IEC para SRGB especifica un umbral de 0.04045 es NO 0.03928 (que era de un borrador temprano obsoleto).
  • Ser útil (es decir, en relación con la percepción), Las distancias euclidianas requieren un espacio vectorial cartesiano perceptualmente uniforme como Cielab. SRGB no es uno.

Lo que sigue es una respuesta correcta y completa:

Debido a que este hilo aparece altamente en los motores de búsqueda, estoy agregando esta respuesta para aclarar los diversos conceptos erróneos sobre el tema.

Brillo es un atributo perceptivo, no tiene una medida directa.

Ligereza percibida se mide por algunos modelos de visión como Cielab, aquí L* (LSTAR) es una medida de ligereza perceptiva, y no es lineal aproximar la curva de respuesta no lineal de visión humana.

Luminancia es una medida lineal de la luz, ponderada espectralmente para la visión normal pero no ajustada para la percepción no lineal de la ligereza.

Luma ( Prime) es una señal de gamma codificada y ponderada utilizada en algunas codificaciones de video. No debe confundirse con luminancia lineal.

Gama o la curva de transferencia (TRC) es una curva que a menudo es similar a la curva perceptiva, y se aplica comúnmente a los datos de imágenes para el almacenamiento o transmisión para reducir el ruido percibido y/o mejorar la utilización de datos (y razones relacionadas).

Para determinar la ligereza percibida, primero convierte los valores de imagen de R´g´b´ con gamma en luminancia lineal (L o Y ) y luego a la ligereza percibida no lineal (L*)


Para encontrar luminancia:

... porque aparentemente estaba perdido en alguna parte ...

Paso uno:

Convierta todos los valores enteros de 8 bits SRGB a decimal 0.0-1.0

  vR = sR / 255;
  vG = sG / 255;
  vB = sB / 255;

Segundo paso:

Convierta un RGB codificado gamma a un valor lineal. SRGB (estándar de computadora), por ejemplo, requiere una curva de potencia de aproximadamente V^2.2, aunque la transformación "precisa" es:

sRGB to Linear

Donde V´ es el canal R, G o B de SRGB.
Seudocódigo:

function sRGBtoLin(colorChannel) {
        // Send this function a decimal sRGB gamma encoded color value
        // between 0.0 and 1.0, and it returns a linearized value.

    if ( colorChannel <= 0.04045 ) {
            return colorChannel / 12.92;
        } else {
            return pow((( colorChannel + 0.055)/1.055),2.4));
        }
    }

Paso tres:

Para encontrar luminancia (y), aplique los coeficientes estándar para SRGB:

Apply coefficients Y = R * 0.2126 + G * 0.7152 + B *  0.0722

Pseudocódigo utilizando las funciones anteriores:

Y = (0.2126 * sRGBtoLin(vR) + 0.7152 * sRGBtoLin(vG) + 0.0722 * sRGBtoLin(vB))

Para encontrar la ligereza percibida:

Paso cuatro:

Tome la luminancia y desde arriba y transforma a l*

L* from Y equation
Seudocódigo:

function YtoLstar(Y) {
        // Send this function a luminance value between 0.0 and 1.0,
        // and it returns L* which is "perceptual lightness"

    if ( Y <= (216/24389) {       // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036
            return Y * (24389/27);  // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296
        } else {
            return pow(Y,(1/3)) * 116 - 16;
        }
    }

L* es un valor de 0 (negro) a 100 (blanco) donde 50 es el "gris medio" perceptivo. L* = 50 es el equivalente de y = 18.4, o en otras palabras una tarjeta gris del 18%, que representa el medio de una exposición fotográfica (Ansel Adams Zone V).

Referencias:

IEC 61966-2-1:1999 Standard
Wikipedia sRGB
Wikipedia CIELAB
Wikipedia CIEXYZ
Preguntas frecuentes de Charles Poynton's Gamma

El espacio de colores HSV debería hacer el truco, ver el artículo de Wikipedia Dependiendo del lenguaje en el que esté trabajando, puede obtener una conversión de biblioteca.

H es un 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.

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 de (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.

La fórmula de gamma inverso de Jive Dadson necesita que se elimine el medio ajustado cuando se implementa en JavaScript, es decir, el retorno de la función GAM_SRGB debe ser return int (V*255); no return int (v*255+.5); Ronda la mediana forma de ajuste, y esto puede causar un valor demasiado alto en una tríada de color gris r = g = b es decir. La conversión de escala de grises en una tríada r = g = b debería producir un valor igual a r; Es una prueba de que la fórmula es válida. Ver Nueve tonos de escala de grises para la fórmula en acción (sin el medio ajustado).

Aquí hay un poco de código C que debería calcular adecuadamente 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
}

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 a los coeficientes de ITU establecidos desde 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 varillas 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 mezcló tanto como sea posible. También repití esa prueba con otros tonos. Repetí la prueba en diferentes pantallas, incluso una con un factor gamma fijo de 3.0, pero todo me parece igual. Más terminado, los coeficientes de la ITU literalmente están equivocados para mis ojos.

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

Defina el brillo. Si está buscando qué tan cerca del blanco está el color que puede usar Distancia euclidiana de (255, 255, 255)

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

Este enlace Explica todo en profundidad, incluyendo por qué existen esas constantes multiplicadoras antes de los valores R, G y B.

Editar: tiene una explicación de una de las respuestas aquí también (0.299*R + 0.587*G + 0.114*b)

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

En mi script, uso el código del sistema hexadecimal antes por otro motivo, pero también puede comenzar con el código del sistema RGB con rgb2hsv {grDevices}. La documentación es aquí.

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

For clarity, the formulas that use a square root need to be

sqrt(coefficient * (colour_value^2))

not

sqrt((coefficient * colour_value))^2

The proof of this lies in the conversion of a R=G=B triad to greyscale R. That will only be true if you square the colour value, not the colour value times coefficient. See Nine Shades of Greyscale

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top