标签:
帧差法是背景减图法中的一种,只不过是帧差法不需要建模,因为它的背景模型就是上一帧的图,所以速度非常快。对于帧差法的”双影”现象,有人提出来了三帧差法。其原理如下所示:
1. 由I(t) - I(t-1)得到前景图 F1
2. 由I(t+1) - I(t)得到前景图 F2
3. F1 ∩ F2得到前景图 F3
为了减少图像深拷贝带来的时间开销,我使用了一个储存三帧图像的循环队列,只需调整队首、队尾指针,就可以定位相对的前、中、后三帧,避免直接使用数组造成的图像数据深拷贝。
#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;
}
#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