Формула для определения яркости цвета RGB

StackOverflow https://stackoverflow.com/questions/596216

  •  09-09-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

  • Яркости (стандарт для определенных цветовых пространств): (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]

Другие советы

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

Фотометрический/цифровой 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

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

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 Color Model

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

4 -я картина - WCAG 2.0 SC 1.4.3 Относительная яркости а также Контрастность Формула (см @Синхро отвечать здесь)

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

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

Perceived brightness algorithm comparison

Ниже представлен единственный правильный алгоритм для преобразования изображений SRGB, как используется в браузерах и т. Д., В Greyscale.

Необходимо применить обратную гамма -функцию для цветового пространства, прежде чем вычислять внутренний продукт. Затем вы применяете гамма -функцию к сниженному значению. Неспособность включить гамма -функцию может привести к ошибкам до 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)
    );
}

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

Я проверил и на странице 575 Хирн и Бейкер Вот как они также вычисляют «ценность».

From Hearn&Baker pg 319

я нашел этот код (Написано в C#), которая отлично справляется с расчетом «яркости» цвета. В этом сценарии код пытается определить, размещать ли белый или черный текст на цвет.

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

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

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

Вместо того, чтобы терять среди случайного выбора формул, упомянутых здесь, я предлагаю вам пойти на формулу, рекомендованную стандартами 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);
}

«Принятый» ответ неверный и неполный

Единственные ответы, которые точны, - это @Jive-Dadson а также @Eddingtonsmonkey Ответы и в поддержку @Nils-Pipenbrinck. Анкет Другие ответы (в том числе принятый) ссылаются на или ссылаются на источники, которые являются неправильными, неактуальными, устаревшими или сломанными.

Кратко:

  • SRGB должен быть Линеаризованный Перед нанесением коэффициентов.
  • Яркости (L или Y) линейна, как и свет.
  • Воспринимаемая легкость (L*) нелинейная, как и человеческое восприятие.
  • HSV и HSL даже не являются отдаленно точными с точки зрения восприятия.
  • Стандарт IEC для SRGB определяет порог 0,04045 это НЕТ 0,03928 (это было из устаревшего раннего проекта).
  • Быть полезным (т.е. относительно восприятия), Евклидские расстояния требуют однородного однородного декартового векторного пространства, такого как Cielab. SRGB не один.

Далее следует правильный и полный ответ:

Поскольку этот поток показывается в поисковых системах, я добавляю этот ответ, чтобы прояснить различные заблуждения по этому вопросу.

Яркость это атрибут восприятия, он не имеет прямой меры.

Воспринимаемая легкость измеряется некоторыми моделями зрения, такими как Cielab, здесь L* (LSTAR) является мерой воспринимающая легкость, и не является линейным, чтобы приблизить кривую нелинейного ответа человека.

Яркости является линейной мерой света, спектрально взвешенной для нормального зрения, но не приспособлена для нелинейного восприятия легкого.

Люма (Ты Prime) - это взвешенный сигнал гамма, используемый в некоторых видеокодиках. Это не следует путать с линейной яркости.

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

Определить воспринимаемую легкость, сначала преобразовать кодируемые гамма значения изображений R´G´BL или же Y ) а затем к нелинейной воспринимаемой легкостью (L*)


Чтобы найти яркости:

... потому что, очевидно, это где -то было потеряно ...

Шаг первый:

Преобразовать все 8-битные целочисленные значения SRGB в десятичное значение 0,0-1,0

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

Шаг второй:

Преобразовать RGB, закодированный гамма, в линейное значение. SRGB (компьютерный стандарт), например, требует кривой мощности приблизительно V^2.2, хотя «точное» преобразование:

sRGB to Linear

Где V´-кодированный гамма-канал R, G или B SRGB.
Псевдокод:

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

Шаг третий:

Чтобы найти яркость (y) применить стандартные коэффициенты для SRGB:

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

Псевдокод с использованием вышеуказанных функций:

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

Чтобы найти воспринимаемую легкость:

Шаг четвертый:

Возьмите яркость Y сверху и преобразовать в L*

