YUV420 to BGR conversion issue

Hello,

I’m trying to convert YUV420 image to BGR (32bit) format (writing function for avisynth plugin).
Using nppiYUV420ToBGR_8u_P3C4R function from npp.h.
Result is flipped (looks like first pixel becomes last - so, flipped horizontally & vertically).
Also result looses contrast (becomes lighter).

I don’t have such issue when using nppiYUV420ToRGB_8u_P3R conversion.

Am I doing something wrong or is it a “feature”/“bug”?

Here is a code:

BYTE* data = newFrame->GetWritePtr();

Npp8u* pSrc[3];
pSrc[0] = (Npp8u*)planeYcuda;
pSrc[1] = (Npp8u*)planeUcuda;
pSrc[2] = (Npp8u*)planeVcuda;

int rSrcStep[3];
rSrcStep[0] = planeYpitch;
rSrcStep[1] = planeUpitch;
rSrcStep[2] = planeVpitch;

NppiSize roi;
roi.width = viout.width;
roi.height = viout.height;

cudaMemcpy(planeYcuda, planeY, planeYheight * planeYpitch, cudaMemcpyHostToDevice);
cudaMemcpy(planeUcuda, planeU, planeUheight * planeUpitch, cudaMemcpyHostToDevice);
cudaMemcpy(planeVcuda, planeV, planeVheight * planeVpitch, cudaMemcpyHostToDevice);

int rowsize = newFrame->GetRowSize();
nppiYUV420ToBGR_8u_P3C4R(pSrc, rSrcStep, RGBcuda, rowsize, roi);

cudaMemcpy(data, RGBcuda, newFrame->GetRowSize() * newFrame->GetHeight(), cudaMemcpyDeviceToHost);
cudaDeviceSynchronize();

Update:
It does not really matter much because converting back from BGR result to YUV420 gives nearly same picture as original (as should). And in my case BGR is just an intermediate step.

Update 2:
I also have the need to get normal BGR.
So I’v checked the results.
I’v created RGB image that is R = 0x50,G = 0x60,B=0x70
Then it was converted in avisynth to YUV444.
Resulting to: Y = 0x60, U = 0x89, V = 0x78
And ofcourse resulting YUV image is nearly same in brightness.

Then I use nppiYUVToRGB_8u_P3R to get RGB.
And RGB result is: R = 0x56, G = 0x61, B = 0x72.
Same RGB results if I just use formula specified in documentation:

Npp32f nY = (Npp32f)Y;
Npp32f nU = (Npp32f)U - 128.0F;
Npp32f nV = (Npp32f)V - 128.0F;
Npp32f nR = nY + 1.140F * nV; 
if (nR < 0.0F)
nR = 0.0F;
if (nR > 255.0F)
nR = 255.0F;    
Npp32f nG = nY - 0.394F * nU - 0.581F * nV;
if (nG < 0.0F)
nG = 0.0F;
if (nG > 255.0F)
nG = 255.0F;    
Npp32f nB = nY + 2.032F * nU;
if (nB < 0.0F)
nB = 0.0F;
if (nB > 255.0F)
nB = 255.0F;

But result is brighter.

If I use Microsoft formula for conversion I get nearly source results:

C = Y - 16
D = U - 128
E = V - 128
R = clip( round( 1.164383 * C + 1.596027 * E  ) )
G = clip( round( 1.164383 * C - (0.391762 * D) - (0.812968 * E) ) )
B = clip( round( 1.164383 * C +  2.017232 * D ) )

R = 0x50, G = 0x60, B = 0x6F
On Microsoft page it is stated that this is BT.601 conversion.

So the question is why this “unknown” YUV2RGB conversion formula is used and why BGR result is pixel reversed?

There are multiple conversion options in npp between YUV and RGB that follow different formulas. There are also a number of questions here on this forum about the conversions and formulas. I think you can find them with a bit of searching.

I can’t compile or run your code so I can’t comment on the pixel reversal. You’re mentioning both “BGR” and “RGB” in this thread.

There are multiple conversion options in npp between YUV and RGB that follow different formulas.

Can you specify a function name to use different formula? I have seen only different color mode conversions. And only one formula is specified in documentation.

About pixel reversal:
I have made my own function to convert YUV to BGR and first time I’v got same reversed result as Nvidia (flipped horizontally & vertically).
It is so when pixels are placed from beginning to end like:
Row1: Pixel 1, Pixel 2… + padding
Row 2: Pixel … padding
For result to be not flipped pixels should be placed this way:

last row: padding … last pixel… pixel

first row: padding … pixel … pixel1

Padding is extra bytes added for pitch size difference to data.
Maybe it is just AviSynth representation of BGR source.

  • There is a lack of functions to convert between YUV444 & YUV420.

search for 709 in the docs. And we may be using the word “formula” differently. I’m referring to the coefficient applied to the R,G,B values to create YUV-type colorspace values.