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)
此时,第一个参数用于绑定使用摄像头的编号,从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<opencv2/opencv.hpp>
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
标签:视频,vc1,int,frame,Opencv,VideoCapture,cv,摄像头 来源: https://blog.csdn.net/phinoo/article/details/112211963