这篇博客主要参考了《opencv2计算机视觉编程手册》中的chap10中的10.6提取视频中的前景物体的定期更新背景模型。该书在实现这个模型时,编写了一个关于处理视频的类,进行了封装。而下面是我根据书的源代码稍作改写,方便以后写实验性质的代码进行参考:
#include
#include
#include
#include
using namespace std;
using namespace cv;
void process(Mat& frame,Mat &background,Mat &backImage,Mat &foreground,Mat &output,int threshold,double learningRate) {
//当前灰度图像
Mat gray;
//将读取的帧图像转化为灰度图像
cvtColor(frame, gray, CV_BGR2GRAY);
if (background.empty())
//第一帧
gray.convertTo(background, CV_32F);
//背景转为CV_8U格式以便求取和当前帧差的绝对值
background.convertTo(backImage, CV_8U);
//求当前帧与背景的差别
absdiff(backImage, gray, foreground);
//过滤掉前景中与背景差别不大的扰动点
cv::threshold(foreground, output, threshold, 255, THRESH_BINARY_INV);
//更新背景,output作为掩码
accumulateWeighted(gray, background, learningRate, output);
}
int main() {
//视频路径
string FilePath = "E:/study/book/opencv/opencv-2-cookbook-src-master/images/bike.avi";
//读取视频
VideoCapture capture(FilePath);
if (!capture.isOpened()) {
cout << "Can't open the video!" << endl;
return 1;
}
//读取帧率
double rate = capture.get(CV_CAP_PROP_FPS);
bool stop(false);
namedWindow("Extracted Frame");
Mat frame;
int delay = 1000 / rate;
Mat gray; //当前灰度图像
Mat background;//累积的背景图像
Mat backImage; //背景图像
Mat foreground;//前景图像
Mat output;
double learningRate = 0.01;
int threshold = 10;
while (!stop) {
if (!capture.read(frame))
break;
//处理的程序应该放在这里...
process(frame, background, backImage, foreground, output, threshold, learningRate);
imshow("Extracted Frame", output);
if (waitKey(delay) > 0)
stop = true;
}
capture.release();
waitKey();
return 0;
}
整理这个代码主要想要学习以下几点:
1.学习这个框架,以后对视频进行处理时,只需要在“//处理的程序应该放在这里...”下面填写对每帧图像进行处理的程序即可
2.if (!capture.read(frame))
break;
很巧妙,这个语句将帧传入到frame中,且也用做控制循环是否退出
主要是实现上面图片的那个公式
accumulateWeighted实现了滑动平均值的计算,其具体功能如下:
该函数是浮点型运算,要转化类型
accumulateWeighted(gray, background, learningRate, output);也就是:
background=(1-alpha)*background+alpha*gray
gray是由frame转化来到(当前帧图像)cvtColor(frame, gray, CV_BGR2GRAY);
background是累积的背景图像,刚开始认为是第一帧frame,然后利用
accumulateWeighted(gray, background, learningRate, output);
来计算累积值。
但程序中还有几行代码:
background.convertTo(backImage, CV_8U);
absdiff(backImage, gray, foreground);
cv::threshold(foreground, output, threshold, 255, THRESH_BINARY_INV);
即foreground是前景,通过原frame减去背景得到,而cv::threshold的用法请参照:
http://blog.csdn.net/iracer/article/details/49232703
这里实现的功能如下:
output=0 if foreground>threshold;
=255, otherwise
其实实现的是过滤掉与背景差距不大的扰动点。