Подтвердить что ты не робот

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

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

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

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

Ответ 1

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

Если вы хотите

Red + Black        = Red
Red + Green        = Yellow
Red + Green + Blue = White
Red + White        = White 
Black + White      = White

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

Если вы хотите

Red + Black        = Dark Red
Red + Green        = Dark Yellow
Red + Green + Blue = Dark Gray
Red + White        = Pink
Black + White      = Gray

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

Ответ 2

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

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

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();
r.A = 1 - (1 - fg.A) * (1 - bg.A); // 0.75
r.R = fg.R * fg.A / r.A + bg.R * bg.A * (1 - fg.A) / r.A; // 0.67
r.G = fg.G * fg.A / r.A + bg.G * bg.A * (1 - fg.A) / r.A; // 0.33
r.B = fg.B * fg.A / r.A + bg.B * bg.A * (1 - fg.A) / r.A; // 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 (r.A - fg.A < -1.0e-6) return null; // No result -- 'fg' can't make the result more transparent
if (r.A - fg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important
bg.A = 1 - (1 - r.A) / (1 - fg.A);
bg.R = (r.R * r.A - fg.R * fg.A) / (bg.A * (1 - fg.A));
bg.G = (r.G * r.A - fg.G * fg.A) / (bg.A * (1 - fg.A));
bg.B = (r.B * r.A - 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 (r.A - bg.A < -1.0e-6) return null; // No result -- 'bg' can't make the result more transparent
if (r.A - bg.A < 1.0e-6) return bg; // Fully transparent -- R,G,B not important
fg.A = 1 - (1 - r.A) / (1 - bg.A);
fg.R = (r.R * r.A - bg.R * bg.A * (1 - fg.A)) / fg.A;
fg.G = (r.G * r.A - bg.G * bg.A * (1 - fg.A)) / fg.A;
fg.B = (r.B * r.A - bg.B * bg.A * (1 - fg.A)) / fg.A;

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


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

Ответ 3

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

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)) просто не читается как чистый.

Ответ 4

Несколько точек:

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

Это даст:

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

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

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

Ответ 5

Функция 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
       }
     } 

Ответ 6

PYTHON ЦВЕТ СМЕШИВАНИЕ ЧЕРЕЗ ДОБАВЛЕНИЕ IN 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% второго цвета.

Ответ 7

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

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

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

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

Ответ 8

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

//same as Markus Jarderot answer
float red, green, blue;
alpha = (1.0 - (1.0 - back.alpha)*(1.0 - front.alpha));
red   = (front.red   * front.alpha / alpha + back.red   * back.alpha * (1.0 - front.alpha));
green = (front.green * front.alpha / alpha + back.green * back.alpha * (1.0 - front.alpha));
blue  = (front.blue  * front.alpha / 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   * front.alpha);
green = (back.green * (1.0 - front.alpha) + front.green * front.alpha);
blue  = (back.blue  * (1.0 - front.alpha) + front.blue  * front.alpha);

//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   * front.alpha) / 255;
green = (back.green * (255 - front.alpha) + front.green * front.alpha) / 255;
blue  = (back.blue  * (255 - front.alpha) + front.blue  * front.alpha) / 255;

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

Ответ 9

Когда я пришел сюда, я не нашел алгоритм "аддитивного смешения цветов", который действительно искал, который также доступен в Photoshop и описывается как "Экран" в Википедии. (Ака "ярче" или "инвертировать умножение".) Это дает результат, похожий на объединение двух источников света.

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

Вот:

// (rgb values are 0-255)
function screen(color1, color2) {
    var r = Math.round((1 - (1 - color1.R / 255) * (1 - color2.R / 255)) * 255);
    var g = Math.round((1 - (1 - color1.G / 255) * (1 - color2.G / 255)) * 255);
    var b = Math.round((1 - (1 - color1.B / 255) * (1 - color2.B / 255)) * 255);
    return new Color(r, g, b);
}

Ответ 10

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

https://github.com/fyngyrz/colorblending

Ответ 11

Спасибо Маркус Жардеро, Андрас Золтан и Хкурабко; Вот код Python для смешивания списка изображений RGB.

Используя код Markus Jarderot, мы можем генерировать цвет RGBA, затем я использую метод Андраса Золтана и hkurabko для преобразования RGBA в RGB.

Спасибо!

import numpy as np
def Blend2Color(C1,C2):
    c1,c1a=C1
    c2,c2a=C2
    A = 1 - (1 - c1a) * (1 - c2a);
    if (A < 1.0e-6): 
        return (0,0,0) #Fully transparent -- R,G,B not important
    Result=(np.array(c1)*c1a+np.array(c2)*c2a*(1-c1a))/A
    return Result,A
def RGBA2RGB(RGBA,BackGround=(1,1,1)):# whilt background
    A=RGBA[-1]
    RGB=np.add(np.multiply(np.array(RGBA[:-1]),A),
               np.multiply(np.array(BackGround),1-A))
    return RGB

def BlendRGBList(Clist,AlphaList=None,NFloat=2,ReturnRGB=True,
                 RGB_BackGround=(1,1,1)):
    N=len(Clist)
    if AlphaList==None:
        ClistUse=Clist.copy()
    else:
        if len(AlphaList)==N:
            AlphaListUse=np.multiply(AlphaList,10**NFloat).astype(int)
            ClistUse=np.repeat(np.array(Clist), AlphaListUse, axis=0)
        else:
            raise('len of AlphaList must equal to len of Clist!')
    while N!=1:
        temp=ClistUse.copy()
        ClistUse=[]
        for C in temp[:-1]:
            c1,a1=C
            c2,a2=temp[-1]
            ClistUse.append(Blend2Color(C1=(c1,a1*(1-1/N)),C2=(c2,a2*1/N)))
        N=len(ClistUse)
    Result=np.append(ClistUse[0][0],ClistUse[0][1])
    if ReturnRGB:
        Result=RGBA2RGB(Result,BackGround=RGB_BackGround)

    return Result

Тестовое задание

BlendRGBList([[(1,0,0),1],[(0,1,0),1]],ReturnRGB=True)
#array([0.75, 0.5 , 0.25])
BlendRGBList([[(1,0,0),1],[(0,1,0),1]],ReturnRGB=False)
#array([0.66666667, 0.33333333, 0.        , 0.75      ])