背景减法——Vibe

VIBE是Barnich和Droogenbroeck在2011年发表的《VIBE:A universalbackground
subtraction algorithm for video sequence》中提出。其在模型中大量的使用了随机策略,有着意想不到的准确率和鲁棒性,该方法简单实用,计算代价低,可以应用于嵌入式系统中。

模型表示:

对输入视频帧的每个像素都建立一个背景模型M(x)={},里面包含N个样本值,每个样本值是从之前的帧提取的像素的颜色值。

分类方法:一个像素当前输入的颜色值v(x),该像素对应的背景模型M(x);

在RGB颜色空间中,以v(x)为球心,R为半径画一个球体,统计包含在球体内的M(x)中样本点的个数,如果数目超过给定的阈值的话判定其为背景点。

在编程实现的时候只要计算v(x)和每个样本点在RGB空间的距离,如果距离小于R就表示样本点在v(x)为球心的球体内。

图6.1.8.1   
在2-D空间中比较输入的颜色值和样本点

在实验过程中设定了背景模型的样本数为20,R值为20,球体内样本点数的阈值为2.

模型更新:

与自组织背景模型的核心思想一样,VIBE也认为第一帧极大的近似于真实模型。同时也基于另一个假设:相邻的像素点有着相似的空间分布关系。

其优势就是可以最大程度的减少训练背景模型的时间。而且在遇到全局的光源突变时可以抛弃背景模型中所有的样本点,重新初始化,然后在第二帧就可以继续进行前景检测

具体的实施方法:从相邻的像素点中随机的抽取N个像素点作为其背景模型的样本点

模型更新:

(1)无记忆的更新策略:

作者认为在更新背景时使用先进-先出(即用新的样本值替代模型中最久的样本值)的策略是不合适的,,这样只能维持在很少一段时间内保留下来的样本值,时间相关性很低。过去的背景减法为了处理这种方法往往是将模型中的样本数目扩大,这会只用大量内存,而且计算量也大大提高。

作者使用了无记忆的更新策略,具体方法是从N个样本中随机的选择一个样本,然后用新的样本点进行替换。这样可以极大(理论上是无限)的延长其时间相关性。假设我们输入一个图6.1.8.1的颜色值v(x),用其进行更新背景模型,如下图随机的选择

图6.1.8.2  
无记忆更新图示

(2)随机的时间子采样

作者认为没有必要每当输入一个颜色值并且其判定为背景值时都进行模型更新。但是如果每隔一个固定时间进行更新也会错过一些重要的更新。

再次作者依然采取了一个随机策略,在该像素输入的16个判定为背景的值的过程中,有一次机会进行模型更新。

(3)空间传播策略

作者认为在好的样本点不能独用,通过空间传播的方法可以让邻居像素点共享更新的像素点,这一策略是VIBE中极富革新性的一个策略,可以有效的消除ghost,并且在相机抖动的情况下也能有一定程度的改善。

具体方法:同样的是某个像素在16个被判定为背景的值中,有一次机会从该像素的8个相邻像素中挑选一个像素,用该值对其背景模型进行更新。

个人依照论文思想实现的代码如下

平台:vs2010

函数库:opencv2.3.1

运行成功后具体操作:

1、可以将生成的vibe.exe文件复制到磁盘根目录下,以方便调用,在同一磁盘根目录放置要检测的视频,如都放在F盘根目录下

2、打开命令执行程序CMD,输入“F:”回车,进入f:盘的目录,再输入“vibe.exe  
sequence.avi”回车即可查看效果

实验效果:

#include <stdio.h>
#include <cv.h>
#include
<cxcore.h>
#include
<highgui.h>
#include
<stdlib.h> 
#include <time.h> 
#define
cvConvert( src, dst )  cvConvertScale( (src), (dst), 1, 0 )

int random(int
a,int b)          
        //产生随机数函数 
{
    int
i;  
    i=rand()%b+a ;      
              //产生a--a+b的随机数。
    return
(i)  ;
}

int main( int argc, char**
argv )


    IplImage* pFrame = NULL;  
       
    IplImage* segmap =
NULL; 
    IplImage*
simple[20]={NULL};
    //IplImage* smooth=NULL;
   
CvCapture* pCapture =
NULL;
    int nFrmNum
= 0;
    int T=0;
   
int N=20;double R=20;int min=2;int ts=16;
        //定义vibe基本参数
    int
height,width,step,chanels;
    uchar* data;              
            //定义指针型访问!!!! 
    uchar* simdata[20];
    uchar* sg;
    int change=0;
    int index;          
                 //定义样本索引
   
