【从零学习OpenCV】 视频数据的读取&摄像头的直接调用
重磅干货,第一时间送达
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。
1
01
视频数据的读取
虽然视频文件是由多张图片组成的,但是imread()函数并不能直接读取视频文件,需要由专门的视频读取函数进行视频读取,并将每一帧图像保存到Mat类矩阵中,代码清单2-27中给出了VideoCapture类在读取视频文件时的构造方式。
代码清单2-27 读取视频文件VideoCapture类构造函数
cv :: VideoCapture :: VideoCapture(); //默认构造函数
cv :: VideoCapture :: VideoCapture(const String& filename,
int apiPreference =CAP_ANY
)
filename:读取的视频文件或者图像序列名称
apiPreference:读取数据时设置的属性,例如编码格式、是否调用OpenNI等,详细参数及含义在表2-5给出。
该函数是构造一个能够读取与处理视频文件的视频流,在代码清单2-27中的第一行是VideoCapture类的默认构造函数,只是声明了一个能够读取视频数据的类,具体读取什么视频文件,需要在使用时通过open()函数指出,例如cap.open(“1.avi”)是VideoCapture类变量cap读取1.avi视频文件。
第二种构造函数在给出声明变量的同时也将视频数据赋值给变量。可以读取的文件种类包括视频文件(例如video.avi)、图像序列或者视频流的URL。其中读取图像序列需要将多个图像的名称统一为“前缀+数字”的形式,通过“前缀+%02d”的形式调用,例如在某个文件夹中有图片img_00.jpg、img_01.jpg、img_02.jpg……加载时文件名用img_%02d.jpg表示。函数中的读取视频设置属性标签默认的是自动搜索合适的标志,所以在平时使用中,可以将其缺省,只需要输入视频名称即可。与imread()函数一样,构造函数同样有可能读取文件失败,因此需要通过isOpened()函数进行判断,如果读取成功则返回值为true,如果读取失败,则返回值为false。
通过构造函数只是将视频文件加载到了VideoCapture类变量中,当我们需要使用视频中的图像时,还需要将图像由VideoCapture类变量里导出到Mat类变量里,用于后期数据处理,该操作可以通过“>>”运算符将图像按照视频顺序由VideoCapture类变量复制给Mat类变量。当VideoCapture类变量中所有的图像都赋值给Mat类变量后,再次赋值的时候Mat类变量会变为空矩阵,因此可以通过empty()判断VideoCapture类变量中是否所有图像都已经读取完毕。
VideoCapture类变量同时提供了可以查看视频属性的get()函数,通过输入指定的标志来获取视频属性,例如视频的像素尺寸、帧数、帧率等,常用标志和含义在表2-5中给出。
表2-5 VideoCapture类中get方法中的标志参数
标志参数 |
简记 |
作用 |
CAP_PROP_POS_MSEC |
0 |
视频文件的当前位置(以毫秒为单位) |
CAP_PROP_FRAME_WIDTH |
3 |
视频流中图像的宽度 |
CAP_PROP_FRAME_HEIGHT |
4 |
视频流中图像的高度 |
CAP_PROP_FPS |
5 |
视频流中图像的帧率(每秒帧数) |
CAP_PROP_FOURCC |
6 |
编解码器的4字符代码 |
CAP_PROP_FRAME_COUNT |
7 |
视频流中图像的帧数 |
CAP_PROP_FORMAT |
8 |
返回的Mat对象的格式 |
CAP_PROP_BRIGHTNESS |
10 |
图像的亮度(仅适用于支持的相机) |
CAP_PROP_CONTRAST |
11 |
图像对比度(仅适用于相机) |
CAP_PROP_SATURATION |
12 |
图像饱和度(仅适用于相机) |
CAP_PROP_HUE |
13 |
图像的色调(仅适用于相机) |
CAP_PROP_GAIN |
14 |
图像的增益(仅适用于支持的相机) |
为了更加熟悉VideoCapture类,在代码清单2-28中给出了读取视频,输出视频属性,并按照原帧率显示视频的程序,运行结果在图2-6给出。
代码清单2-28 VideoCapture.cpp读取视频文件
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
system("color F0"); //更改输出界面颜色
VideoCapture video("cup.mp4");
if (video.isOpened())
{
cout << "视频中图像的宽度=" << video.get(CAP_PROP_FRAME_WIDTH) << endl;
cout << "视频中图像的高度=" << video.get(CAP_PROP_FRAME_HEIGHT) << endl;
cout << "视频帧率=" << video.get(CAP_PROP_FPS) << endl;
cout << "视频的总帧数=" << video.get(CAP_PROP_FRAME_COUNT);
}
else
{
cout << "请确认视频文件名称是否正确" << endl;
return -1;
}
while (1)
{
Mat frame;
video >> frame;
if (frame.empty())
{
break;
}
imshow("video", frame);
waitKey(1000 / video.get(CAP_PROP_FPS));
}
waitKey();
return 0;
}
图2-6 读取视频程序运行结果
1
02
摄像头的直接调用
VideoCapture类还可以调用摄像头,构造方式如代码清单2-29中所示。
代码清单2-29 VideoCapture类调用摄像头构造函数
cv :: VideoCapture :: VideoCapture(int index,
int apiPreference = CAP_ANY
)
通过与代码清单2-27中对比,调用摄像头与读取视频文件相比,只有第一个参数不同。调用摄像头时,第一个参数为要打开的摄像头设备的ID,ID的命名方式从0开始。从摄像头中读取图像数据的方式与从视频中读取图像数据的方式相同,通过“>>”符号读取当前时刻相机拍摄到的图像。并且读取视频时VideoCapture类具有的属性同样可以使用。我们将代码清单2-28中的视频文件改成摄像头ID(0),再次运行代码清单2-28的程序,运行结果如图2-7所示。
图2-7 调用摄像头程序运行结果