Hello,
we are converting NV12_709 images decoded by Gstreamer nvv4l2decoder to BGRA images using both VPI vpiSubmitConvertImageFormat and NvBufSurfTransform with VIC backend. We noticed the converted RGB color is different from the result we got by using NPP nppiNV12ToBGR_709CSC_8u_P2C3R.
The test video we are using is just 10 secs of frames completely filled with RGB color (126,126,126). In the NV12_709 decoded buffer we can see the pixels have the expected YUV value of (124,128,128). After the conversion to BGRA we got RGB values of (138,138,138) using VPI/NvBufSurfTransform with VIC and RGB values of (125,125,125) using nppiNV12ToBGR_709CSC_8u_P2C3R.
Why this difference? It seems the NPP function is performing the conversion correctly while VPI/NvBuf is a little off.
We are missing something? Could you help us understand what’s wrong?
Hello,
sadly the CUDA backend from VPI desent support NV12 Limited Range, only NV12 Extended Range (see documentation: https://docs.nvidia.com/vpi/group__VPI__ConvertImageFormat.html#gaae47f1e840253de76af91a4f6aea9b71) so we cannot perform the test you requested.
In the previous post i forgot to mention the source image format is NV12_709 Limited Range which seems only supported by VIC backend and NvBufSurfTransform.
Any ideas? Anyone else is experiencing this color conversion issue? Converting a limited range YUV value of (124,128,128) to RGB (138,138,138) seems wrong according to standard conversion formulas…
Thanks.
Hello again,
we further experimented with this issue. We created an artificial NV12_709 Limited Range image with pixel on the X axis with values ranging from [16,128,128] to [235,128,128]. The image in RGB is an horizontal grayscale gradient from 0 to 255.
We then converted this image to RGB with NPP and VPI/NvBufSurfTransform with VIC backend and printed and plotted the R value obtained (G and B values are the same since its a grayscale image). This is what we got: npp_cuda.txt (6.5 KB) vpi_vic.txt (7.9 KB)
NPP output a linear transformation from NV12 to RGB while VPI/NvBufSurfTransform VIC seems not linear. What kind of conversion maths is applied inside the VIC to perform this conversion? We’re not expert in this area but we want to have a clear understanding on what’s going on. NPP results seems consistent to the standard conversion formulas we found while researching this issue, while VIC not.
Hello,
yes, we can create a small reproducible example and share the code here. We’re pretty busy until friday (deadline looming), so it may take a while to produce the example. We hope to share the source by the end of the week.
Thank a lot!
Hello again,
here is the source code of a simple example: color_conversion.zip (1.7 KB)
It reproduces the issue as described in the previous posts, it also prints to console the converted values and plot the two curves.
Hello,
thanks for the answer. We’ll check what you suggested and let you know.
Since in production code we’re using NvBufSurfTransform (on VIC backend) function to perform color conversions AND resize/crop in one step how we can apply your suggestion in this scenario? We couldn’t find anything similar to VPI color spec in the NvBufSurface object…there’s only the NvBufSurfaceColorFormat field and (for RGBA we can only use NVBUF_COLOR_FORMAT_BGRA).
Thanks.
As mentioned before, the difference comes from gamma correction.
Below are two cases in which no gamma correction is required.
If both image formats are linear
If images have the same gamma.
If you want to try 2nd option, here is a small snippet to convert RGBA to the same gamma as input before image format conversion
#include <vpi/ImageFormat.h>
#include <vpi/ColorSpec.h>
#include <vpi/Image.h>
VPIImage input; #Get this from gstreamer
VPIImageFormat inFormat;
vpiImageGetFormat(input, &inFormat);
# Get input image format colorSpec
VPIColorSpec inputSpec = vpiImageFormatGetColorSpec(inFormat);
# Create an image with RGBA format and change its colorSpec
VPIImageFormat outFormatNew = vpiImageFormatSetColorSpec(VPI_IMAGE_FORMAT_RGBA8, inputSpec);
#Create Output image using outFormatNew and use it for convertImageFormat, as this is same gamma as input there will be no correction
Thank you for the reply.
Next we’ll do some experiments with the 2nd suggested option. How we can obtain the same result (we mean disabling gamma correction during color conversion) with the NvBufSurfTransform API instead of VPI?