C++ Direct2D-如何使用位图进行gamma校正透明度(alpha)

C++ Direct2D-如何使用位图进行gamma校正透明度(alpha),c++,png,alpha,direct2d,gamma,C++,Png,Alpha,Direct2d,Gamma,我正在用Direct2D绘制位图。位图利用透明度(alpha通道) 混合看起来不对 作为测试,我加载了一个透明度为50%的纯黑色png图像,并将其绘制在白色背景上。结果是红色、绿色和蓝色值为127(0x7F7F)的像素。这表明Direct2D的混合忽略了gamma,并将颜色值视为线性 (位图使用常规sRGB颜色空间,每像素32位,红色、绿色、蓝色和Alpha各8位)。它们以GUID_WICPixelFormat32bppPBGRA格式加载 在sRGB中,介于黑色和白色之间的混合物为186(0xB

我正在用Direct2D绘制位图。位图利用透明度(alpha通道)

混合看起来不对

作为测试,我加载了一个透明度为50%的纯黑色png图像,并将其绘制在白色背景上。结果是红色、绿色和蓝色值为127(0x7F7F)的像素。这表明Direct2D的混合忽略了gamma,并将颜色值视为线性

(位图使用常规sRGB颜色空间,每像素32位,红色、绿色、蓝色和Alpha各8位)。它们以GUID_WICPixelFormat32bppPBGRA格式加载

在sRGB中,介于黑色和白色之间的混合物为186(0xBABABA)。这是我想要的理想结果

Direct2D能否显示与gamma相关的透明度?我该怎么做?谢谢你的帮助


混合是在线性颜色空间中正确完成的,因此混合sRGB像素的过程应该是

  • 转换为线性
  • 调和
  • 转换回sRGB
  • 注意,对于黑色或白色像素,步骤(1)和(3)不是操作,可以省略

    请参阅PNG规范的一节。请特别注意:

    计算合成样本值的方程式为

    output=alpha*前景+(1-alpha)*背景

    其中alpha值以及输入和输出样本值为 表示为0到1范围内的分数。这个计算应该是 使用强度样本(非伽马编码样本)执行

    本节包含用于alpha通道处理的示例C代码


    在提出此问题时,HWND渲染目标(绘制到屏幕)不支持线性像素格式;但是,Direct-2D HwnRender目标现在已被接口ID2D1DeviceContext取代。它们是通过
    IDXGIFactory2::CreateSwapChainForHwnd()
    创建的,支持更多像素格式,如DXGI\u格式\u B8G8R8A8\u UNORM\u SRGB,在混合时自动执行正确的颜色空间转换(由@Jeff McClintock提供的信息).

    Direct-2D 1.0 HwnRenderTarget直接对像素值执行混合计算。这导致使用alpha通道合成标准sRGB图像时出错。错误是因为Direct 2D将gamma压缩强度值视为线性强度值

    忽略gamma会导致合成质量差、几何体抗锯齿、图像大小调整和文本渲染

    有一种解决方法,即“预扭曲”位图的alpha值,以补偿混合计算引入的错误

    例如: 通过在线性颜色空间中执行混合,左边的图像是正确的合成,中间的图像是直接2D(阴影太暗和“对比度”),右边的图像是预扭曲alpha通道后的直接2D

    见:


    更新!:较新版本的Direct-2D(1.1)支持正确执行混合的SRGB后台缓冲区。使用IDXGIFactory2::CreateSwapChainForHwnd()来使用改进的颜色深度选项。

    我认为您的方法是反向的。在sRGB中,50%看起来像介于黑色和白色之间(在亮度方面)。它看起来是太亮还是太暗?这可能是因为它的显示方式。我的理解是,sRGB颜色空间定义了像素强度和实际存储数量之间的非线性变换。i、 e.伽马曲线。例如,8位颜色值的范围为0-255,但由于伽马曲线,127(中间)的值以约20%的亮度显示。因此,伽马校正50%黑白混合的像素值应为186(73%满标度)。因此,在Direct2d中,我的混合看起来太暗。@astraycat如果您查看黑白交替像素并将其与实心块进行比较,则在正确校准的显示器上,BABABA块的亮度应相同。即使在未校准的显示器上,BABABA也应该比7F7F7F更接近。干杯,这很有意义(在线性颜色空间中执行混合),但如何在Direct2D中实现这一点?(也许渲染目标和位图需要设置为特定的像素格式?)。AFAIK Direct2D HWND渲染目标(绘制到屏幕)不支持线性像素格式,如果将位图转换为线性格式,它将不再支持硬件加速(Direct2D的主要优点)。DIrect3D(Direct2D的基础)支持位图上的操作,在混合操作期间,像素将转换为线性颜色空间并返回。遗憾的是Direct2D不支持此功能。更新:Direct-2D HwnRender目标已被接口ID2D1DeviceContext取代。这些是通过IDXGIFactory2::CreateSwapChainForHwnd()创建的,支持更多像素格式,如DXGI_格式_B8G8R8A8_UNORM_SRGB,它在混合时自动执行正确的颜色空间转换。谢谢@Jeff McClintock,我将您的更新合并到了答案中。