Suggestion: cv::Mat RGB to YUV full range conversion using libYUV. NvJPEGEnc encoding

We recently faced the problem of RGB → YUV conversion described on (OpenCV mat to NvJPEGEncoder jpg limited range)
As the thread shows, OpenCV conversion abides to the I420 convention, which constrains the pixel intensities Y (16 to 235) and UV (16 to 240).
LibYUV (libyuv/libyuv - Git at Google) can be used as a safe way to convert a RGB CvMat to NvBuffer.
Given that the parameters were properly allocated, the function libyuv::RGB24ToJ420 can be used to perform the conversion.

bool convertRGBtoYUV(const cv::Mat& rgb, NvBuffer& nvbuf)
{
    NvBuffer::NvBufferPlane &planeY = nvbuf.planes[0];
    NvBuffer::NvBufferPlane &planeU = nvbuf.planes[1];
    NvBuffer::NvBufferPlane &planeV = nvbuf.planes[2];
    const int strideY = planeY.fmt.stride;
    const int strideU = planeU.fmt.stride;
    const int strideV = planeV.fmt.stride;
    
    uint8_t* dst_y = planeY.data;
    uint8_t* dst_u = planeU.data;
    uint8_t* dst_v = planeV.data;
    return libyuv::RGB24ToJ420(rgb.data,
                              rgb.step,
                              dst_y,
                              strideY,
                              dst_u,
                              strideU,
                              dst_v,
                              strideV,
                              rgb.cols,
                              rgb.rows);
}

Differently from I420, RGB → J420 conversion leads to images that use the full 0 to 255 intensity range.
So, when the NvBuffer is used as argument of the method encodeFromBuffer, the JPEG will be encoded with the full intensity range.

Cheers,

Diego Carvalho - Fugro (http://fugro.com/)

Hi,
Do you mean you would like to encode the YUV420 in limited range [16.235]? Not sure what the issue is. Please check if you can reproduce it on TX2 developer kit and share us the steps for checking.

And please share your release version $ head -1 /etc/nv_tegra_release

Hi DaneLLL,

Thank you for your reply.
There is no issue with the TX2 nor Tegra libraries.

I posted because I would like to share to the community a solution to the JPG encoding (using NvJPEGEncoder) from pixels initially stored in a cv::Mat as RGB.

The solution posted on originally in the forum suggested using cv::imwrite to circumvent the pixel intensity clamp when an RGB is converted to YUV by OpenCV. The drawback is that cv::imwrite requires writing a file to disk. By using libyuv::RGB24ToJ420 it is possible to convert a cv:Mat to a full range YUV and write the result directly to the planes of a NvBuffer.

Cheers,

Diego Carvalho - Fugro (http://fugro.com/)

1 Like