【问题标题】:opencv can't open a yuv422 image while rawpixels.net can display the imageopencv 无法打开 yuv422 图像,而 rawpixels.net 可以显示图像
【发布时间】:2021-04-20 05:28:42
【问题描述】:

我正在尝试打开一个 yuv 格式的图像。我可以用 rawpixels.net 打开它并在设置以下后显示它

width:1920
height:1080
predefined format: yuv420 (nv12)
pixel format yuv

但是如果我用下面的代码用opencv打开我就打不开。

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/opencv.hpp>

int main() {
    std::cout << "OpenCV version: " << CV_VERSION << std::endl;


    cv::Mat image = cv::imread("camera_capture_256_2020_10_07_11_11_02.yuv");
    if (image.empty() == true) {

        std::cout << "image empty"<< std::endl;

        return 0;
    }   
        
    cv::imshow("opencv_logo", image);
    cv::waitKey(0);    

    return 0;
}

程序打印为“图像为空”。

我很疑惑为什么用opencv打不开文件。

样本图片在here找到。

用 rawpixels.net 打开的 yuv 图像是这样的。

谢谢,

【问题讨论】:

  • 是的。这里link
  • 我不知道 OpenCV 能够编写这样的 YUV 文件 - cv2.imwrite() 的文档中没有提到它。我认为你需要做 YUV = cvtColor(...BGR2YUV...) 并使用标准 Python write(YUV.tobytes())
  • 如果你的 YUV 图像是 1920x1080 和 nv12 格式,它应该是 1920*1080*1.5 字节,因为 nv12 是 12 位/像素。那是 3110400 字节,但你的文件是 8355840 字节,还是 2.7 倍太大?
  • @enhzflep 很有趣。事实上,当我用 rawpixels.net 打开时,会看到一条绿线,这可能是神秘的标题。
  • 进行这种开发的一个技巧是从超清晰的数据开始。一个正方形的盒子,尺寸、颜色等都完美匹配。当我做类似的事情从损坏的 CDROM 中提取数据时,我在整个磁盘上刻录了一个图案,然后用一台钻孔机在上面钻了一个大洞。

标签: c++ image opencv yuv libyuv


【解决方案1】:

在处理原始(RGB、BGR、YUV、NV12 和其他)图像时,首先要做的是了解图像的像素尺寸——没有这些你真的很迷茫——尽管你可以做一些技巧寻找相关性以找到行宽,因为每一行通常与上面的行基本相似。


接下来是检查文件大小是否正确。因此,如果它是 RGB 和 8 位 1920x1080,则您的文件大小必须为 1920x1080x3 像素 - 如果不是,则存在问题。您的图像为 1920x1080 和 NV12,即每像素 12 位或 1.5 字节,所以我希望您的文件为 1920x1080*1.5 字节。不是这样,所以马上就有问题了。有一个标题,或多个帧或尾随数据或其他一些问题。

那么,文件中的图像数据在哪里?在开始时?在末尾?解决此问题的一种方法是将文件视为纯粹的灰度图像,并查看是否有大块黑色为零字节或填充。由于没有已知的图像大小,我通常以字节为单位获取文件大小,然后转到Wolfram Alpha 网站并输入 "factors of XXX" 其中 XXX 是文件大小,然后选择附近的 2 个数字文件大小的平方根,所以我得到一个方形图像。因此,对于您的,我选择了 2720x3072 并将您的文件视为该尺寸的单个灰度图像。在终端中使用 ImageMagick

magick -depth 8 -size 2720x3072 gray:camera_preview_250_2020_10_07_11_11_02.yuv image.jpg

我可以一眼看出,数据在文件的开头,而文件的结尾是零填充,即黑色。如果黑色出现在图像的开头,我会取最后的H x W x 1.5 字节。

此步骤的另一个替代方法是以字节为单位的文件大小,然后将其除以图像宽度以获得行数并查看其外观。因此,您的文件是 8355840 字节,即 8355840/1920 或 4,325 行。让我们试试吧:

magick -depth 8 -size 1920x4352 gray:camera_preview_250_2020_10_07_11_11_02.yuv image.jpg

这非常令人鼓舞,因为我们可以在文件的开头看到 Y(灰度)图像和一些较低分辨率的 UV 通道,并且后面没有 2 个单独的通道这一事实可能意味着它们是交错的,交替 UV 样本,而不是平面 U 样本,然后是 V 样本。


好的,如果您的数据是 YUV 或 NV12,那么最好的工具是 ffmpeg。我们已经知道数据位于文件的开头,并且我们知道尺寸和格式。我们也知道图片后面有padding,所以我们只需要像这样取第一帧:

ffmpeg -s 1920x1080 -pix_fmt nv12 -i cam*yuv -frames:v 1 image.png


现在我们对尺寸和格式有了信心,我们需要 OpenCV 来读取它。普通的cv2.imread() 无法读取,因为它只是原始数据,并且与 JPEG、PNG 或 TIFF 不同,标题中没有图像高度和宽度 - 它只是纯粹的传感器数据。

因此,您需要使用常规 C/C++ read() 系统调用来获取前 1920x1080x1.5 字节。然后需要在接收到的缓冲区上调用cv2.cvtColor(),将其转换为常规的BGR格式Mat

【讨论】:

    猜你喜欢
    • 2021-07-02
    • 1970-01-01
    • 2021-12-04
    • 2015-12-03
    • 2016-05-12
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    相关资源
    最近更新 更多