《学习openCV》例程解析 ex_9_2(背景减除)

56帧时分割出手效果

63帧时分割出手的效果

/***
平均背景法进行图像分割, 在图像背景相对稳定的情况下, 检测闯入图像的前景目标

*/

/***
	Averaging Background Method

	We’ve just seen a simple method of learning background scenes and segmenting fore-
	ground objects. It will work well only with scenes that do not contain moving background 
	components (like a waving curtain or waving trees). It also assumes that the lighting 
	remains fairly constant (as in indoor static scenes). 
*/
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"

/***************************************************/
//我们为需要的不同临时图像和统计属性的图像创建指针

//Float 3-channel images
IplImage *IavgF, *IdiffF, *IprevF, *IhiF, *IlowF;
IplImage *Iscratch, *Iscratch2;

//Float 1-channel images
IplImage *Igray1, *Igray2, *Igray3;
IplImage *Ilow1, *Ilow2, *Ilow3;
IplImage *Ihi1, *Ihi2, *Ihi3;

//Byte 1-channel image
IplImage *Imaskt;
IplImage *Imask;

float Icount;
/**************************************************/


void AllocateImages(IplImage* I)
//该函数为需要的所有临时图像分配内存,传入来自视频的首帧图像作为大小参考
{
	CvSize sz = cvGetSize(I);

	IavgF	= cvCreateImage(sz, IPL_DEPTH_32F, 3);
	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 = 1e-5;

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

	cvZero(Iscratch);
	cvZero(Iscratch2);

	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);
	Imask	= cvCreateImage(sz, IPL_DEPTH_8U, 1);

}

void accumulateBackground(IplImage* I)
//累积背景图像和前后帧图像差值的绝对值
//当累积够一定数量后就将其转换成一个背景统计模型
{
	static int first = 1;
	//局部静态变量,只初始化一次,意思就是第一次被赋值为1

	cvCvtScale(I, Iscratch, 1, 0);
	//将I指向的图像复制给Iscratch 不能用cvCopy,因为像素的位深度不同

	if (!first)
	{
		cvAcc(Iscratch, IavgF);
		//累积原始的浮点图像到IIavgF
		cvAbsDiff(Iscratch, IprevF, Iscratch2);
		//计算前后帧图像绝对差图像到Iscratch2
		cvAcc(Iscratch2, IdiffF);
		//将前后帧差值图像累加到IdiffF 中
		Icount += 1.0;
		//记录累加的次数用于背景统计时计算均值
	}
	first = 0;
	//first 为局部静态变量,以后调用该函数将不再初始化为1
	//意思就是除了第一次,以后调用该函数均进入if 语句

	cvCopy(Iscratch, IprevF);
	//IprevF用来保存前一帧图像
}

void setHighThreshold(float scale)
{
	cvConvertScale(IdiffF, Iscratch, scale);
	//将统计的绝对差分图像值放大scale 倍赋给Iscratch
	cvAdd(Iscratch, IavgF, IhiF);
	//IhiF = Iscratch + IavgF 
	cvSplit(IhiF, Ihi1, Ihi2, Ihi3, 0);
	//将阀值上限分割为多通道
}

void setLowThreshold(float scale)
{
	cvConvertScale(IdiffF, Iscratch, scale);
	cvSub(IavgF, Iscratch, IlowF);
	//IlowF = IavgF - Iscratch
	cvSplit(IlowF, Ilow1, Ilow2, Ilow3, 0);
	//将阀值下限分割为多通道
}

void createModelsfromStats()
//当累积足够多的帧图后,就将其转化成一个背景统计模型
//该函数用于计算每个像素的均值和平均绝对差分
{
	cvConvertScale(IavgF, IavgF, (double)(1.0/Icount));
	//计算平均原始图像到 IavgF
	cvConvertScale(IdiffF, IdiffF, (double)(1.0/Icount));
	//计算绝对差分图像到 IdiffF

	cvAddS(IdiffF, cvScalar(1.0, 1.0, 1.0), IdiffF);
	//使得到的绝对差分图像每个像素值均不为空

	setHighThreshold(7.0);
	setLowThreshold(6.0);
	//根据统计的背景模型设定一个阀值上限和下限
	//如果 IlowF <= Temp < IhiF 时认为其为背景,否则为视频中出现的运动目标物体
}



void backgroundDiff(IplImage* I)
{
	cvCvtScale(I, Iscratch, 1, 0);
	//将I指向的图像复制给Iscratch 不能用cvCopy, 因为像素的位深度不同
	cvSplit(Iscratch, Igray1, Igray2, Igray3, 0);
	//得到的当前帧分割成3个单通道图像
	cvInRange(Igray1, Ilow1, Ihi1, Imask);
	//        src     lower  upper dst
	//检查这些单通道图像是否在平均背景像素高低阀值之间
	//如果src(I)在范围内(lower <= src < upper)dst(I)被设置为0xff(每一位都是 '1')否则置0
	cvInRange(Igray2, Ilow2, Ihi2, Imaskt);
	cvOr(Imask, Imaskt, Imask);
	//计算两个数组每个元素的按位或值赋值给第三个参数
	cvInRange(Igray3, Ilow3, Ihi3, Imaskt);
	cvOr(Imask, Imaskt, Imask);
	//最后Imask 为分离出的前景二值图
	cvSubRS(Imask, cvScalar(255), Imask);
	//计算数量和数组之间的差,将Imask反相处理
}

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);
	cvReleaseImage(&Imask);
}

int main()
{
	CvCapture* capture = cvCreateFileCapture("tree.avi");
	//初始化从文件中获取视频
	if (!capture)
	{
		printf("Couldn't Open the file.");
		return -1;
	}
	
	cvNamedWindow("raw");
	cvNamedWindow("avg");

	IplImage* rawImage = cvQueryFrame(capture);
	//这个函数仅仅是函数cvGrabFrame和函数cvRetrieveFrame在一起调用的组合
	cvShowImage("raw", rawImage);
	
	AllocateImages(rawImage);
	
	for (int i=0;;i++)
	{
		if (i <= 30) 
		{
			accumulateBackground(rawImage);
			//前30帧用于累积计算背景图像
			if (i == 30)
				//将前30真转换成一个背景统计模型
				createModelsfromStats();
		}
		else 
			//建立好背景模型后调用此函数进行图像分割
			backgroundDiff(rawImage);

		cvShowImage("avg", Imask);
		//播放分割后的目标图像结果

		if (cvWaitKey(33) == 27)
			//每33ms 播放一帧
			break;

		if (!(rawImage = cvQueryFrame(capture)))
			break;
		cvShowImage("raw", rawImage);
		//显示原图像

		if (i == 56 || i == 63)
			//56帧和63帧时暂停
			cvWaitKey();
	}	

	DeallocateImages();
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值