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++){//Heightfor(int x=0;x<pFrameMat->cols;x++){//Widthfor(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++){//Heightfor(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;}
啟動並執行結果如下: