Алгоритм добавления смешанного цвета для значений RGB
Я ищу алгоритм для добавления аддитивного смешивания цветов для значений RGB.
Это так же просто, как добавление значений RGB вместе максимум до 256?
(r1, g1, b1) + (r2, g2, b2) = (min(r1+r2, 256), min(g1+g2, 256), min(b1+b2, 256))
- Использование цвета и color.darker в Android?
- Преобразовать строку в название кисти / кисти в C #
- Плавный спектр для создания Мандельброта
- Как преобразовать целое число цвета в шестнадцатеричную строку в Android?
- цвет андроида между двумя цветами, в зависимости от процента?
- Функция создания цветных колес
- Как установить цвет фона операции на белый программным путем?
- Изменение оттенка цвета RGB
- Разница между Color.red и Color.RED
- Цветной grep - просмотр всего файла с выделенными совпадениями
- Алгоритм случайного генерирования эстетически приятной цветовой палитры
- Как генерировать случайные имена цветов в C #
- Как использовать 3-значные цветовые коды, а не 6-значные цветовые коды в CSS?
Это зависит от того, что вы хотите, и это может помочь увидеть, какие результаты имеют разные методы.
Если ты хочешь
Красный + черный = красный Красный + зеленый = желтый Красный + зеленый + синий = белый Красный + белый = белый Черный + белый = белый
затем добавление с помощью зажима (например, 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-битные механизмы смешивания как в форматах функций, так и в макроформах, а также техническое обсуждение как проблемы, так и важности, а также важности , оптимизация этой проблемы:
Написали / использовали что-то вроде ответа на смешение 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;
больше информации: что-каждый-кодер-должен-знать-о-гамма