L* from Y equation
Псевдокод:

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* - это значение от 0 (черное) до 100 (белое), где 50 - восприятие «Средний серый». L* = 50 является эквивалентом y = 18,4, или, другими словами, 18% серой карты, представляющей середину фотографической экспозиции (зона V Ansel Adams V).

Использованная литература:

IEC 61966-2-1:1999 Standard
Wikipedia sRGB
Wikipedia CIELAB
Wikipedia CIEXYZ
Чарльз Пойнтон в гамма.

Цветовое пространство HSV должно сделать свое дело, увидеть Википедия статья В зависимости от языка, на котором вы работаете, вы можете получить конверсию в библиотеке.

H - это HUE, что является численным значением для цвета (то есть красный, зеленый ...)

S - насыщение цвета, то есть, как это «интенсивно»

V - «яркости» цвета.

Значение яркости RGB = 0,3 r + 0,59 г + 0,11 b

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

Если вы ищете, насколько близко к белому цвет, вы можете использовать евклидовое расстояние от (255, 255, 255)

Я думаю, что цветовое пространство RGB воспринимается неравномерным по отношению к дистанции Euclidian L2. Единые пространства включают CIE Lab и Luv.

Формула обратной гамма от Jive Dadson должна быть удалена полужеустройства при реализации в JavaScript, то есть возврат от функции GAM_SRGB должен быть возврат int (v*255); не возвращать int (v*255+.5); Половина построения обстановки, и это может привести к тому, что значение слишком высокое на r = g = b Ie СЕРЕЙ ЦВЕТА. Преобразование серого на r = g = b триада должна создавать значение, равное r; Это одно доказательство того, что формула действительна. Видеть Девять оттенков серого для формулы в действии (без полукорегистрирования).

Вот немного 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
}

Интересно, как были определены эти коэффициенты RGB. Я прошел эксперимент сам, и я закончил следующим образом:

Y = 0.267 R + 0.642 G + 0.091 B

Близко, но, очевидно, отличается от давно установленных коэффициентов МСЭ. Интересно, могут ли эти коэффициенты быть различными для каждого наблюдателя, потому что у всех нас может быть разное количество шишек и стержней на сетчатке в наших глазах, и особенно соотношение между различными типами конусов может отличаться.

Для справки:

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

Я провел тест, быстро перемещая маленькую серую стержни на ярко -красном, ярко -зеленом и ярко -синем фоне и отрегулировал серой, пока он не смешался как можно больше. Я также повторил этот тест с другими оттенками. Я повторил тест на разных дисплеях, даже один с фиксированным гамма -фактором 3,0, но для меня все выглядит одинаково. Более того, коэффициенты ITU буквально неверны для моих глаз.

И да, у меня, вероятно, есть нормальное цветовое зрение.

Пожалуйста, определите яркость. Если вы ищете, насколько близко к белому цвет, вы можете использовать Евклидово расстояние от (255, 255, 255)

«V» HSV - это, вероятно, то, что вы ищете. Matlab имеет функцию RGB2HSV, а ранее цитируемая статья в Википедии полна псевдокода. Если преобразование RGB2HSV невозможно, менее точной моделью была бы версия изображения в серых масштабах.

Эта ссылка Объясняет все в глубине, в том числе почему эти константы множителя существуют до значений R, G и B.

Изменить: здесь также есть объяснение одного из ответов (0,299*r + 0,587*g + 0,114*b)

Чтобы определить яркость цвета с R, я преобразую цвет системы RGB в цвете системы HSV.

В моем скрипте я использую системный код HEX до другой причины, но вы также можете начать с системного кода RGB с rgb2hsv {grDevices}. Анкет Документация здесь.

Вот эта часть моего кода:

 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

Для ясности, формулы, которые используют квадратный корень, должны быть

sqrt(coefficient * (colour_value^2))

нет

sqrt((coefficient * colour_value))^2

Доказательство этого заключается в преобразовании R = G = B триады в Greyscale R., который будет правдой только в том случае, если вы квадрате значение цвета, а не коэффициент времени цвета цвета. Видеть Девять оттенков серого

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top