opencv 无法打开 yuv422 图像,而 rawpixels.net 可以显示图像
opencv can't open a yuv422 image while rawpixels.net can display the image
我正在尝试打开 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图像是这样的。
谢谢,
处理原始(RGB、BGR、YUV、NV12 和其他)图像时要做的第一件事是了解图像的像素尺寸——没有这些你真的很迷茫——尽管你可以做到寻找相关性以找到行宽的某些技巧,因为每一行通常与上面的行基本相似。
接下来是检查文件大小是否正确。因此,如果它是 RGB 和 8 位 1920x1080,则您的文件大小必须为 1920x1080x3 像素 - 如果不是,则存在问题。您的图像是 1920x1080 和 NV12,即每像素 12 位或 1.5 字节,因此我希望您的文件为 1920x1080*1.5 字节。不是那样的,所以马上就有问题了。存在 header、多帧或尾随数据或其他问题。
那么,文件中的图像数据在哪里?在开始时?在最后?解决这个问题的一种方法是查看文件,就好像它是一个纯灰度图像一样,看看是否有大块黑色的零字节或填充。由于没有已知的图像大小,我通常以字节为单位获取文件大小,然后转到 Wolfram Alpha 网站并输入 "factors of XXX",其中 XXX 是文件大小,然后选择文件大小 square-root 附近的 2 个数字,这样我就得到了 square-ish 图像。因此,对于您的文件,我选择了 2720x3072 并将您的文件视为该尺寸的单个灰度图像。在终端中使用 ImageMagick:
magick -depth 8 -size 2720x3072 gray:camera_preview_250_2020_10_07_11_11_02.yuv image.jpg
我一看,数据在文件的开头,文件的结尾是zero-padding,即黑色。如果黑色位于图像的开头,我会采用最后的 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
(灰度)图像,然后是一些 lower-resolution UV
通道,事实上后面没有 2 个单独的通道可能意味着它们是交错的,交替 U
和 V
样本而不是平面 U
样本后跟 V
样本。
好的,如果您的数据是 YUV 或 NV12,那么最好的工具是 ffmpeg
。我们已经知道数据位于文件的开头,并且我们知道尺寸和格式。我们也知道图像后面有填充,所以我们只需要像这样拍摄第一帧:
ffmpeg -s 1920x1080 -pix_fmt nv12 -i cam*yuv -frames:v 1 image.png
现在我们对维度和格式有了信心,我们需要 OpenCV 来读取它。普通 cv2.imread()
无法读取,因为它只是原始数据,与 JPEG 或 PNG 或 TIFF 不同,header 中没有图像高度和宽度 - 它只是纯粹的传感器数据。
因此,您需要使用常规 C/C++ read()
系统调用来获取前 1920x1080x1.5 个字节。然后你需要在收到的缓冲区上调用 cv2.cvtColor()
将其转换为常规 BGR 格式 Mat
.
我正在尝试打开 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图像是这样的。
谢谢,
处理原始(RGB、BGR、YUV、NV12 和其他)图像时要做的第一件事是了解图像的像素尺寸——没有这些你真的很迷茫——尽管你可以做到寻找相关性以找到行宽的某些技巧,因为每一行通常与上面的行基本相似。
接下来是检查文件大小是否正确。因此,如果它是 RGB 和 8 位 1920x1080,则您的文件大小必须为 1920x1080x3 像素 - 如果不是,则存在问题。您的图像是 1920x1080 和 NV12,即每像素 12 位或 1.5 字节,因此我希望您的文件为 1920x1080*1.5 字节。不是那样的,所以马上就有问题了。存在 header、多帧或尾随数据或其他问题。
那么,文件中的图像数据在哪里?在开始时?在最后?解决这个问题的一种方法是查看文件,就好像它是一个纯灰度图像一样,看看是否有大块黑色的零字节或填充。由于没有已知的图像大小,我通常以字节为单位获取文件大小,然后转到 Wolfram Alpha 网站并输入 "factors of XXX",其中 XXX 是文件大小,然后选择文件大小 square-root 附近的 2 个数字,这样我就得到了 square-ish 图像。因此,对于您的文件,我选择了 2720x3072 并将您的文件视为该尺寸的单个灰度图像。在终端中使用 ImageMagick:
magick -depth 8 -size 2720x3072 gray:camera_preview_250_2020_10_07_11_11_02.yuv image.jpg
我一看,数据在文件的开头,文件的结尾是zero-padding,即黑色。如果黑色位于图像的开头,我会采用最后的 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
(灰度)图像,然后是一些 lower-resolution UV
通道,事实上后面没有 2 个单独的通道可能意味着它们是交错的,交替 U
和 V
样本而不是平面 U
样本后跟 V
样本。
好的,如果您的数据是 YUV 或 NV12,那么最好的工具是 ffmpeg
。我们已经知道数据位于文件的开头,并且我们知道尺寸和格式。我们也知道图像后面有填充,所以我们只需要像这样拍摄第一帧:
ffmpeg -s 1920x1080 -pix_fmt nv12 -i cam*yuv -frames:v 1 image.png
现在我们对维度和格式有了信心,我们需要 OpenCV 来读取它。普通 cv2.imread()
无法读取,因为它只是原始数据,与 JPEG 或 PNG 或 TIFF 不同,header 中没有图像高度和宽度 - 它只是纯粹的传感器数据。
因此,您需要使用常规 C/C++ read()
系统调用来获取前 1920x1080x1.5 个字节。然后你需要在收到的缓冲区上调用 cv2.cvtColor()
将其转换为常规 BGR 格式 Mat
.