1.确认输出文件类型与fourcc需匹配。具体可参考官网http://www.fourcc.org/codecs.php。
简单点就用 .avi 配 VideoWriter::fourcc(‘M’, ‘J’, ‘P’, ‘G’)。
网上搜到一个贴说什么fourcc是旧版本用的,现在不用了,这种说发的是错的哈。对于Opencv4.3.x,依然采用fourcc。当编译不过时应把类名加上VideoWriter::fourcc(‘X’, ‘X’, ‘X’, ‘X’)。
2.第1步无误但还是报错的话:
Linux平台:重新安装ffmpeg,然后重新编译opencv并安装。opencv编译时 cmake需加上参数-DWITH_FFMPEG=ON。
Window平台:可将输出文件类型改为.mp4。此方法为偷懒法,无需安装ffmpeg。
以下详细解释偷懒法能生效的原因。
#define VIDEO_OUTPUT_PATH "D:\\test_project\\output.avi" //我原来代码输出文件类型为.avi
int main()
{
Mat frame;
frame = imread("xxx.jpg");
// Mat数据保存为视频
VideoWriter vWriter(VIDEO_OUTPUT_PATH, CAP_OPENCV_MJPEG, 30, Size(frame.cols, frame.rows));
//上面参数使用CAP_OPENCV_MJPEG是错误的哈,VideoWriter::fourcc('M', 'J', 'P', 'G')才是正确的参数
int frameNum = 90; //定义我要存多少帧
while (frameNum) {
vWriter << dst;
frameNum--;
}
return 0;
}
[ERROR:0] global C:\build\master_winpack-build-win64-vc14\opencv\modules\videoio\src\cap.cpp (563) cv::VideoWriter::open VIDEOIO(CV_IMAGES): raised OpenCV exception:
OpenCV(4.5.1) C:\build\master_winpack-build-win64-vc14\opencv\modules\videoio\src\cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name of file): D:\\test_project\\output.avi in function 'cv::icvExtractPattern'
上面两句是运行时的报错信息。
第一句就是VideoWriter::open运行时收到异常。
第二句是具体的异常内容:
OpenCV(4.5.1) C:\build\master_winpack-build-win64-vc14\opencv\modules\videoio\src\cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can’t find starting number (in the name of file): D:\test_project\output.avi in function ‘cv::icvExtractPattern’
我们可以从报错log中得出以下信息:
- 错误log由文件cap_images.cpp 第253行打印
- 貌似是文件名有点问题
- 具体是cv::icvExtractPattern函数中打印的
那么接下来就看下opencv源码,查一查我的文件名到底有什么问题
//在opencv\modules\videoio\src\cap.cpp 中找到 icvExtractPattern 函数
std::string icvExtractPattern(const std::string& filename, unsigned *offset)
{
size_t len = filename.size(); //记录文件名长度
。。。。。。//一堆操作,不用关心
pos = filename.rfind('/'); //找到文件名中最后一个"/"的位置
#ifdef _WIN32
if (pos == std::string::npos)
pos = filename.rfind('\\'); //对于window 系统,找到文件名中最后一个"\\"的位置
#endif
if (pos != std::string::npos)
pos++;
else
pos = 0;
while (pos < len && !isdigit(filename[pos])) pos++; //文件名错误的关键点
if (pos == len) //如果位置等于文件名长度,则抛出异常
{
CV_Error_(Error::StsBadArg, ("CAP_IMAGES: can't find starting number (in the name of file): %s", filename.c_str()));
}
。。。。。。//一堆操作,不用关心
}
以上代码实现的应该是从输出文件名找到需要输出的文件类型。
因为关键点 while (pos < len && !isdigit(filename[pos])) pos++; 这里实现的是如果文件名中 pos所指的字符不是数子,那么pos就++,指向下一个字符。看起来因该就是想要找到带数子的文件名。
因此灵机一动,将输出文件的文件类型设置为mp4,然后问题就解决了。
#define VIDEO_OUTPUT_PATH “D:\test_project\output.avi”
改为:
#define VIDEO_OUTPUT_PATH “D:\test_project\output.mp4”
如有帮助,不妨点赞关注以支持。