Image processing 混合透明颜色

Image processing 混合透明颜色,image-processing,colors,libgdx,photoshop,image-editing,Image Processing,Colors,Libgdx,Photoshop,Image Editing,我正在开发自己的图像编辑器,我遇到了一点障碍。对于其他图像编辑器如何将透明颜色混合在一起,我感到困惑 以下是Photoshop和其他一些程序的实现方式: 正如你们所看到的,这不是一个简单的颜色组合!这取决于你画的是哪一个而不是另一个 这是迄今为止我在编辑器中所能得到的最接近的近似值。透明的红色和透明的绿色绘制正确,但当我在红色上绘制绿色时,我会得到一个真正明亮的绿色(0.5,1,0,0.75),当我在绿色上绘制红色时,我会得到一个明亮的橙色(1,0.5,0,0.75) 让我如此接近的公式如下

我正在开发自己的图像编辑器,我遇到了一点障碍。对于其他图像编辑器如何将透明颜色混合在一起,我感到困惑

以下是Photoshop和其他一些程序的实现方式:

正如你们所看到的,这不是一个简单的颜色组合!这取决于你画的是哪一个而不是另一个

这是迄今为止我在编辑器中所能得到的最接近的近似值。透明的红色和透明的绿色绘制正确,但当我在红色上绘制绿色时,我会得到一个真正明亮的绿色(0.5,1,0,0.75),当我在绿色上绘制红色时,我会得到一个明亮的橙色(1,0.5,0,0.75)

让我如此接近的公式如下:

pixmap.setBlending(Blending.None);
memtex.pixmap.setBlending(Blending.None);
for(int x = 0; x < width; x++) {
    for(int y = 0; y < height; y++) {
        int src_color = pixmap.getPixel(x, y);
        float src_r = (float)((src_color & 0xff000000) >>> 24) / 255f;
        float src_g = (float)((src_color & 0x00ff0000) >>> 16) / 255f;
        float src_b = (float)((src_color & 0x0000ff00) >>> 8) / 255f;
        float src_a = (float)(src_color & 0x000000ff) / 255f;

        int dst_color = memtex.pixmap.getPixel(x, y);
        float dst_r = (float)((dst_color & 0xff000000) >>> 24) / 255f;
        float dst_g = (float)((dst_color & 0x00ff0000) >>> 16) / 255f;
        float dst_b = (float)((dst_color & 0x0000ff00) >>> 8) / 255f;
        float dst_a = (float)(dst_color & 0x000000ff) / 255f;

        //Blending formula lines! The final_a line is correct.
        float final_r = (src_r * (1f - dst_r)) + (dst_r * (1f - src_a));
        float final_g = (src_g * (1f - dst_g)) + (dst_g * (1f - src_a));
        float final_b = (src_b * (1f - dst_b)) + (dst_b * (1f - src_a));
        float final_a = (src_a * 1) + (dst_a * (1f - src_a));

        memtex.pixmap.drawPixel(x, y, Color.rgba8888(final_r, final_g, final_b, final_a));
    }
}
pixmap.setblen(Blending.None);
memtex.pixmap.setBlending(Blending.None);
对于(int x=0;x>>24)/255f;
float src_g=(float)((src_color&0x00ff0000)>>>16)/255f;
浮点数src_b=(浮点数)((src_color&0x0000ff00)>>>8)/255f;
浮点数src_a=(浮点数)(src_color&0x000000ff)/255f;
int dst_color=memtex.pixmap.getPixel(x,y);
浮点数dst_r=(浮点数)((dst_颜色&0xff000000)>>>24)/255f;
浮点数dst_g=(浮点数)((dst_颜色&0x00ff0000)>>>16)/255f;
浮点数dst_b=(浮点数)((dst_颜色&0x0000ff00)>>>8)/255f;
浮动dst_a=(浮动)(dst_颜色&0x000000ff)/255f;
//混合公式行!最后一行是正确的。
最终浮点数r=(src_r*(1f-dst_r))+(dst_r*(1f-src_a));
最终浮点数=(src_g*(1f-dst_g))+(dst_g*(1f-src_a));
最终浮点数b=(src_b*(1f-dst_b))+(dst_b*(1f-src_a));
最终浮点数a=(src_a*1)+(dst_a*(1f-src_a));
memtex.pixmap.drawPixel(x,y,Color.rgba8888(final_r,final_g,final_b,final_a));
}
}
正如您可能猜到的,我正在逐像素地将一个libGDX pixmap合并到另一个libGDX pixmap。如果你想混合像素,就我所知,似乎没有其他方法

对于记录,画布是透明的黑色(0,0,0,0)。有人能指出我的公式哪里出了问题吗?

