OpenCV保存未压缩原始视频文件的格式与报错问题排查
我尝试用OpenCV把若干帧保存为未压缩原始视频文件。查OpenCV官方文档得知:
若启用FFMPEG,设置
codec=0、fps=0即可创建未压缩(原始)视频文件。
通过cv::getBuildInformation()确认我的OpenCV已启用FFMPEG,相关信息如下:
Video I/O: DC1394: NO FFMPEG: YES (prebuilt binaries) avcodec: YES (58.134.100) avformat: YES (58.76.100) avutil: YES (56.70.100) swscale: YES (5.9.100) avresample: YES (4.0.0) GStreamer: NO DirectShow: YES Media Foundation: YES DXVA: YES
我写了如下测试代码:
#include <opencv2/videoio.hpp> void testLosslessWriter() { cv::VideoCapture cap(0, cv::CAP_DSHOW); int w = int(cap.get(cv::CAP_PROP_FRAME_WIDTH)); int h = int(cap.get(cv::CAP_PROP_FRAME_HEIGHT)); cv::VideoWriter writerUncompressed("test_raw", 0, 0, cv::Size(w, h)); }
运行后报错:
OpenCV(4.7.0-dev) Error: Bad argument (CAP_IMAGES: can't find starting number (in the name of file): test_raw) in cv::icvExtractPattern, file C:\workspace\libs\opencv\modules\videoio\src\cap_images.cpp, line 253 [ERROR:0@0.325] global cap.cpp:597 cv::VideoWriter::open VIDEOIO(CV_IMAGES): raised OpenCV exception: OpenCV(4.7.0-dev) C:\workspace\libs\opencv\modules\videoio\src\cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name of file): test_raw in function 'cv::icvExtractPattern'
试过用"test_raw.avi"、"test_raw.mp4"或"test_raw.raw"等后缀,还是报同样的错。请问怎么按文档提示正确实现需求?
补充说明1
根据Rotem的回答,问题确实出在fps=0上,改用.avi后缀并设置fourcc为"RGBA"后,上述问题解决了,但又出现新问题:
// 返回错误: // OpenCV: FFMPEG: tag 0x00000000/'????' is not supported with codec id 13 and format 'rawvideo / raw video' cv::VideoWriter writerUncompressed("test_raw.rgb", 0, 1, cv::Size(w, h)); // 使用test_raw.yuv时情况相同
虽然输出文件已生成且不为空,但用VideoCapture(Python环境,设置CAP_FFMPEG或CAP_ANY API偏好)读取时,报错[IMGUTILS @ 0000003dbc7edaf0] Picture size 0x0 is invalid,无法读取任何帧。
解决方案
初始报错的修复
设置fps=0会导致OpenCV误将输出识别为图像序列而非视频文件,触发CAP_IMAGES错误。必须指定有效帧率(比如摄像头实际帧率30),搭配支持未压缩编码的容器后缀(推荐.avi),并明确指定未压缩FourCC编码:// 示例:使用RGBA未压缩编码,帧率设为30 cv::VideoWriter writerUncompressed("test_raw.avi", cv::VideoWriter::fourcc('R','G','B','A'), 30, cv::Size(w, h));裸数据文件(.rgb/.yuv)的问题处理
.rgb/.yuv这类裸数据文件没有容器头存储分辨率、像素格式等元数据,FFMPEG无法自动识别,因此VideoWriter无法正确生成可读取的文件,VideoCapture也无法解析。- 若只需保存裸原始帧数据,直接写入二进制文件即可,无需用
VideoWriter:// 假设帧为BGR格式的8位图像 std::ofstream raw_file("test_raw.bgr", std::ios::binary); raw_file.write(reinterpret_cast<const char*>(frame.data), frame.total() * frame.elemSize()); raw_file.close(); - 若要生成能被
VideoCapture正常读取的未压缩视频,必须使用带容器的格式(如.avi),确保FFMPEG写入完整的元数据。
- 若只需保存裸原始帧数据,直接写入二进制文件即可,无需用
读取未压缩视频的正确方式
对于用.avi容器保存的未压缩视频,直接用VideoCapture读取即可,无需额外配置:import cv2 cap = cv2.VideoCapture("test_raw.avi", cv2.CAP_FFMPEG) if not cap.isOpened(): print("无法打开视频") while cap.isOpened(): ret, frame = cap.read() if not ret: break # 处理帧逻辑 cap.release()
内容的提问来源于stack exchange,提问作者Buzz

