我们的目标是对于每个视频帧都应用一些处理函数,我们将自己的类中封装OpenCV的视频获取框架,它将允许我们指定每帧调用的处理函数。
下面的例子中的回调处理函数为Canny边缘提取。
// ProcessFrame.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <opencv/highgui.h>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
//定义视频处理类
class VideoProcessor
{
private:
VideoCapture capture;//OpenCV视频捕获对象
void(*canny)(Mat &,Mat &);//每帧调用的回调函数
bool callIt;//确定是否调用回调函数的bool变量
string windowNameInput;//输入窗口的名称
string windowNameOutput;//输出窗口的名称
int delay;//延迟
long fnumber;//已处理的帧数
long frameToStop;//在该帧数停止
bool stop;//是否停止处理
double rate;
public:
VideoProcessor():callIt(true),delay(0),fnumber(0),stop(false),frameToStop(-1){}
bool setInput(string filename);
void displayInput(string wn);
void displayOutput(string wn);
void dontDisplay();
void setFrameProcessor(void (*canny)(Mat &,Mat &));
void run();
void stopIt();
bool isStopped();
bool isOpened();
void setDelay(int d);
bool readNextFrame(Mat &frame);
long getFrameNumber();
double getFrameRate();
};
//设置视频文件的名称
bool VideoProcessor::setInput(string filename)
{
fnumber=0;
capture.release();//释放之前打开过的资源
//images.clear();
return capture.open(filename);//打开视频文件
}
//创建输入窗口
void VideoProcessor::displayInput(string wn)
{
windowNameInput=wn;
namedWindow(windowNameInput);
}
//创建输出窗口
void VideoProcessor::displayOutput(string wn)
{
windowNameOutput=wn;
namedWindow(windowNameOutput);
}
//不再显示处理后的帧
void VideoProcessor::dontDisplay()
{
destroyWindow(windowNameInput);
destroyWindow(windowNameOutput);
windowNameInput.clear();
windowNameOutput.clear();
}
//设置回调函数,即canny
void VideoProcessor::setFrameProcessor(void (*frameProcessingCallback)(Mat &,Mat &))
{
canny=frameProcessingCallback;
}
//停止运行
void VideoProcessor::stopIt()
{
stop=true;
}
//是否已停止?
bool VideoProcessor::isStopped()
{
return stop;
}
//是否开始了捕获设备?
bool VideoProcessor::isOpened()
{
return capture.isOpened();
}
//设置帧间的延迟
//0意味着在每帧都等待用户按键
//负数意味着没有延迟
void VideoProcessor::setDelay(int d)
{
delay=d;
}
//得到下一帧
//可能是:视频文件或摄像头
bool VideoProcessor::readNextFrame(Mat &frame)
{
return capture.read(frame);
}
//返回下一帧的帧数
long VideoProcessor::getFrameNumber()
{
long fnumber=static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES));//得到捕获设备的信息
return fnumber;
}
//获取帧率
double VideoProcessor::getFrameRate()
{
double rate=static_cast<double>(capture.get(CV_CAP_PROP_FPS));
return rate;
}
//获取并处理序列帧
void VideoProcessor::run()
{
Mat frame;//当前帧
Mat output;//输出帧
if(!isOpened())//打开失败时
return;
stop=false;
while(!isStopped())
{
if(!readNextFrame(frame))//读取下一帧
break;
if(windowNameInput.length()!=0)//显示输出帧
imshow(windowNameInput,frame);
if(callIt)//调用处理函数
{
canny(frame,output);//处理当前帧
fnumber++;//增加帧数
}
else
{
output=frame;
}
if(windowNameOutput.length()!=0)//显示输出帧
imshow(windowNameOutput,output);
if(delay>=0&&waitKey(delay)>=0)//引入延迟
stopIt();
if(frameToStop>=0&&getFrameNumber()==frameToStop)//检查是否需要停止运行
stopIt();
}
}
void canny(Mat &img,Mat &out)
{
if(img.channels()==3)//灰度转换
{
cvtColor(img,out,CV_BGR2GRAY);
}
Canny(out,out,100,200);//计算canny边缘
threshold(out,out,128,255,THRESH_BINARY_INV);//反转图像
}
int _tmain(int argc, _TCHAR* argv[])
{
VideoProcessor processor;
processor.setInput("walk.avi");//打开视频文件
processor.displayInput("Current Frame");//声明显示窗口
processor.displayOutput("Output Frame");
processor.setDelay(1000./processor.getFrameRate());//以原始帧率播放视频
processor.setFrameProcessor(canny);//设置处理回调函数canny
processor.run();//开始处理过程
return 0;
}