Opencv学习笔记|3、OpenCV播放视频、保存、暂停视频,打开摄像头


OpenCV播放视频、保存、暂停视频,打开摄像头

    • 一、加载视频或摄像头
    • 二、获取视频帧或摄像头的帧
    • 三、循环逻辑控制视频显示
    • 四、暂停视频播放和中断视频播放
    • 五、视频保存
    • 六、完整代码示例
    • 七、致谢

一、加载视频或摄像头 1、原理理解
所谓的视频播放,无非就是将一堆有序的图片序列,按照顺序,以一定的间隔显示出来。这个间隔的多少与我们所听到的帧率相关。有了这个意识后,我们其实按照自己的思想都可以实现视频的播放:视频文件是由一帧帧具有先后顺序的图片组成,我们只需要将视频的每一帧按照原有的顺序显示出来即可。为此OpenCV提供了专用的对象和API以供加载视频并按顺序提取视频的每一帧。
2、视频管理类 cv::VideoCapture加载视频或摄像头
Opencv提供了用于获取视频文件的类 cv::VideoCapture,这个类提供了c++ API,用于从摄像机捕捉视频,或者读取视频文件和图像序列。实例化该类的对象后,便可以通过该类提供的方法获取视频帧和获得视频文件的相关信息。
通常使用如下两种方法构造 cv::VideoCapture对象。
方法一:先声明 cv::VideoCapture的对象,再调用该对象的open方法打开指定的视频文件
VideoCapture vc1; vc1.open("O:\\image\\1.mp4");

注意:cv::VideoCapture对象的open方法的函数原型为:
virtual bool cv::VideoCapture::open (const String & filename, int apiPreference = CAP_ANY)

open方法的第一个参数指定视频文件,第二个参数可忽略。open方法的另一个常用的重载为:
virtual bool cv::VideoCapture::open (int index, int apiPreference = CAP_ANY)

【Opencv学习笔记|3、OpenCV播放视频、保存、暂停视频,打开摄像头】此时,第一个参数用于绑定使用摄像头的编号,从0开始计数。
方法二:声明 cv::VideoCapture对象的时候,调用有参构造函数直接绑定视频文件
VideoCapture vc1("O:\\image\\1.mp4");

该构造函数的原型为:
cv::VideoCapture::VideoCapture (const String & filename, int apiPreference = CAP_ANY)

其中,第一个参数指定视频文件,第二个参数可忽略。其对应的打开摄像头的重载为:
cv::VideoCapture::VideoCapture (int index, int apiPreference = CAP_ANY)

此时,第一个参数还是指定摄像头编号,从0开始计数。
二、获取视频帧或摄像头的帧 1、在获取视频帧之前,通常我们需要判断一下视频或者摄像头有无打开(初始化):
if (!vc1.isOpened()) { fprintf(stderr, "failed to open %s\n", "O:\\image\\1.mp4"); return EXIT_FAILURE; }

如果视频或者摄像头初始化成功,该方法会返回 true。
2、获取视频帧或者摄像头的帧内容有两种方式
方法一:
Mat frame; vc1.read(frame);

该函数将VideoCapture::grab() 和 VideoCapture::retrieve() 组合在一个调用中。这是最方便的读取视频文件或捕获数据解码和返回方法。如果没有捕获帧(相机已断开连接,或没有更多帧),方法返回false,函数返回空图像。
方法二:
Mat frame; vc1 >> frame;

这主要是基于cv::VideoCapture类重载了 >> 操作符。
三、循环逻辑控制视频显示 结合原理理解,现在已经有方法获取视频的每一帧内容了,接下来要做的就是写好循环逻辑来逐帧显示图像即可。
Mat frame; vc1 >> frame; while (!frame.empty()) { imshow("demo", frame); vc1 >> frame; waitKey(30); } destroyAllWindows();

四、暂停视频播放和中断视频播放 前面已经实现了视频的连续播放,接下来要做的就是实现按下空格键(space,其ASCII值为32)时视频暂停播放,再次按下的时候继续播放。按下退出键(ESC,ASCII值为27)时中断视频播放。这儿会使用到一点简单的编程技巧,直接看代码:
Mat frame; vc1 >> frame; while (!frame.empty()) { imshow("demo", frame); vc1 >> frame; int k = waitKey(30); if (k == 27) break; else if (k == 32) { while (waitKey(0) != 32) waitKey(0); } } destroyAllWindows();

在每隔30ms显示一帧图像后会等待用户按键,如果在30ms内用户没按键,则waitKey(30) 的返回值为-1,程序继续显示下一帧,循环继续。如果用户按下了ESC键,则直接break退出循环,视频播放结束,如果按下空格后,则程序会一直等待用户再次按下空格后才继续。
五、视频保存 Opencv实现视频的保存需要定义编解码器并创建cv::VideoWriter对象。
1、实例化视频写对象cv::VideoWriter
VideoWriter writer;

cv::VideoWriter类有很多个重载的构造方法,可以在声明对象的同时定义编解码器,也可以在后面调用该对象的fourcc 方法指定编解码器。
int code = writer.fourcc('M', 'J', 'P', 'G'); writer.open("O:\\image\\result.avi", code, 40, Size(1280, 720), true);

声明对象的同时绑定文件和编解码器,其函数原型为:
CV_WRAP VideoWriter(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);

  • 参数 filename:指定保存视频的文件名(路径+名称)
  • 参数 fourcc:指定编解码器
  • 参数 fps:指定保存视频的帧率
  • 参数 frameSize:指定保存视频的尺寸,为Size对象
  • 参数 isColor:指定保存视频是否为彩色,默认为true
调用实例为:
string fileName = "O:\\image\\result.avi"; VideoWriter writer = VideoWriter(fileName, VideoWriter::fourcc('M', 'J', 'P', 'G'), 30, Size(1280, 720), true);

其它构造函数基本一致,感兴趣的小伙伴自行查阅资料。
2、在视频显示的循环帧中,将每一帧保存即可
调用 cv::VideoWriter对象的write函数:
writer.write(frame);

在写完视频后,记得释放资源:
writer.release();

六、完整代码示例
#include using namespace std; using namespace cv; int main(int argc, char** argv) { // 初始化视频管理对象,直接指定视频文件的路径 VideoCapture vc1("O:\\image\\1.mp4"); // 判断视频是否初始化成功 if (!vc1.isOpened()) { fprintf(stderr, "failed to open %s\n", "O:\\image\\1.mp4"); return EXIT_FAILURE; }// 声明视频写入对象 string fileName = "O:\\image\\result.avi"; VideoWriter writer = VideoWriter(fileName, VideoWriter::fourcc('M', 'J', 'P', 'G'), 30, Size(1280, 720), true); // 循环处理视频的每一帧,先显示,再写入 Mat frame; vc1 >> frame; while (!frame.empty()) { imshow("demo", frame); // 写入视频帧 writer.write(frame); vc1 >> frame; int k = waitKey(30); // 实现按键暂停和退出视频播放功能 if (k == 27) break; else if (k == 32) { while (waitKey(0) != 32) waitKey(0); } } // 释放资源,清空缓存 destroyAllWindows(); writer.release(); system("pause"); return EXIT_SUCCESS; }

七、致谢 1、常规的谢天谢地谢父母,谢朋友
2、感兴趣的小伙伴欢迎入群一起探讨学习 :725027506。 去群飞机票

    推荐阅读