前景检测算法-SACON(SAMPLE CONSENSUS)

      SACON是Hanzi Wang and David Suter合作完成的一篇论文《Background subtraction based on a robust consensu method>>里的算法。乍看之下,算法思路很简单,后来的大作VIBE算法似乎与其有异曲同工之妙。废话少说,下面来简单介绍下该算法:

     (1)建立背景模型

           文章中背景模型的建立比较简单,就是为each pixel 保存N个background samples,这个可以很容易的提取视频序列的前N帧实现。

     (2)前景提取

       该部分分为3阶段,其实每个阶段都是相互融合的:第一步利用邻域帧差法提取可能的前景掩膜(FMForeground Mask),即时间域内连续两帧相减,提取Possible moving pixels;第二部,针对第一步的得到的possible moving pixels以及background samples给SACON算法处理,主要的处理过程是按以下两个公式得到:

                               

 

                                

其中Tr为常量(constant),N是背景样本的数目(sample number),k表示通道数目(channel number), 在实现程序中默认取值为15. Tn的取值与N相关,其值可以表示为Tn~cNTr(C is a constant)。实现程序Tn默认取值为2N.

      (3) 阴影去除(该文阴影去除算法是借鉴其他文章的,具体参考section 3.1)

      (4) 空洞填充

       考虑到提取的前景区域内部可能存在一些小的空洞,于是文章采用了空洞填充技术。在实现中,采用的是形态学的碰撞腐蚀(Dilate and erode)来进行填充的。

     (5)考虑到背景的移出或前景的停止,文章介绍了TOM(TIme OF MAP)来对其处理,可以讲移出的背景留下的区域很快的内容到背景中,而对于停止在场景中的目标,也能很快的融入到背景中去。

     下面是实现代码的.h文件

class SACON  
{
public:
 SACON();
 // 构造函数,其中iteration表示样本的数目,也即用于学习的帧数N
 SACON(IplImage *img,int iteration);
 /* Description: 
  To implement the function to distinguish whether a pixel is foreground or background
 and then update the background model */
 void Detect(IplImage *img);
 /* 设置当前像素是否为背景还是前景,即当前像素与背景样本比较,存在较大差异的数目
  该值与样本的数目gIteration相关,默认为gIteration*2
 */
 void SetAlpha(double al){gAlpha=al;}
 // 设置两个像素值的差异,默认为15
 void SetValDiff(int ival){valDiff=ival;}
 // 用于标记一个像素最多为
 void SetTomTh(int Count){Th_Tom=Count;}
 IplImage* getForeground(){return pForeImg;}
 virtual ~SACON();

private:
 void InnerDetect(IplImage *img);
 // 填充前景区域的空洞,思想是填充,
 void ValidateForeground(IplImage *foreImg);
 IplImage **pBkImgArr;
 IplImage *pForeImg; 
 IplImage *pPreImg;
 IplImage *pGray;
 IplImage *pDiffImg;
 int gHeight;
 int gWidth;
 CvSize gSize;
 int gIteration;
 int frmNum;
 int valDiff; // 两个像素值的差异
 double gAlpha;//the value that determines a pixel whether a foreground or background
 int **Tom; //用来记录一个像素被连续判为前景的次数
 int Th_Tom; // 用于标记一个像素最多为前景的次数,默认为100

};

 

     下面是实现代码cpp文件:

SACON::SACON(IplImage *img,int iteration)
{
 frmNum=0; 
 Th_Tom=100;
 gHeight=img->height;
 gWidth=img->width;
 gIteration=iteration;
 gAlpha=gIteration*2; // 值的设置还有待商榷
 gSize=cvGetSize(img);
 pForeImg=cvCreateImage(gSize,8,1); 
 pGray=cvCreateImage(gSize,8,1); 
 pPreImg=cvCreateImage(gSize,8,3);
 pDiffImg=cvCreateImage(gSize,8,3); 
 int i=0,j=0;
 Tom=new int *[gHeight];
 for (i=0;i<gHeight;i++)
 {
  Tom[i]=new int[gWidth];
  for (j=0;j<gWidth;j++)
  {
   Tom[i][j]=0;
  }
 }
 pBkImgArr=new IplImage*[gIteration];
 for (i=0;i<gIteration;i++)
 {
  pBkImgArr[i]=cvCreateImage(gSize,IPL_DEPTH_8U,3);
 }
 cvCopyImage(img,pBkImgArr[frmNum]);
 frmNum++;
}

// 实现前景检测,如果学习没完,则继续进行学习
void SACON::Detect(IplImage *img)
{  
 if (frmNum<gIteration)
 {
  cvCopyImage(img,pBkImgArr[frmNum]);
  frmNum++;
  if (frmNum==gIteration)
  {
   cvCopyImage(img,pPreImg);
  }
 }
 else
 {
  InnerDetect(img);
  ValidateForeground(pForeImg);
 }
}

// 实现前景检测,并进行背景更新
void SACON::InnerDetect(IplImage *img)
{
 cvZero(pForeImg);
 cvZero(pGray);
 cvAbsDiff(img,pPreImg,pDiffImg);
 cvCvtColor(pDiffImg,pGray,CV_BGR2GRAY);
 cvThreshold(pGray,pGray,20,255,CV_THRESH_BINARY);
 cvCopyImage(img,pPreImg);

 int i=0,j=0,k=0,p=0;
 int cnt=0, iTom;
 CvScalar cs0,cs1,cs2,cs3;
 cs3.val[0]=255; 
 for (i=0;i<gHeight;i++)
 {
  for (j=0;j<gWidth;j++)
  {
   cs0=cvGet2D(pGray,i,j);
   if (cs0.val[0]==255)
   {
    cs1=cvGet2D(img,i,j);
    cnt=0;
    for (k=0;k<gIteration;k++)
    {
     cs2=cvGet2D(pBkImgArr[k],i,j);
     for (p=0;p<3;p++)
     {
      if (fabs(cs1.val[p]-cs2.val[p])>valDiff)
      {
       cnt++;
      }
     }
    }
    //与背景比较完成
    if (cnt>gAlpha)
    {
     iTom=Tom[i][j];
     if (iTom>Th_Tom) // 如果当前像素为前景的次数超过Th_Tom,则判为背景
     {
      Tom[i][j]=0;  // 怎么更新背景
     }
     else
     {
      Tom[i][j]++;
      cvSet2D(pForeImg,i,j,cs3);     
     }
    }
   }
   else
   {
    continue;
   }
  }
  
 }
}

void SACON::ValidateForeground(IplImage *foreImg)
{
 // 膨胀腐蚀的默认结构元素是3×3的长方形
 cvDilate(foreImg,foreImg,NULL,1);
 cvErode(foreImg,foreImg,NULL,1);
 /*
 int i=0,j=0,p=0,q=0;
 int cnt;
 CvScalar cs0,cs;
 cs.val[0]=255;
 for (i=1;i<gHeight-1;i++)
 {
  for (j=1;j<gWidth-1;j++)
  {
   cnt=0;
   for (p=i-1;p<=i+1;p++)
   {
    for(q=j-1;q<=j+1;q++)
    {
     cs0=cvGet2D(foreImg,p,q);
     if (cs0.val[0]==255)
     {
      cnt++;
     }
    }
   }
   if (cnt>5)
   {
    cvSet2D(foreImg,i,j,cs);
   }
  }
 }
 */
}

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值