【问题标题】:Creating a Mat object from a YV12 image buffer从 YV12 图像缓冲区创建一个 Mat 对象
【发布时间】:2013-09-11 09:46:35
【问题描述】:

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

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

【问题讨论】:

  • 这是个好问题。请考虑@jaro 的回答,它帮助了我,也可能帮助许多其他人。
  • @douglasjfm 一段时间后更改接受的答案不是一个坏习惯吗?
  • 是的,至少在社交上,人们可能会灰心给出答案。对此herehere 进行更多讨论。但是公认的和最好的(或正确的;我测试过,对我帮助很大!)答案彼此之间非常矛盾,这对其他读者来说可能是不好的遗产。
  • @douglasjfm 那么你的建议是什么?
  • 我已经阅读了更多关于此的内容。在这种情况下,我真诚地建议您更改已接受的答案。更多关于 here 的信息,赞同我的建议。

标签: opencv yuv


【解决方案1】:

这是可能的。

    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);

【讨论】:

  • 你能解释一下乘以 3/2 吗?
  • @dustymax 一张 YV12 或 YUV420 图像的大小为 width * height * 3 / 2。fourcc.org/yv12
【解决方案2】:

这里是java(Android)中对应的版本...

此方法比其他技术如 renderscript 或 opengl(glReadPixels) 从 yuv12/i420 数据流中获取位图更快(使用 webrtc i420 测试)。

long startTimei = SystemClock.uptimeMillis();

Mat picyv12 = new Mat(768,512,CV_8UC1);  //(im_height*3/2,im_width), should be even no...
picyv12.put(0,0,return_buff); // buffer - byte array with i420 data
Imgproc.cvtColor(picyv12,picyv12,COLOR_YUV2RGB_YV12);// or use COLOR_YUV2BGR_YV12 depending on output result

long endTimei = SystemClock.uptimeMillis();
Log.d("i420_time", Long.toString(endTimei - startTimei));

Log.d("picyv12_size", picyv12.size().toString()); // Check size
Log.d("picyv12_type", String.valueOf(picyv12.type())); // Check type

Utils.matToBitmap(picyv12,tbmp2); // Convert mat to bitmap (height, width) i.e (512,512) - ARGB_888

save(tbmp2,"itest"); // Save bitmap

【讨论】:

    【解决方案3】:

    那是不可能的。

    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;
    }
    

    【讨论】:

    • ucharpU 是什么?
    【解决方案4】:

    你可以试试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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      • 2019-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多