double beta;        
                    //设定一个光源突变检测阈值
    int
fgcount=0;  
                   
 //定义一帧检测中属于前景的像素点数,用于判断是否光源突变;
   
int i,j,x,y;
   
cvNamedWindow("video", 1);         //创建视频窗口
    cvNamedWindow("segment
map",1);     //创建切割图窗口
    cvMoveWindow("video",
30, 0); 
    cvMoveWindow("segment
map", 690, 0);
    if( argc > 2 )   
    {  
  
        fprintf(stderr, "Usage: bkgrd [video_file_name]\n");  
  
        return -1;
  
    }

    //打开视频文件 
   
if(argc ==
2)   
   
    if( !(pCapture =
cvCaptureFromFile(argv[1])))  
  
        {
  
           
fprintf(stderr, "Can not open video file %s\n",
argv[1]);   
   
        return
-2;  
  
        }
   
    //打开摄像头 
       
if (argc ==
1)   
   
        if(
!(pCapture =
cvCaptureFromCAM(-1)))
    
           
{   
           
    fprintf(stderr, "Can not open
camera.\n");   
       
        return
-2;  
  
            }
 
            srand( (int)time( NULL ) );        
                  //初始化随机数产生器,它产生随机数种子
   
       
       
    while(pFrame =
cvQueryFrame( pCapture ))   //获取视频帧
       
    {     
   
            nFrmNum++;
   
            T++;              
                   //T=0时初始化,T>0时开始减背景
   
           
cvSmooth(pFrame,pFrame,CV_GAUSSIAN,3,3);
        //添加高斯滤波
       
        data=(uchar
*)pFrame->imageData;
   
            if(nFrmNum==1)              
         //第一帧建立样本数组,切割图,样本的像素数据
   
            {
   
               
for(index=0;index<20;index++)
       
            {
   
               
    simple[index]  =
cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,3);
       
               
simdata[index]=(uchar *)simple[index]->imageData;
   
               
}
               
    segmap =
cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,3);
       
            sg=(uchar *)segmap->imageData;
       
            height   =pFrame->height;
           //获取视频的高度,宽度,step,通道
   
               
width    =pFrame->width;
       
            step =pFrame->widthStep;
 
           
        chanels =pFrame->nChannels; 
   
               
beta=0.55*height*width;
       
        }
       
        if(T==1)
                     
   //当T=1时,初始化样本
   
            {   for(index=0;index<20;index++)
       
        {  
  
           
        for(i=0;i<height;i++)  
                 //将周围像素值赋予样本空间
   
               
    for(j=0;j<width;j++)
   
               
    {
           
               
if(i>1&&i<height-1&&j>1&&j<width-2)      
     //根据像素点位置选取,考虑到样本像素点位于图像边缘的时候要特殊处理
   
               
        { x=i+index/5-2;y=j+index%5-2;
       
               
    }  
       
               
    if(i<2&&j<2)
                     
   //图像左上角
   
               
        { x=i+index/5+1;y=j+index%5+1;
       
               
    }
           
               
if(i>height-3&&j<2)
                     
//图像左下角
       
               
    {  x=i+index/5-7 ;y=j+index%5+1;
       
               
    }
           
               
if(i<2&&j>width-3)      
                //图像右上角
       
               
    {  x=i+index/5 ;y=j+index%5-7;
       
               
    }
           
               
if(i>height-3&&j>width-3)      
                //图像右下角
       
               
    {  x=i+index/5-7 ;y=j+index%5-7;
       
               
    }
           
               
if(i<2&&j>1&&j<width-2)      
            //图像上边
       
               
    { x=i+index/5;y=j+index%5-2;
       
               
    }  
       
               
    if(i>height-3&&j>1&&j<width-2)      
         //图像下边
       
               
    { x=i+index/5-7;y=j+index%5-2;
       
               
    }  
       
               
    if(i>1&&i<height-1&&j<2)
                 //图像左边
   
               
        { x=i+index/5-2;y=j+index%5;
       
               
    }  
       
               
    if(i>1&&i<height-1&&j>width-3)      
         //图像右边
       
               
    { x=i+index/5-2;y=j+index%5-7;
       
               
    }
           
               
simdata[index][i*step+j*chanels+0]=data[x*step+y*chanels+0];  
       
               
    simdata[index][i*step+j*chanels+1]=data[x*step+y*chanels+1];  
       
               
    simdata[index][i*step+j*chanels+2]=data[x*step+y*chanels+2];  

       
               
}
               
}
               
}
               
if(T!=1&&nFrmNum%3==2)      
                     
          //T不等于1时减背景
       
        {
       
            double a[3]={0,0,0};

       
            for(x=1;x<width-1;x++)              
    //按行列顺序执行
   
               
{
               
        for(y=1;y<height-1;y++)
       
               
{
               
            int count=0;             //定义分类阈值count,距离dist,
   
               
        double
dist=0;
       
               
    index=0; 
       
               
    while((count<min)&&(index<N))
         //循环方法将图像检测值与样本空间值进行比较
   
               
        {
       
               
        a[0]=data[y*step+x*chanels+0]-simdata[index][y*step+x*chanels+0];
       
               
        a[1]=data[y*step+x*chanels+1]-simdata[index][y*step+x*chanels+1];
       
               
        a[2]=data[y*step+x*chanels+2]-simdata[index][y*step+x*chanels+2];
       
               
        dist=sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);           //计算出欧氏颜色空间的距离
   
               
            if(dist<R)  
                     
                 //判断是否小于设定的距离,是的话计数器加1
   
               
            {count++;
}
               
               
index++;
       
               
       
       
               
    }
           
               

               
           
   
               
        if(count>=min)              
                     
    //该检测值属于背景,则分割图显示为背景,且存在1/5的可能性存为样本值
   
               
        {   //printf("count=%d\n",count);   
            
 //调试用
           
               
    sg[y*step+x*chanels+0]=0;               //令切割图中相应点为黑色
       
               
        sg[y*step+x*chanels+1]=0;
   
               
            sg[y*step+x*chanels+2]=0;
       
               
        int
rdm=random(0,5);
       
               
        if(rdm==0)
   
               
            {   rdm=random(0,19);
                     
        //随即选择一个样本并替换
       
               
        simdata[rdm][y*step+x*chanels+0]=data[y*step+x*chanels+0];
   
               
            simdata[rdm][y*step+x*chanels+1]=data[y*step+x*chanels+1];
   
               
            simdata[rdm][y*step+x*chanels+2]=data[y*step+x*chanels+2];
   
               
            }
   
               
            rdm=random(0,5); 
       
               
        if(rdm==0)
                     
           //检测值属于背景,存在1/5的可能性向邻居一个节点传播
   
               
            {  int
xng=0, yng=0;
       
               
        while(xng==0 && yng==0)
       
               
        {
       
               
            xng=random(-1,2);              
         //随机选择八个中的一个邻居像素点
   
               
               
yng=random(-1,2); 
       
               
        }
       
               
        rdm=random(0,19);
   
               
            simdata[rdm][(y+yng)*step+(x+xng)*chanels+0]=data[y*step+x*chanels+0];
       
               
        simdata[rdm][(y+yng)*step+(x+xng)*chanels+1]=data[y*step+x*chanels+1];
       
               
        simdata[rdm][(y+yng)*step+(x+xng)*chanels+2]=data[y*step+x*chanels+2];
       
               
        }
       
               
    }
           
               
else
   
               
        {
       
               
        sg[y*step+x*chanels+0]=255;      
        //令切割图中相应点为白色
       
               
        sg[y*step+x*chanels+1]=255;
   
               
            sg[y*step+x*chanels+2]=255;
       
               
        fgcount++;
       
               
    }
           
           
}

           
        }

   
               
if(fgcount>beta)            
                  //超越阈值时判定为光源突变,令T=0,重新初始化
   
                {
  
           
            T=0;
   
               
}
               
    fgcount=0;              
                  //初始fgcount=0,为下一帧检测做准备;
   
           


           
    cvShowImage("video", pFrame);
   
           
    cvShowImage("segment map",
segmap); 
           
    if( cvWaitKey(2) >= 0 )    
 
           
        break;
   
           
}
           
cvDestroyWindow("video"); 
       
    cvDestroyWindow("segment map");
  
           
cvReleaseImage(&pFrame); 
   
        cvReleaseImage(&segmap);
       
    cvReleaseImage(simple);
   
        //cvReleaseImage(&smooth);
   
        cvReleaseCapture(&pCapture);   
   
        return
0;

}

