Алгоритм добавления смешанного цвета для значений RGB

Я ищу алгоритм для добавления аддитивного смешивания цветов для значений RGB.

Это так же просто, как добавление значений RGB вместе максимум до 256?

(r1, g1, b1) + (r2, g2, b2) = (min(r1+r2, 256), min(g1+g2, 256), min(b1+b2, 256)) 

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

Если ты хочешь

 Красный + черный = красный
 Красный + зеленый = желтый
 Красный + зеленый + синий = белый
 Красный + белый = белый 
 Черный + белый = белый

затем добавление с помощью зажима (например, min(r1 + r2, 255) ). Это больше похоже на модель света, о которой вы говорили.

Если ты хочешь

 Красный + черный = темно-красный
 Красный + зеленый = темно-желтый
 Красный + Зеленый + Синий = Темно-серый
 Красный + белый = розовый
 Черный + белый = серый

то вам нужно будет усреднить значения (например, (r1 + r2) / 2 ). Это лучше работает для освещения / затемнения цветов и создания gradleиентов.

Чтобы использовать альфа-каналы, вы можете использовать следующие формулы:

 r = new Color(); rA = 1 - (1 - fg.A) * (1 - bg.A); if (rA < 1.0e-6) return r; // Fully transparent -- R,G,B not important rR = fg.R * fg.A / rA + bg.R * bg.A * (1 - fg.A) / rA; rG = fg.G * fg.A / rA + bg.G * bg.A * (1 - fg.A) / rA; rB = fg.B * fg.A / rA + bg.B * bg.A * (1 - fg.A) / rA; 

fg - цвет краски. bg - фон. r - полученный цвет. 1.0e-6 - это действительно очень небольшое число, чтобы компенсировать ошибки округления.

ПРИМЕЧАНИЕ. Все используемые здесь переменные находятся в диапазоне [0.0, 1.0]. Вы должны разделить или умножить на 255, если вы хотите использовать значения в диапазоне [0, 255].

Например, 50% красного цвета на 50% зеленого:

 // background, 50% green var bg = new Color { R = 0.00, G = 1.00, B = 0.00, A = 0.50 }; // paint, 50% red var fg = new Color { R = 1.00, G = 0.00, B = 0.00, A = 0.50 }; // The result var r = new Color(); rA = 1 - (1 - fg.A) * (1 - bg.A); // 0.75 rR = fg.R * fg.A / rA + bg.R * bg.A * (1 - fg.A) / rA; // 0.67 rG = fg.G * fg.A / rA + bg.G * bg.A * (1 - fg.A) / rA; // 0.33 rB = fg.B * fg.A / rA + bg.B * bg.A * (1 - fg.A) / rA; // 0.00 

Результирующий цвет: (0.67, 0.33, 0.00, 0.75) , или 75% коричневый (или темно-оранжевый).


Вы также можете изменить эти формулы:

 var bg = new Color(); if (1 - fg.A <= 1.0e-6) return null; // No result -- 'fg' is fully opaque if (rA - fg.A < -1.0e-6) return null; // No result -- 'fg' can't make the result more transparent if (rA - fg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important bg.A = 1 - (1 - rA) / (1 - fg.A); bg.R = (rR * rA - fg.R * fg.A) / (bg.A * (1 - fg.A)); bg.G = (rG * rA - fg.G * fg.A) / (bg.A * (1 - fg.A)); bg.B = (rB * rA - fg.B * fg.A) / (bg.A * (1 - fg.A)); 

или

 var fg = new Color(); if (1 - bg.A <= 1.0e-6) return null; // No result -- 'bg' is fully opaque if (rA - bg.A < -1.0e-6) return null; // No result -- 'bg' can't make the result more transparent if (rA - bg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important fg.A = 1 - (1 - rA) / (1 - bg.A); fg.R = (rR * rA - bg.R * bg.A * (1 - fg.A)) / fg.A; fg.G = (rG * rA - bg.G * bg.A * (1 - fg.A)) / fg.A; fg.B = (rB * rA - bg.B * bg.A * (1 - fg.A)) / fg.A; 

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


Если ваш фон непрозрачен, результат также будет непрозрачным. Цвет переднего плана может затем принимать диапазон значений с разными значениями альфа. Для каждого канала (красного, зеленого и синего) вы должны проверить, какой диапазон альфа приводит к действительным значениям (0 - 1).

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

 blendColorValue(a, b, t) return sqrt((1 - t) * a^2 + t * b^2) 

Где a и b – цвета для смешивания, а t – число от 0-1, представляющее точку в смеси, которую вы хотите между a и b.

Альфа-канал отличается; он не представляет интенсивности фотонов, а только процент фона, который должен проявляться; поэтому при смешении альфа-значений достаточно линейного среднего:

 blendAlphaValue(a, b, t) return (1-t)*a + t*b; 

Итак, для обработки смешивания двух цветов, используя эти две функции, следующий псевдокод должен сделать вам хорошо:

 blendColors(c1, c2, t) ret [r, g, b].each n -> ret[n] = blendColorValue(c1[n], c2[n], t) ret.alpha = blendAlphaValue(c1.alpha, c2.alpha, t) return ret 

Кстати, я хочу, чтобы язык программирования и клавиатура позволяли отображать математику (или более) чисто (объединение символов юникода overline не работает для надстроек, символов и большого массива других символов) и правильно интерпретирует их. sqrt ((1-t) * pow (a, 2) + t * pow (b, 2)) просто не читается как чистый.

Несколько пунктов:

  • Я думаю, вы хотите использовать min вместо max
  • Я думаю, вы хотите использовать 255 вместо 256

Это даст:

