当观察场景的是一个固定的相机,背景几乎保持不变。在这种情况下,感兴趣的元素是在场景中运动的物体。为了提取出这些前景物体,我们需要对背景建模,然后将当前帧的模型与背景模型进行比较,以检测前景物体。这正是我们将要实现的,前景提取是智能监控应用的基础步骤。
实现方法:
如果我们能够获取当前场景背景的图像,那么通过简单的图像差分便可以提取出前景:
//计算当前图像与背景的差异
cv::absdiff(backgroundImage,currentImage,foreground);
差异足够大的像素都将被视为前景像素。
背景通常会随着时间变化,例如,从日出到日落之间光照条件会发生变化,同时新的物体可能会进入或离开背景。
因此我们必须能够动态创建背景的模型,这可以通过长时间观察场景来实现。
定期更新背景模型:通过计算滑动平均值,即对时序信号计算均值时考虑接收到的最新值。如果p(t)是t时刻的像素值,u(t-1)是当前的平均值,那么新的平均值将是 u(t)=(1-a)[u(t-1)]+ap(t) 参数a被称为学习率,它定义了当前值对平均值的影响程度。该值越大,滑动平均值对观察值的适应速度更快。
部分代码参考来源
// FeatureTracker.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <string>
#include <iomanip>
using namespace cv;
using namespace std;
//帧处理基类
class FrameProcessor
{
public:
virtual void process(Mat &input,Mat &ouput)=0;
};
class BGFGSegmentor:public FrameProcessor
{
Mat gray;//当前帧灰度图
Mat background;//背景图,格式为32位浮点
Mat backImage;//CV_8U格式背景图
Mat foreground;//前景图
double learningRate;//学习率
int Thres;//阈值,滤去扰动
public:
BGFGSegmentor():Thres(25),learningRate(0.2){}
//帧处理函数
void process(Mat &frame,Mat &output)
{
//转化为灰度图
cvtColor (frame,gray,CV_BGR2GRAY);
if(background.empty ())
//第一帧
gray.convertTo(background,CV_32F);
//背景转为CV_8U格式以便求取和当前帧差的绝对值
background.convertTo(backImage,CV_8U);
//求当前帧与背景的差别
absdiff (backImage,gray,foreground);
//过滤掉前景中与背景差别不大的扰动点
threshold(foreground,output,Thres,255,THRESH_BINARY_INV);
//更新背景,output作为掩码
accumulateWeighted (gray,background,learningRate,output);
}
};
class VideoProcessor
{
private:
VideoCapture caputure;
//写视频流对象
VideoWriter writer;
//输出文件名
strin