Подбор цветов в фильтре feColorMatrix

У меня есть изображение в оттенках серого. Я хочу отфильтровать его так, чтобы white -> color1 и black -> color2. Оба цвета имеют шестнадцатеричный синтаксис CSS. Какую математику мне нужно сделать, чтобы получить этот эффект?

Я использую этот синтаксис:

<!-- just an example -->
<filter id="colorMeMatrix">
  <feColorMatrix in="SourceGraphic"
    type="matrix"
    values="0 0 0 0 0
            1 1 1 1 0
            0 0 0 0 0
            0 0 0 1 0" />


person PythonNut    schedule 24.02.2014    source источник
comment
У меня нет времени писать это прямо сейчас, но это может помочь вам начать: codepen.io/ АмелияBR/pen/AiHEJ   -  person AmeliaBR    schedule 24.02.2014


Ответы (1)


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

Матрица имеет пять столбцов и четыре строки. Каждая строка представляет одно из выходных чисел: R,G,B,A. Столбцы представляют ваш входной RGBA и константу 1. Вы вычисляете выходное значение для каждой строки, складывая каждое из значений в строке, умноженное на соответствующее входное значение.

Как входные, так и выходные числа стандартизированы в диапазоне 0-1, поэтому вам не нужно беспокоиться об умножении всего на 256.

Итак, для матрицы в вашем примере:

      /*R G B A 1 */
        0 0 0 0 0 // R = 0*R + 0*G + 0*B + 0*A + 0
        1 1 1 1 0 // G = 1*R + 1*G + 1*B + 1*A + 0
        0 0 0 0 0 // B = 0*R + 0*G + 0*B + 0*A + 0
        0 0 0 1 0 // A = 0*R + 0*G + 0*B + 1*A + 0

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

Это не то, что вы хотели, конечно. Вы хотели, чтобы черные области были одного цвета, а белые области — другого цвета, а все серые области — где-то посередине.

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

Если ваш color2, значение, которое вы хотите использовать для черного в своем монохромном изображении, равно (r2, g2, b2), то ваши постоянные коэффициенты должны быть такими:

      /*R G B A 1  */
        ? ? ? 0 r2 // R = ?*0 + ?*0 + ?*0 + 0*0 + r2 = r2
        ? ? ? 0 g2 // G = ?*0 + ?*0 + ?*0 + 0*0 + g2 = g2
        ? ? ? 0 b2 // B = ?*0 + ?*0 + ?*0 + 0*0 + b2 = b2
        0 0 0 1 0  // A = 1*A 

Конечно, приведенная выше матрица преобразует любой входной цвет в этот выходной цвет, потому что она не учитывает ничего из входных значений RGBA. Чтобы получить желаемый градиент, вам нужны белые области — с входными значениями 1 для R, G и B, чтобы получить ваш цвет1, который я собираюсь записать как (r1, g1, b1).

Теперь, чтобы немного упростить задачу, помните, что для изображения в градациях серого значения R, G и B для любой точки будут равны. Таким образом, мы можем просто использовать любое из этих значений в качестве входных данных и игнорировать другие. Итак, если мы просто установим R-фактор для каждого канала, когда входное значение белое, входное значение R равно 1, и уравнения

      /*R G B A 1  */
        ? 0 0 0 r2 // R = ?*1 + r2 = r1
        ? 0 0 0 g2 // G = ?*1 + g2 = g1
        ? 0 0 0 b2 // B = ?*1 + b2 = b1
        0 0 0 1 0  // A = 1*A 

Простая алгебра говорит вам, что для того, чтобы эти уравнения работали, вам нужно заменить вопросительные знаки разницей между значениями color1 и color2:

      /*   R    G B A 1  */
        (r1-r2) 0 0 0 r2 // R = (r1-r2)*1 + r2 = r1
        (g1-g2) 0 0 0 g2 // G = (g1-g2)*1 + g2 = g1
        (b1-b2) 0 0 0 b2 // B = (b1-b2)*1 + b2 = b1
           0    0 0 1 0  // A = 1*A 

Например, если вы хотите, чтобы белые области входного изображения отображались голубыми (r=0,g=1,b=1), а ваши черные области ввода отображались темно-фиолетовыми (r=0,1, g=0, b = 0,2), вы должны использовать матрицу вроде

        /*R  G B A  1  */
        -0.1 0 0 0 0.1 // R = (-0.1)*R + 0.1
          1  0 0 0  0  // G = 1*R + 0
         0.8 0 0 0 0.2 // B = 0.8*R + 0.2
          0  0 0 1  0  // A = 1*A 

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

Обратите внимание, что это на самом деле сильно отличается от примера, на который я ссылался в комментарии; в этом фильтре я пытался сохранить белый как белый и черный как черный, но изменить оттенки серого на цветные. Для этого я использовал фильтр гамма-коррекции, а не цветовую матрицу.

person AmeliaBR    schedule 24.02.2014
comment
Очень хорошо объяснил!! - person vals; 24.02.2014
comment
Вы, вероятно, захотите добавить в свой фильтр атрибут color-interpolation-filters=sRGB — он дает более естественную цветовую интерполяцию для изображений (с гамма-коррекцией). - person Michael Mullany; 26.02.2014
comment
@MichaelMullany Я не играл с этим - это имеет огромное значение, хотя я не знаю, обязательно ли версия sRGB лучше. Вам просто нужно знать, чего вы хотите, и убедиться, что вы вычисляете значения RGB для ваших цветов в правильном цветовом пространстве. Я обновил связанный пример для сравнения. - person AmeliaBR; 26.02.2014
comment
Я думаю, что большинство jpg и png в sRGB, поэтому я думаю, что для большинства изображений sRGB, вероятно, даст вам правильный результат в том смысле, что это, вероятно, результат, который вы ищете. Хотя не мешало бы открыть метаданные и посмотреть, что такое цветовой профиль. В спецификации SVG не совсем ясно, как именно должны применяться различные цветовые пространства. Я видел, как обработка linearRGB в Safari давала результаты, не похожие ни на какие другие браузеры. sRGB, похоже, обеспечивает хорошую кросс-браузерную точность. - person Michael Mullany; 26.02.2014
comment
Что ж, если вы начинаете с оттенков серого, начальный цветовой профиль не имеет значения. Но если вы пытаетесь сопоставить цвета на другом изображении, то это, безусловно, будет. И если спецификация sRGB будет более четко определена и совместима с разными браузерами, это будет большим аргументом в ее пользу. - person AmeliaBR; 26.02.2014
comment
Благодарю вас! Это сработало отлично (я пытаюсь сопоставить вывод TeX с Solarized). - person PythonNut; 28.02.2014
comment
Рекомендация @MichaelMullany добавить color-interpolation-filters="sRGB" дала эффект, который я искал. По сути, у меня был желаемый целевой цвет (# 002A78), и следующий фильтр теперь правильно сопоставляет полный источник с указанной целью: <feColorMatrix result="matrixOut" in="source" type="matrix" color-interpolation-filters="sRGB" values="0 0 0 0 0 0 0 0 0 0.17 0 0 0 0 0.47 0 0 0 1 0" /> - person Mike Jarema; 12.12.2014
comment
@MichaelMullany спасибо, вы спасли мне день! С color-interpolation-filters=sRGB цвета фильтра (0,5, 0,44 и т. д.) отображаются в RGB линейно: 0,5 0,5 0,5 точно соответствует rgb (128, 128, 128). - person cronfy; 14.07.2016
comment
Цветовые пространства — настоящая кроличья нора — рад помочь - person Michael Mullany; 15.07.2016