【OpenCV】图像代数运算:平均值去噪,减去背景

代数运算,就是对两幅图像的点之间进行加、减、乘、除的运算。四种运算相应的公式为:


代数运算中比较常用的是图像相加和相减。图像相加常用来求平均值去除addtive噪声或者实现二次曝光(double-exposure)。图像相减用于减去背景或周期噪声,污染等。

图像相加


OpenCV中提供了相加的函数
void cvAcc( 
           const CvArr* image,//输入图像
           CvArr* sum,  //累积图像 
           const CvArr* mask=NULL//可选的运算
 );
我们还需要用到一个线性变换转换函数来对相加的结果求平均
void cvConvertScale( 
        const CvArr* src, //输入数组
        CvArr* dst,//输出数组
        double scale=1,//比例
        double shift=0 //缩放比例,可选
);
#define cvCvtScale cvConvertScale
#define cvScale  cvConvertScale
#define cvConvert( src, dst )  cvConvertScale( (src), (dst), 1, 0 )


实践:平均值去噪

我们用NASA的一段幸运团的视频做实验,截取视频的某几个连续帧求平均值:
int main()
{
	CvCapture* capture=cvCaptureFromFile("media.avi");
	IplImage* frame=  NULL;
	IplImage * imgsum =NULL;
	
	int start=301;
	int end=304;
	cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, start);
	
	int count = start;
	while( cvGrabFrame(capture) && count <= end )
	{
		frame = cvRetrieveFrame(capture);// 获取当前帧
		if(imgsum==NULL){
			imgsum=cvCreateImage(cvGetSize(frame),IPL_DEPTH_32F,3);
			cvZero(imgsum);
		}
		cvAcc(frame,imgsum);

		char testname[100];
		sprintf(testname,"%s%d%s","image",count,".jpg");
		cvShowImage(testname,frame);
		cvSaveImage(testname,frame);
		
		count++;
	}
	IplImage * imgavg = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3);
	cvConvertScale(imgsum,imgavg,1.0/4.0);
	
	cvShowImage("imageavg",imgavg);
	cvSaveImage("imageavg_4.jpg",imgavg);
	
	cvWaitKey(0);
	cvReleaseCapture(&capture);
	return 0;
}
以下从左到右分别是连续两帧、四帧、八帧、十六帧求均值的结果:


实践:图像二次曝光

曝光和去噪是一样的,也是对几幅图像求平均
//通过求平均二次曝光
int main()
{
	IplImage* image1=  cvLoadImage("psu3.jpg");
	IplImage* image2=  cvLoadImage("psu4.jpg");
	
	IplImage * imgsum =cvCreateImage(cvGetSize(image1),IPL_DEPTH_32F,3);
	cvZero(imgsum);
	cvAcc(image1,imgsum);
	cvAcc(image2,imgsum);

	IplImage * imgavg = cvCreateImage(cvGetSize(image1),IPL_DEPTH_8U,3);
	cvConvertScale(imgsum,imgavg,1.0/2.0);

	cvShowImage("imageavg",imgavg);
	cvSaveImage("avg.jpg",imgavg);

	cvWaitKey(0);
	cvReleaseImage(&image1);
	cvReleaseImage(&image2);
	cvReleaseImage(&imgsum);
	cvReleaseImage(&imgavg);
	return 0;
}
下图是对同学街舞截图的“二次曝光”效果:


图像相减


OpenCV中用cvAbsDiff函数计算两数组的差的绝对值
void cvAbsDiff( 
        const CvArr* src1,//第一个输入数组
        const CvArr* src2,//第二个输入数组
        CvArr* dst//输出数组
);


实践:减去背景

减去背景是通过两幅图像代数相减,可以判断出前景区域和运动区域,这是最简单(很多时候也是效果很好的)运动检测方法。
//减去背景
int main()
{
	IplImage* pFrame = NULL; 
	IplImage* pFrImg = NULL;
	IplImage* pBkImg = NULL;

	CvMat* pFrameMat = NULL;
	CvMat* pFrMat = NULL;
	CvMat* pBkMat = NULL;

	CvCapture* pCapture = NULL;

	int nFrmNum = 0;

	//创建窗口
	cvNamedWindow("video", 1);
	cvNamedWindow("background",1);
	cvNamedWindow("foreground",1);

	pCapture = cvCaptureFromFile("media.avi");
	while(pFrame = cvQueryFrame( pCapture ))
	{
		nFrmNum++;

		//如果是第一帧,需要申请内存,并初始化
		if(nFrmNum == 1)
		{
			pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);
			pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);

			pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
			pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
			pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);

			//转化成单通道图像再处理
			cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
			cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);

			cvConvert(pFrImg, pFrameMat);
			cvConvert(pFrImg, pFrMat);
			cvConvert(pFrImg, pBkMat);
		}
		else
		{
			cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
			cvConvert(pFrImg, pFrameMat);
			//当前帧跟背景图相减
			cvAbsDiff(pFrameMat, pBkMat, pFrMat);
			//二值化前景图
			cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
			//更新背景
			cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);
			//将背景转化为图像格式,用以显示
			cvConvert(pBkMat, pBkImg);

			cvShowImage("video", pFrame);
			cvShowImage("background", pBkImg);
			cvShowImage("foreground", pFrImg);

			if( cvWaitKey(2) >= 0 )
				break;
		}
	}
	cvDestroyWindow("video");
	cvDestroyWindow("background");
	cvDestroyWindow("foreground");
	cvReleaseImage(&pFrImg);
	cvReleaseImage(&pBkImg);
	cvReleaseMat(&pFrameMat);
	cvReleaseMat(&pFrMat);
	cvReleaseMat(&pBkMat);
	cvReleaseCapture(&pCapture);
	return 0;
}
效果图:

转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7610665
实验代码及视频下载:http://download.csdn.net/detail/xiaowei_cqu/4335573







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值