Kinect橋接OpenCV代碼簡介KinectBridge With OpenCV
Kinect
Bridge With MATLAB & OpenCV簡介文檔和項目下載
驅動版本:Kinect forWindows SDK v1.7
項目名稱:KinectBridgeWithOpenCVBasics-D2D
程式設計語言:C++
程式配置和運行
安裝程式後,在檔案夾KinectBridgeWithOpenCVBasics-D2D中看到KinectBridgeWithOpenCVBasics-D2D.docx這個文檔。文檔中只說了如何配置OpenCV環境變數等等之類的,使用OpenCV的孩紙一眼就明白了。這裡我還是使用自己常用的方法配置。(如果沒有配置過OpenCV的,請去opencv.org.cn去學習如何配置,初學者往往需要1個小時到1天才能學會,熟練後5分鐘)【你也可以按照微軟說的方法進行配置,微軟的方法雖然麻煩,但是一勞永逸!】
我是把OpenCV2.4.4安裝在F盤的Softs檔案夾下。使用VS2010進行配置。
在屬性頁面中--->VC++目錄:
包含目錄:
F:\Softs\OpenCV244\opencv\build\include
$(KINECTSDK10_DIR)\inc
庫目錄:
F:\Softs\OpenCV244\opencv\build\x86\vc10\lib
$(KINECTSDK10_DIR)\lib\x86
來源目錄:
F:\Softs\OpenCV244\opencv\modules\core\src
F:\Softs\OpenCV244\opencv\modules\imgproc\src
F:\Softs\OpenCV244\opencv\modules\highgui\src
在屬性頁面中--->連結器:
附加依賴項:
opencv_core244d.lib
opencv_imgproc244d.lib
opencv_highgui244d.lib
Kinect10.lib
comctl32.lib
全部配置完畢後,編譯F7,再執行Ctrl+F5。一點沒有問題(如果有問題是你的配置問題,不要留言,請去OpenCV論壇求救),得到以下運行映像(頭像被我用畫筆刷掉了):
程式簡要解讀
FrameRateTracker類
用於計算視訊框架率,使用clock()函數,每秒鐘會調整一次幀率顯示結果。
KinectHelper類
這個類的定義和實現都放在標頭檔中了。主要作用就是調用Kinect SDK中的函數,對Kinect進行初始化(開啟Kinect和各種資料流,更新彩色、深度映像資料幀和骨骼資料幀),使用事件對象進行同步。資料被存放在m_pColorBuffer,m_pDepthBuffer,m_skeletonFrame數組中。
OpenCVHelper類
用於對映像進行濾波(高斯模糊GaussianBlur,腐蝕erode,膨脹dilate,canndy邊緣檢測),把骨骼資料滑到彩色映像和深度映像中(line和circle方法)。
OpenCVFrameHelper類
KinectHelper的子類,把資料存放到OpenCV的Mat矩陣結構中(方法pImage->ptr<Vec4b>(y))。
=================================================================
MainWindow類
主程式。使用互斥鎖(CreateMutex)進行同步(他們以前的程式不進行同步),CreateMutex()函數可用來建立一個有名或無名的互斥量對象。
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全屬性的指標
BOOL bInitialOwner,// 初始化互斥對象的所有者
LPCTSTR lpName // 指向互斥對象名的指標);
傳回值
Long,如執行成功,就返回互斥體對象的控制代碼;零表示出錯。會設定GetLastError。即使返回的是一個有效控制代碼,但倘若指定的名字已經存在,GetLastError也會設為ERROR_ALREADY_EXISTS
參數表 參數 類型及說明
lpMutexAttributes SECURITY_ATTRIBUTES,指定一個SECURITY_ATTRIBUTES結構,或傳遞零值(將參數聲明為ByVal As Long,並傳遞零值),
表示使用不允許繼承的預設描述符。
bInitialOwner BOOL,如建立進程希望立即擁有互斥體,則設為TRUE。一個互斥體同時只能由一個線程擁有。是FALSE,表示剛剛建立的這個Mutex不屬於任何線程
也就是沒有任何線程擁有他,一個Mutex在沒有任何線程擁有他的時候,他是處於激發態的, 所以處於有訊號狀態。
lpName String,指定互斥體對象的名字。用vbNullString建立一個未命名的互斥體對象。如已經存在擁有這個名字的一個事件,則開啟現有的已命名互斥體。這個名字可能不與現有的事件、訊號機、可等待計時器或檔案對應相符該名稱可以有一個"Global\" 或"Local\" 首碼,明確地建立在全域或會話命名空間的對象。剩餘的名稱可以包含任何字元,除反斜線字元(\)。
產生方法:
m_hColorResolutionMutex =CreateMutex(NULL, FALSE, NULL);
微軟建立的所有的互斥鎖參數都一樣。表明,1使用不允許繼承的預設描述符,2剛剛建立的這個Mutex不屬於任何線程,3互斥體對象沒有名字。
調用方法:
WaitForSingleObject(m_hColorResolutionMutex,INFINITE);
m_colorResolution = NUI_IMAGE_RESOLUTION_640x480;
ReleaseMutex(m_hColorResolutionMutex);
從使用方法看,和臨界區的方法一模一樣。之所以使用這些同步方法(互斥鎖,臨界區)是因為有些變數(或稱為資源)會同時在多個線程中使用,為了避免資源使用衝突,使得多個線程排隊使用這個變數。凡是在多個線程中同時使用的變數,都需要為它們設定一個同步方法(如果變數太多,最好把它組合成一個變數結構)。
線程開始(Run函數中):
m_hProcessThread= CreateThread(NULL, 0, ProcessThread,
this, 0,NULL);
線程結束事件:
m_hProcessStopEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
主線程ProcessThread中使用while無限迴圈
四個事件對象(426行)
HANDLE hEvents[4]= {m_hProcessStopEvent(退出), 彩色, 深度, 骨骼};
等待某個核心對象被觸發(一共四個)
int eventId = WaitForMultipleObjects(numEvents,hEvents, FALSE, 100);
之後就針對不同情況進行處理。除了對退出(eventId==0)進行判斷,其它的都直接對所有資料進行更新,而不針對eventId的大小(1,2,3)而分別處理。這算是改進吧,其它的C++程式都改成這樣子的了,應該算變得簡單了。但這樣會導致每次只有1個函數是實際啟動並執行,另外二個是不啟動並執行。可以把我之前Kinect人臉跟蹤Kinect Face Tracking SDK文章中的if
(WAIT_OBJECT_0 == WaitForSingleObject(m_hNextDepthFrameEvent, 0))都去掉,程式一樣可以運行,但是會提示資料沒有捕獲到(三個資料不是同時都能擷取的,得排隊)。
在MainWindow中還可以看到OpenCV的Mat如何被使用的:
1.未經處理資料BYTE-->存放到m_pColorBuffer中(m_frameHelper.UpdateColorFrame())
2.m_pColorBuffer構建成m_colorMat結構(m_frameHelper.GetColorImage(&m_colorMat)),3.對m_colorMat進行各種濾波方法(m_openCVHelper.ApplyColorFilter(&m_colorMat))
4.最後把濾波後的畫出來(UpdateBitmap(&m_colorMat,&m_hColorBitmap, &m_bmiColor);底層又調用了SetDIBits(m_hdc, *phBitmap, 0, height,pImg->ptr(), pBmi, DIB_RGB_COLORS);)
5.最最後還需要重新整理螢幕地區(InvalidateRect(m_hWndMain, NULL, false);)
由於使用windows api建立表單,這個程式顯得很臃腫,一共3000行代碼(包含注釋和空行)。但依舊有很多可以學習的地方,特別是他們寫代碼都很精美。這個程式僅僅是把資料傳到OpenCV的結構中,並使用OpenCV的基本函數進行一些影像處理,最後再顯示出來,一年多前寫的文章代碼實現的就是這個原理。
如果你一直使用windows api顯示視窗,那麼很容入門。如果不是,那麼需要很多時間學習它(我一直用簡單的MFC作視窗)。微軟給的例子很強健,很穩定,考慮了許多情況。但如果想要自己實現更好的軟體,還是建議使用MFC吧。
可以直接在我前些天的文章Kinect人臉跟蹤Kinect Face Tracking SDK中做一些修改,即可得到OpenCV顯示的映像。也不知道有多少人使用MFC,如果人多的話,可以花時間寫一個簡單範例出來,更不知道Qt(VS2010中開發)是否可以進行顯示。