OpenCV色域转换

 

OpenCV一系列色域转换函数的验证。

(cv::COLOR_RGB2YUV_YV12 / cv::COLOR_RGB2YUV_I420) + libyuv::I420ToRGB24

按照fourcc的定义,YV12属于Planar YUV Formats中的一种,yuv是分开存储的(看作三个独立的内存块),但是在内存上又是连续的,即YYYYYYYY…..VVVVVVV….UUUUUUUU…..

而I420也属于Planar YUV Formats的一种,但其排列为YYYYYYYY…..UUUUUUUU….VVVVVVVV…..

采用代码进行测试,发现cv上定义的YV12和I420好像是反过来了,因为:

  1. libyuv是由Google开发的,在其页面中也描述了它是使用FOURCC来对色域空间进行描述,所以认为I420ToRGB24中的I420种yuv的顺序确为YYYYYYYY…..VVVVVVV….UUUUUUUU…..
  2. 而事实上采用 cv::COLOR_RGB2YUV_YV12 + libyuv::I420ToRGB24 得到的图像是正确的BGR,使用 cv::imshow 可以正确显示此图像颜色
  3. 采用 cv::COLOR_RGB2YUV_I420 + libyuv::I420ToRGB24 得到的图像是RGB,使用imshow之后图像是BGR的颜色
#include <opencv2/opencv.hpp>
#include "libyuv.h"

int main() {
    cv::Mat img = cv::imread("test.jpeg");
    cv::Mat yuv_yv12_img;
    cv::cvtColor(img, yuv_yv12_img, cv::COLOR_RGB2YUV_YV12);
//    cv::cvtColor(img, yuv_yv12_img, cv::COLOR_RGB2YUV_I420);

    int width = img.cols;
    int height = img.rows;

    // 获取Y、U和V的指针
    const uint8_t* y_data = yuv_yv12_img.data;
    const uint8_t* u_data = yuv_yv12_img.data + width * height;
    const uint8_t* v_data = yuv_yv12_img.data + width * height + width * height / 4;

    cv::Mat bgr_img(height, width, CV_8UC3);
    uint8_t* bgr_data = bgr_img.data;

    libyuv::I420ToRGB24(y_data, width,
                        u_data, width / 2,
                        v_data, width / 2,
                        bgr_data, width * 3,
                        width, height);
//    libyuv::I420ToRGB24(y_data, width,
//                        v_data, width / 2,
//                        u_data, width / 2,
//                        bgr_data, width * 3,
//                        width, height);

    cv::imshow("RGB Image", bgr_img);
//    cv::imshow("RGB Image", img);
    cv::waitKey(0);

    return 0;
}

参考资料

  1. fourcc
  2. libyuv