背景分离-平均背景法

平均背景法

为达到前景目标的识别,譬如,交通路口对车辆的识别、监控器对行人的识别,常用的且较为有效的方法就是背景差分法(还有其他的方法,比如光流场法,帧差法),即用一张有要识别目标的图像减去相应的背景图像,那么所得的结果便是我们所要的目标。

然而,如何获取一个“美好”的背景图,是背景差分法的关键和难点。此处介绍一种最为简单的获取背景的方法——平均背景法。

顾名思义,其基本思想就是,将所采集到的背景图片叠加求和,而后求取平均值作为要求的背景。其大致算法流程如下:

1.将采集到的部分图片,利用OpenCV的cvAcc函数累加求和,并统计累加次数,累加完成后在用cvConvertScale函数求取平均值,记为A。(注意理解该平均值的意思是在(x,y)位置处,所有参与求和计算的图像在该点出的像素平均值,每一点的像素平均值是不同的)

2.前一帧图像和当前参与累加的图像求差的绝对值,利用cvAbsDiff函数,而后该绝对值图像也进行累加求平均值,记为D。(同理这是某点的差值平均值)它描述的是某点像素值得波动幅度。

3.那么有1和2便可以认为,图像某点的像素值P若满足A-D < P < A+D,则认为此点属于背景,然而由于前景目标的加入,可能对背景点的亮度有一定的影响,故对波动幅度D进行一定的放缩,若 A -KD < p < A + KD,便认为该点为背景点。自然在该范围外的点,便是我们需要的前景点。那么用cvThreshold函数完成二值化。我们的目的就达到了。


#include "highgui.h"
#include "cv.h"
#include "cxcore.h"

/*为不同临时图像和统计属性图像创建指针*/

//三通道float图像
IplImage *IavgF, *IdiffF, *IprevF, *IhiF, *IlowF;//平均 不同 先前 高 低

IplImage *Iscratch, *Iscratch2;

//单通道float图像
IplImage *Igray1, *Igray2, *Igray3;

IplImage *Ilow1, *Ilow2, *Ilow3;

IplImage *Ihi1, *Ihi2, *Ihi3;

//单通道Byte图像
IplImage *Imaskt;

//自己定义的图像
//IplImage *mypic;

//计算背景建模使用图片的张数 
float Icount;

/*调用函数的声明*/
void AllocateImages(IplImage *I);
void accumulateBackground(IplImage * I);
void createModelsfromStats();
void setHighThreshold(float scale);
void setLowThreshold(float scale);
void backgroundDiff(IplImage *I, IplImage * Imask);
void DeallocateImages();




int main(int argc, char** argv)
{
	cvNamedWindow("intput", CV_WINDOW_AUTOSIZE);                    //创建输入显示窗口
	cvNamedWindow("output", CV_WINDOW_AUTOSIZE);                    //创建输出显示窗口
	//返回一个capture指针,指向视频
	CvCapture* capture = cvCreateFileCapture("C:/Users/Administrator/Desktop/OPENCV/MV版.avi"); 

	IplImage*Img = cvQueryFrame(capture);                          //从视频中取出的图片
	//创建输出图片,这里不能去掉cvCreateImage(cvGetSize(Img),IPL_DEPTH_8U,1),虽然我看例程里省略了
	IplImage * Imask = cvCreateImage(cvGetSize(Img), IPL_DEPTH_8U, 1);

	AllocateImages(Img);                                           //调用创建临时图片函数

	/*累积图像,只取了前30帧图片*/
	while (Icount<30){

		accumulateBackground(Img);                                   //调用累积图像的函数,循环30次                               
		Img = cvQueryFrame(capture);   //从摄像头或者文件中抓取并返回一帧
		cvShowImage("intput", Img);
		cvWaitKey(20);
	}


	createModelsfromStats();                                        //背景建模

	while (1)
	{
		Img = cvQueryFrame(capture);
		if (!Img) break;

		backgroundDiff(Img, Imask);                                 //根据模型分割前景

		cvShowImage("output", Imask);                               //显示图像,视频是一张一张图片连续播放的结果
		cvShowImage("intput", Img);
		char c = cvWaitKey(33);                                    //当前帧被显示后,等待33ms再读取下一张图片
		if (c == 27) break;                                           //等待期间按下esc键,ASCII码为27,则循环退出
	}
	cvReleaseCapture(&capture);
	cvDestroyWindow("output");
	cvDestroyWindow("intput");
	DeallocateImages();
}



/*给需要的所有临时图像分配内存。为了方便,传递一副图像作为大小参考来分配临时图像*/

