从零开始:数字图像处理的编程基础与应用
上QQ阅读APP看书,第一时间看更新

1.5 视频读取与输出

OpenCV中视频的读和写操作,分别是通过cv::VideoCapture和cv::VideoWriter两个类来实现的。

· 1.5.1 视频读取

cv::VideoCapture类是读取视频的,cv::VideoCapture既支持视频文件的读取,也支持从视频捕捉设备中读取视频。cv::VideoCapture类的对象创建方式有以下3种。

cv::VideoCapture capture(const string& filename,);
// 第一种:从输入文件名对应的文件中读取
cv::VideoCapture capture(int device);
// 第二种:从视频捕捉设备 ID中读取视频
cv::VideoCapture capture();
//第三种:调用无参构造函数创建对象

第一种方式是从文件(AVI格式或者MP4格式等)中读取视频,对象创建完成以后,OpenCV将会打开文件并准备读取它。如果打开成功,将可以开始读取视频的帧,通过cv::VideoCapture类的成员函数isOpened()返回的true结果可以判断打开读取对象成功(建议在打开视频或摄像头时都使用该成员函数,以判断是否打开成功)。

第二种方式是从视频捕捉设备中读取视频。这种情况下,可以给出一个标识符,用于表示想要访问的视频捕捉设备,及其与操作系统的握手方式。对于视频捕捉设备而言,这个标识符就是一个标识数字——如果只有一台视频捕捉设备,那么就是0,如果系统中有多台视频捕捉设备,那么增加标识数字的值即可。

第三种方式仅创建一个捕获对象,而不提供任何关于打开的信息。对象创建以后通过成员函数open()来设定打开的信息。open()操作也有以下两种方式。

cv::VideoCapture cap;
cap.open( "my_video.avi"); //第一种方式打开视频文件
cap.open(0); //第二种方式打开视频捕捉设备

打开视频后,需要将视频帧读取到cv::Mat矩阵中,共有两种方式,一种是read()操作,另一种是>>操作。示例如下。

cv::Mat frame;
cap.read(frame); //读取方式一
cap >> frame; //读取方式二

综上,视频的读取操作步骤如下。

(1)创建cv::VideoCapture的对象。

cv::VideoCapture capture("D:/images/test1.mp4");

参数类型为const string&,即从文件中读取,若设置为0则读取视频捕捉设备。

(2)验证视频读取是否成功。

if (!capture.isOpened())
{
std::cout << "Vidoe open failed!" << std::endl;
return -1;
}

(3)验证完成,开始读取视频。

cv::Mat frame;
capture >> frame;

用户可以将VideoCapture对象像流一样读入Mat类型的对象(即图像)中。

下面将创建例1-4来展示视频文件的读取操作。

例1-4:视频文件读取。

项目完整代码文件(main.cpp文件)如下(需在1-4.pro文件中加入OpenCV配置信息,此处不再重复,详情可参考例1-3)。

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
VideoCapture capture("D:/images/test1.mp4");
if (!capture.isOpened())
{
cout << "Read video Failed !" << std::endl;
return -1;
}
Mat frame;
namedWindow("video test");
int frame_num = capture.get(cv::CAP_PROP_FRAME_COUNT);
cout << "total frame number is: " << frame_num << std::endl;
for (int i = 0; i < frame_num - 1; ++i)
{
capture >> frame;
//capture.read(frame); 第二种方式
imshow("video test", frame); //展示帧图像
if (cv::waitKey(30) == 'q')
{
break;
}
}
destroyWindow("video test"); //销毁窗口
capture.release(); //释放对象
return 0;
}

注意,上面的代码中使用cv::VideoCapture类的成员函数get()和设定标识cv::CAP_PROP_FRAME_COUNT获取了读取视频的总帧数。同样,可以通过指定其他标识来获取读取视频或视频捕捉设备的其他属性。

程序运行结果如图1-51所示。

图1-51 例1-4程序运行结果

· 1.5.2 视频输出

cv::VideoWriter类用于写入视频,该类使用起来比cv::VideoCapture类稍微复杂一些。cv::VideoWriter类的对象的创建有两种方式,第一种是使用构造函数,第二种是使用open()函数,具体示例如下。

第一种方式。

     cv::VideoWriter out(
const string& filename, // 输出文件名
int fourcc, // 编码形式,使用 CV_FOURCC()宏
double fps, // 输出视频帧率
cv::Size frame_size, // 单帧图像的大小
bool is_color = true // 如果是false,则可传入灰度图像,true为彩色图像
);

第二种方式。

     cv::VideoWriter out;
out.open(
"my_video.mpg", //输出文件名
CV_FOURCC('D','I','V','X'), // MPEG-4 编码
30.0, // 输出视频帧率
cv::Size( 640, 480 ), // 单帧图像分辨率为 640像素×480像素
true // 只可传入彩色图像,false为灰度图像
);

其中需要注意的是FOURCC编码形式,操作时常用以下函数把4个字符连接起来形成一个FOURCC 码,形式为cv::VideoWriter::fourcc(char c1,char c2,char c3,char c4)。

常用的格式有如下几种。

  • CV_FOURCC('P','I','M','1') = MPEG-1 codec。
  • CV_FOURCC('M','J','P','G') = motion-jpg codec。
  • CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec。
  • CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec。
  • CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec。

向创建的cv::VideoWriter对象写入图像也有两种方式,即write()操作和<<操作,示例如下。

     cv::VideoWriter::write(
const Mat& image // 写入图像作为下一帧
);
out << frame;

下面通过创建例1-5展示完整的视频读取(同例1-4,需要在1-5.pro文件中加入OpenCV配置信息)、处理及输出操作。

例1-5: 读取视频。

具体代码如下。

#include<stdio.h>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat frame;
string filename = "D:/images/test1.mp4";
VideoCapture cap(filename);
VideoWriter out;
out.open("D:/images/out.mp4",
cv::VideoWriter::fourcc('D','I','V','X'),
cap.get(CAP_PROP_FPS),
Size(cap.get(CAP_PROP_FRAME_WIDTH),cap.get(CAP_PROP_FRAME_HEIGHT)),
true);
if (!cap.isOpened())
{
cout << "Video load failed!" << endl;
return -1;
}
while (1)
{
cap >> frame;
if (frame.empty())
{
cout << "Video process finished!" << endl;
return 0;
}
imshow("video",frame);
if (waitKey(10) == 'q') break;
out << frame;
}
cap.release();
return 0;
}

注意,上面的代码中使用cv::VideoCapture类的成员函数get()和设定标识CAP_PROP_FPS获取读取视频的帧率。标识CAP_PROP_FRAME_WIDTH和CAP_PROP_FRAME_HEIGHT分别表示获取的视频图像的长度和宽度。

程序运行结果如图1-52所示。

图1-52 例1-5程序运行结果