保存使用 glReadPixels 读取的图像,其中 alpha 值不是一
Posted
技术标签:
【中文标题】保存使用 glReadPixels 读取的图像,其中 alpha 值不是一【英文标题】:Saving images read with glReadPixels where alpha value is not one 【发布时间】:2015-03-05 16:34:21 【问题描述】:当使用glReadPixels
保存图像时,颜色会在其 alpha 值小于 1 的位置出现失真。
表面由 QtQuick 管理。使用glGetInteger
,我发现每个通道都有 8 位,包括 alpha。
使用这样的方法,我可以获得更好的结果,但并不完美:
for x := 0; x < m.Bounds().Dx(); x++
for y := 0; y < m.Bounds().Dy(); y++
c := m.RGBAAt(x, y)
w := float64(c.A) / 255
c.R = uint8(float64(c.R)*w + 255*(1-w) + 0.5)
c.G = uint8(float64(c.G)*w + 255*(1-w) + 0.5)
c.B = uint8(float64(c.B)*w + 255*(1-w) + 0.5)
c.A = 255
m.SetRGBA(x, y, c)
我尝试使用以下方法清除 OpenGL 本身中的 alpha 组件:
s.gl.ClearColor(0, 0, 0, 1)
s.gl.ColorMask(false, false, false, true)
s.gl.Clear(GL.COLOR_BUFFER_BIT)
现在的结果与我的手动构图相似,而且显示和捕获的图像相同,但仍然与之前显示的不同(并且比之前显示的更暗)。
我对 OpenGL/Qt 在显示颜色缓冲区时如何使用 alpha 通道感兴趣。也许 QtQuick 用一个支持层来组合它?
【问题讨论】:
您熟悉预乘 alpha 吗?您的解决方案基于它(尽管有一些我无法解释的多余细节)。但是,如果您不确定它为什么会起作用,我会觉得您可能不会。 不,我没有。感谢您为我指明正确的方向。如果我理解正确,我必须将图像与白色背景混合。但为什么?无论如何,我尝试了一些东西,考虑到 glReadPixels 的输出是预乘的,但我仍然无法得到精确的结果。另外,为什么这是预乘?你能帮我找到相关的文件吗?谢谢。 比如标签的颜色(RGBA 133,30,30,159)怎么会变成白色(RGB 255,255,255)? 最常用的预乘 alpha 用于 alpha 合成。预乘 alpha 混合是关联的,它允许更多的灵活性。它还避免了过滤透明像素的问题;在非透明像素之间进行插值时,具有 0 alpha 的像素应忽略其 RGB 颜色。提前将 RGB 乘以 A 可以在数学上实现这一点,而不是使用像if (alpha == 0.0) ...
这样愚蠢的东西。至于颜色,如果使用预乘 alpha 存储帧缓冲区,那么您应该能够简单地将 RGB 除以 A 以获得正确的颜色。
不是这样:在上面的例子中,133,30,30,159 应该变成 255,255,255。一定有别的东西。
【参考方案1】:
我通过在绘图期间从不更改 alpha 解决了这个问题。因此,我现在使用gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
代替gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
,并修改了其他参数以使其看起来像以前一样。
正如 Andon M. Coleman 在他的 cmets 中指出的那样,这与使用预乘 alpha 混合相同。这样,颜色缓冲区的 alpha 值始终保持为 1,并且问题得到解决。
glBlendFuncSeparate
,分别为 RGB 和 alpha 分量指定像素算术,对于获得相同的结果很有用。
【讨论】:
以上是关于保存使用 glReadPixels 读取的图像,其中 alpha 值不是一的主要内容,如果未能解决你的问题,请参考以下文章
使用 OpenCV 处理来自 glReadPixels 的图像并将其作为纹理返回