YUV_NV21圖像數據到RGB顏色空間的轉換


本文主要介紹YUV_NV21顏色空間到RGB(BGR in OpenCV)顏色空間的轉換,並給出示例代碼,另附YUV圖像查看工具。

NV21(YUV420)介紹

NV12和NV21屬於YUV420格式(每2x2四個Y,共用一組uv),是一種two-plane模式,即Y和UV分爲兩個Plane,但是UV(CbCr)爲交錯存儲,而不是分爲三個plane。先存儲所有的Y,然後UV交錯存儲:NV12先U後V,NV21先V後U。

YUV420sp示例格式如下:
在這裏插入圖片描述

YUV_NV21轉BGR代碼

YUV_NV21顏色空間到RGB(BGR in OpenCV)顏色空間的轉換示例代碼如下:

const int width  = 1280;
const int height = 800;

std::ifstream file_in;
file_in.open("../image_yuv_nv21_1280_800_01.raw", std::ios::binary);
std::filebuf *p_filebuf = file_in.rdbuf();
size_t size = p_filebuf->pubseekoff(0, std::ios::end, std::ios::in);
p_filebuf->pubseekpos(0, std::ios::in);

char *buf_src = new char[size];
p_filebuf->sgetn(buf_src, size);

cv::Mat mat_src = cv::Mat(height*1.5, width, CV_8UC1, buf_src);
cv::Mat mat_dst = cv::Mat(height, width, CV_8UC3);

cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV21);

轉換出的(正確)效果如下:
在這裏插入圖片描述

接下來,我自己按如下邏輯實現該算法,替換掉 OpenCV的 cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV21)

  • 從內存中讀取出每個像素的YUV,即 YUV420 --> YUV444
  • 根據 YUV --> RGB 公式,計算出RGB值
  • 按 BGR888 的內存分佈格式,將RGB值寫入內存傳給 cv::Mat
  • 保存圖片到本地顯示

實現代碼如下:

void yuv_nv21_to_rgb(unsigned char rgb[], char yuv[], int width, int height) {

    int total = width * height;
    char Y, U, V;
    unsigned char R, G, B;
    int index = 0;

    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {

            Y = yuv[h * width + w];
            if ((w & 1) == 0)
                V = yuv[total + (h >> 1) * width + w];
            if ((w & 1) == 1)
                U = yuv[total + (h >> 1) * width + w - 1];

            // OpenCV YCrCb --> RGB
            //B = Y + 1.773*(U-128);
            //G = Y - 0.714*(V-128) - 0.344*(U-128);
            //R = Y + 1.403*(V-128);

            // YUV-->RGB for HDTV(BT.601)
            //B = Y + 2.03211*(U-128);
            //G = Y - 0.39465*(U-128) - 0.5806*(V-128);
            //R = Y + 1.13983*(V-128);

            // YUV-->RGB for HDTV(BT.709)
            //B = Y + 2.12798*(U-128);
            //G = Y - 0.21482*(U-128) - 0.38059*(V-128);
            //R = Y + 1.28033*(V-128);

            // YCbCr-->RGB
            B = 1.164*(Y-16) + 2.018*(U-128);
            G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128);
            R = 1.164*(Y-16) + 1.596*(V-128);

            if (R < 0) R = 0; else if (R > 255) R = 255;
            if (G < 0) G = 0; else if (G > 255) G = 255;
            if (B < 0) B = 0; else if (B > 255) B = 255;

            rgb[index++] = B;
            rgb[index++] = G;
            rgb[index++] = R;
        }
    }
}

該代碼中試了幾種 YUV --> RGB 的算法,效果最好的即上面使用(未註釋)的代碼,轉換結果如下:
在這裏插入圖片描述

歡迎各位同學指正,找出效果不好的原因,並解決問題,謝謝~

  • 在StackOverflow回答的問題:Converting YUV into BGR or RGB in OpenCV
  • 整個工程可參見我的Github工程:https://github.com/cggos/cgocv/tree/master/cv_libs/opencv/image_convertor ,可在此提交 Issue
  • 本代碼 測試yuv raw圖像 可在此下載:https://download.csdn.net/download/u011178262/10791506

YUV圖像 查看工具

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章