void AllocateImages(IplImage* I){
	CvSize sz = cvGetSize(I);    //这个比较好 值得一学

	IavgF = cvCreateImage(sz, IPL_DEPTH_32F, 3);  //IPL_DEPTH_32F    单精度浮点数
	IdiffF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
	IprevF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
	IhiF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
	IlowF = cvCreateImage(sz, IPL_DEPTH_32F, 3);


	Ilow1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	Ilow2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	Ilow3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	Ihi1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	Ihi2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	Ihi3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	//归零
	cvZero(IavgF);
	cvZero(IdiffF);
	cvZero(IprevF);
	cvZero(IhiF);
	cvZero(IlowF);

	Icount = 0.0001;

	Iscratch = cvCreateImage(sz, IPL_DEPTH_32F, 3);
	Iscratch2 = cvCreateImage(sz, IPL_DEPTH_32F, 3);

	Igray1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	Igray2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
	Igray3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);

	Imaskt = cvCreateImage(sz, IPL_DEPTH_8U, 1);  //IPL_DEPTH_8U - 无符号8位整型

	cvZero(Iscratch);
	cvZero(Iscratch2);

	//	mypic    =  cvCreateImage(sz,IPL_DEPTH_8U,1);





}


/*累积背景图像和每一帧图像差值的绝对值*/

void accumulateBackground(IplImage *I){

	static int first = 1;
	cvCvtScale(I, Iscratch, 1, 0);
	if (!first){
		cvAcc(Iscratch, IavgF);  //累加图像
		cvAbsDiff(Iscratch, IprevF, Iscratch2);  //计算一定时间内的每帧图像之差
		cvAcc(Iscratch2, IdiffF);
		Icount += 1.0;   //累加 

	}
	first = 0;
	cvCopy(Iscratch, IprevF);


}

/*累积背景图像与每一帧图像差值的绝对值后,建立一个背景的统计模型*/

/*先定义setHighThreshold与setLowThreshold*/

void setHighThreshold(float scale){
	cvConvertScale(IdiffF, Iscratch, scale);
	cvAdd(Iscratch, IavgF, IhiF);
	cvSplit(IhiF, Ihi1, Ihi2, Ihi3, 0);
}


void setLowThreshold(float scale){
	cvConvertScale(IdiffF, Iscratch, scale);
	cvSub(IavgF, Iscratch, IlowF);
	cvSplit(IlowF, Ilow1, Ilow2, Ilow3, 0);
}

/*建立模型*/
void createModelsfromStats(){

	cvConvertScale(IavgF, IavgF, (double)(1.0 / Icount));         //IgvgF = IgvgF *(1.0/Icount) + 0   求取平均值
	cvConvertScale(IdiffF, IdiffF, (double)(1.0 / Icount));

	cvAddS(IdiffF, cvScalar(1.0, 1.0, 1.0), IdiffF);

	setHighThreshold(7.0);                                       //函数设置一个阈值,使得对于每一帧图像的绝对差大于平局值7倍的像素都认为是前景
	setLowThreshold(6.0);

}



/*建立模型同时有了高低阈值,我们就能把图像分割成前景(不能被背景模型“解释”的图像部分)*/

void backgroundDiff(
	IplImage *I,
	IplImage *Imask
	){
	cvCvtScale(I, Iscratch, 1, 0);
	cvSplit(Iscratch, Igray1, Igray2, Igray3, 0);

	//Channel 1
	cvInRange(Igray1, Ilow1, Ihi1, Imask);

	//Channel 2
	cvInRange(Igray2, Ilow2, Ihi2, Imaskt);
	cvOr(Imask, Imaskt, Imask);

	//Channel 3
	cvInRange(Igray3, Ilow3, Ihi3, Imaskt);
	cvOr(Imask, Imaskt, Imask);

	//cvCvtScale(Imask,mypic,1,0);

	cvSubRS(Imask, cvScalar(255), Imask);                              //这里书上例程写cvSubRS(Imask,255,Imask);但是这样编译的时候会报错,必须先转换成cvScalar型

}

/*释放内存*/
void DeallocateImages()
{
	cvReleaseImage(&IavgF);
	cvReleaseImage(&IdiffF);
	cvReleaseImage(&IprevF);
	cvReleaseImage(&IhiF);
	cvReleaseImage(&IlowF);
	cvReleaseImage(&Ilow1);
	cvReleaseImage(&Ilow2);
	cvReleaseImage(&Ilow3);
	cvReleaseImage(&Ihi1);
	cvReleaseImage(&Ihi2);
	cvReleaseImage(&Ihi3);
	cvReleaseImage(&Iscratch);
	cvReleaseImage(&Iscratch2);
	cvReleaseImage(&Igray1);
	cvReleaseImage(&Igray2);
	cvReleaseImage(&Igray3);
	cvReleaseImage(&Imaskt);


}


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值