码迷,mamicode.com
首页 > 其他好文 > 详细

三帧帧差法改进——使用循环队列减少深拷贝

时间:2015-04-22 09:40:00      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

使用循环队列的三帧帧差法

    帧差法是背景减图法中的一种,只不过是帧差法不需要建模,因为它的背景模型就是上一帧的图,所以速度非常快。对于帧差法的”双影”现象,有人提出来了三帧差法。其原理如下所示:

    1. 由I(t) - I(t-1)得到前景图   F1

    2. 由I(t+1) - I(t)得到前景图  F2

    3.  F1 ∩ F2得到前景图        F3

    为了减少图像深拷贝带来的时间开销,我使用了一个储存三帧图像的循环队列,只需调整队首、队尾指针,就可以定位相对的前、中、后三帧,避免直接使用数组造成的图像数据深拷贝。

技术分享

二、代码:

cpp1:使用数组存储三帧图像


#include "stdio.h"
#include <cstdio>   
#include <windows.h> 
#include "highgui.h"   
#include "cv.h"  
using namespace std;
int main()  
{  
	int ncount=0;  
	IplImage *image1=NULL;  
	IplImage *image2=NULL;  
	IplImage *image3=NULL;  
	IplImage *Imask =NULL;  
	IplImage *Imask1=NULL;  
	IplImage *Imask2=NULL;  
	IplImage *Imask3=NULL;  
	IplImage *mframe=NULL;  
	DWORD start=GetTickCount();  
	CvCapture *capture = cvCreateFileCapture("E:\\Test\\video\\fire1.mp4");  
	int fps = cvGetCaptureProperty(capture,CV_CAP_PROP_FPS);
	printf("\n普通三帧帧差法\n");
	printf("\n视频帧率: %d 帧/秒\n",fps);
	int frameNum = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT); 
	printf("\n总帧数%d\n",frameNum);
	while(mframe=cvQueryFrame(capture))  
	{ 
		ncount += 1;  
		//初始化
if(!mframe){		//视频结束
	break;
}
		if(ncount==1)  
		{  
			image1=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			image2=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			image3=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			Imask =cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			Imask1=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			Imask2=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			Imask3=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			cvCvtColor(mframe,image1,CV_BGR2GRAY);  
			printf("视频帧宽度%d\n",mframe->width);
			printf("视频帧高度%d\n",mframe->height);
		}
		if(ncount==2)  
			cvCvtColor(mframe,image2,CV_BGR2GRAY);  

		if(ncount>=3)  
		{  
			if(ncount==3)  
				cvCvtColor(mframe,image3,CV_BGR2GRAY);  
			else  
			{  
				cvCopy(image2,image1);  
				cvCopy(image3,image2);  
				cvCvtColor(mframe,image3,CV_BGR2GRAY);  
			}  
			cvAbsDiff(image2,image1,Imask1);  
			cvAbsDiff(image3,image2,Imask2);  

			cvThreshold(Imask1,Imask1,20, 255, CV_THRESH_BINARY);  
			cvThreshold(Imask2,Imask2,20, 255, CV_THRESH_BINARY); 
			cvAnd(Imask1,Imask2,Imask);  
			cvShowImage("diff Frame",Imask);
			cvWaitKey(33);
		}  
	}  
	DWORD finish=GetTickCount();  
	cout<<finish-start<<"ms"<<endl;  
	return 0;  
}  


 

cpp2:使用循环队列存储三帧图像

#include "stdio.h"
#include <cstdio>   
#include <windows.h> 
#include "highgui.h"   
#include "cv.h" 
#define MAX_QUEUE 4
using namespace std;
int main()  
{  
	IplImage *diffQueue[4] = {NULL};//用于三帧帧差法的循环队列,增加一个空位用来队列判满
	int front ,rear;				//队头,队尾
	int ncount = 0;					//记录帧数
	IplImage *frontImg = NULL;  //前一帧
	IplImage *midImg = NULL;	//中间帧
	IplImage *rearImg = NULL;	//后一帧
	IplImage *Imask = NULL;  
	IplImage *Imask1=NULL;  
	IplImage *Imask2=NULL;  
	IplImage *Imask3=NULL;  
	IplImage *mframe=NULL;  
	DWORD start=GetTickCount();  
	CvCapture *capture = cvCreateFileCapture("E:\\Test\\video\\fire1.mp4");  
	int fps = cvGetCaptureProperty(capture,CV_CAP_PROP_FPS);
	printf("\n使用循环队列的三帧帧差法\n");
	printf("\n视频帧率: %d 帧/秒\n",fps);
	int frameNum = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT); 
	printf("\n总帧数%d\n",frameNum);
	while(mframe=cvQueryFrame(capture))  
	{ 
		ncount ++;  
		//初始化
		if(!mframe){		//视频结束
			break;
		}
		if(ncount==1)  
		{  
			Imask =cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			Imask1=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);  
			Imask2=cvCreateImage(cvGetSize(mframe),IPL_DEPTH_8U,1);   
			rear = front = 0;				//初始化队首、队尾
			for(int i = 0;i < MAX_QUEUE;i++){						//初始化循环队列
				diffQueue[i] = cvCreateImage(cvGetSize(mframe),mframe->depth,1);//循环队列只存需要帧差的灰度图
			}
			rear = (rear + 1)%MAX_QUEUE;		//第一帧疑似火焰图像入队
			cvCvtColor(mframe,diffQueue[rear],CV_BGR2GRAY);	//将图形帧的灰度图保存在循环队列中
			printf("\n视频帧宽度%d\n",mframe->width);
			printf("视频帧高度%d\n\n",mframe->height);		
		}
		//队列不满则火焰疑似帧继续入队
		else if((rear+1)%MAX_QUEUE != front){
			//for Debug,March.12,2015
			//printf("\n入队\n");	
			rear = (rear + 1)%MAX_QUEUE;		
			cvCvtColor(mframe,diffQueue[rear],CV_BGR2GRAY);		//疑似火焰图像入队
		}
		//队满,即队列中符合要求的视频帧数为3,开始对中间帧的每一个ROI进行帧差法
		else{
			frontImg = diffQueue[(front+1)%MAX_QUEUE];
			midImg = diffQueue[(front+2)%MAX_QUEUE];
			rearImg = diffQueue[(front+3)%MAX_QUEUE];
			cvAbsDiff(midImg,frontImg,Imask1);  
			cvAbsDiff(rearImg,midImg,Imask2);  

			cvThreshold(Imask1,Imask1,20, 255, CV_THRESH_BINARY);  
			cvThreshold(Imask2,Imask2,20, 255, CV_THRESH_BINARY); 
			cvAnd(Imask1,Imask2,Imask);  
			cvShowImage("diff Frame",Imask);
			cvWaitKey(33);
			front = (front+1)%MAX_QUEUE;		//前一帧出队
		}  
	}  
	DWORD finish=GetTickCount();  
	cout<<finish-start<<"ms"<<endl;  
	return 0;  
}


三、实验对比

    普通三帧帧差法处理速度:        48.8ms/帧

    使用循环队列帧差法处理速度:25.5ms/帧

    相对于使用cvCopy的普通三帧帧差法,使用循环队列储存图像的用时只是前者的52.2%。

技术分享


技术分享

三帧帧差法改进——使用循环队列减少深拷贝

标签:

原文地址:http://blog.csdn.net/solomon1558/article/details/45177551

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!