从 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?