(r1, g1, b1) + (r2, g2, b2) = (min (r1 + r2, 255), min (g1 + g2, 255), min (b1 + b2, 255))

Однако «естественный» способ смешивания цветов – использовать среднее значение, а затем вам не нужно мин:

(r1, g1, b1) + (r2, g2, b2) = ((r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2)

Функция Javascript для смешивания цветов rgba

c1, c2 и результат – JSON как c1 = {r: 0.5, g: 1, b: 0, a: 0.33}

  var rgbaSum = function(c1, c2){ var a = c1.a + c2.a*(1-c1.a); return { r: (c1.r * c1.a + c2.r * c2.a * (1 - c1.a)) / a, g: (c1.g * c1.a + c2.g * c2.a * (1 - c1.a)) / a, b: (c1.b * c1.a + c2.b * c2.a * (1 - c1.a)) / a, a: a } } 

ПЯТЬ ЦВЕТОВОГО СМЕШЕНИЯ ЧЕРЕЗ ДОПОЛНЕНИЕ В ПРОЦЕССЕ CMYK

Один из возможных способов сделать это – сначала преобразовать цвета в формат CMYK , добавить их туда и обратно в RGB.

Вот пример кода в Python:

 rgb_scale = 255 cmyk_scale = 100 def rgb_to_cmyk(self,r,g,b): if (r == 0) and (g == 0) and (b == 0): # black return 0, 0, 0, cmyk_scale # rgb [0,255] -> cmy [0,1] c = 1 - r / float(rgb_scale) m = 1 - g / float(rgb_scale) y = 1 - b / float(rgb_scale) # extract out k [0,1] min_cmy = min(c, m, y) c = (c - min_cmy) m = (m - min_cmy) y = (y - min_cmy) k = min_cmy # rescale to the range [0,cmyk_scale] return c*cmyk_scale, m*cmyk_scale, y*cmyk_scale, k*cmyk_scale def cmyk_to_rgb(self,c,m,y,k): """ """ r = rgb_scale*(1.0-(c+k)/float(cmyk_scale)) g = rgb_scale*(1.0-(m+k)/float(cmyk_scale)) b = rgb_scale*(1.0-(y+k)/float(cmyk_scale)) return r,g,b def ink_add_for_rgb(self,list_of_colours): """input: list of rgb, opacity (r,g,b,o) colours to be added, o acts as weights. output (r,g,b) """ C = 0 M = 0 Y = 0 K = 0 for (r,g,b,o) in list_of_colours: c,m,y,k = rgb_to_cmyk(r, g, b) C+= o*c M+=o*m Y+=o*y K+=o*k return cmyk_to_rgb(C, M, Y, K) 

Результатом вашего вопроса будет тогда (предполагая половину смеси двух цветов:

 r_mix, g_mix, b_mix = ink_add_for_rgb([(r1,g1,b1,0.5),(r2,g2,b2,0.5)]) 

где 0,5 года, чтобы сказать, что мы смешиваем 50% первого цвета с 50% второго цвета.

Да, это так просто. Другой вариант – найти среднее значение (для создания gradleиентов).

Это действительно зависит от эффекта, которого вы хотите достичь.

Однако, когда Alpha добавляется, это становится сложным. Существует несколько различных методов для смешивания с использованием альфы.

Пример простого альфа-смешивания: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending

Вот высоко оптимизированный автономный class c ++, общеansible домен с плавающей запятой и два по-разному оптимизированные 8-битные механизмы смешивания как в форматах функций, так и в макроформах, а также техническое обсуждение как проблемы, так и важности, а также важности , оптимизация этой проблемы:

https://github.com/fyngyrz/colorblending

Написали / использовали что-то вроде ответа на смешение sRGB @Markus Jarderot (который не исправляется гаммами, поскольку это наследие по умолчанию) с использованием C ++

 //same as Markus Jarderot's answer float red, green, blue; alpha = (1.0 - (1.0 - back.alpha)*(1.0 - front.alpha)); red = (front.red * front.alpha / result.alpha + back.red * back.alpha * (1.0 - front.alpha)); green = (front.green * front.alpha / result.alpha + back.green * back.alpha * (1.0 - front.alpha)); blue = (front.blue * front.alpha / result.alpha + back.blue * back.alpha * (1.0 - front.alpha)); //faster but equal output alpha = (1.0 - (1.0 - back.alpha)*(1.0 - front.alpha)); red = (back.red * (1.0 - front.alpha) + front.red * frontAlpha); green = (back.green * (1.0 - front.alpha) + front.green * frontAlpha); blue = (back.blue * (1.0 - front.alpha) + front.blue * frontAlpha); //even faster but only works when all values are in range 0 to 255 int red, green, blue; alpha = (255 - (255 - back.alpha)*(255 - front.alpha)); red = (back.red * (255 - front.alpha) + front.red * frontAlpha) / 255; green = (back.green * (255 - front.alpha) + front.green * frontAlpha) / 255; blue = (back.blue * (255 - front.alpha) + front.blue * frontAlpha) / 255; 

больше информации: что-каждый-кодер-должен-знать-о-гамма

  • Определить цвет шрифта на основе цвета фона
  • Алгоритм цветового затухания?
  • Как заполнить geom_polygon разными цветами выше и ниже y = 0?
  • Есть ли простой способ сравнить, насколько близки два цвета друг к другу
  • Android: изменение фонового цвета активности (основной вид)
  • Разница между Color.red и Color.RED
  • Как определить цвета в качестве переменных в CSS?
  • Функция создания цветных колес
  • Цветной grep - просмотр всего файла с выделенными совпадениями
  • Как автоматически генерировать N "разных" цветов?
  • Преобразование цвета HSL в RGB
  • Давайте будем гением компьютера.