Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WICConvertBitmapSource BGR to Gray unexpected pixel format conversion

I am using WICConvertBitmapSource function to convert pixel format from BGR to Gray and I'm getting unexpected pixel values.

...

pIDecoder->GetFrame( 0, &pIDecoderFrame ); 

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

IWICBitmapSource * dst;
WICConvertBitmapSource( GUID_WICPixelFormat8bppGray, pIDecoderFrame, &dst );

Example on 4x3 image with following BGR pixel values:

[  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]

Gray pixel values I am getting:

[127, 220,  76;
 247, 230, 145;
   0, 119, 255;
 168, 168, 168]

Gray pixel values I expected to get (ITU-R BT.601 conversion)

[ 76, 149,  29;
 225, 178, 105;
   0, 119, 255;
 152, 152, 152]

What kind of conversion is happening in the background, and is there a way to force conversion to my wanted behaviour?

Also worth mentioning, the conversions are working properly (as expected) for Gray -> BGR and BGRA -> BGR

like image 349
dCubelic Avatar asked Mar 10 '21 13:03

dCubelic


Video Answer


1 Answers

As for the question "What kind of conversion is happening in the background": it seems like a different conversion algorithm is used. Using the WINE project to calculate the greyscale values, seem to give the same results, so it gives us a pretty good approximation what is happening. The formula used is R * 0.2126 + G * 0.7152 + B * 0.0722.

copypixels_to_8bppGray (source):

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

In addition to that, it is corrected for the sRGB color space.

copypixels_to_8bppGray (source):

gray = to_sRGB_component(gray) * 255.0f;

to_sRGB_component (source):

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

Plugging in some values:

    B    G    R    WINE          You're getting
      0    0  255  127.1021805   127
      0  255    0  219.932749    220
    255    0    0   75.96269736   76
    0    255  255  246.7295889   247
    255  255    0  229.4984163   230
    255    0  255  145.3857605   145
      0    0    0   12.92          0

As for the other question, I'm too unfamiliar with the framework to answer that, so I'll leave that open for others to answer.

like image 103
Caramiriel Avatar answered Oct 02 '22 05:10

Caramiriel