2014年4月3日 星期四

Background Subtraction Using Mask

  1. #include <highgui.h>
  2. #include <cv.h>
  3. int main()
  4. {
  5.         IplImage* pFrame=0;
  6.         IplImage* pGrayImg=0;
  7.         IplImage* pFGImg=0;
  8.         IplImage* pBGImg=0;
  9.         IplImage* pBGImg_Gray=0;
  10.         IplImage* temp=0;
  11.         CvCapture* cap = cvCreateCameraCapture(1);
  12.  
  13.         if(!(pFrame = cvQueryFrame(cap))) return -1;
  14.         else
  15.         {
  16.                 pFGImg = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 3);
  17.                 pGrayImg = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 1);
  18.                 temp = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 1);
  19.                 pBGImg_Gray = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 1);
  20.                 pBGImg = cvCloneImage(pFrame);
  21.         }
  22.  
  23.         while(1){
  24.                 pFrame=cvQueryFrame(cap);
  25.                 cvShowImage("present",pFrame);
  26.                 cvShowImage("background",pBGImg);
  27.  
  28.                 cvCvtColor(pFrame, pGrayImg, CV_BGR2GRAY);
  29.                 cvCvtColor(pBGImg, pBGImg_Gray, CV_BGR2GRAY);
  30.                 cvAbsDiff(pGrayImg, pBGImg_Gray, temp);
  31.                 cvThreshold(temp, temp, 40, 255, CV_THRESH_BINARY);
  32.  
  33.                 cvZero(pFGImg);
  34.                 cvCopy(pFrame, pFGImg, temp);
  35.                 cvShowImage("foreground", pFGImg);
  36.        
  37.                 int key=cvWaitKey(1);
  38.                 if(key==27)break;
  39.                 if(key=='b') cvCopyImage(pFrame, pBGImg);
  40.  
  41.         }
  42.         cvReleaseCapture(&cap);
  43. }


程式碼解析

      先宣告CvCaptureIplImage資料結構並先初始其資料,其程式碼執行方式為先擷取第一個Frame作為背景,之後進入迴圈使用cvQueryFrame()不斷獲取Frame並顯示在螢幕,將獲取到的影像和背景藉由cvCvtColor()將輸入的影像從RGB色彩空間轉換成灰階影像,利用cvAbsDiff()做背景相減取出前景,再使用cvThreshold()將影像二元化。最後利用cvZero()cvCopy完成圖形遮罩的功能,將前景圖形開圖顯示於畫面,利用cvWaitKey()鍵盤事件設定功能,如果鍵盤按入'ESC'則程式就會結束並釋放記憶體,若鍵盤按下'b'則背景就會更新。


函示說明
cvAbsDiff()
cvAbsDiff(目前影像, 背景影像, 前景影像);
將當前的frame當作目前影像,而把已建置好的背景影像作為參數,兩個影像作相減並取絕對值得到前景。

cvZero()
cvZero(IplImage資料結構)
#define cvZero cvSetZero
IplImage資料結構中的imageData圖形空間像素全部設為0(黑色),這裡預先將pFGImg的背景底圖預設為黑色。

cvCopy()
cvCopy(來源影像, 輸出影像, 二值化遮罩);
Mask(遮罩)在影像處理是很重要的功能,是一種二值化圖片(Threshold Image),遮罩可以用來幫助擷取圖形物件(車牌,移動物體,膚色偵測)、圖形去背或是一些影像最佳化處理,利用這些二元圖片跟原始圖片做對應,白色255的部份為顯示出來的區域,黑色為0的部份則為不顯示出來的區域,也就是將白色的影像還原成圖片,OpenCV提供許多支援Mask功能的函式,cvCopy()即是其中一個。

cvCopyImage()
cvCopyImage(來源影像, 目的影像)
#define cvCopyImage(src, dst) cvCopy(src, dst, 0)

此函式使用方法類似於cvCopy(),只是他將mask參數值設定為0,這裡特別要提到cvCopyImage()cvCloneImage()的不同之處, cvCopyImage()只是複製值,並不會分配一個空間給賦值對象,但cvCloneImage()卻會在賦值的同時會分配一個新的空間給定義的變數,因此,cvCloneImage()只適合用於變數開始定義,最好不要使用在程式執行中間使用(特別是迴圈)。大部分的資料結構建立,都是跟作業系統借空間使用,對於未先釋放記憶體而任意配置空間進去會造成Memory Leak,也就是記憶體漏失,遺失的記憶體部分就變成垃圾空間,找不到位址存取它而程式也不能使用它,它也會永遠卡死在那邊直到程式關閉,在程式關閉前也不可能會有記憶體回收的動作,因為他是被認定為可存取的但是找不到指標位址。


沒有留言:

張貼留言