vibe在opencv的2.3.1以上,但在2.4.6下有提供这个算法。但是必须在gpu模式下,这个比较蛋疼。首先要重新编译opencv,再就要学习c++接口的opencv,原始的c接口的是不行的。显卡的配置也要求比较高,我测试时是使用GeForce 660测试的,再低端的显卡不知道可不可以。效率跟vibe算法作者提供的程序类似。如果项目的预算不是很高,可以使用我改的程序,预算高的话可以使用opencv的gpu_vibe函数。
vibe官方提供的程序的运行截图:
命令的输入简图:
由于网上可以找到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.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.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; }