主要包括以下内容:
1.使用的主要函数的说明。
2.两个实例:视频读取和显示。搭建视频读取和处理框架,调用canny函数提取边缘并显示。
3.一些注意事项和代码说明。
一.使用的主要函数
1.延时函数cv::waitKey
函数原型:
intwaitKey(int delay=0)
参数说明:
1). delay<=0代表相对无限等待一个按键;delay>0的时候,函数延时delay毫秒(milliseconds)。但延时是相对的最小延时, 延时不会超过操作系统的a minimumtime between switching threads。在延时的时候,如有按键读入,那么返回按键的ASCII编 码;否则返回-1;
2).至少应该有一个窗口正在使用(Active)。如果有多个,那么延时的对象是所有有效的窗口。
使用范例:
1).if(waitKey(200)>=0) return true;//如果在200毫秒内有按键时间,则返回
2).if (char(waitKey(200))=='q') return true;//如果在200毫秒内按下了‘q’键,则返回
2.返回视频文件的性质函数VideoCapture::get()
视频文件的性质包括比如帧率,下一帧的序列号等等
函数原型:C++: doubleVideoCapture::get(int propId)
参数说明:
参数为实际为枚举类型,如下图
使用范例
VideoCapture capture(“traffic.avi”);
Long count=capture.get(CV_CAP_PROP_FRAME_COUNT)//返回视频文件的帧总数。
3.判断视频文件是否打开成功函数VideoCapture::Isopen()
二.使用实例
1.实例1:基本视频文件的读取和显示
// VideoCapture.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include"iostream"
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
VideoCapture capture("traffic.avi");
if(!capture.isOpened())
return true;
double rate=capture.get(CV_CAP_PROP_FPS);
int delay=1000/rate;
bool stop=false;
Mat cframe;
namedWindow("视频获取框",2);
while(!stop)
{
if(!capture.read(cframe))
break;
imshow("视频获取框",cframe);
if(waitKey(delay)>=0)
stop=true;
}
capture.release();
return 0;
}
2.实例2:搭建视频文件读取处理显示框架,调用canny算子提取边缘
//VideoProc.h
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include "cv.h"
using namespace std;
using namespace cv;
class VideoProc{
VideoCapture capture;//视频文件指针
string InputWindow,OutputWindow;//输入输出窗口名
void(*process)(Mat&,Mat&);//回调处理函数指针,指向返回类型为void参数为(Mat&,Mat&)的函数
long Fnumber;//已经处理的帧数合计
long FrameToStop;//需要停止的帧序号
bool callIt;//是否调用回调处理函数标志位,true->call , false->donnt call
bool stop_flag;//是否停止处理标准位,true->stop , false->donnt stop
int delay;//延时参数
public:
VideoProc():process(NULL),Fnumber(0),FrameToStop(-1),callIt(true),stop_flag(false),delay(0){}
/*******************参数设置/初始化函数************************/
bool InputVideo(const string);//读取视频
void setProcess(void (*)(Mat&,Mat&));//设置回调函数
void Window_ShowInput(const string);//创建原始视频显示窗口
void Window_ShowOutput(const string);//创建处理过的视频显示窗口
void dontDisplay(void);//不再显示处理后的帧
long getNextFrame();//返回下一帧的序号
/********************处理过程控制函数**************************/
void run(void);
double getFrameRate(){return capture.get(CV_CAP_PROP_FPS);}//返回每秒显示的帧数
void setStopFlag(bool flag){stop_flag=flag;}//停止整个过程运行标志位设置
void setDelay(int d){delay=d;}//设置延迟参数
void setcallProcesss(bool flag){callIt=flag;}//是否调用回调函数,不调用回调函数输出未经处理的视频文件
void stopAtFrameNumber(long frame){FrameToStop=frame;}//停止在特定帧设置
bool readNextFrame(Mat& frame){return capture.read(frame);}//读取下一帧
};
bool VideoProc::InputVideo(const string filename)//打开视频文件
{
Fnumber=0;
capture.release();
return capture.open(filename);
}
void VideoProc::setProcess(void(*freamProccessingCallback)(Mat&,Mat&))//传递回调函数地址
{
process=freamProccessingCallback;
}
void VideoProc::Window_ShowInput(const string filename)//创建原始视频显示窗口
{
InputWindow=filename;
namedWindow(InputWindow,2);
}
void VideoProc::Window_ShowOutput(const string filename)//创建处理过的视频显示窗口
{
OutputWindow=filename;
namedWindow(OutputWindow,2);
}
void VideoProc::dontDisplay()
{
destroyWindow(InputWindow);
destroyWindow(OutputWindow);
InputWindow.clear();
OutputWindow.clear();
}
long VideoProc::getNextFrame()//返回下一帧的序号
{
long fsquence=static_cast
(capture.get(CV_CAP_PROP_POS_FRAMES));
return fsquence;
}
void VideoProc::run(void)
{
Mat CurrentFrame,OutputFrame;//分别为当前帧和输出帧
if(!capture.isOpened()) return;
long FrameCount=static_cast
(capture.get(CV_CAP_PROP_FRAME_COUNT))-1;//视频文件帧总数
while(!stop_flag)
{
if(!readNextFrame(CurrentFrame))//读取下一帧不成功
break;
if(InputWindow.length()!=0)//字符串的长度不为0代表已经有窗口创建
imshow(InputWindow,CurrentFrame);
if(callIt)
{process(CurrentFrame,OutputFrame);
Fnumber++;}
else
OutputFrame=CurrentFrame;
if(OutputWindow.length()!=0)
imshow(OutputWindow,OutputFrame);
if((delay>=0&&waitKey(delay)>=0))
setStopFlag(true);//有任意按键按下则停止整个处理过程
if(FrameToStop>=0&&FrameToStop<=FrameCount&&getNextFrame()==FrameToStop)//到达设定需要暂停的帧,始终等待按键按下
waitKey(0);
}
}
//VideoProc.cpp
#include "stdafx.h"
#include"iostream"
#include"VideoProc.h"
void canny(Mat& in,Mat& out)
{
if(in.channels()==3) cvtColor(in,out,CV_BGR2GRAY);//转变为灰度图像,即3通道转变为1通道
Canny(out,out,100,200);//计算Canny边缘
threshold(out,out,128,255,THRESH_BINARY_INV);//反转图像
}
int _tmain(int argc, _TCHAR* argv[])
{
VideoProc sv;//定义对象
sv.InputVideo("traffic.avi");//视频读取
sv.Window_ShowInput("inputWindow");//创建原始视频显示窗口
sv.Window_ShowOutput("outputWindow");//创建处理过的视频显示窗口
sv.setDelay(1000./sv.getFrameRate());//设置延迟参数,设置为"0"表示每帧均需要用户按键,
//1000./sv.getFrameRate()表示此时的播放速率和原始视频的频率相同
sv.setProcess(canny);//帧处理函数调用接口
sv.stopAtFrameNumber(25);//在25帧处暂停
sv.setcallProcesss(false);//不调用处理函数
sv.run();//视频处理过程控制函数
return 0;
}
三.注意事项和代码说明
1.看实例:2的代码,在头文件VideoProc.h中定义了视频处理类VideoProc。请注意成员函数指针*process的定义void(*process)(Mat&,Mat&)。这里定义回调处理函数指针,其类型为指向返回类型为void参数为(Mat&,Mat&)的函数,成员函数void setProcess(void (*)(Mat&,Mat&))对这个指针具体化,但是请注意:在函数声明时形参也被设置同类型的函数指针。
在主函数中,使用了sv.setProcess(canny)使回调函数指针指向canny,而在canny函数中,对单张灰度图像(彩色图像先灰度化)使用Canny算子提取了边缘并返回二值化后的图像。也就是说,视频处理的实质是单张图片的处理;而视频处理的多态性体现在函数指针指向不同的处理函数。
2.实例二实现的目标如下:设置某个帧index即帧序列号(本文中为25),处理过程将在这里暂停,但是按任意键后,处理过程将继续。在整个处理过程中,按下任意键,处理过程将结束。
3.这里的按键事件,并不是意味在命令行窗口或者DOS窗口输出某个字符,而是当光标停留在所创建的窗口上的时候的按键事件。
4.成员函数setcallProcesss(false);设置是否调用处理函数标志位。若设为false->callIt=0,意味输入输出文件一样,即视频文件没有经过处理。设为true->callIt=1,则输出文件经过了处理。
5.注意延时参数设置,假设源视频文件的帧率为FPS,设置延时参数1000/FPS,则经过处理后的视频以相同的帧率播放,注意延时参数为毫秒级,故分子为1000。