前段時間跟着實驗室師兄,做智能交通的項目,研究了一下opencv裏自帶的Blob_Tracking(塊追蹤)模塊,這裏記錄一下自己的收穫。
首先是從opencv裏面三個文檔裏開始作了解的,這三個文檔在opencv2.4.8\opencv\sources\doc\vidsurv裏面,分別是Blob_Tracking——Modules.doc、Blob_Tracking_Test.doc、TestSeq.doc。這三個文檔網上有很多資料,我也作一下自己的見解。
Blob_Tracking裏面介紹了塊追蹤所使用到的數據結構與類。塊處理的流程如下:
其中主要用到了兩個數據結構:CvBlob和CvBlobList。
CvBlob描述了一個目標塊的位置、大小和ID。
typedef struct CvBlob
{
float x,y; /* blob position */
float w,h; /* blob sizes */
int ID; /* blbo ID */
}CvBlob;
CvBlobList則是一個類,即一系列CvBlob的集合,可以是軌跡或者同一幀的目標塊。class CvBlobSeq
{
public:
CvBlobSeq(int BlobSize = sizeof(CvBlob));
virtual ~CvBlobSeq();
virtual CvBlob* GetBlob(int BlobIndex);
virtual CvBlob* GetBlobByID(int BlobID);
virtual void DelBlob(int BlobIndex);
virtual void DelBlobByID(int BlobID);
virtual void Clear();
virtual void AddBlob(CvBlob* pB);
virtual int GetBlobNum();
};
CvFGDetector:
class CvFGDetector
{
public:
virtual IplImage* GetMask() = 0;
/* process current image */
virtual void Process(IplImage* pImg) = 0;
/* release foreground detector */
virtual void Release() = 0;
};
前景檢測模塊CvFGDetector:它的輸入數據爲當前幀圖像,輸出結果數據爲當前幀圖像的前景圖像(mask)。前景圖像是一個和輸入的視頻幀具有同樣大小的二值圖像,即如果當前幀中的像素點被判斷爲運動前景,則前景掩碼中相應位置的像素點值爲1,否則,相應的像素點值爲0。
開發者需要繼承CvFGDetector類,並實現其中的純虛函數。其中在函數Virtual void process(IplImage *pImg){}中寫入自己開發的運動目標檢測算法。而函數Virtual IplImage *GetMask()是得到前景檢測的結果圖像,並負責傳遞到後續的模塊中。而函數Virtual void Release()負責一些動態分配內存的釋放。
CvBlobDetector:
class CvBlobDetector
{
public:
/* try to detect new blob entrance based on foreground mask */
/* pFGMask - image of foreground mask */
/* pNewBlobList - pointer to sequence to save new detected blobs */
/* pOldBlobList - pointer to blob list which already exist on image */
virtual int DetectNewBlob(IplImage* pFGMask, CvBlobSeq* pNewBlobList, CvBlobSeq* pOldBlobList) = 0;
/* return number of detected blobs */
/* release blob detector */
virtual void Release()=0;
};
新團塊檢測模塊CvBlobDetector:該模塊的作用是檢測進入監控範圍的新目標的位置和大小。模塊的輸入是當前幀的前景圖像(前景檢測模塊的結果)和已經檢測並標定的團塊,輸出的結果是新檢測到的團塊。
開發者可以將虛類實例化,然後將自己的新團塊檢測算法寫入到相應的函數中。
新團塊檢測模塊的處理流程爲:首先從前景圖像中檢測出所有團塊,然後將較小的團塊(可能是由噪聲引起的)和與已經被跟蹤團塊有重疊的團塊丟棄,並對剩餘的團塊按照大小順序排列,只保留其中幾個比較大的團塊(默認爲10)。最後利用特定規則篩選,篩選不合標準的團塊,將真正的新團塊保存到團塊列表中。
CvBlobTracker:
class CvBlobTracker
{
public:
/* Add new blob to track it and assign to this blob personal ID */
/* pBlob - pinter to structure with blob parameters (ID is ignored)*/
/* pImg - current image */
/* pImgFG - current foreground mask */
/* return pointer to new added blob */
virtual CvBlob* AddBlob(CvBlob* pBlob, IplImage* pImg, IplImage* pImgFG = NULL ) = 0;
/* return number of currently tracked blobs */
virtual int GetBlobNum() = 0;
/* return pointer to specified by index blob */
virtual CvBlob* GetBlob(int BlobIndex) = 0;
/* delete blob by its index */
virtual void DelBlob(int BlobIndex) = 0;
/* process current image and track all existed blobs */
virtual void Process(IplImage* pImg, IplImage* pImgFG = NULL) = 0;
/* release blob tracker */
virtual void Release() = 0;
/* return pinter to blob by its unique ID */
virtual int GetBlobIndexByID(int BlobID);
/* return pinter to blob by its unique ID */
virtual CvBlob* GetBlobByID(int BlobID);
/* delete blob by its ID */
virtual void DelBlobByID(int BlobID);
/* Set new parameters for specified (by index) blob */
virtual void SetBlob(int BlobIndex, CvBlob* pBlob);
/* Set new parameters for specified (by ID) blob */
virtual void SetBlobByID(int BlobID, CvBlob* pBlob);
};
團塊跟蹤模塊CvBlobTracker:該模塊的作用就是在前面兩個模塊(前景檢測模塊、新團塊檢測模塊)對運動目標檢測的基礎上,實現對運動目標的跟蹤。此模塊的輸入爲當前幀的前景圖像和團塊列表以及當前幀圖像,輸出結果是當前視頻幀中所有運動目標的信息,以團塊表示(ID,pos,size)。使用新團塊檢測模塊的結果初始化該模塊,並跟蹤新進入的團塊。
開發者根據自己的算法開發相應的跟蹤系統時,可以繼承該類,然後用自己的算法實現函數Virtural void process(IplImage *pImg,IplImage *pImgFG=NULL)。此虛類中還定義了許多其他的輔助處理函數接口,例如跟蹤索引或ID返回指定團塊指針的函數,根據索引或ID爲指定團塊設置參數函數等。
團塊跟蹤模塊的處理流程爲:首先從前景圖像提取所有團塊,並計算團塊的質心、寬度和高度;然後對每一個已被跟蹤的軌跡,利用卡爾曼濾波器預測該軌跡在當前幀的團塊的位置和大小;最後對每個跟蹤的軌跡進行處理,尋找離上一幀裏的團塊最近的當前幀的團塊,將此團塊添加到跟蹤軌跡。
CvBlobTrackerList:是Blob Tracking模塊中一個產生追蹤模塊的類,其中一個重要的參數是CvBlobTrackerOne,它們的關係爲:CvBlobTracker* cvCreateBlobTrackerList(CvBlobTrackerOne* (*create)());
CvBlobTrackerOne相當於一個指針。它生產一個軌跡的追蹤模塊,每來一幀,就會調用Process函數來估計模塊新的位置和大小,並返回到這個模塊。
class CvBlobTrackerOne
{
public:
virtual void Init(CvBlob* pBlobInit, IplImage* pImg, IplImage* pImgFG = NULL) = 0;
virtual CvBlob* Process(CvBlob* pBlobPrev, IplImage* pImg, IplImage* pImgFG = NULL) = 0;
virtual void Release() = 0;
};
CvBlobTrackGen:
class CvBlobTrackGen
{
public:
virtual void SetFileName(char* pFileName) = 0;
virtual void AddBlob(CvBlob* pBlob) = 0;
virtual void Process(IplImage* pImg = NULL, IplImage* pFG = NULL) = 0;
virtual void Release() = 0;
};
軌跡生成模塊CvBlobTrackGen:該模塊的作用是生成運動目標的運動軌跡,然後將軌跡導出到指定數據庫或文件中(如.txt、.csv文件)。該模塊的輸入是代表當前處理視頻幀中各個運動目標的團塊,輸出結果是存儲在指定位置下的軌跡文件。該模塊主要是保存操作,它收集所有團塊的位置,並在每條軌跡結束時(例如跟蹤丟失時或者物體離開場景時)將其保存到硬盤上,同時也可以爲每個團塊計算一些特徵並保存。
CvBlobTrackPostProc:
class CvBlobTrackPostProc
{
public:
virtual void AddBlob(CvBlob* pBlob) = 0;
virtual void Process() = 0;
virtual int GetBlobNum() = 0;
virtual CvBlob* GetBlob(int index) = 0;
virtual void Release() = 0;
/* additional functionality */
virtual CvBlob* GetBlobByID(int BlobID);
};
軌跡後處理模塊CvBlobTrackPostProc:該模塊的作用是在前一個模塊所產生的團塊軌跡上做一些處理,例如採用Kalman濾波或平滑濾波處理等。此模塊是可選的,可以不包含在處理流程中。它的輸入是當前處理圖像的所有團塊,輸出結果是處理後所處理圖像的團塊列表。
軌跡後處理模塊跟團塊跟蹤模塊一樣有CvBlobTrackPostProcList跟CvBolbtrackPostProcOne這兩個輔助類。
在代碼裏面還有,軌跡分析模塊CvBlobTrackAnalysis:當某個目標跟蹤結束後,會產生一個軌跡,CvBlobTrackAnalysis的子類用於對軌跡進行數據分析;
跟蹤流程模塊CvBlobTracterAuto:爲了方便開發者開發自己的系統,同時也爲了保證系統的模塊化設計,OpenCV設計了此虛類描述整個跟蹤流程,這個代表整個跟蹤流程的虛類將各個模塊相互聯繫起來成爲一個有機的整體。本模塊將前面提到的五個模塊連接起來,形成一個完整的處理流程。
此類中的函數Process負責調用其它各個子模塊,首先對背景圖像進行更新並檢測前景,將獲取的前景圖像保存於成員變量m_pFG中。獲取前景圖像後,便依次調用團塊跟蹤模塊(注意:而不是新團塊檢測模塊,這樣做的主要目的是先執行跟蹤可將當前幀的跟蹤結果傳入新團塊檢測模塊,以提供新團塊檢測的準確度。如果團塊跟蹤在後,則新團塊跟蹤模塊只能與上一幀的團塊列表進行比較,新團塊檢測的準確度將會有所降低),軌跡後處理模塊,團塊檢測模塊,軌跡生成模塊,軌跡分析模塊。
如果想將自己實現的算法加入到以上模塊中也很方便,如將背景差分算法加入到前景檢測模塊中,只要繼承CvFGDetector類,然後主要在Process函數中實現自己的算法就可以了。
原始代碼中,用紅色標註運動目標的表示跟蹤不穩定,綠色則表示穩定跟蹤。
軌跡生成模塊中默認有兩種方法實現數據的保存,其中一種是”RawTracks”方法,每行存放一個運動目標數據,單位爲像素,依次爲運動目標出現的起始幀,運動目標中心x座標,運動目標中心y座標,運動目標寬度,運動目標高度,運動目標中心x座標,運動目標中心y座標,運動目標寬度,運動目標高度,……。
模塊說明大部分來至參考文獻3,因爲我覺得作者理解得比我好,直接引用了,特此感謝該作者。以後還會做這方面的工作,有理解不對的地方以後更正,更歡迎大家爲我指出,謝謝!
參考文獻:
1.http://www.doc88.com/p-896576154875.html
2.http://blog.csdn.net/wk119911/article/details/7664478
3.http://blog.csdn.net/fengbingchun/article/details/7872325