解决 CAP_IMAGES: can‘t find starting number (in the name of file)

解决 CAP_IMAGES: can't find starting number (in the name of file)

  • 1. 解决方法
  • 2.报错代码
  • 3.报错Log
  • 4.错误分析
  • 5.opencv源码分析

1. 解决方法

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。

以下详细解释偷懒法能生效的原因。

2.报错代码

#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;
}
	

3.报错Log

[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'

4.错误分析

上面两句是运行时的报错信息。
第一句就是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中得出以下信息:

  1. 错误log由文件cap_images.cpp 第253行打印
  2. 貌似是文件名有点问题
  3. 具体是cv::icvExtractPattern函数中打印的

那么接下来就看下opencv源码,查一查我的文件名到底有什么问题

5.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”

如有帮助,不妨点赞关注以支持。

你可能感兴趣的:(opencv,c++)