UFO ET IT

RGB 값에 대한 추가 색상 혼합 알고리즘

ufoet 2020. 11. 25. 21:44
반응형

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:). 이것은 색상을 밝게 / 어둡게하고 그라디언트를 만드는 데 더 효과적입니다.


알파 채널을 사용하여 블렌딩하려면 다음 공식을 사용할 수 있습니다.

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] 범위에 있습니다. [0, 255] 범위의 값을 사용하려면 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)이되는 알파 범위를 확인해야합니다.


재미있는 사실 : 컴퓨터 RGB 값은 광자 플럭스의 제곱근에서 파생됩니다. 따라서 일반적인 함수로서 수학은이를 고려해야합니다. 주어진 채널에 대한 일반적인 기능은 다음과 같습니다.

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

여기서 a와 b는 혼합 할 색상이고 t는 a와 b 사이에서 원하는 혼합 지점을 나타내는 0-1의 숫자입니다.

알파 채널은 다릅니다. 그것은 광자 강도를 나타내는 것이 아니라 보여야하는 배경의 비율만을 나타냅니다. 따라서 알파 값을 혼합 할 때 선형 평균이면 충분합니다.

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

덧붙여서, 나는 (또는 그 이상) 깔끔하게 수학을 표현하고 (위 첨자, 기호 및 기타 다양한 문자에 대해 결합 된 윗줄 유니 코드 문자가 작동하지 않음) 올바르게 해석 할 수있는 프로그래밍 언어와 키보드를 원합니다. sqrt ((1-t) * pow (a, 2) + t * pow (b, 2))는 깨끗한 것으로 읽지 않습니다.


몇 가지 사항 :

  • max 대신 min을 사용하고 싶다고 생각합니다.
  • 256 대신 255를 사용하고 싶다고 생각합니다

이것은 다음을 줄 것입니다 :

(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)


RGBA 색상을 혼합하는 Javascript 함수

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
       }
     } 

PYTHON 컬러 믹싱 통해 ADDITION 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 %를 혼합한다고 말할 수 있습니다.


예, 그렇게 간단합니다. 또 다른 옵션은 평균을 찾는 것입니다 (그라데이션 생성 용).

실제로 달성하려는 효과에 따라 다릅니다.

However, when Alpha gets added, it gets complicated. There are a number of different methods to blend using an alpha.

An example of simple alpha blending: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending


When I came here I didn't find the "additive color mixing" algorithm I was actually looking for, which is also available in Photoshop and is described as "Screen" on Wikipedia. (Aka "brighten" or "invert multiply".) It produces a result similar to two light sources being combined.

With Screen blend mode the values of the pixels in the two layers are inverted, multiplied, and then inverted again. This yields the opposite effect to multiply. The result is a brighter picture.

Here it is:

// (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);
}

Have written/used something like @Markus Jarderot's sRGB blending answer (which is not gamma corrected since that is the default legacy) using 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 / 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;

more info: what-every-coder-should-know-about-gamma


Here's a highly optimized, standalone c++ class, public domain, with floating point and two differently optimized 8-bit blending mechanisms in both function and macro formats, as well as a technical discussion of both the problem at hand and how to, and the importance of, optimization of this issue:

https://github.com/fyngyrz/colorblending


Thank you Markus Jarderot, Andras Zoltan and hkurabko; here is the Python code for blending a list of RGB images.

Using Markus Jarderot's code we can generate RGBA color, then i use Andras Zoltan and hkurabko's method to trans RGBA to RGB.

Thank you!

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

Test

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      ])

참고URL : https://stackoverflow.com/questions/726549/algorithm-for-additive-color-mixing-for-rgb-values

반응형