Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cpp rgb to yuv422 conversion

I'm trying to convert an image (originally from QImage) in a RGB/RGBA format (can be changed) to a YUV422 format. My initial intention was to use OpenCV cvtColor to do the work but it does not enable the conversion of RGB/RGBA to 422 format.

I searched for alternatives and even considered to write my own conversion according to this but it would not work fast enough.

I searched for another library to use and found this post but it is relay old and not so relevant.

So my question is what good options do I have for RGB->YUV422 conversions? It would be better if they perform conversions on the GPU instead of the CPU.

Thanks in advance

like image 997
Avner Gidron Avatar asked Oct 17 '25 02:10

Avner Gidron


1 Answers

A simple implementation for OpenCV:

void rgb_to_yuv422_uyvy(const cv::Mat& rgb, cv::Mat& yuv) {
    assert(rgb.size() == yuv.size() &&
           rgb.depth() == CV_8U &&
           rgb.channels() == 3 &&
           yuv.depth() == CV_8U &&
           yuv.channels() == 2);
    for (int ih = 0; ih < rgb.rows; ih++) {
        const uint8_t* rgbRowPtr = rgb.ptr<uint8_t>(ih);
        uint8_t* yuvRowPtr = yuv.ptr<uint8_t>(ih);

        for (int iw = 0; iw < rgb.cols; iw = iw + 2) {
            const int rgbColIdxBytes = iw * rgb.elemSize();
            const int yuvColIdxBytes = iw * yuv.elemSize();

            const uint8_t R1 = rgbRowPtr[rgbColIdxBytes + 0];
            const uint8_t G1 = rgbRowPtr[rgbColIdxBytes + 1];
            const uint8_t B1 = rgbRowPtr[rgbColIdxBytes + 2];
            const uint8_t R2 = rgbRowPtr[rgbColIdxBytes + 3];
            const uint8_t G2 = rgbRowPtr[rgbColIdxBytes + 4];
            const uint8_t B2 = rgbRowPtr[rgbColIdxBytes + 5];

            const int Y  =  (0.257f * R1) + (0.504f * G1) + (0.098f * B1) + 16.0f ;
            const int U  = -(0.148f * R1) - (0.291f * G1) + (0.439f * B1) + 128.0f;
            const int V  =  (0.439f * R1) - (0.368f * G1) - (0.071f * B1) + 128.0f;
            const int Y2 =  (0.257f * R2) + (0.504f * G2) + (0.098f * B2) + 16.0f ;

            yuvRowPtr[yuvColIdxBytes + 0] = cv::saturate_cast<uint8_t>(U );
            yuvRowPtr[yuvColIdxBytes + 1] = cv::saturate_cast<uint8_t>(Y );
            yuvRowPtr[yuvColIdxBytes + 2] = cv::saturate_cast<uint8_t>(V );
            yuvRowPtr[yuvColIdxBytes + 3] = cv::saturate_cast<uint8_t>(Y2);
        }
    }
}

Note this assumes (and checks) RGB as well as YUV422 UYVY flavor. I found this to be quite fast, but obviously it's embarrassingly parallel.

like image 169
Roy Shilkrot Avatar answered Oct 18 '25 14:10

Roy Shilkrot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!