vibe前景提取方法学习

vibe在opencv的2.3.1以上,但在2.4.6下有提供这个算法。但是必须在gpu模式下,这个比较蛋疼。首先要重新编译opencv,再就要学习c++接口的opencv,原始的c接口的是不行的。显卡的配置也要求比较高,我测试时是使用GeForce 660测试的,再低端的显卡不知道可不可以。效率跟vibe算法作者提供的程序类似。如果项目的预算不是很高,可以使用我改的程序,预算高的话可以使用opencv的gpu_vibe函数。

vibe官方提供的程序的运行截图:

vibe前景提取方法学习_第1张图片

命令的输入简图:

由于网上可以找到vibe的实现的源代码,所以我也下了一个。

原始的代码地址在:http://pan.baidu.com/share/link?shareid=409860&uk=3373051938   但是在网友“开心每一天的提醒下,发现代码有问题,于是我自己改了改。,原来的代码的随机数产生有问题。

更改后的代码如下:

//vibe.cpp
#include "stdafx.h"
#include "hanshu.h"
#include <opencv2/opencv.hpp>
#include "highgui.h"
#include <math.h>
#include <iostream>

using namespace std;
using namespace cv;

static int c_xoff[9] = {-1,  0,  1, -1, 1, -1, 0, 1, 0};//x的邻居点
static int c_yoff[9] = {-1,  0,  1, -1, 1, -1, 0, 1, 0};//y的邻居点

float samples[1024][1024][defaultNbSamples+1];//保存每个像素点的样本值


//初始化
void Initialize(CvMat* pFrameMat,RNG rng){

	//记录随机生成的 行(r) 和 列(c)
	int rand,r,c;

	//对每个像素样本进行初始化
	for(int y=0;y<pFrameMat->rows;y++){//Height
		for(int x=0;x<pFrameMat->cols;x++){//Width
			for(int k=0;k<defaultNbSamples;k++){
				//随机获取像素样本值
				//rand=rng.uniform( 0, 9 );
				//r=y+c_yoff[rand]; if(r<0) r=0; if(r>=pFrameMat->rows) r=pFrameMat->rows-1;	//行
				//c=x+c_xoff[rand]; if(c<0) c=0; if(c>=pFrameMat->cols) c=pFrameMat->cols-1;	//列
				rand = rng.uniform(-1,1);
				r=y+rand;if(r<0) r=0; if(r>=pFrameMat->rows) r=pFrameMat->rows-1;	//行
				rand = rng.uniform(-1,1);
				c= x+rand; if(c<0) c=0; if(c>=pFrameMat->cols) c=pFrameMat->cols-1;	//列

				//存储像素样本值
				samples[y][x][k]=CV_MAT_ELEM(*pFrameMat,float,r,c);
			}
			samples[y][x][defaultNbSamples]=0;
		}
	}
}


