WICConvertBitmapSource BGR 到 Gray 意外像素格式转换

dCu*_*lic 10 c++ windows imaging image-processing color-space

我正在使用WICConvertBitmapSource函数将像素格式从 BGR 转换为灰色,但我得到了意外的像素值。

...

pIDecoder->GetFrame( 0, &pIDecoderFrame ); 

pIDecoderFrame->GetPixelFormat( &pixelFormat ); // GUID_WICPixelFormat24bppBGR

IWICBitmapSource * dst;
WICConvertBitmapSource( GUID_WICPixelFormat8bppGray, pIDecoderFrame, &dst );
Run Code Online (Sandbox Code Playgroud)

具有以下 BGR 像素值的 4x3 图像示例:

[  0,   0, 255,   0, 255,   0, 255,   0,   0;
   0, 255, 255, 255, 255,   0, 255,   0, 255;
   0,   0,   0, 119, 119, 119, 255, 255, 255;
 233, 178,  73, 233, 178,  73, 233, 178,  73]
Run Code Online (Sandbox Code Playgroud)

我得到的灰色像素值:

[127, 220,  76;
 247, 230, 145;
   0, 119, 255;
 168, 168, 168]
Run Code Online (Sandbox Code Playgroud)

我期望得到的灰色像素值(ITU-R BT.601 转换

[ 76, 149,  29;
 225, 178, 105;
   0, 119, 255;
 152, 152, 152]
Run Code Online (Sandbox Code Playgroud)

后台发生了什么样的转换,有没有办法强制转换为我想要的行为?

同样值得一提的是,Gray -> BGR 和 BGRA -> BGR 的转换工作正常(如预期)

Car*_*iel 2

至于“后台发生什么样的转换”的问题:似乎使用了不同的转换算法。使用 WINE 项目来计算灰度值,似乎给出了相同的结果,因此它为我们提供了一个非常好的近似值。使用的公式是R * 0.2126 + G * 0.7152 + B * 0.0722.

copypixels_to_8bppGray来源):

float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
Run Code Online (Sandbox Code Playgroud)

除此之外,它还针对 sRGB 色彩空间进行了校正。

copypixels_to_8bppGray来源):

gray = to_sRGB_component(gray) * 255.0f;
Run Code Online (Sandbox Code Playgroud)

to_sRGB_component来源):

static inline float to_sRGB_component(float f)
{
    if (f <= 0.0031308f) return 12.92f * f;
    return 1.055f * powf(f, 1.0f/2.4f) - 0.055f;
}
Run Code Online (Sandbox Code Playgroud)

插入一些值:

float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
Run Code Online (Sandbox Code Playgroud)

至于另一个问题,我对框架太不熟悉,无法回答,所以我将这个问题留给其他人来回答。