从YV12图像缓冲区创建Mat对象

时间:2013-09-11 09:46:36

标签: opencv yuv

我有一个缓冲区,其中包含 YV12 格式的图像。现在我要将此缓冲区转换为 RGB 格式或直接从中创建Mat对象!有人能帮我吗?我试过这段代码:

cv::Mat input(widthOfImg, heightOfImg, CV_8UC1, vy12Buffer);
cv::Mat converted;
cv::cvtColor(input, converted, CV_YUV2RGB_YV12);

4 个答案:

答案 0 :(得分:11)

这是可能的。

    cv::Mat picYV12 = cv::Mat(nHeight * 3/2, nWidth, CV_8UC1, yv12DataBuffer);
    cv::Mat picBGR;
    cv::cvtColor(picYV12, picBGR, CV_YUV2BGR_YV12);
    cv::imwrite("test.bmp", picBGR);  //only for test

Opencv color conversion flags

高度乘以3/2,因为有4个Y样本,每2x2平方像素存储1 U和1 V样本。这导致字节样本与像素的比率为3/2

4*1+1+1 samples per 2*2 pixels = 6/4 = 3/2

YV12 Format

更正:在最新版本的OpenCV中(我使用最旧的2.4.13版本)将颜色转换代码更改为 COLOR_YUV2BGR_YV12

    cv::cvtColor(picYV12, picBGR, COLOR_YUV2BGR_YV12);

答案 1 :(得分:1)

那是不可能的。

  

Y'UV420p是平面格式,意味着Y',U和V值是   聚集在一起而不是穿插。原因是这样的   通过将U和V值分组在一起,图像变得更加明显   压缩。当给出Y'UV420p格式的图像阵列时,   首先是所有Y'值,然后是所有U值,然后是   最后是所有V值。

cv::Mat是RGB颜色模型,排列方式如B0 G0 R0 B1 G1 R1 ...因此,我们无法直接从YV12缓冲区创建Mat对象。

以下是一个例子:

cv::Mat Yv12ToRgb( uchar *pBuffer,long bufferSize, int width,int height )
{
    cv::Mat result(height,width,CV_8UC3);
    uchar y,cb,cr;

    long ySize=width*height;
    long uSize;
    uSize=ySize>>2;

    assert(bufferSize==ySize+uSize*2);

    uchar *output=result.data;
    uchar *pY=pBuffer;
    uchar *pU=pY+ySize;
    uchar *pV=pU+uSize;

    uchar r,g,b;
    for (int i=0;i<uSize;++i)
    {
        for(int j=0;j<4;++j)
        {
            y=pY[i*4+j];
            cb=ucharpU[i];
            cr=ucharpV[i];

                //ITU-R standard
            b=saturate_cast<uchar>(y+1.772*(cb-128));
            g=saturate_cast<uchar>(y-0.344*(cb-128)-0.714*(cr-128));
            r=saturate_cast<uchar>(y+1.402*(cr-128));

            *output++=b;
            *output++=g;
            *output++=r;
        }
    }
    return result;
}

答案 2 :(得分:1)

这是Java(Android)中的相应版本...

此方法比诸如renderscript或opengl(glReadPixels)之类的其他技术从yuv12 / i420数据流中获取位图的速度更快(已通过webrtc i420测试)。

set /?

答案 3 :(得分:0)

您可以尝试YUV_I420阵列

char filePath[3000];
int width, height;
cout << "file path = ";
cin >> filePath;
cout << "width = ";
cin >> width;
cout << "height = ";
cin >> height;

FILE *pFile = fopen(filePath, "rb");
unsigned char* buff = new unsigned char[width * height *3 / 2];
fread(buff, 1, width * height* 3 / 2, pFile);
fclose(pFile);


cv::Mat imageRGB;
cv::Mat picI420 = cv::Mat(height * 3 / 2, width, CV_8UC1, buff);
cv::cvtColor(picI420, imageRGB, CV_YUV2BGRA_I420);
imshow("imageRGB", imageRGB);
waitKey(0);