运动侦测算法概论及汇总

运动目标检测是指在序列图像中检测出变化区域并将运动目标从背景图像中提取出来。通常情况下,目标分类、跟踪和行为理解等后处理过程仅仅考虑图像中对应于运动目标的像素区域,因此运动目标的正确检测与分割对于后期处理非常重要然而,由于场景的动态变化,如天气、光照、阴影及杂乱背景干扰等的影响,使得运动目标的检测与分割变得相当困难。根据摄像头是否保持静止,运动检测分为静态背景和运运动目标检测是指在序列图像中检测出变化区域并将运动目标从背景图像中提取出来。通常情况下,目标分类、跟踪和行为理解等后处理过程仅仅考虑图像中对应于运动目标的像素区域,因此运动目标的正确检测与分割对于后期处理非常重要然而,由于场景的动态变化,如天气、光照、阴影及杂乱背景干扰等的影响,使得运动目标的检测与分割变得相当困难。根据摄像头是否保持静止,运动检测分为静态背景和运动背景两类。大多数视频监控系统是摄像头固定的,因此静态背景下运动目标检测算法受到广泛关注,常用的方法有帧差法、光流法、背景减除法、 ViBe算法、ViBe+算法等。本文将对算法做概论介绍和优缺点比较。

一. 帧间差分法

1. 算法原理

帧间差分法是将视频流中相邻两帧或相隔几帧图像的两幅图像像素值相减,并对相减后的图像进行阈值化来提取图像中的运动区域。 若相减两帧图像的帧数分别为第k帧, 第(k+1)帧,其帧图像分别为fk(x,y),fk+1(x,y),差分图像二值化阈值为T,差分图像用D(x, y)表示,则帧间差分法的公式如下: 