//更新函数
void update(CvMat* pFrameMat,CvMat* segMat,RNG rng,int nFrmNum){

	for(int y=0;y<pFrameMat->rows;y++){	//Height
		for(int x=0;x<pFrameMat->cols;x++){	//Width

			//用于判断一个点是否是背景点,index记录已比较的样本个数,count表示匹配的样本个数
			int count=0,index=0;float dist=0;
			//
			while((count<defaultReqMatches) && (index<defaultNbSamples)){
				dist=CV_MAT_ELEM(*pFrameMat,float,y,x)-samples[y][x][index];
				if(dist<0) dist=-dist;
				if(dist<defaultRadius) count++;
				index++;
			}
			if(count>=defaultReqMatches){

				//判断为背景像素,只有背景点才能被用来传播和更新存储样本值
				samples[y][x][defaultNbSamples]=0;//??????????

				*((float *)CV_MAT_ELEM_PTR(*segMat,y,x))=background;

				int rand=rng.uniform(0,defaultSubsamplingFactor-1);
				if(rand==0){
					rand=rng.uniform(0,defaultNbSamples-1);///////////////
					samples[y][x][rand]=CV_MAT_ELEM(*pFrameMat,float,y,x);
				}
				rand=rng.uniform(0,defaultSubsamplingFactor-1);
				if(rand==0){
					int xN,yN;
					//rand=rng.uniform(0,9);yN=y+c_yoff[rand];if(yN<0) yN=0; if(yN>=pFrameMat->rows) yN=pFrameMat->rows-1;
					//rand=rng.uniform(0,9);xN=x+c_xoff[rand];if(xN<0) xN=0; if(xN>=pFrameMat->cols) xN=pFrameMat->cols-1;
					rand = rng.uniform(-1,1);yN = y+rand ;if(yN<0) yN=0; if(yN>=pFrameMat->rows) yN=pFrameMat->rows-1;
					rand = rng.uniform(-1,1);xN = x+rand ;if(xN<0) xN=0; if(xN>=pFrameMat->cols) xN=pFrameMat->cols-1;
					rand=rng.uniform(0,defaultNbSamples-1);
					samples[yN][xN][rand]=CV_MAT_ELEM(*pFrameMat,float,y,x);
				} 
			}
			else {
				//判断为前景像素
				*((float *)CV_MAT_ELEM_PTR(*segMat,y,x))=foreground;

				samples[y][x][defaultNbSamples]++;
				if(samples[y][x][defaultNbSamples]>50){
					int rand=rng.uniform(0,defaultNbSamples);
					if(rand==0){
						rand=rng.uniform(0,defaultNbSamples);
						samples[y][x][rand]=CV_MAT_ELEM(*pFrameMat,float,y,x);
					}
				}
			}

		}
	}

}

vibe的头文件没有更改,和原来的一样。

vibe.h
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include "highgui.h"
#include <iostream>

using namespace std;
using namespace cv;

#define defaultNbSamples 20		//每个像素点的样本个数
#define defaultReqMatches 2		//#min指数
#define defaultRadius 20		//Sqthere半径
#define defaultSubsamplingFactor 16	//子采样概率
#define background 0		//背景像素
#define foreground 255		//前景像素

void Initialize(CvMat* pFrameMat,RNG rng);//初始化
void update(CvMat* pFrameMat,CvMat* segMat,RNG rng,int nFrmNum);//更新

测试用的main函数如下:

//main.cpp
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include "highgui.h"
#include "hanshu.h"
#include <iostream>

using namespace std;
using namespace cv;

int nFrmNum = 0;//记录帧数
int Width;//记录帧的宽度
int Height;//记录帧的高度
int FrameRate;//记录视频帧率