谢谢你给我指明了正确的方向

这是最终的代码,派生自

pixmap.setblen(Blending.None);
memtex.pixmap.setBlending(Blending.None);
对于(int x=0;x>>24)/255f;
float src_g=(float)((src_color&0x00ff0000)>>>16)/255f;
浮点数src_b=(浮点数)((src_color&0x0000ff00)>>>8)/255f;
浮点数src_a=(浮点数)(src_color&0x000000ff)/255f;
if(src_a==0)continue;//如果src color是完全透明的,则不绘制。这还可以防止在src_a和dst_a都为0时被零除。
int dst_color=memtex.pixmap.getPixel(x,y);
浮点数dst_r=(浮点数)((dst_颜色&0xff000000)>>>24)/255f;
浮点数dst_g=(浮点数)((dst_颜色&0x00ff0000)>>>16)/255f;
浮点数dst_b=(浮点数)((dst_颜色&0x0000ff00)>>>8)/255f;
浮动dst_a=(浮动)(dst_颜色&0x000000ff)/255f;
//混合公式行!所有行现在都正确。
//我们需要先计算最终的α。
最终浮点数a=src_a+dst_a*(1-src_a);
浮点数final_r=((src_r*src_a)+(dst_r*dst_a*(1f-src_a))/final_a;
浮点数final_g=((src_g*src_a)+(dst_g*dst_a*(1f-src_a))/final_a;
浮点数final_b=((src_b*src_a)+(dst_b*dst_a*(1f-src_a))/final_a;
memtex.pixmap.drawPixel(x,y,Color.rgba8888(final_r,final_g,final_b,final_a));
}
}
如果不先计算最终的alpha并除以它,在连续的绘制操作中,颜色会变得越来越暗,因为即使(0,0,0,0)被绘制到像素上,它们也会通过将RGB乘以alpha一次又一次使自己变暗

最终结果:


我认为它更像是
float final_r=(src_r*src_a+(dst_r*dst_a*(1f-src_a));
等等on@MarkSetchell使用此选项,颜色可以很好地混合,但它们并不完全正确。绘图(1,0,0,0.5)的结果是(0.5,0,0,0.5)致力于画布,并在连续绘制操作中不断将这些像素的R值减半。Pic:再次从HSB角度来看,在我的第二张图像中,颜色的色调和饱和度是正确的!唯一不正确的部分是亮度。仍然没有弄清楚如何将其纳入公式中。。。Dang,刚刚检查过,但事实上并非每种情况都如此。在0.5 alpha处绘制白色,在1.0 alpha处绘制红色,会给我一个完全错误的青色。在“alpha混合”下检查干得好!感谢您与社区分享。您可以也应该接受您自己的答案为正确-只需单击计票旁边的空心勾号/复选标记。@MarkSetchell就可以了!在我接受正确答案(还剩20小时)之前会有延迟,所以我会设置一个提醒。
pixmap.setBlending(Blending.None);
memtex.pixmap.setBlending(Blending.None);
for(int x = 0; x < width; x++) {
    for(int y = 0; y < height; y++) {
        int src_color = pixmap.getPixel(x, y);
        float src_r = (float)((src_color & 0xff000000) >>> 24) / 255f;
        float src_g = (float)((src_color & 0x00ff0000) >>> 16) / 255f;
        float src_b = (float)((src_color & 0x0000ff00) >>> 8) / 255f;
        float src_a = (float)(src_color & 0x000000ff) / 255f;
        if(src_a == 0) continue; //don't draw if src color is fully transparent. This also prevents a divide by zero if both src_a and dst_a are 0.

        int dst_color = memtex.pixmap.getPixel(x, y);
        float dst_r = (float)((dst_color & 0xff000000) >>> 24) / 255f;
        float dst_g = (float)((dst_color & 0x00ff0000) >>> 16) / 255f;
        float dst_b = (float)((dst_color & 0x0000ff00) >>> 8) / 255f;
        float dst_a = (float)(dst_color & 0x000000ff) / 255f;

        //Blending formula lines! All lines are now correct.

        //we need to calculate the final alpha first.
        float final_a = src_a + dst_a * (1 - src_a);

        float final_r = ((src_r * src_a) + (dst_r * dst_a * (1f - src_a))) / final_a;
        float final_g = ((src_g * src_a) + (dst_g * dst_a * (1f - src_a))) / final_a;
        float final_b = ((src_b * src_a) + (dst_b * dst_a * (1f - src_a))) / final_a;

        memtex.pixmap.drawPixel(x, y, Color.rgba8888(final_r, final_g, final_b, final_a));
    }
}