Matrix HDR颜色空间变换会导致RGB值为负值(从Yxy到XYZ到sRGB)

Matrix HDR颜色空间变换会导致RGB值为负值(从Yxy到XYZ到sRGB),matrix,color-space,srgb,hdr,Matrix,Color Space,Srgb,Hdr,我目前正在将HDR添加到一个旧引擎中,偶然发现了一个颜色空间转换问题 我在Yxy颜色空间中定义灯光 然后我将Yxy转换为XYZ XYZ到sRGB的转换 渲染和规格化结果时使用RGB值>1.0,最后使用色调映射 我正在研究大量的数据,因为主要光源是太阳,照度高达150k勒克斯 YxyToXYZ函数 osg::Vec3 YxyToXYZ( const osg::Vec3& Yxy ) { if ( Yxy[2] > 0.0f ) { return osg

我目前正在将HDR添加到一个旧引擎中,偶然发现了一个颜色空间转换问题

  • 我在Yxy颜色空间中定义灯光
  • 然后我将Yxy转换为XYZ
  • XYZ到sRGB的转换
  • 渲染和规格化结果时使用RGB值>1.0,最后使用色调映射
  • 我正在研究大量的数据,因为主要光源是太阳,照度高达150k勒克斯

    YxyToXYZ函数

    osg::Vec3 YxyToXYZ( const osg::Vec3& Yxy )
    {
        if ( Yxy[2] > 0.0f )
        {
            return osg::Vec3( Yxy[0] * Yxy[1] / Yxy[2] , Yxy[0] , Yxy[0] * ( 1.0f - Yxy[1] - Yxy[2])  / Yxy[2] );
        }
        else
        {
            return osg::Vec3( 0.0f , 0.0f , 0.0f );   
        }
    }
    
    XYZtosRGB

    osg::Vec3 XYZToSpectralRGB( const osg::Vec3& XYZ )
    {
        // Wikipedia matrix
        osg::Vec3 rgb;
        rgb[0] = 3.240479  * XYZ[0] - 1.537150 * XYZ[1] - 0.498535 * XYZ[2];
        rgb[1] = -0.969256 * XYZ[0] + 1.875992 * XYZ[1] + 0.041556 * XYZ[2];
        rgb[2] = 0.055648 * XYZ[0]  - 0.204043 * XYZ[1] + 1.057311 * XYZ[2];
    
        std::cout << "newrgb rgb r:" << rgb[0] << " g:" << rgb[1] << " b:" << rgb[2] << std::endl;
    
        // The matrix in pbrt book p. 235 gives unexpected results. We expect that if we have
        // x = y = 0.33333 we get a white pixel but that matrix gives red. Hence we use a different
        // matrix that is often used by 3D people
        rgb[0] = 2.5651  * XYZ[0] -1.1665 * XYZ[1] -0.3986 * XYZ[2];
        rgb[1] = -1.0217 * XYZ[0] + 1.9777 * XYZ[1] + 0.0439 * XYZ[2];
        rgb[2] = 0.0753 * XYZ[0]  -0.2543 * XYZ[1] + 1.1892 * XYZ[2];
    
        std::cout << "oldrgb rgb r:" << rgb[0] << " g:" << rgb[1] << " b:" << rgb[2] << std::endl;
    
        return rgb;
    }
    
    问题:

  • 我想负值应该被钳制掉?还是我的计算有错误
  • 这两个矩阵产生相似但不同的值(基本值非常接近sRGB)。我想用一个替换旧的矩阵(我不知道它来自哪里)。有人知道旧矩阵是从哪里来的吗?哪个是正确的矩阵
  • 我找到了一个部分答案@,听起来像是来自一位前同事:)。。。但这并不能解决我的问题

  • 非常感谢您的
    新rgb rgb
    计算是正确的,我使用以下方法获得相同的输出:

    导入颜色
    xyY=(1.0,1.0,1.0)
    XYZ=颜色。xyY_到XYZ(xyY)
    打印(color.XYZ_to_sRGB(XYZ,apply_encoding_cctf=False))
    xyY=(0.26,0.28,25.0)
    XYZ=颜色。xyY_到XYZ(xyY)
    打印(color.XYZ_to_sRGB(XYZ,apply_encoding_cctf=False))
    xyY=(0.27,0.293100.0)
    XYZ=颜色。xyY_到XYZ(xyY)
    打印(color.XYZ_to_sRGB(XYZ,apply_encoding_cctf=False))
    xyY=(0.33,0.33,6e+06)
    XYZ=颜色。xyY_到XYZ(xyY)
    打印(color.XYZ_to_sRGB(XYZ,apply_encoding_cctf=False))
    # [ 2.2020461   0.86530782 -1.20530687]
    # [ 16.31921754  26.10605109  39.60507773]
    # [ 2242.49706509  3213.58480355  4499.85141917]
    # [ 7138073.69325106  5697605.86069197  5644291.15301836]
    
    你在第一次转换中得到负值,因为你的
    xy
    色度坐标在光谱轨迹之外,因此它们代表假想的颜色


    维基百科矩阵是正确的,并且是来自
    IEC 61966-2-1:1999
    的矩阵,这是
    sRGB
    颜色空间的官方标准。

    非常感谢验证我的值!我仍然不确定的是,为了正确使用该矩阵,RGB值必须是线性的,并且在标称范围[0.0,1.0]内,这是否意味着我必须将我的Yxy值除以150k,因为这将是最大lux值,然后进行矩阵计算,然后乘以65504来实现这是一个很好的问题实际上,RGB值必须是线性的,现在关于归一化,老实说,我看不出在浮点处理链中需要它的明确原因。这在8位或任何整数处理链中可能更有意义,因为您希望优化代码分配以避免量化伪影。在你的情况下,我会避免这种正常化。
    Yxy Y:1 x:1 y:1
    XYZ X:1 Y:1 Z:-1
    newrgb rgb r:2.20186 g:0.86518 b:-1.20571
    oldrgb rgb r:1.7972  g:0.9121  b:-1.3682
    
    Yxy Y:25 x:0.26 y:0.28
    XYZ X:23.2143 Y:25 Z:41.0714
    newrgb rgb r:16.3211 g:26.106  b:39.616
    oldrgb rgb r:14.0134 g:27.5275 b:44.2327
    
    Yxy Y:3100 x:0.27 y:0.29
    XYZ X:2886.21 Y:3100 Z:4703.45
    newrgb rgb r:2242.7  g:3213.56 b:4501.09
    oldrgb rgb r:1912.47 g:3388.51 b:5022.34
    
    Yxy Y:6e+06 x:0.33 y:0.33
    XYZ X:6e+06 Y:6e+06 Z:6.18182e+06
    newrgb rgb r:7.13812e+06 g:5.69731e+06 b:5.64573e+06
    oldrgb rgb r:5.92753e+06 g:6.00738e+06 b:6.27742e+06