- #include <highgui.h>
- #include <cv.h>
- int main()
- {
- IplImage* pFrame=0;
- IplImage* pGrayImg=0;
- IplImage* pFGImg=0;
- IplImage* pBGImg=0;
- IplImage* pBGImg_Gray=0;
- IplImage* temp=0;
- CvCapture* cap = cvCreateCameraCapture(1);
- if(!(pFrame = cvQueryFrame(cap))) return -1;
- else
- {
- pFGImg = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 3);
- pGrayImg = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 1);
- temp = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 1);
- pBGImg_Gray = cvCreateImage(cvGetSize(pFrame), IPL_DEPTH_8U, 1);
- pBGImg = cvCloneImage(pFrame);
- }
- while(1){
- pFrame=cvQueryFrame(cap);
- cvShowImage("present",pFrame);
- cvShowImage("background",pBGImg);
- cvCvtColor(pFrame, pGrayImg, CV_BGR2GRAY);
- cvCvtColor(pBGImg, pBGImg_Gray, CV_BGR2GRAY);
- cvAbsDiff(pGrayImg, pBGImg_Gray, temp);
- cvThreshold(temp, temp, 40, 255, CV_THRESH_BINARY);
- cvZero(pFGImg);
- cvCopy(pFrame, pFGImg, temp);
- cvShowImage("foreground", pFGImg);
- int key=cvWaitKey(1);
- if(key==27)break;
- if(key=='b') cvCopyImage(pFrame, pBGImg);
- }
- cvReleaseCapture(&cap);
- }
程式碼解析
先宣告CvCapture、IplImage資料結構並先初始其資料,其程式碼執行方式為先擷取第一個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,也就是記憶體漏失,遺失的記憶體部分就變成垃圾空間,找不到位址存取它而程式也不能使用它,它也會永遠卡死在那邊直到程式關閉,在程式關閉前也不可能會有記憶體回收的動作,因為他是被認定為可存取的但是找不到指標位址。
沒有留言:
張貼留言