Как определить цвета воспринимаемой яркости? - PullRequest
1 голос
/ 05 января 2020

Я много читал в очень полном посте: Формула для определения яркости цвета RGB

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

Быстрый пример с формулой: (0,2126 * R + 0,7152 * G + 0,0722 * B), который кажется наиболее распространенным ответом Интернет.

Отредактировано после ответа Петра

function colorCodeToRGB(colorCode) {
    colorCode = colorCode.substr(1);
    return [
        colorCode.substr(0, 2),
        colorCode.substr(2, 2),
        colorCode.substr(4, 2)
    ].map(it => parseInt(it, 16));
}

const luminanceCoefficients = [.2126, .7152, .0722];
function getLuminance(color) {
  const [r, g, b] = colorCodeToRGB(color);
  return r * luminanceCoefficients[0] + g * luminanceCoefficients[1] + b * luminanceCoefficients[2];
}
function linearizeSRGB(colorChannel) {
    colorChannel /= 255;
    if (colorChannel <= .04045 ) {
        return colorChannel / 12.92;
    } else {
        return Math.pow((colorChannel + .055)/1.055, 2.4);
    }
}
console.log('First set of colors');
console.log('#1883b1', getLuminance('#1883b1'));
console.log('#2c3b4c', getLuminance('#2c3b4c'));
console.log('Second set of colors');
console.log('#920f1e', getLuminance('#920f1e'));
console.log('#c3313d', getLuminance('#c3313d'));
.c {
  height: 2rem;
  width: 2rem;
}
Sample of colors 
<span class="c" style="background-color: #1883b1">&nbsp;&nbsp;&nbsp;</span>
<span class="c" style="background-color: #2c3b4c">&nbsp;&nbsp;&nbsp;</span>
<span class="c" style="background-color: #920f1e">&nbsp;&nbsp;&nbsp;</span>
<span class="c" style="background-color: #c3313d">&nbsp;&nbsp;&nbsp;</span>

Каждый может видеть, что первый синий цвет светлее второго, и его значение меньше, хотя во втором наборе первый красный цвет кажется темнее второго, хотя и имеет меньшее значение ...

Я не понимаю, есть ли способ на самом деле определить воспринимаемую яркость?

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

Спасибо, ребята, заранее!

Ответы [ 2 ]

2 голосов
/ 05 января 2020

Очевидно, что с вашей реализацией есть как минимум две проблемы.

Во-первых, оператор ^^2.4) - это не оператор питания в JavaScript, а "исключительный или "оператор. Замените строку, где появляется этот оператор, следующим:

        return Math.pow(((colorChannel + .055)/1.055), 2.4);

Кроме того, метод getLuminance реализован неправильно; Основной причиной этого может быть метод reduce, который может сбить с толку, по крайней мере, мне. Замените эту реализацию следующим (которая использует гораздо более простое map, а также прямое сложение и умножение):

function getLuminance(color) {
  var cv=colorCodeToRGB(color).map(v=>linearizeSRGB(v))
  return cv[0]*luminanceCoefficients[0]+
            cv[1]*luminanceCoefficients[1]+
            cv[2]*luminanceCoefficients[2]
}
0 голосов
/ 08 февраля 2020

Ультра простой sRGB в воспринимаемую легкость

Супер простая JS функция для преобразования sRGB (как целые числа R, G, B) в воспринимаемую легкость (~ L *). Это упрощенный упрощенный метод, который должен обеспечить разумный прогноз для большинства общих случаев использования.

function lightness(Rint,Gint,Bint) { // takes sRGB channels as 8 bit integers

    var Rlin = (Rint / 255.0) ** 2.218;   // Convert int to decimal 0-1 and linearize
    var Glin = (Gint / 255.0) ** 2.218;   // ** is the exponentiation operator, older JS needs Math.pow() instead
    var Blin = (Bint / 255.0) ** 2.218;   // 2.218 Gamma for sRGB linearization. 2.218 sets unity with the piecewise sRGB at #777 .... 2.2 or 2.223 could be used instead

    var Ylum = Rlin * 0.2126 + Glin * 0.7156 + Blin * 0.0722;   // convert to Luminance Y

    return Math.pow(Ylum, 0.43) * 100;  // Convert to lightness (0 to 100)
}

Те, кто знаком с sRGB и CIELAB, заметят, что кусочные функции с почти черными линейностями имеют вид упал здесь. Это было сделано в интересах простоты. На практике это работает, поскольку нас обычно интересует воспринимаемая яркость для фотопи c зрения, а не для очень темных значений.

Показатель 0,43 в возвращении хорош для большинства случаев, но если вы сравниваете большие области (большие цветные блоки), вы можете понизить его до 0,33, или, если вы пытаетесь предсказать легкость крошечных точек света, вы можете увеличить его до 0,5 (см. Стивенс для справки об этих значениях)

...