来自为知笔记(Wiz)

时间: 2024-08-09 19:53:43

背景减法——Vibe的相关文章

背景减法——自组织算法

自组织背景减法是Maddalena于2008年发表的<A self-organizing approach to background subtraction for visual surveillance applications>中提出的,通过自组织的方法自动的生成一张神经网格背景模型.这个背景减法在2012年和2013年的Change detection背景减法比赛中均排名前列.  模型表示: 对输入视频的每个像素p都建立一个对应的神经图,每个神经图由n*n个权重向量组成. ={(p),

背景建模技术(三):背景减法库(BGS Library)的基本框架与入口函数main()的功能

背景减法库(BGS Library = background subtraction library)包含了37种背景建模算法,也是目前国际上关于背景建模技术研究最全也最权威的资料.本文将更加详细的介绍背景减法库(BGS Library)的基本框架与入口函数main()的功能. BGS库的整体框架在背景建模技术(二)中已经全部给出,此处从函数的角度再次给出BGS库的基本框架,有利于代码的修改与维护. 如下图所示是基于C++的BGS库的函数流程图: 接下来将会对每个函数进行更加详细的分析. 首先,

运动目标检测--改进的背景减法

一.概述 本文提出了一种改进的基于背景减法的运动目标检测算法,该算法能自适应地对背景进行初始化和实时更新,并能有效克服光照等外界条件变化对运动目标检测的影响. 二.算法介绍 基于背景减法的视频运动目标检测主要包括预处理.背景建模.目标检测和后处理四个步骤.本文的算法流程如图 1 所示,算法中的预处理是对每一帧图像都进行去噪和亮度归一化处理,以抑制光照突变和噪声的影响:背景建模则采用改进的均值滤波法自动初始化背景,并不断实时更新背景,以克服环境光照变化所产生的影响:目标检测是在背景减法的基础上采用

运动目标检测知识整理(背景建模 VIBE 背景差分 帧间差分 光流 HOG Adaboost SVM 显著性检测)

“背景建模/背景减法/前景检测”测试视频库

Background Subtraction Datasets -  Article (11 Datasets)   1.Wallflower Test Images Sequences (J. Krumm, Microsoft Research, USA)  (7 videos, 1 Ground Truth image for each sequence) http://research.microsoft.com/en-us/um/people/jckrumm/wallflower/tes

学习OpenCV范例(二十四)—ViBe前景检测(二)

最近导师没给什么项目做,所以有那么一点点小时间,于是就研究起了前景检测,既然前景检测有很多种算法,那干脆就把这些模型都学起来吧,以后用到前景检测时至少还有那么几种方法可以选择,上次介绍的是GMM模型,其实GMM模型本身就是一个很不错的模型,现在也很多人在研究,并且做改进,主要是OpenCV有函数调用,用起来非常方便,当我们都在兴高采烈的讨论GMM各种好的时候,B哥不爽了,他说老子是搞前景检测的,怎么可能让你们这么嚣张,而且老子就不按照你那套路来,什么高斯模型,混合高斯模型,我统统不用,就来个简单

背景建模技术(二):BgsLibrary的框架、背景建模的37种算法性能分析、背景建模技术的挑战

背景建模技术(二):BgsLibrary的框架.背景建模的37种算法性能分析.背景建模技术的挑战 1.基于MFC的BgsLibrary软件下载 下载地址:http://download.csdn.net/detail/frd2009041510/8691475 该软件平台中包含了37种背景建模算法,可以显示输入视频/图像.基于背景建模得到的前景和背景建模得到的背景图像,还可以显示出每种算法的计算复杂度等等.并且,测试的可以是视频.图片序列以及摄像头输入视频.其界面如下图所示: 2.BgsLibr

行人检测 深度学习篇

樊恒徐俊等基于深度学习的人体行为识别J武汉大学学报2016414492-497 引言 行为识别整体流程 前景提取 行为识别过程 实验分析 芮挺等 基于深度卷积神经网络的行人检测 计算机工程与应用 2015 引言 卷积神经网络结构与特点 行人检测卷积神经网络结构 实验对比总结 张 阳 基于深信度网络分类算法的行人检测方法J 计算机应用研究 20163302 总体来说大部分浏览下就行. 樊恒,徐俊等.基于深度学习的人体行为识别[J].武汉大学学报,2016,41(4):492-497. 0 引言 目

Non-planar Infrared-Visible Registration for Uncalibrated Stereo Pairs简介

摘要 对于非平面场景可见光-红外视频配准是视觉监控的一个新领域.它使用两种光谱信息的结合来更好的行人检测和分割.这里,提出一个新的用于非平面场景的可见光和红外配准的在线框架,这个框架包括前景分割.特征匹配.修正和差异计算.提出的方法基于稀疏轮廓点相关性.这个框架的关键想法是在视频的开始移除错误的区域和用于非平面场景的配准方法. 1. 介绍 红外和可见光(TIR-Vis)视频内容配准问题是计算机视觉的一个基本问题.配准的基本想法是找到视频帧对的相关性让场景和目标在一个共同的坐标系统中表示.一些人用