opencv学习之路(2)、读取视频,读取摄像头
一、介绍
视频读取本质上就是读取图像,因为视频是由一帧一帧图像组成的。1秒24帧基本就能流畅的读取视频了。
①读取视频有两种方法:
A. VideoCapture cap;
cap.open(“1.avi”);
B. VideoCapture cap(“1.avi”);
②循环显示每一帧:
while(1)
{
Mat frame; //定义Mat变量,用来存储每一帧
cap>>frame; //读取当前帧方法一
//cap.read(frame); //读取当前帧方法二
imshow(“视频显示”, frame); //显示一帧画面
waitKey(30); //延时30ms
}
二、读取视频示例程序
1 #include<opencv2/opencv.hpp> 2 using namespace cv; 3 4 void main(){ 5 VideoCapture cap; 6 cap.open("E://2.avi"); //打开视频,以上两句等价于VideoCapture cap("E://2.avi"); 7 8 //cap.open("http://www.laganiere.name/bike.avi");//也可以直接从网页中获取图片,前提是网页有视频,以及网速够快 9 if(!cap.isOpened())//如果视频不能正常打开则返回 10 return; 11 Mat frame; 12 while(1) 13 { 14 cap>>frame;//等价于cap.read(frame); 15 if(frame.empty())//如果某帧为空则退出循环 16 break; 17 imshow("video", frame); 18 waitKey(20);//每帧延时20毫秒 19 } 20 cap.release();//释放资源 21 }
三、读取视频说明
- 打开的视频可以是本地视频如:
VideoCapture cap(“1.avi”);
也可以是网络视频如:
VideoCapture cap(“http://www.laganiere.name/bike.avi“); - 读取视频一定要加异常判断
A.打开视频失败(各种原因)
B. 取帧失败异常(程序结尾判断)
ex1:
if(!cap.isOpened()) //检查打开是否成功
return;
ex2:
cap>>frame;
if(!frame.empty()) //判断当前 帧是否为空
{
imshow(“video”, frame);
waitKey(30);
}
else break;
四、获取指定视频类的相关参数信息
1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 using namespace cv; 4 using namespace std; 5 6 void main(){ 7 VideoCapture cap; 8 cap.open("E:\\2.avi"); //打开视频,等价于 VideoCapture cap("E://2.avi"); 9 10 if(!cap.isOpened()) 11 return; 12 13 int width = cap.get(CV_CAP_PROP_FRAME_WIDTH); //帧宽度 14 int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //帧高度 15 int frameRate = cap.get(CV_CAP_PROP_FPS); //帧率 x frames/s 16 int totalFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); //总帧数 17 18 cout<<"视频宽度="<<width<<endl; 19 cout<<"视频高度="<<height<<endl; 20 cout<<"视频总帧数="<<totalFrames<<endl; 21 cout<<"帧率="<<frameRate<<endl; 22 23 Mat frame; 24 while(1) 25 { 26 cap>>frame;//等价于cap.read(frame); 27 if(frame.empty()) 28 break; 29 imshow("video", frame); 30 if(waitKey(20)>0) 31 break; 32 } 33 cap.release(); 34 }
五、读取摄像头
读取摄像头和读取视频大同小异,主要是这句代码有些许不同。
VideoCapture cap;
cap.open(0);
读取视频时可以传入视频路径,而读取摄像头传入的是index索引号。
注:
1)如果默认笔记本/台式机只有一个USB摄像头,Index=0; 如果有2个,一般Index为0和1,根据具体情况区分,摄像头接入和断开会改变Index值
2)如果接入2个以上,但只想用指定的一个,可以在设备管理器中禁用其他,同时Index设置为0
3)因为开启摄像头后一直在进行读取,所以需要用waitKey()返回值判断退出预览
imshow(“video”, frame);
if(waitKey(30)>0)//无按键按下返回-1,按键按下时退出
break;
也可以指定按键退出:
if(waitKey(30)==27) //Esc键退出,ESC的ASCLL码为27
break;
六、读取摄像头后加入简单处理效果
如果只是读取摄像头不进行处理的话,那毫无意义,现在以canny边缘检测以及颜色空间转换为目标进行处理。
1 #include<opencv2/opencv.hpp> 2 using namespace cv; 3 4 void main(){ 5 VideoCapture cap; 6 cap.open(0); //打开摄像头 7 8 if(!cap.isOpened()) 9 return; 10 11 Mat frame; 12 while(1) 13 { 14 cap>>frame;//等价于cap.read(frame); 15 Canny(frame, frame, 30, 100);//canny边缘检测,去掉这一行就是纯粹的读取摄像头了 16 //cvtColor(frame, frame, CV_BGR2HSV);//BGR空间转为HSV颜色空间,注意,两者不能同时对同一张图片(在此为frame)进行处理,否则报错 17 if(frame.empty()) 18 break; 19 imshow("video", frame); 20 if(waitKey(20)>0)//按下任意键退出摄像头 因电脑环境而异,有的电脑可能会出现一闪而过的情况 21 break; 22 } 23 cap.release(); 24 destroyAllWindows();//关闭所有窗口 25 }
针对第20行代码:最开始电脑配置的opencv2.x版本,上述代码打开摄像头没有问题;后来使用opencv3.x版本,重新编译了contrib包,发现摄像头打开后一闪而过。
原因是 waitkey() 如果不按键的时候是返回 oxff,oxff无符号时是255,有符号时是-1。windows vs 的环境默认了这个为非符号数 即255,而opencv的有些配置环境中是-1。
解决方案:把原始代码中循环读取帧的
if (waitKey(20)>=0) break;
改为
if (waitKey(20) != 255) break;
或者把waitkey的返回值用有符号数去读取。
uchar c=waitkey(20); if(c!=255) break;
七、写入视频
1、介绍
①VideoWriter: OpenCV提供VideoWriter类写视频文件,类的构造函数可以指定文件名、播放帧率、帧尺寸、是否创建彩色视频。
②两种写入帧方法:
1 ) writer.write(frame);
2)writer >>frame(这里的箭头方向应该相反,不知道为什么箭头不能向←);
③注意事项:
1)写入视频前需安装对应的编解码器
2)生成视频是否支持彩色应与构造函数设置一致
3)生成视频尺寸需与读取视频尺寸一致
2、代码示例
1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 using namespace cv; 4 using namespace std; 5 6 void main(){ 7 VideoCapture cap; 8 cap.open("E://2.avi"); 9 Size size0=Size(cap.get(CV_CAP_PROP_FRAME_WIDTH),cap.get(CV_CAP_PROP_FRAME_HEIGHT)); 10 VideoWriter writer("E://out.avi",-1,cap.get(CV_CAP_PROP_FPS),size0,false); 11 12 if(!cap.isOpened()) 13 return; 14 15 Mat frame; 16 while(1) 17 { 18 cap>>frame; 19 Canny(frame,frame,30,100); 20 if(frame.empty()) 21 break; 22 writer<<frame;//等同于writer.write(frame); 23 imshow("video", frame); 24 if(waitKey(10)>0) 25 break; 26 } 27 cout<<"write end!"; 28 cap.release(); 29 destroyAllWindows(); 30 }