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

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

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

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%。

时间: 2024-11-05 21:47:17

三帧帧差法改进——使用循环队列减少深拷贝的相关文章

Java实现循环队列

一.分析 队列是一种先进先出的线性表,它只允许在表的一端进行插入,而在另一端删除元素.允许插入的一端称为队尾,允许删除的一端称为队头. 循环队列是一种以顺序存储结构表示的队列,为了解决“假溢出”问题而将它设计成头尾相接的循环结构,它的基本操作如下: 1.初始化循环队列 2.销毁循环队列 3.清空循环队列 4.检测循环队列是否为空 5.返回循环队列的元素个数 6.返回循环队列头元素 7.向队尾插入元素 8.删除并返回队头元素 9.遍历循环队列 在循环队列中,除了用一组地址连续的存储单元依次存储从队

【数字图像处理】帧差法与Kirsch边缘检测实现运动目标识别与分割

本文链接:https://blog.csdn.net/qq_18234121/article/details/82763385 作者:冻人的蓝鲸梁思成 视频分割算法可以从时域和空域两个角度考虑.时域分割算法利用视频流时域连续性,通过 相邻帧的时域变化来检测运动目标.在摄像头静止的情况下,常用的方法有帧差法和减背景法. 帧差法比较直观实用,对光照的变化干扰不敏感,但是 对目标的检测不准确,对于缓慢运动的目标甚至可 能无法提取出目标边界,对于快速运动的目标提取 出的目标区域又过大.减背景法容易得到目

11 帧差法获取运动

帧差法 三帧差法 录频工具转gif #include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/imgproc.hpp" using namespace cv; int main(int argc, char *argv[]) { VideoCapture videoCap(0); if (!videoCap.isOpened()) { return -1;

OpenCV运动目标检测——帧间差,混合高斯模型方法

一.简单的帧间差方法 帧差法是在连续的图像序列中两个或三个相邻帧间采用基于像素的时间差分并且闽值化来提取图像中的运动区域. 代码: int _tmain(int argc, _TCHAR* argv[]) { VideoCapture capture("bike.avi"); if(!capture.isOpened()) return -1; double rate = capture.get(CV_CAP_PROP_FPS); int delay = 1000/rate; Mat

转载 ------ 三次指数平滑法

原文地址: http://blog.csdn.net/nieson2012/article/details/51980943 目录 ?1.指数平滑定义及公式 ?2.一次指数平滑 ?3二次指数平滑 ?4.三次指数平滑 ?5指数平滑系数α的确定 1.指数平滑的定义及公式 产生背景:指数平滑由布朗提出.他认为时间序列的态势具有稳定性或规则性,所以时间序列可被合理地顺势推延:他认为最近的过去态势,在某种程度上会持续的未来,所以将较大的权数放在最近的资料. 基本原理:指数平滑法是移动平均法中的一种,其特点

图论之随机配流02——基于LOGIT的STOCH配流法-改进的dial算法

function dialsuanfaxishujuzhen(T) %程序说明 clc disp('======================================================================================'); disp('                   <基于LOGIT的STOCH配流法--改进的dial算法>'); disp('运行环境:MATLAB 8.3.0.532 '); disp('制 作 人:兰州交通大学

JavaScript的三种工业化玩法

JavaScript的三种工业化玩法 软件工程中任何的语言如果想要写出健壮的代码都需要锋利的工具,当然JavaScript也不例外,很多朋友刚入门的时候往往因为工具选的不对而事半功倍,JavaScript同样需要软件调试技术,希望本文总结的三种工具会对大家的学习有所帮助. 任何语言的学习都离不开实践,不写代码是永远学不会编程的,当然javascript也不例外,很多人推荐直接浏览器调试,个人觉得这个推荐应该是非常初级的,比如Chrome, Firefox确实提供了实用的前端调试工具,但是个人认为

[问题2014A01] 解答三(升阶法,由董麒麟同学提供)

[问题2014A01] 解答三(升阶法,由董麒麟同学提供) 引入变量 \(y\),将 \(|A|\) 升阶,考虑如下行列式: \[|B|=\begin{vmatrix} 1 & x_1-a & x_1(x_1-a) & x_1^2(x_1-a) & \cdots & x_1^{n-1}(x_1-a) \\ 1 & x_2-a & x_2(x_2-a) & x_2^2(x_2-a) & \cdots & x_2^{n-1}(x_

PHP远程DoS漏洞深入分析快三红黑玩法及防护方案源码搭建

PHP远程DoS漏洞 PHP远程DoS漏洞深入分析快三红黑玩法(企鹅:212303635)及防护方案源码搭建(aqiulian.com) 4月3日,有人在PHP官网提交PHP 远程DoS漏洞(PHP Multipart/form-data remote dos Vulnerability),代号69364.由于该漏洞涉及PHP的所有版本,故其影响面较大,一经发布迅速引发多方面关注.14日,各种PoC已经在网络上流传.此次漏洞具备如下特性: 一旦被利用成功,可以在迅速消耗被***主机的CPU资源,