从 QByteArray 创建一个适当的 cv::Mat,包含 YUV420p 帧

Posted

技术标签:

【中文标题】从 QByteArray 创建一个适当的 cv::Mat,包含 YUV420p 帧【英文标题】:Create a proper cv::Mat from QByteArray, containing YUV420p frame 【发布时间】:2017-12-29 11:23:49 【问题描述】:

我有一个 .yuv 文件,其中包含 YUV420p 格式的 560x320 帧,我想通过使用 opencv 将每个帧解码为 RGB 来播放它。 我数了一下,一帧的大小必须是268800字节(560x320x12位/8,因为YUV420p每像素12位)。

所以我打开文件并逐帧读取,将每个 268800 字节存储在 QByteArray 中:

qint64 SIZE_OF_YUV420p_FRAME = 268800;
QByteArray  sendBuffer;

   QFile file("/home/YUVdecoding/small.yuv");

if(file.open(QIODevice::ReadOnly))
    
       while (!file.atEnd()) 

             sendBuffer = file.read(SIZE_OF_YUV420p_FRAME); //capture one frame
             cv::Mat yuvImg = cv::Mat(560+280,320,CV_8UC1,sendBuffer.data()); //translating QByteArray to Mat
             cv::Mat rgbImage;
             cv::cvtColor(yuvImg,rgbImage,cv::COLOR_YUV420p2RGB);// converting to RGB
             cv::imshow("bgr",rgbImage);
             cv::waitKey(30);
       

    
    file.close();

为什么 yuvImg 的行数是 560+280?因为560是它的致命错误,我不知道为什么。然后我在互联网上找到了这个代码sn-p:

QVideoFrame copy(frame);
if (frame.isValid() && copy.map(QAbstractVideoBuffer::ReadOnly)) 
  Mat frameYUV=Mat(copy.height() + copy.height()/2, copy.width(),CV_8UC1, (void*)copy.bits() );

  Mat frameRGB;
  cvtColor(frameYUV, frameRGB, CV_YUV2BGRA_I420);

  imshow("Video", frameRGB);

所以这里是它的高度 + 高度/2,我试了一下 (560 / 2 = 280)。突然,它起作用了,视频播放良好,但所有帧看起来 像这样:

它甚至有一个错误的分辨率。

.yuv 文件中的原始框架如下所示:

我玩了另一种尺寸的垫子,是的,它会影响图像显示的正确程度,但我无法达到原始框架外观。 如何从 QByteArray 正确创建 Mat?如何计算合适的 Mat 尺寸?

【问题讨论】:

你的Mat高度和宽度不对。 检查图像格式(通道) - 例如,您看到的错误似乎类似于尝试将 RGBA 垫显示为 RGB。这可能会弄乱您图像的宽度和高度,并且还会导致您看到的像素混乱...... @Silencer ,那怎么算对呢? @ZubkoArtyom 见@Leonardo 的回复。另一个问题是你说你的图像深度是 12 字节,所以它不应该直接转换 mat 。您可以手动将其传输到 8 字节数组(如果存在 API,则通过 Qt),然后传输到 Mat。寻找 Mat 构造函数以确保宽度/高度顺序。可能是交换 height() 和 width()。 @Silencer,@Leonardo 感谢您的回答,我仔细检查了 cv::Mat,这是我的错误 【参考方案1】:

成立的解决方案: cv::Mat 行和列必须是 cv::Mat yuvImg = cv::Mat(320+320/2,560,CV_8UC1,sendBuffer.data()); 而不是 560+280,320。 奇怪的是它使用 8bit 设置正确解码 12bit 图像,但它的工作完美

【讨论】:

以上是关于从 QByteArray 创建一个适当的 cv::Mat,包含 YUV420p 帧的主要内容,如果未能解决你的问题,请参考以下文章

如何将 cv::mat 标头和数据部分转换为单个 qbytearray?

从 QBytearray 创建 QImage

如何从数据库文件中创建 QByteArray

如何从 QByteArray 获取结构

从 QByteArray 以 bigendian 格式获取浮点数组的有效方法

如何通过级联QML在blackberry 10设备文档目录中创建XML文件?