现在找一个能拍摄视频的设备真是太容易了。结果大家都用视频来代替以前的序列图像。视频可能由两种形式得到,一个是像网络摄像头那样实时视频流,或者由其他设备产生的压缩编码后的视频文件。幸运的是,OpenCV可以使用相同的C++类、用同一种方式处理这些视频信息。在接下来的教程里你将学习如何使用摄像头或者视频文件。
- 如何打开和读取视频流
- 两种检查相似度的方法:PSNR和SSIM
如何读取一个视频流(摄像头或者视频文件)?
总的来说,视频捕获需要的所有函数都集成在 VideoCapture C++ 类里面。虽然它底层依赖另一个FFmpeg开源库,但是它已经被集成在OpenCV里所以你不需要额外地关注它的具体实现方法。你只需要知道一个视频由一系列图像构成,我们用一个专业点儿的词汇来称呼这些构成视频的图像:“帧”(frame)。此外在视频文件里还有个参数叫做“帧率”(frame rate)的,用来表示两帧之间的间隔时间,帧率的单位是(帧/秒)。这个参数只和视频的播放速度有关,对于单独的一帧图像来说没有任何用途。
你需要先定义一个 VideoCapture 类的对象来打开和读取视频流。具体可以通过 constructor 或者通过 open 函数来完成。如果使用整型数当参数的话,就可以将这个对象绑定到一个摄像机,将系统指派的ID号当作参数传入即可。例如你可以传入0来打开第一个摄像机,传入1打开第二个摄像机,以此类推。如果使用字符串当参数,就会打开一个由这个字符串(文件名)指定的视频文件。
CvCapture 是一个结构体,用来保存图像捕获所需要的信息。 opencv提供两种方式从外部捕获图像:
VideoCapture类 用于从视频文件或摄像机捕获视频.该类提供了用于从摄像机捕获视频或者读取视频文件的C++ API。 注意:在C API中使用黑盒子结构CvCapture来代替VideoCapture。 构造函数 VideoCapture::VideoCapture() VideoCapture::VideoCapture(const string& filename)//filename – 文件名 VideoCapture::VideoCapture(int device)//device – 捕获视频的编号. 如果只有一个设备,默认编号为0 open函数 打开视频文件或捕获设备进行视频捕获 bool VideoCapture::open(const string& filename)//filename – 文件名 bool VideoCapture::open(int device)//device – 捕获视频的编号. 如果只有一个设备,默认编号为0 isopened函数 如果视频捕获已经初始化,则返回true。 bool VideoCapture::isOpened() release函数 关闭视频文件或捕获设备 void VideoCapture::release() grap函数 从视频文件或捕获设备中捕获下一帧 bool VideoCapture::grab() retrieve函数 解码并返回抓取的视频帧 bool VideoCapture::retrieve(Mat& image, int channel=0) read函数 抓取,解码并返回下一个视频帧 bool VideoCapture::read(Mat& image) get函数 返回指定的VideoCapture属性 double VideoCapture::get(int propId)//propId - 属性标识符 CV_CAP_PROP_POS_MSEC - 视频文件的当前位置(以毫秒为单位)或视频捕获时间戳。 CV_CAP_PROP_POS_FRAMES - 下一个要解码/捕获的帧的基于0的索引。 CV_CAP_PROP_POS_AVI_RATIO - 视频文件的相对位置:0 - 电影的开始,1 - 电影的结束。 CV_CAP_PROP_FRAME_WIDTH - 视频流中帧的宽度。 CV_CAP_PROP_FRAME_HEIGHT - 视频流中帧的高度。 CV_CAP_PROP_FPS - 帧速率。 CV_CAP_PROP_FOURCC - 编解码器的4个字符代码。 CV_CAP_PROP_FRAME_COUNT - 视频文件中的帧数。 CV_CAP_PROP_FORMAT - retrieve()返回的Mat对象的格式。 CV_CAP_PROP_MODE - 指示当前捕获模式的后端特定值。 CV_CAP_PROP_BRIGHTNESS - 图像的亮度(仅适用于相机)。 CV_CAP_PROP_CONTRAST - 图像的对比度(仅适用于相机)。 CV_CAP_PROP_SATURATION - 图像的饱和度(仅适用于相机)。 CV_CAP_PROP_HUE - 图像的色调(仅适用于摄像机)。 CV_CAP_PROP_GAIN - 图像的增益(仅适用于摄像机)。 CV_CAP_PROP_EXPOSURE - 曝光(仅适用于相机)。 CV_CAP_PROP_CONVERT_RGB - 指示图像是否应转换为RGB的布尔标志。 CV_CAP_PROP_WHITE_BALANCE - 目前不支持 CV_CAP_PROP_RECTIFICATION - 立体相机的校正标志(注意:目前仅由DC1394 v 2.x后端支持) set函数 设置VideoCapture中的属性。 bool VideoCapture::set(int propertyId, double value)//propId - 属性标识符,同get;value - 属性的值。
#include<opencv2/opencv.hpp> using namespace cv; void main() { VideoCapture cap; cap.open("E:\VS2015Opencv\vs2015\project\video\01.avi"); //打开视频,以上两句等价于VideoCapture cap("E://01.avi"); //cap.open("http://www.laganiere.name/bike.avi");//也可以直接从网页中获取图片,前提是网页有视频,以及网速够快 if (!cap.isOpened())//如果视频不能正常打开则返回 return ; Mat frame; while (1) { cap >> frame;//等价于cap.read(frame); if (frame.empty())//如果某帧为空则退出循环 break; imshow("video", frame); waitKey(20);//每帧延时20毫秒 } cap.release();//释放资源 }
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; void main() { VideoCapture cap; cap.open("E:\VS2015Opencv\vs2015\project\video\01.avi"); if (!cap.isOpened()) return; int width = cap.get(CV_CAP_PROP_FRAME_WIDTH); //帧宽度 int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //帧高度 int frameRate = cap.get(CV_CAP_PROP_FPS); //帧率 x frames/s int totalFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); //总帧数 cout << "视频宽度=" << width << endl; cout << "视频高度=" << height << endl; cout << "视频总帧数=" << totalFrames << endl; cout << "帧率=" << frameRate << endl; Mat frame; while (1) { cap >> frame;//等价于cap.read(frame); if (frame.empty()) break; imshow("video", frame); if (waitKey(33) != 255) break; } cap.release(); }
将左边的waitkey(33)改成右边的if(waitKey(20)>0)break;
程序会直接跳出,不放视频
opencv学习之等待按键事件-waitKey函数
waitkey(20) 如果不按键的时候是返回 oxff,这个无符号就是255,有符号就是-1
windows vs 的环境默认了这个为非符号数 即255,而opencv的新手书中,往往作者环境会认为是-1
解决方案:把原始代码中循环读取帧的
if (waitKey(33)>=0)break;
改为
if (waitKey(33) != 255)break;
或者把waitkey的返回值用有符号数去读取。