介绍读写视频之前,首先要明确编解码器codec的概念。如果是图像文件我们可以通过文件扩展名得知图像的格式,但是视频文件并不适用,在opencv中,都是avi视频文件,有些能用opencv打开,有些则不能。
视频的格式主要由压缩算法决定。压缩算法称之为编码器(coder),解压算法称之为解码器(decoder),编解码算法统称为编解码器(codec)。视频文件能读或者写,关键看是否有相应的编解码器。编解码器的种类非常多,比如MJPG,XVID,DIVX等,因此视频文件的扩展名往往只能表示这是一个视频文件。
opencv中提供了两个类来实现视频的读写,读视频的类是VideoCapture,写视频的类是VideoWriter。
读视频
VideoCapture既可以从视频文件读取图像,也可以从摄像头读取图像,可以使用该类的构造函数打开视频文件或摄像头。如果VideoCapture对象已经创建,也可以使用VideoCapture::open()打开,VideoCapture::open()函数会自动调用VideoCapture::release()函数,先释放已经打开的视频,然后在打开新视频。
如果要读一帧,可以使用VideoCapture::read()函数。VideoCapture类重载了>>操作符,实现了读视频帧的功能。
保存视频或摄像头视频到本地磁盘
代码演示
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc,char **argv)
{
//打开第一个摄像头
VideoCapture cap(0);
//检查是否成功打开
if (!cap.isOpened())
{
printf("could not open the camera\n");
return -1;
}
Mat gray_image;
Mat edges;
namedWindow("edges", WINDOW_AUTOSIZE);
for (;;)
{
Mat frame;
//从cap中读取一帧,存到frame
cap >> frame;
if (frame.empty())
break;
//转为灰度图
cvtColor(frame, gray_image, COLOR_BGR2GRAY);
//边缘提取
Canny(gray_image, edges, 0, 30, 3);
//显示
imshow("edges", edges);
if (waitKey(10) >= 0)
break;
}
return 0;
}
写视频
与读视频不同的是,需要在创建视频时设置一系列参数,包括文件名,编解码器,帧率,高度和宽度等。编解码器使用四个字符表示,可以是CV_FOURCC('M','J','P','G'),CV_FOURCC('D', 'I', 'V', 'X')等。
将图像写入视频可以使用VideoWriter::write(),VideoWriter类函数中也重载了<<操作符,另外需要注意的是:待写入的图像尺寸必须与创建视频时指定的尺寸一致
VideoWriter
构造函数:
VideoWriter writer(const string& filename, int fourcc, double fps,Size frameSize, bool isColor=true);
参数说明:
文件名,codec,帧率,宽和高
fourcc 表示所使用的编码方式,为四个字符用来表示压缩帧的codec
如果输入-1,会弹出一个选择对话框来选择编码器
PS:在opencv4.0.0中,fourcc:CAP_OPENCV_MJPEG
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc,char **argv)
{
//定义视频的宽和高
Size s(320, 240);
VideoWriter writer("video0.mp4", CAP_OPENCV_MJPEG, 25, s);
//判断是否创建成功
if (!writer.isOpened())
{
cout << "could not craet video file" << endl;
return -1;
}
//视频帧
Mat frame(s, CV_8UC3);
for (int i = 0; i < 100; i++)
{
//将图像设置为黑色
frame = Scalar::all(0);
//将整数i转为i字符串类型
char test[128];
snprintf(test, sizeof(test), "%d", i);
//将数字绘到画面上
putText(frame, test, Point(s.width / 3, s.height / 3), FONT_HERSHEY_SCRIPT_SIMPLEX, 3,Scalar(0, 0, 255), 3, 8);
//将图像写入视频
writer << frame;
}
return 0;
}