【问题标题】:Blending transparent colors混合透明颜色
【发布时间】:2017-09-23 09:59:27
【问题描述】:

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

以下是 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));
    }
}

您可能已经猜到了,我正在将一个 libGDX 像素图逐个像素地合并到另一个上。如果你想混合像素,据我所知,似乎没有其他方法可以做到。

为了记录,画布是透明的黑色 (0, 0, 0, 0)。谁能指出我的公式哪里出错了?

【问题讨论】:

  • 我觉得更像float final_r = (src_r * src_a + (dst_r * dst_a * (1f - src_a));等等
  • @MarkSetchell 使用它可以很好地混合颜色,但它们并不完全正确。绘制 (1, 0, 0, 0.5) 导致 (0.5, 0, 0, 0.5) 被提交到画布上,并且在连续的绘制操作中,它不断将这些像素的 R 值减半。图片:i.imgur.com/eFS5FXt.png
  • 从 HSB 的角度再看一遍,在我的第二张图片中,颜色的色调和饱和度是正确的!唯一不正确的组件是亮度。仍然没有弄清楚如何将其纳入公式...
  • Dang,刚刚检查过,这实际上并非适用于所有情况。以 0.5 alpha 绘制白色而不是 1.0 alpha 绘制红色给我一个完全错误的青色。
  • 检查下"Alpha Blending" en.m.wikipedia.org/wiki/Alpha_compositing

标签: image-processing colors libgdx photoshop image-editing


【解决方案1】:

感谢Mark Setchell 为我指明了正确的方向!

这是最终代码,源自alpha blending formulas on Wikipedia

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

如果不先计算最终的 alpha 并除以它,颜色会在连续绘制操作中变得越来越暗,因为即使 (0, 0, 0, 0) 被绘制到像素,它们也会使自己变得更暗通过一遍又一遍地将它们的 RGB 乘以它们的 alpha。

最终结果:

【讨论】:

  • 干得好!并感谢您与社区分享。您可以而且应该接受您自己的答案是正确的 - 只需单击计票旁边的空心对勾/复选标记即可。
  • @MarkSetchell 会的!在我接受它为正确之前有一个延迟(还剩 20 小时),所以我会设置一个提醒。
猜你喜欢
  • 2012-05-10
  • 2021-02-18
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 2011-04-09
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
相关资源
最近更新 更多