RGB值的加法混合算法

89

我正在寻找一种算法来执行RGB颜色值的加法混合。

是否只需要将RGB值相加,最大值为256?

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

为什么需要这个?简单的加法可能并不总是能给出你想要的结果。 - dirkgently
4
理想情况下,它应该像彩色光一样呈现颜色混合效果。我可能不正确,但我认为这就是加法混色所代表的。也许我错了。 - Gaidin
你说得完全正确,应该是最小值。 - Gaidin
1
通常,颜色通道的值范围是从0到255,而不是1到256。 - Mr Fooz
13个回答

1
我曾经遇到过类似的问题,最终不得不自己编写实现。我的想法是将新的前景色“覆盖”在现有的背景色之上(而不使用任意中点,如 t)。我相信我的实现仍然是“累加”的。这种方法在我的所有测试用例中都能很好地混合。在这里,new_argb 只是将 int 转换为一个具有 4 个 unsigned char 的结构体,以便我可以减少位移量。
int blend_argb(int foreground, int background)
{
    t_argb fg;
    t_argb bg;
    t_argb blend;
    double ratio;

    fg = new_argb(foreground);
    bg = new_argb(background);

    // If background is transparent,
    // use foreground color as-is and vice versa.
    if (bg.a == 255)
        return (foreground);
    if (fg.a == 255)
        return (background);

    // If the background is fully opaque,
    // ignore the foreground alpha. (Or the color will be darker.)
    // Otherwise alpha is additive.
    blend.a = ((bg.a == 0) ? 0 : (bg.a + fg.a));

    // When foreground alpha == 0, totally covers background color.
    ratio = fg.a / 255.0;
    blend.r = (fg.r * (1 - ratio)) + (bg.r * ratio);
    blend.g = (fg.g * (1 - ratio)) + (bg.g * ratio);
    blend.b = (fg.b * (1 - ratio)) + (bg.b * ratio);

    return (blend.a << 24 | blend.r << 16 | blend.g << 8 | blend.b);
}

为了提供上下文,我正在将颜色int写入1D像素数组中,该数组使用0字节进行初始化,并增加alpha值将使像素趋向于黑色。(00 0 0将是不透明的黑色,255255 255 255将是透明的白色...也就是黑色。)


0

这是一个高度优化的、独立的C++类,公共领域,具有浮点数和两种不同优化的8位混合机制,分别以函数和宏格式呈现,以及对问题本身、如何进行优化以及优化此问题的重要性的技术讨论:

https://github.com/fyngyrz/colorblending


仅提供链接的答案并不是一个好主意,链接会失效,你最终得到的是一些毫无价值的东西。如果你不能在这里发布代码,请至少进行描述和总结。 - Mark Ransom
1
如果SO拥有与Github稍微一样好的机制,我很乐意在这里发布代码。但它没有。更不用说SO令人讨厌的许可政策了。至于链接到Github出现问题的可能性,那几乎等同于链接到SO出现问题的可能性。链接是网络的核心。我发布的内容与此问题完全相关,并且提供了一个针对此特定问题的绝妙解决方案,我已将其放入公共领域。你的评论根本没有任何帮助或用处,只是想制造麻烦。 - fyngyrz
1
不,我试图明确 StackOverflow 有 答案,而不是指向答案的链接。Google 已经有很多这样的链接了。 - Mark Ransom
4
我给出了一个与问题相关的答案,包含代码链接。Stack Overflow没有包含重要C类别的机制,也没有适用于在网站上出现的代码的可接受许可证,因此您想要的根本不可能实现。选择是包括链接回答或根本不回答。后者对任何人都没有好处。前者是相关、信息丰富和非常有用的。至于Google,那里的结果是无关和广告的污水坑。因此,也许您应该重新考虑您的立场。最后一个话语留给您。我对我的答案感到满意。 - fyngyrz
2
对于一个人发布指向他自己的 Github 存储库中解决方案的链接而被 downvote,似乎有点肤浅了。 - BobRodes

0

感谢Markus Jarderot、Andras Zoltan和hkurabko;这里是混合RGB图像列表的Python代码。

使用Markus Jarderot的代码,我们可以生成RGBA颜色,然后我使用Andras Zoltan和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      ])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接