Формула для определения яркости цвета RGB - PullRequest
356 голосов
/ 27 февраля 2009

Я ищу какую-то формулу или алгоритм для определения яркости цвета по значениям RGB. Я знаю, что это не может быть так просто, как сложить значения RGB вместе и получить более высокие суммы, чтобы быть ярче, но я не знаю, с чего начать.

Ответы [ 18 ]

431 голосов
/ 27 февраля 2009

Вы имеете в виду яркость? Воспринимаемая яркость? Luminance

  • Яркость (стандартная для определенных цветовых пространств): (0.2126*R + 0.7152*G + 0.0722*B) [1]
  • Яркость (воспринимается вариант 1): (0.299*R + 0.587*G + 0.114*B) [2]
  • Яркость (воспринимается вариант 2, медленнее для расчета): 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 ) (благодаря @ MatthewHerbst ) [3]
276 голосов
/ 27 февраля 2009

Я думаю, что вы ищете RGB -> Luma формула преобразования.

Фотометрический / цифровой ITU BT.709 :

Y = 0.2126 R + 0.7152 G + 0.0722 B

Цифровой ITU BT.601 (придает больший вес компонентам R и B):

Y = 0.299 R + 0.587 G + 0.114 B

Если вы хотите обменять точность на производительность, есть две формулы для аппроксимации:

Y = 0.33 R + 0.5 G + 0.16 B

Y = 0.375 R + 0.5 G + 0.125 B

Их можно быстро вычислить как

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

Y = (R+R+R+B+G+G+G+G)>>3
94 голосов
/ 14 июня 2014

Я сделал сравнение трех алгоритмов в принятом ответе. Я генерировал цвета в цикле, где использовался только каждый 400-й цвет. Каждый цвет представлен размером 2х2 пикселя, цвета сортируются от самых темных к самым светлым (слева направо, сверху вниз).

1-е изображение - Яркость (относительная)

0.2126 * R + 0.7152 * G + 0.0722 * B

2-е изображение - http://www.w3.org/TR/AERT#color-contrast

0.299 * R + 0.587 * G + 0.114 * B

3-е изображение - Модель цвета HSP

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

4-е изображение - WCAG 2.0 SC 1.4.3 относительная яркость и коэффициент контрастности формула (см. @ Synchro's ответ)

Рисунок иногда можно увидеть на 1-м и 2-м изображении в зависимости от количества цветов в одном ряду. Я никогда не замечал никаких паттернов на картинке из 3-го или 4-го алгоритма.

Если бы мне пришлось выбирать, я бы использовал алгоритм № 3, так как его гораздо проще реализовать и он примерно на 33% быстрее, чем 4-й.

Perceived brightness algorithm comparison

42 голосов
/ 26 ноября 2012

Ниже приведен единственный ПРАВИЛЬНЫЙ алгоритм преобразования изображений sRGB, используемый в браузерах и т. Д., В оттенки серого.

Необходимо применить обратную гамма-функцию для цветового пространства, прежде чем вычислять внутреннее произведение. Затем вы применяете гамма-функцию к уменьшенному значению. Невыполнение гамма-функции может привести к ошибкам до 20%.

Для типичных компьютерных вещей цветовое пространство sRGB. Правильные цифры для sRGB - ок. 0,21, 0,72, 0,07. Гамма для sRGB - это составная функция, которая приближает возведение в степень на 1 / (2.2). Здесь все это в 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)
    );
}
10 голосов
/ 03 апреля 2013

Интересно, что эта формулировка для RGB => HSV просто использует v = MAX3 (r, g, b). Другими словами, вы можете использовать максимум of (r, g, b) в качестве V в HSV.

Я проверил, и на странице 575 из Hearn & Baker так же они вычисляют "Value".

From Hearn&Baker pg 319

10 голосов
/ 26 мая 2010

Я нашел этот код (написанный на C #), который отлично справляется с расчетом "яркости" цвета. В этом сценарии код пытается определить, нужно ли поместить белый или черный текст поверх цвета.

8 голосов
/ 27 июня 2013

Вместо того, чтобы потеряться среди случайного выбора формул, упомянутых здесь, я предлагаю вам перейти на формулу, рекомендованную стандартами W3C.

Вот простая, но точная реализация PHP WCAG 2.0 SC 1.4.3 относительная яркость и коэффициент контрастности формул. Он генерирует значения, которые подходят для оценки соотношений, необходимых для соответствия WCAG, как на этой странице , и как таковые подходят и подходят для любого веб-приложения. Это просто для переноса на другие языки.

/**
 * 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);
}
7 голосов
/ 27 февраля 2009

Чтобы добавить то, что сказали все остальные:

Все эти уравнения на практике работают довольно хорошо, но если вам нужно быть очень точным, сначала нужно преобразовать цвет в линейное цветовое пространство (применить обратную гамму изображения), сделать средневзвешенное значение основных цветов и - если Вы хотите отобразить цвет - вернуть яркость обратно в гамму монитора.

Разница в яркости между поглощением гаммы и выполнением правильной гаммы составляет до 20% в темных серых тонах.

1 голос
/ 04 июня 2016

Вот немного кода C, который должен правильно рассчитать воспринимаемую яркость.

// 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
}
1 голос
/ 19 января 2016

При реализации в Javascript формулу обратной гаммы от Jive Dadson необходимо удалить с половиной корректировки, то есть возвращение функции gam_sRGB должно возвращать int (v * 255); не вернуть int (v * 255 + .5); Полу-корректировка округляется, и это может привести к значению, слишком высокому для R = G = B, то есть для триады серого цвета. Преобразование в оттенках серого в триаде R = G = B должно давать значение, равное R; это одно из доказательств того, что формула верна. См. Девять оттенков серой шкалы для формулы в действии (без регулировки на половину).

...