int main(int argc, char* argv[])
{
	IplImage* pFrame=NULL;CvMat* pFrameMat = NULL;//pFrame对象
	IplImage* pAfter=NULL;CvMat* pAfterMat=NULL;//保存pFrame对应的灰度图像
	IplImage* segMap=NULL;CvMat* segMat=NULL;//保存处理后的信息

	//要读取的视频文件和保存的视频文件路径
	char* openfile="video.avi";
	char* outfile="out.avi";
	char filename[100];//保存的图像位置和名称

	//打开视频文件
	CvCapture* pCapture=cvCreateFileCapture(openfile);
	//CvCapture* pCapture= cvCreateCameraCapture(-1);
	if(pCapture==NULL) {
		cout<<"video file open error!"<<endl;
		return -1;
	}
	int array_cross[] ={    0,  0xff,   0,  
                            0xff,0xff,  0xff,  
                            0   ,0xff,  0  
                        };  
    IplConvKernel * rectCross= cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,array_cross); 
	//获取视频相关信息,帧率和大小
	double fps=cvGetCaptureProperty(pCapture,CV_CAP_PROP_FPS);
	CvSize size=cvSize((int)cvGetCaptureProperty(pCapture,CV_CAP_PROP_FRAME_WIDTH)*3,
		(int)cvGetCaptureProperty(pCapture,CV_CAP_PROP_FRAME_HEIGHT));

	//创建输出视频文件
	CvVideoWriter* Save_result=NULL;
	Save_result=cvCreateVideoWriter(outfile,CV_FOURCC('X','V','I','D'),fps,size,1);
	IplImage* dstImg=cvCreateImage(size,IPL_DEPTH_8U,3);//创建要保存的图像

	//创建窗口
	cvNamedWindow("video",CV_WINDOW_AUTOSIZE);

	//创建一个随机数生成器
	RNG rng(0xFFFFFFFF);
	//定义字体
	CvFont font;
	cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX_SMALL ,1, 1, 0, 1, 8);

	//逐帧读取视频并进行处理
	while(pFrame = cvQueryFrame( pCapture )){
		
		nFrmNum++;

		//如果是第一帧,申请内存并进行初始化
		if(nFrmNum==1){
			segMap = cvCreateImage(cvSize(pFrame->width, pFrame->height), 
				IPL_DEPTH_8U,1);
			segMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
			pAfter=cvCreateImage(cvSize(pFrame->width, pFrame->height), 
				IPL_DEPTH_8U,1);
			pAfterMat=cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);

			//转化成单通道图像再处理
			cvCvtColor(pFrame, pAfter, CV_BGR2GRAY);
			cvConvert(pAfter, pAfterMat);
			//
			Initialize(pAfterMat,rng);
		}
		else {
			cvCvtColor(pFrame,pAfter,CV_BGR2GRAY);
			cvConvert(pAfter,pAfterMat);
			update(pAfterMat,segMat,rng,nFrmNum);//更新背景
			cvConvert(segMat,segMap);

			//载入原图像到目标图像
			cvSetImageROI(dstImg, cvRect(0, 0, pFrame->width, pFrame->height));
			cvCopy(pFrame, dstImg);
			cvResetImageROI(dstImg);
			//将segMap转换成三通道图像存在pFrame中
			cvCvtColor(segMap,pFrame,CV_GRAY2BGR);
			//载入检测后的图像到目标图像
			cvSetImageROI(dstImg, cvRect(pFrame->width, 0, pFrame->width, pFrame->height));
			cvCopy(pFrame, dstImg);
			cvResetImageROI(dstImg);
			cvSetImageROI(dstImg,cvRect(pFrame->width*2,0,pFrame->width,pFrame->height));
			cvDilate(pFrame,dstImg);
			cvResetImageROI(dstImg);
			//显示提示文字
			cvPutText(dstImg, "Origin Video", cvPoint(0,pFrame->height-5), &font,CV_RGB(255,255,0));
			cvPutText(dstImg, "ViBe Video", cvPoint(pFrame->width,pFrame->height-5),&font,CV_RGB(255,255,0));

			//保存视频和输出
			//cvWriteFrame(Save_result,dstImg);

			/*输出图片
			if(nFrmNum<11)
				sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\000%d_Vibe.jpg",nFrmNum-1);
			else if(nFrmNum<101)
				sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\00%d_Vibe.jpg",nFrmNum-1);
			else if(nFrmNum<1001)
				sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\0%d_Vibe.jpg",nFrmNum-1);
			else if(nFrmNum<10001)
				sprintf(filename,"E:\\Result\\Vibe\\AVSS_PV_Easy_Divx_Xvid\\%d_Vibe.jpg",nFrmNum-1);
			cvSaveImage(filename,dstImg);
			*/

			cvShowImage("video",dstImg);
			cvWaitKey();
			//if(cvWaitKey(5)>=0) break;
		}
	}
	cvReleaseImage(&pFrame);cvReleaseMat(&pFrameMat);
	cvReleaseImage(&pAfter);cvReleaseMat(&pAfterMat);
	cvReleaseImage(&segMap);cvReleaseMat(&segMat);
	cvReleaseVideoWriter(&Save_result);
	cvReleaseImage(&dstImg);
	cvDestroyWindow("video");
	return 0;
}

运行的结果如下:






你可能感兴趣的:(vibe前景提取方法学习)