D(x,y)={1,|fk+1(x,y)−fk(x,y)|>T0,others

帧间差分法的优缺点如下:

  • 优点:算法简单,不易受环境光线影响
  • 缺点: 
    • 不能用于运动的摄像头中;
    • 无法识别静止或运动速度很慢的目标;
    • 运动目标表面有大面积灰度值相似区域的情况下,在做差分时图像会出现孔洞;

2. 算法源码

笔者已经将把源码上传到GitHub网站上,地址如下: 
https://github.com/upcAutoLang/BackgroundSplit-OpenCV/tree/master/src/FramesDifference

二帧差值(相邻帧间差分法直接对相邻的两帧图像做差分运算,并取差分运算的绝对值构成移动物体,优点是运算快速,实时性高,缺点是无法应对光照的突变,物体间一般具有空洞)

opencv、c++实现:

#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
 
using namespace cv;
 
int main(int argc,char *argv[])
{
	VideoCapture videoCap(argv[1]);
	if(!videoCap.isOpened())
	{
		return -1;
	}
	double videoFPS=videoCap.get(CV_CAP_PROP_FPS);  //获取帧率
	double videoPause=1000/videoFPS;
 
	Mat framePre; //上一帧
	Mat frameNow; //当前帧
	Mat frameDet; //运动物体
	videoCap>>framePre;
	cvtColor(framePre,framePre,CV_RGB2GRAY);	
	while(true)
	{
		videoCap>>frameNow;
		if(frameNow.empty()||waitKey(2500)==27)
		{
			break;
		}
		cvtColor(frameNow,frameNow,CV_RGB2GRAY);
		absdiff(frameNow,framePre,frameDet);
		framePre=frameNow;		
		imshow("Video",frameNow);
		imshow("Detection",frameDet);		
	}
	return 0;
}

调用了Opencv自带的视频文件“768x576.avi”,视频文件位置:“opencv\sources\samples\gpu”,下图是视频第100帧时图像:

右图是相邻两帧差法检测到的物体,检测效果没有经过膨胀或腐蚀等处理。可以看到物体的轮廓是“双边”的,并且物体的移动速度越快,双边轮廓现象越粗越明显(这是不是给监控中速度检测提供了一个思路~~),另一个就是物体具有较大的空洞。

 

三帧差法是在相邻帧差法基础上改进的算法,在一定程度上优化了运动物体双边,粗轮廓的现象,相比之下,三帧差法比相邻帧差法更适用于物体移动速度较快的情况,比如道路上车辆的智能监控。

三帧差法基本实现步骤:1. 前两帧图像做灰度差;2. 当前帧图像与前一帧图像做灰度差;3. 1和2的结果图像按位做“与”操作。

opencv、C++实现:

#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
 
using namespace cv;
 
int main(int argc,char *argv[])
{
	VideoCapture videoCap(argv[1]);
	if(!videoCap.isOpened())
	{
		return -1;
	}
	double videoFPS=videoCap.get(CV_CAP_PROP_FPS);  //获取帧率
	double videoPause=1000/videoFPS;
	Mat framePrePre; //上上一帧
	Mat framePre; //上一帧
	Mat frameNow; //当前帧
	Mat frameDet; //运动物体
	videoCap>>framePrePre;
	videoCap>>framePre;
	cvtColor(framePrePre,framePrePre,CV_RGB2GRAY);	
	cvtColor(framePre,framePre,CV_RGB2GRAY);	
	int save=0;
	while(true)
	{
		videoCap>>frameNow;
		if(frameNow.empty()||waitKey(videoPause)==27)
		{
			break;
		}
		cvtColor(frameNow,frameNow,CV_RGB2GRAY);	
		Mat Det1;
		Mat Det2;
		absdiff(framePrePre,framePre,Det1);  //帧差1
		absdiff(framePre,frameNow,Det2);     //帧差2
		threshold(Det1,Det1,0,255,CV_THRESH_OTSU);  //自适应阈值化
		threshold(Det2,Det2,0,255,CV_THRESH_OTSU);
		Mat element=getStructuringElement(0,Size(3,3));  //膨胀核
		dilate(Det1,Det1,element);    //膨胀
		dilate(Det2,Det2,element);
		bitwise_and(Det1,Det2,frameDet);		
		framePrePre=framePre;		
		framePre=frameNow;		
		imshow("Video",frameNow);
		imshow("Detection",frameDet);
	}
	return 0;
}

同样是“768x576.avi”视频文件,并且也保存了第100帧的原始图像和运动物体检测图像:

原始帧图像;未经形态学处理的原始的三帧差法检测到的运动物体,未经任何形态学处理的原始的三帧差法检测到的物体的双边轮廓现象有所改善,但同时也有丢失轮廓的现象;最后两个帧差图像按位与操作之前做了一下膨胀处理的效果。

相比相邻两帧差法,原始的三帧差法对物体的双边粗轮廓和“鬼影”现象有所改善,比较适合对运动速度较快物体的检测,但是仍然会有空洞出现,并且物体移动速度较慢时容易丢失轮廓。当然三帧差法做了两次的差分运算,给了三帧差法更多可操作和优化的空间,为更优秀的检测效果提供了可能。

二. 背景差分法

参考网址: 
《背景差分法》 
《帧间差分法和背景建模法》

1. 算法原理

背景差分法是一种对静止场景进行运动分割的通用方法,它将当前获取的图像帧与背景图像做差分运算,得到目标运动区域的灰度图,对灰度图进行阈值化提取运动区域,而且为避免环境光照变化影响,背景图像根据当前获取图像帧进行更新。 
根据前景检测,背景维持和后处理方法,存在几种不同的背景差方法。若设It,BtIt,Bt分别为当前帧与背景帧图像,T为前景灰度阈值,则其中一种方法流程如下:

  • 取前几帧图像的平均值,将其作为初始的背景图像BtBt;
  • 当前帧图像与背景图像作灰度减运算,并取绝对值;公式即为|It(x,y)−Bt(x,y)|;
  • 对当前帧的像素(x,y),若有|It(x,y)−Bt(x,y)|>T,则该像素点为前景点;
  • (可选)对前景像素图进行形态学操作(腐蚀、膨胀、开闭操作等)
  • 用当前帧图像对背景图像进行更新;

背景差分法的优缺点如下:

  • 优点: 
    • 算法比较简单;
    • 一定程度上克服了环境光线的影响;
  • 缺点: 
    • 不能用于运动的摄像头;
    • 对背景图像实时更新困难;

高斯背景模型 在运动检测中的应用

     原理 : 高斯模型就是用高斯概率密度函数(正态分布曲线)精确地量化事物,将一个事物分解为若干的基于高斯概率密度函数(正态分布曲线)形成的模型。

    对图像背景建立高斯模型的原理及过程:图像灰度直方图反映的是图像中某个灰度值出现的频次,也可以认为是图像灰度概率密度的估计。如果图像所包含的目标区域和背景区域相比,区域面积较大且区域在灰度上有一定的差异,那么该图像的灰度直方图呈现双峰-谷形状,其中一个峰对应于目标的重心灰度,另一个峰对应于背景的中心灰度。对于复杂的图像,尤其是医学图像,一般是多峰的。通过将直方图的多峰特性看作是多个高斯分布的叠加,可以解决图像的分割问题。

    在智能监控系统中,对于运动目标的检测是中心内容,而在运动目标检测提取中,背景目标对于目标的识别和跟踪至关重要。而建模正是背景目标提取的一个重要环节。

    我们首先要提起背景和前景的概念,前景是指在假设背景为静止的情况下,任何有意义的运动物体即为前景。建模的基本思想是从当前帧中提取前景,其目的是使背景更接近当前视频帧的背景。即利用当前帧和视频序列中的当前背景帧进行加权平均来更新背景,但是由于光照突变以及其他外界环境的影响,一般的建模后的背景并非十分干净清晰,而高斯混合模型是是建模最为成功的方法之一。

     混合高斯模型使用K(基本为3到5个)个高斯模型来表征图像中各个像素点的特征,在新一帧图像获得后更新混合高斯模型, 用当前图像中的每个像素点与混合高斯模型匹配,如果成功则判定该点为背景点, 否则为前景点。 通观整个高斯模型,主要是有方差和均值两个参数决定,对均值和方差的学习,采取不同的学习机制,将直接影响到模型的稳定性、精确性和收敛性 。由于我们是对运动目标的背景提取建模,因此需要对高斯模型中方差和均值两个参数实时更新。为提高模型的学习能力,改进方法对均值和方差的更新采用不同的学习率;为提高在繁忙的场景下,大而慢的运动目标的检测效果,引入权值均值的概念,建立背景图像并实时更新,然后结合权值、权值均值和背景图像对像素点进行前景和背景的分类。

       到这里为止,混合高斯模型的建模基本完成,我在归纳一下其中的流程,首先初始化预先定义的几个高斯模型,对高斯模型中的参数进行初始化,并求出之后将要用到的参数。其次,对于每一帧中的每一个像素进行处理,看其是否匹配某个模型,若匹配,则将其归入该模型中,并对该模型根据新的像素值进行更新,若不匹配,则以该像素建立一个高斯模型,初始化参数,代理原有模型中最不可能的模型。最后选择前面几个最有可能的模型作为背景模型,为背景目标提取做铺垫。

    方法: 目前,运动物体检测的问题主要分为两类,摄像机固定和摄像机运动。对于摄像机运动的运动物体检测问题,比较著名的解决方案是光流法,通过求解偏微分方程求的图像序列的光流场,从而预测摄像机的运动状态。对于摄像机固定的情形,当然也可以用光流法,但是由于光流法的复杂性,往往难以实时的计算,所以我采用高斯背景模型。因为,在摄像机固定的情况下,背景的变化是缓慢的,而且大都是光照,风等等的影响,通过对背景建模,对一幅给定图像分离前景和背景,一般来说,前景就是运动物体,从而达到运动物体检测的目的。

  单分布高斯背景模型

  单分布高斯背景模型认为,对一个背景图像,特定像素亮度的分布满足高斯分布,即对背景图像B, (x,y)点的亮度满足:

  IB (x,y) ~ N(u,d)

  这样我们的背景模型的每个象素属性包括两个参数:平均值u 和 方差d。

  对于一幅给定的图像G,如果 Exp(-(IG (x,y)-u(x,y))^2/(2*d^2)) > T,认为(x,y)是背景点,反之是前景点。

  同时,随着时间的变化,背景图像也会发生缓慢的变化,这时我们要不断更新每个象素点的参数

  u(t+1,x,y) = a*u(t,x,y) + (1-a)*I(x,y)

  这里,a称为更新参数,表示背景变化的速度,一般情况下,我们不更新d(实验中发现更不更新 d,效果变化不大)。

opencv

int main( int argc, char** argv )
{ 
 
 
	VideoCapture cam("bike.avi");// 0打开默认的摄像头
	if(!cam.isOpened())
		return -1;
	namedWindow("mask",CV_WINDOW_AUTOSIZE);
	namedWindow("frame",CV_WINDOW_AUTOSIZE);
	Mat frame,mask,threImage,output;
	int delay = 1000/cam.get(CV_CAP_PROP_FPS);
	BackgroundSubtractorMOG bgSubtractor(10,10,0.5,false);
	//构造混合高斯模型 参数1:使用历史帧的数量 2:混合高斯个数,3:背景比例 4::噪声权重
	while (true)
	{
		cam>>frame;
		imshow("frame",frame);
		bgSubtractor(frame,mask,0.001);
		imshow("mask",mask);
		waitKey(delay);
	}
		return 0;
}

 

累积权重构建背景模型

运动物体检测与跟踪中的帧差分法,除了相邻帧差分法和三帧差分法外,还有一种差分方法,可以通过建立不含前景的背景模型,用当前帧和背景模型做差,差值就可以体现运动物体大概的位置和大小信息。相比相邻帧差分法和三帧差分法,背景模型做差法可以较为完整的体现运动物体的整体轮廓,运动物体的双重轮廓、“鬼影”、空洞现象改善明显,下文的对比效果可以看到这一点。

但背景模型的选取和建立的要求条件也更为苛刻:

1.  背景模型中不能包含前景物体,如果包含前景物体,则在之后检测到的运动物体结果中,会一直保留有前景运动物体初始的轮廓。

例如下边这个例子,选取了第一帧作为背景模型,不幸的是,第一帧中含有运动物体,用红色框标示出:

正如前边所说的,在之后检测到的运动物体结果中,3个前景运动物体初始的轮廓一直存在,即使运动物体早已经不在初始的位置,用红色框标示出。

若使用完全不包含前景物体的背景图像作为背景模型,上述情况就不会出现了,检测效果也比较好。比如使用下边这个图像作为背景模型:

由于这个视频没有完全不包含前景物体的背景图像,我的方法是求所有视频帧序列和的平均值作为背景模型,在一定程度上可以代表不含前景的背景图,部分位置处移动物体停留的事件比较久,所以有一些黑影出现,如图像中部区域。检测效果中不再有之前的3个“伪影像”,并且可以看到,相比相邻帧差分法和三帧差分法,背景模型做差法可以较为完整的体现运动物体的整体轮廓,运动物体的双重轮廓、“鬼影”、空洞现象改善明显。

2.  背景模型对环境的变化非常敏感,比如光照的变化、背景模型建立之后监控中加入的静止的物体、或背景模型中原本的物体位置被挪动等等,这些因素都会造成静止的物体被当做运动物体检测出来。造成误检,

还以上一个视频为例,当背景模型中原本静止的物体位置被挪动:

建立背景模型时视频中彩带的位置在下图用蓝色线段标示出,之后由于一些原因彩带的位置发生了改变,用红色线段标示,位置改变后,即使彩带一直保持静止,在检测结果中仍然会错误的检测出静止的彩带。

现实情况中,想要消除以上两点影响,一次性建立一个理想的背景模型,几乎是不可能的。基于此,我们可以建立一个动态的背景模型,这个动态模型实现以下两个功能:

1.  如果初始建立的背景模型中包含有前景物体,动态模型应该能够快速将前景物体的影响降低或消除掉;

2.  对于背景模型中静止的物体位置改变或者新加入视频画面中静止的物体,动态模型应该能够快速觉察到这种变化,      并把这种改变纳入到下一轮的背景模型构建中。

基于这两个基本的要求,构建动态背景模型的步骤如下:

1.  以初始第一帧作为第一个背景模型

2.  检测第二帧中运动物体,得到前景图像

3.  把第二帧图像抠除检测到的前景物体后,以一定比例系数累加到上一轮构建的背景模型中

4.  更新背景模型,在随后帧上,重复1,2,3

 

Opencv中,accumulateWeighted方法可以实现以上构建动态模型的要求。

方法原型:

void accumulateWeighted( InputArray src, InputOutputArray dst,
                                      double alpha, InputArray mask=noArray() );

第一个参数:src,新加入的构建背景模型的图像矩阵;

第二个参数:dst,累计新元素src后生成的新的背景模型;

第三个参数:alpha,新加入原型src的系数,公式表述为:

                      dst = dst*(1-alpha) + src*alpha;

即alpha越大,当前新元素对构建动态模型的影响越大如下,当alpha取值为0.9时,背景模型为,此时新加入背景模型的新元素占比较大,对新的背景模型的影响也大,从上图可以看到,除有少许拖影外 ,基本跟上一帧图像特征一致;当alpha取值为0.2时,背景模型为,此时,新加入背景模型的元素占比较小,意味着之前加入的元素比重相应较大,累计的背景模型有很                       重的“鬼影”,每一个虚影代表了最近新加入背景模型的一个元素。

第四个参数:mask,英文释义“面具”,顾名思义,指在背景模型中需要减去的,不予考虑的部分,可以使用在当前背景模型下检出的前景物体作为mask,进一步减少对背景模型的干扰,可以为空。

累积权重构建背景模型代码实现:

#include "core/core.hpp"  
#include "highgui/highgui.hpp"  
#include "imgproc/imgproc.hpp"  
#include "iostream"
 
using namespace std; 
using namespace cv;  
 
int main(int argc,char *argv[])  
{
	VideoCapture videoCap(argv[1]);
	if(!videoCap.isOpened())
	{
		return -1;
	}
	Mat image;
	Mat imageBackground;  //动态背景模型
	Mat imageFront;   //前景	
	double videoFPS=videoCap.get(CV_CAP_PROP_FPS);  //获取帧率  
	double videoPause=1000/videoFPS;
	videoCap>>imageBackground;  //第一帧作为初始背景模型  
	cvtColor(imageBackground,imageBackground,CV_RGB2GRAY);  
	Mat element=getStructuringElement(0,Size(3,3));  //腐蚀核
	while(true)  
	{  		
		videoCap>>image;  
		if(image.empty()||waitKey(videoPause)==27)  //视频播放完成,或Esc键退出
		{ 
			break;  
		}  
		Mat image1;
		cvtColor(image,image1,CV_RGB2GRAY);		
		absdiff(image1,imageBackground,imageFront);   
		imageBackground.convertTo(imageBackground,CV_32FC1);  //扩展至32位做运算
		accumulateWeighted(image1,imageBackground,0.6,imageFront);
		imageBackground.convertTo(imageBackground,CV_8UC1);  //转换回8位
		threshold(imageFront,imageFront,0,255,CV_THRESH_OTSU);  //阈值分割 	
		morphologyEx(imageFront,imageFront,CV_MOP_OPEN,element); //消除孤立的点
		//膨胀操作,消除孔洞
		dilate(imageFront,imageFront,element);
		dilate(imageFront,imageFront,element);
		dilate(imageFront,imageFront,element);
		dilate(imageFront,imageFront,element);
		dilate(imageFront,imageFront,element);
		vector> contours;  
		vector hierarchy;  
		findContours(imageFront,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());    
		for(int i=0;i

测试效果:

2. 算法源码

笔者已经将把源码上传到GitHub网站上,地址如下: 
https://github.com/upcAutoLang/BackgroundSplit-OpenCV/tree/master/src/GaussBGDifference

三. ViBe背景提取算法

ViBe - a powerful technique for background detection and subtraction in video sequences 
——摘自ViBe算法官网

ViBe是一种像素级视频背景建模或前景检测的算法,效果优于所熟知的几种算法,对硬件内存占用也少。该算法主要不同之处是背景模型的更新策略,随机选择需要替换的像素的样本,随机选择邻域像素进行更新。在无法确定像素变化的模型时,随机的更新策略,在一定程度上可以模拟像素变化的不确定性。

参考地址: 
《ViBe算法原理和代码解析 》 
《背景建模–Vibe 算法优缺点分析》 
《第一次总结报告——Vibe 》 
《运动检测(前景检测)之(一)ViBe 》 
《VIBE改进算法》

参考论文: 
《O. Barnich and M. Van Droogenbroeck. ViBe: a powerful random technique to estimate the background in video sequences.》 
《O. Barnich and M. Van Droogenbroeck. ViBe: A universal background subtraction algorithm for video sequences.》

算法官网: 
http://www.telecom.ulg.ac.be/research/vibe/

1. 一般背景提取算法存在的问题

前文提到的帧间差分法、背景差分法中存在若干问题如下:

  • 对于环境变化的适应并不友好(如光照的变化造成色度的变化);
  • 相机抖动导致画面抖动
  • 物体检测中常出现的Ghost区域;

其中值得一提的是Ghost区域:Ghost区域常常出现于帧间差分法,当一个原本静止的物体开始运动时,帧间差分法检测时,可能会将原本该物体覆盖区域错误的检测为运动的,这块被错误检测到的区域被称为Ghost。同样的,原本正在运动的物体变成静止物体时,也会出现Ghost区域。 
例如下图,原图像中只有三个正在运动的人,但由于帧间差分法取得的背景图中包含这三个运动的人的某一帧运动状态,后面的一系列帧序列与背景图相减,都会存在背景图中三个人所在的位置,这时候取得的前景会多出三个被检测区域,即Ghost区域。 

Ghost区域在检测中,一定要尽快消除。

2. ViBe算法原理

ViBe比较特殊的地方它的思想:它为所有像素点存储了一个样本集,样本集里面保存的采样值是该像素点过去的像素值其邻居点的像素值。后面每一帧的新像素值和样本集里的样本历史值进行比较,判断是否属于背景点。 
下面从几点讲解ViBe算法:

(1) 背景、前景模型

模型中,背景就是静止的,或者移动非常缓慢的物体;前景就是相对于背景的物体,即正在移动的物体。所以背景提取算法也可以看成是一个分类问题,遍历像素点的过程中,来确定一个像素点是属于前景点,还是属于背景点。 
在ViBe模型中,背景模型为每个像素点存储了样本集,样本集大小一般为20个点。对于采入的新一帧图像,该帧的某个像素点与该像素点的样本集内采样值比较接近时,就可以判断其是一个背景点。 
用公式表示,我们可以认为:

  • v(x,y):像素点(x, y)处的当前像素值;
  • M(x,y)={v1(x,y),v2(x,y),...vN(x,y)}:像素点(x, y)的背景样本集(样本集大小为N);
  • R:上下取值范围;

将v(x,y)与M(x,y)中所有样本值作差,所有差值中,在±R范围内的个数为Nb,若Nb大于一个给定的阈值min,就说明当前像素值与该点历史样本中的多个值相似,那么就认为(x,y)点属于背景点。

(2) 背景模型初始化

初始化是建立背景模型的过程,一般的检测算法需要一定长度的视频序列学习完成,影响了检测的实时性,而且当视频画面突然变化时,重新学习背景模型需要较长时间。 
ViBe算法建立背景模型只需要一帧,即使用单帧视频序列初始化背景模型。将视频的第一帧作为背景模型的同时,算法也将该帧中每一个像素点周围随机取多个像素点,填充该像素点的样本集,这样样本集中就包含了像素点的时空分布信息。 
用公式表示,我们可以认为:

  • M0(x,y):初始背景模型中的像素点(x, y);
  • NG:邻居点;
  • v0(x,y):初始原图像中像素点(x, y)的像素值;

于是有: 
M0(x)={v0(y|y∈NG(x))},t=0

这种背景模型初始化的优缺点如下:

  • 优点: 
    • 对于噪声的反应比较灵敏;
    • 计算量小速度快;
    • 不仅减少了背景模型建立的过程,还可以处理背景突然变化的情况,当检测到背景突然变化明显时,只需要舍弃原始的模型,重新利用变化后的首帧图像建立背景模型。
  • 缺点: 
    • 用于作平均的几帧初始图像中可能采用了运动物体的像素,这种条件下初始化样本集,容易引入拖影(Ghost)区域;

初始背景模型建立完毕后,就可以进行前景的检测和背景模型的更新了。

(3) 前景检测

此时已经建立起了背景模型,便可以已经建立好的背景模型进行前景的检测。 
遍历新一帧图像的所有像素点。用公式表示,则有:

  • v(x,y):新一帧的像素点(x, y);
  • M(x,y)={v1(x,y),v2(x,y),...vN(x,y)}:像素点(x, y)的背景样本集(样本集大小为N);
  • D(x,y)={d1(x,y),d2(x,y),...dN(x,y)}:像素点(x, y)当前值与样本集里所有样本值之差(样本集大小为N) 
    • 其中,di=v(x,y)−vi(x,y);
  • R:判断像素点与历史样本值是否相近的阈值;
  • T:判断前景点的阈值; 
    • 统计当前像素点的值与历史样本值之差大于R的个数,若个数大于T,则判断该点为前景点;

检测前景的流程如下:

  • 将某像素点的当前像素值v(x,y),与该像素点的样本集M(x,y)作差值,即得到D(x,y)。
  • 遍历D(x,y)中的元素di(x,y),比较它与阈值R的大小;并计满足di(x,y)>R的个数为Nf;
  • 若有Nf>T,则该点为前景点;

检测过程的主要三个参数是:样本集数目N,阈值R,与阈值T。一般设置N = 20, R = 20, T = 2;

(4) 背景模型更新策略

即使已经建立起了背景模型,也应该对背景模型进行不断的更新,这样才能使得背景模型能够适应背景的不断变化(如光照变化,背景物体变更等)。

A. 普通更新策略

对于其他的背景提取算法,背景模型有两种不同的更新策略:

  • 保守更新策略:前景点永远不会用来填充模型 
    • 这样会引起死锁,产生Ghost区域。比如初始化的时候如果一块静止的区域被错误的检测为运动的,那么在这种策略下它永远会被当做运动的物体来对待;
  • Blind策略:对死锁不敏感,前景和背景都可以用来更新背景模型; 
    • 这样的缺点在于,缓慢移动的物体会融入到背景中,无法检测出来;

B. ViBe算法更新策略

ViBe算法中,使用的更新策略是:保守更新策略 + 前景点计数法 + 随机子采样。

  • 前景点计数法:对像素点进行统计,如果某个像素点连续N次被检测为前景,则将其更新为背景点;
  • 随机子采样:在每一个新的视频帧中都去更新背景模型中的每一个像素点的样本值是没有必要的,当一个像素点被分类为背景点时,它有1/φ的概率去更新背景模型。

这就决定了ViBe算法的更新策略的其他属性:

  • 无记忆更新策略:每次确定需要更新像素点的背景模型时,以新的像素值随机取代该像素点样本集的一个样本值;
  • 时间取样更新策略:并非每处理一帧数据,都需要更新处理,而是按一定的更新率更新背景模型; 
    • 当一个像素点被判定为背景时,它有1/φ的概率更新背景模型;
    • φ是时间采样因子,一般取值为16;
  • 空间邻域更新策略:针对需要更新像素点,在该像素点的邻域中随机选择一个像素点,以新选择的像素点更新被选中的背景模型;

C. ViBe算法具体更新的方法:

  • 每个背景点都有1/φ的概率更新该像素点的模型样本值
  • 有1/φ的概率去更新该像素点邻居点的模型样本值
  • 前景点计数达到临界值时,将其变为背景,并有1/ φ的概率去更新自己的模型样本值。

更新邻居的样本值利用了像素值的空间传播特性,背景模型逐渐向外扩散,这也有利于Ghost区域的更快的识别。 
在选择要替换的样本集中的样本值时,我们是随机选取一个样本值进行更新。这样就可以保证,样本值的平滑的生命周期的原因是由于是随机的更新,这种情况下一个样本值在时刻t不被更新的概率是(N - 1) / N。假设时间是连续的,那么在极小时间dt过去后,样本值仍然保留的概率是: 
P(t,t+dt)=(N−1N)(t+dt)−t
也可以写作: 
P(t,t+dt)=e−ln(NN−1)dt
上面的公式表明,样本值在模型中是否被替换,与时间t无关,即更新策略是合适的。

3. ViBe算法优缺点

(1) 优点

Vibe背景建模为运动目标检测研究领域开拓了新思路,是一种新颖、快速及有效的运动目标检测算法。优点主要有两点:

  • 思想简单,易于实现: 
    • 初始化背景图像时,Vibe算法通常随机选取邻域20个样本,作为每个像素点建立一个基于样本的背景模型,具有初始化速度快、内存消耗少和占用资源少等优点;
    • 随后,利用一个二次抽样因子φ,使有限的样本基数能近似表示无限的时间窗口,即在较少样本前提下,保证算法的准确性;
    • 最后,并采用一种邻域传播机制保证算法的空间一致性。
  • 样本衰减最优: 
    • 有人通过增加样本基数(上至200个)来处理复杂场景,也有人结合两个子模型分别处理快速更新和缓慢更新的情况。其实,选取被替换样本更新背景模型,实质上是样本寿命问题。
    • 传统方式采用先进先出的替换策略,而Vibe背景模型中每个样本被选中为替换样本的概率是相等的,与样本存在时间的长短无关,这种策略保证背景模型中的样本寿命呈指数衰减,模型更新达到最佳状态。
  • 运算效率高: 
    • Vibe背景模型是基于少量样本的背景模型;
    • Vibe算法优化了背景模型中的相似度匹配算法;

关于运算效率的比较,《背景建模–Vibe 算法优缺点分析》中做了实验:为了得到最佳样本数量N值,分别选取N为5、15、20、25进行了实验对比:结果如图所示: 
 
实验结果表明,N取20、25时,检测结果理想;考虑计算负载,N取20最优。与混合高斯的3-5个高斯模型的计算匹配比较,基于20个样本的背景模型计算具有计算开销低、检测速度快等优点。 
Vibe的背景模型相似度匹配函数只与判断像素点与历史样本值是否相近的阈值R,以及判断前景点的阈值T有关(具体见本文三.2.(3))。背景模型中的样本与待分类像素的欧式距离小于R的个数超过T时,更新背景模型;而找到T个匹配样本时,便立即判断该像素为背景像素点,并停止计算,这样提高了运算效率。

(2) 缺点

ViBe算法自身也存在着局限性。主要有静止目标、阴影前景和运动目标不完整等问题。

A. 静止目标

如下图所示: 

图(a)红框中的人在等地铁,从图(a)到图(c)经过498帧,长时间驻留未运动,该人物运动目标逐渐被背景吸收。而在本视频中,将在450帧以上都没有明显位移的运动目标区域定义成为静止目标区域。 
这样可以总结产生静止目标问题的原因有两个:

  • 运动目标从运动到静止;
  • 运动目标运动速度太过缓慢:当ViBe背景模型更新速度过快时,会将静止或缓慢运动目标吸收成为背景的一部分;

B. 阴影前景

如下图所示: 
 
图(b)和图(d)分别是用Vibe算法对人体运动目标(a)和车体运动目标(c)的检测结果。由于光线被人体或车体运动目标所遮挡,投射阴影区的背景被误检为运动目标前景。阴影的存在导致检测出来的运动目标形状不准确,影响后续目标分类、跟踪、识别和分析等其他智能视频处理模块。 
产生阴影前景问题的根源是:光线被运动目标前景遮挡,投射阴影区的颜色比背景的颜色暗,即阴影和背景颜色值的距离相差较大,背景差分后被误检为运动目标前景。

C. 运动目标不完整问题

如下图所示: 

  • 图(a)中的人内部出现空洞;
  • 图(b)中的人中间出现断层;
  • 图(c)中的人上半身出现边缘残躯;
  • 图(d)车体的挡风玻璃出现空洞;

总结图中的结果,可以将运动目标不完整现象大致分为三类:

  • 运动目标内部有大量空洞(图a);
  • 运动目标边缘残缺,呈现C字形凹陷(图d);
  • 运动目标中间有断层(图b);

产生运动目标不完整问题的根源主要有两点:

  • ViBe算法自身存在的缺陷; 
    • 基于统计学原理的Vibe样本模型受限于模型的样本个数,当样本趋于无穷大时才能准确描述场景,这在实际应用中是不可能实现的;
  • 场景或运动目标的复杂性和多变性; 
    • 瞬时的光线突变,背景模型来不及更新;
    • 前景与背景颜色相近,将前景误判为背景;
    • 噪声干扰,出现孤立噪声点和连通噪声区域;

4. ViBe算法源码

笔者已经将把源码上传到GitHub网站上,地址如下: 
https://github.com/upcAutoLang/BackgroundSplit-OpenCV/tree/master/src/ViBe

5. ViBe的改进算法ViBe+

笔者对ViBe+进行了学习研究,博客地址如下: 
《论文翻译:ViBe+算法(ViBe算法的改进版本)》

笔者已经将把源码上传到GitHub网站上,地址如下: 
https://github.com/upcAutoLang/BackgroundSplit-OpenCV/tree/master/src/ViBe%2B

相关参考地址: 
《ViBe算法原理和代码解析 》 
《VIBE改进算法》

参考论文: 
《M. Van Droogenbroeck and O. Paquot. Background Subtraction: Experiments and Improvements for ViBe.》

你可能感兴趣的:(图像处理)