申明,本文非笔者原创,原文转载自:http://blog.youkuaiyun.com/STELLAR0/article/details/8740594
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
- };
- 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);
- }
- }
- }
- */
- }
1362

被折叠的 条评论
为什么被折叠?



