三幀差法

      這幾天研究了下三幀差法做物體檢測。

      三幀差法的具體算法如下。

      提取連續的三幀圖像,I(k-1),I(k),I(k+1) 。

(1)  d(k,k-1) [x,y] = | I(k)[x,y] - I(k-1)[x,y] |;

      d(k,k+1)[x,y] = | I(k+1)[x,y] - I(k)[x,y] |;

       

 (2)  b(k,k-1)[x,y] = 1;  if  d(k,k-1) [x,y]  >= T;

       b(k,k-1)[x,y] = 0;  if  d(k,k-1) [x,y]  < T;

       b(k+1,k)[x,y] = 1  if  d(k+1,k) [x,y]  >= T;

       b(k+1,k)[x,y] = 0  if  d(k+1,k) [x,y]  < T;

 

(3)   B(k)[x,y] = 1 ; if  b(k,k-1)[x,y] && b(k+1,k)[x,y] == 1 ;

       B(k)[x,y] = 0 ; if  b(k,k-1)[x,y] && b(k+1,k)[x,y] ==0 ;

 

       到了這裏,比較關鍵的就是第2步的閾值T的選取問題,單純用otsu算法分割貌似效果不太好,如果手動設置一個較小的值(如10)效果

還可以,但手動設置有一定的限制性。接下來要研究局部閾值的選取。

       用otsu取閾值實現的一個三分差法代碼。效果不是很好。

       運行環境 VS2008+OpenCV2.0+windows XP .

#include "highgui.h"
#include "cv.h"
#include "cxcore.h"
#include "cvaux.h"
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <windows.h>
using namespace std;

#pragma comment(lib, "highgui200.lib")
#pragma comment(lib, "cv200.lib")
#pragma comment(lib, "cxcore200.lib")
#pragma comment(lib, "cvaux200.lib")

#define GET_IMAGE_DATA(img, x, y)	((uchar*)(img->imageData + img->widthStep * (y)))[x]
int T = 10;
int Num[300];
int Sum[300];

void InitPixel(IplImage * img, int &_low, int &_top)
{
   memset(Num,0,sizeof(Num));
   memset(Sum,0,sizeof(Sum));
   _low = 255;
   _top = 0;
   for(int i = 0;i < img->height;i++)
   {
	   for(int j = 0;j < img->width;j++)
	   {
		   int temp = ((uchar*)(img->imageData + img->widthStep*i))[j];
           if(temp < _low)
			   _low = temp;
		   if(temp > _top)
			   _top = temp;
		   Num[temp] += 1;
	   }
   }
   for(int i = 1 ; i < 256 ; i++)
   {
       Sum[i] = Sum[i-1]+ i*Num[i];
       Num[i] += Num[i-1];
   }
}
int otsu (IplImage *img)
{
   int _low,_top,mbest=0;
   float mn = img->height*img->width;
   InitPixel(img,_low,_top);
   float max_otsu = 0;
   mbest = 0;
   if( _low == _top)
	   mbest = _low;
   else
   {
	   for(int i = _low; i< _top ; i++)
	   {
		   float w0 = (float)((Num[_top]-Num[i]) / mn);
		   float w1 = 1 - w0;
		   float u0 = (float)((Sum[_top]-Sum[i])/(Num[_top]-Num[i]));
		   float u1 = (float)(Sum[i]/Num[i]);
		   float u = w0*u0 + w1*u1;
		   float g = w0*(u0 - u)*(u0 - u) + w1*(u1 - u)*(u1 - u);
		   if( g > max_otsu)
		   {
			   mbest = i;
			   max_otsu = g;
		   }
	   }
   }
   return mbest;
}
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;
	CvCapture *capture = cvCreateFileCapture("E:\\Motion\\IndoorGTTest2.avi");
	//CvCapture *capture = cvCreateCameraCapture(0);
	cvNamedWindow("src");
	cvNamedWindow("dst");
	cvNamedWindow("Imask1");
	cvNamedWindow("Imask2");
	cvNamedWindow("Imask3");
	//cvCreateTrackbar("T","dst",&T,255,0);
	while(mframe=cvQueryFrame(capture))
	{
	    DWORD start=GetTickCount();
		if(ncount>1000000000)
			ncount=100;
		ncount+=1;
        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);
		}
		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);
 
			//cvShowImage("Imask1",Imask1);
			//cvShowImage("Imask2",Imask2);
           
			int mbest1 = otsu(Imask1);
			cvSmooth(Imask1, Imask1, CV_MEDIAN);
			cvThreshold(Imask1,Imask1,mbest1, 255, CV_THRESH_BINARY);

			int mbest2 = otsu(Imask2);
			cvSmooth(Imask2,Imask2,  CV_MEDIAN);
			cvThreshold(Imask2,Imask2,mbest2, 255, CV_THRESH_BINARY);
            
			cout<<mbest1<<" "<<mbest2<<endl;

		    cvAnd(Imask1,Imask2,Imask);

			/*cvErode(Imask, Imask);
			cvDilate(Imask,Imask);*/

			DWORD finish=GetTickCount();
           // cout<<finish-start<<"ms"<<endl;
           
			cvShowImage("src",image2);
			cvShowImage("dst",Imask);
		}
        char c = cvWaitKey(30);
		if(c==27)
			break;
	}

	return 0;
}


具體可參考論文:《一種基於OpenCV實現的三幀差分運動目標檢測算法研究》。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章