上一回簡單瞭解Kinect的用途,以及Kinect v2帶來的進步有哪些後
這一篇要開始著手開發Kinect v2的程式
由於自己主要還是在visual studio下進行開發
因此本篇會從SDK安裝與Visual Studio 2012的專案設定開始
到透過OF去完成簡單的Demo
這一篇要開始著手開發Kinect v2的程式
由於自己主要還是在visual studio下進行開發
因此本篇會從SDK安裝與Visual Studio 2012的專案設定開始
到透過OF去完成簡單的Demo
以下的設定與作法,主要都是筆者參考SDK中C++的範例依樣畫葫蘆
另外OF的部份,其實ofxAddons上有一個ofxKinectV2的add-on
另外OF的部份,其實ofxAddons上有一個ofxKinectV2的add-on
但使用上就是會出一些問題導致無法Compile,所以才決定從原生的SDK寫
因此建議同樣為OF的用戶,可以先嘗試看看ofxKinectV2喔
主要的材料:
- Windows 8以上版本的電腦 x 1
- USB 3.0孔 x 1
- Kinect v2 x 1
- Kinect for Windows SDK 2.0 x 1 [載點]
配料:
- Visual Studio 2012 x 1 (官方說法是要VS2012以上才行)
- Openframeworks 0.8.1 x 1 (其實只用到Display的部份)
環境配製:
=Kinect for Windows SDK=
在安裝好Kinect SDK 2.0以後,應該就能在應用程式中找到SDK Browser 2.0、Kinect Studio 2.0、Visual Gesture Builder
SDK Browser 2.0就跟Kinect SDK 1.x的時候一樣,有許多的C#與C++的Demo可以參考
Kinect Studio 2.0的介面改了不少,可以在此軟體中測試Kinect大部分的功能,也可以將這些資訊錄製成檔案
Visual Gesture Builder...目前還沒碰過
此外,可以去環境變數中檢查一下,是否有"KINECTSDK20_DIR"這個項目
Visual Gesture Builder...目前還沒碰過
此外,可以去環境變數中檢查一下,是否有"KINECTSDK20_DIR"這個項目
=Visual Studio 2012=
隨便新增一個Openframeworks的專案,不需要任何Addon。
首先設定Include的部分,個人是習慣設在[C/C++]>[一般]>[其他Include目錄],當然也可以選擇VC++目錄
設定的目錄為:
$(KINECTSDK20_DIR)\inc
設定完的樣子如下,別忘記Debug跟Release都要設定喔
再來是Linker的部分,位置在[連結器]>[一般]>[其他程式庫目錄]
設定的目錄為:
$(KINECTSDK20_DIR)\lib\x86;
後面"x86"部分根據你Visual Studio 2012在安裝時的版本而定,若是裝64bits則改為x64
然後再[連結器]>[輸入]>[其他相依性]中,加入:
kinect20.lib
設定完的樣子如下,一樣別忘記Debug跟Release都要設定喔
到此,就可以到你的ofApp.h試著加入
#include <Kinect.h>
如果Compile順利通過的話,就表示你的環境設定已經沒問題嘍!
=Kinect v2 Depth Demo=
環境設定都完成後,該是來寫寫第一支程式的時候了
Document的部份可以在SDK Browser 2.0中找到,懶得找的可以點開這裡。
不免俗的,第一支程式當然要把最重要的Depth Map的拿到手再說
在正式開始寫之前,先簡單以Openframeworks的角度來理解的流程:
在正式開始寫之前,先簡單以Openframeworks的角度來理解的流程:
上面的圖表只是以Depth Frame作為翻例,事實上無論是Body Frame、Body Index Frame、IR Frame、Color Frame
用法上都是大同小異的!
接下來就直接看程式碼吧,首先是標頭檔的部份:
ofDepthDemo.h:
1: #pragma once
2: #include "ofMain.h"
3: #include <Kinect.h>
4: class ofDepthDemo : public ofBaseApp{
5: public:
6: void setup();
7: void update();
8: void draw();
9: void exit();
10: private:
11: bool InitialKinectV2();
12: void UpdateKinectV2();
13: private:
14: ofImage _Display;
15: //Base Kinect componer
16: IKinectSensor* _pKinectSensor;
17: //Kinect reader
18: IDepthFrameReader* _pDepthFrameReader;
19: };
所使用到的特殊物件只有16行IKinectSensor以及18行IDepthFrameReader
一個是用來取得Kinect Sensor,另一個則是讀取Depth Map
至於_Display則是用來在OF上顯示Depth Map用
程式檔的部份,就針對其中兩個主要的InitialKinectV2()以及UpdateKinectV2():
ofDepthDemo.cpp ─ InitialKinectV2()
就跟其他Windows for C++的API一樣,用call by address的方式去取得資料
return的部分大多都是回傳HRESULT,並透過FAILED & SUCCEEDED來去檢查是否正確
特別注意pDepthFrameSource_,因為後續並沒有再使用所以使用區域變數
因此在取得_pDepthFrameReader後,就將其release
ofDepthDemo.cpp ─ UpdateKinectV2()
(首先要先承認我偷懶,沒有每一個都用HRESULT去判斷是否成功XD)
14~28:取得資料
透過IFrameDescription*可以取得一個Frame的基本資訊
除了24, 25行的width與height外,還有像是Diagonal FOV等資訊,不過這裡用不到就是了
30~40:資料處裡:
DepthFrame的資料跟Kinect v1一樣,是儲存在unsigned short裡頭(0~65535)。
為了顯示為灰階圖,得將其降unsigned char的數值(0~255)。
方法很簡單,先轉為0.0~1.0在乘上255即可!因此就得取得他的最大最小值來將他轉為0.0~1.0。
(如果懶的話,最大值可以直接採用unsigned short的最大值65535)
唯一跟OF有關的部份就是如何存在ofImage當中了
由於ofImage無法直接更動每個byte,所以是由ofPixels存好值後,再透過setFromPixels轉存到為ofImage中
※不要忘記在exit()中要把_pKinectSensor以及_pDepthFrameReader做release喔
=============分隔線==============
以上就是這次的環境配置與第一支程式
其實絕大部分都跟Kinect v1時期差不多。(個人覺得比OpenNI 2.0包裝得更好)
下一篇的目標是Body Index Frame以及Body Frame
也到了長頸鹿該出現的時候了!!
一個是用來取得Kinect Sensor,另一個則是讀取Depth Map
至於_Display則是用來在OF上顯示Depth Map用
程式檔的部份,就針對其中兩個主要的InitialKinectV2()以及UpdateKinectV2():
ofDepthDemo.cpp ─ InitialKinectV2()
1: bool ofDepthDemo::InitialKinectV2()
2: {
3: HRESULT hr_;
4: hr_ = GetDefaultKinectSensor(&_pKinectSensor);
5: if(FAILED(hr_)){
6: ofLog(OF_LOG_ERROR, "Get Kinect sensor failed!");
7: return false;
8: }
9: if(_pKinectSensor){
10: hr_ = _pKinectSensor->Open();
11: //Depth
12: IDepthFrameSource* pDepthFrameSource_ = nullptr;
13: if(SUCCEEDED(hr_)){
14: hr_ = _pKinectSensor->get_DepthFrameSource(&pDepthFrameSource_);
15: }
16: if(SUCCEEDED(hr_)){
17: hr_ = pDepthFrameSource_->OpenReader(&_pDepthFrameReader);
18: }
19: if(pDepthFrameSource_ != nullptr){
20: pDepthFrameSource_->Release();
21: }
22: }
23: if(!_pKinectSensor || FAILED(hr_)){
24: ofLog(OF_LOG_ERROR, "Initial failed!");
25: return false;
26: }else{
27: return true;
28: }
29: }
就跟其他Windows for C++的API一樣,用call by address的方式去取得資料
return的部分大多都是回傳HRESULT,並透過FAILED & SUCCEEDED來去檢查是否正確
特別注意pDepthFrameSource_,因為後續並沒有再使用所以使用區域變數
因此在取得_pDepthFrameReader後,就將其release
ofDepthDemo.cpp ─ UpdateKinectV2()
1: void ofDepthDemo::UpdateKinectV2()
2: {
3: if (!_pDepthFrameReader)
4: {
5: return;
6: }
7:
8: HRESULT hr_;
9: IDepthFrame* pDepthFrame_ = nullptr;
10:
11: hr_ = _pDepthFrameReader->AcquireLatestFrame(&pDepthFrame_);
12: if (SUCCEEDED(hr_))
13: {
14: //Get the depth information
15: UINT iDepthBufferSize_ = 0;
16: UINT16 *pDepthBuffer_ = nullptr;
17: int iDepthWidth_ = 0;
18: int iDepthHeight_ = 0;
19: USHORT usMinDepth_ = 0;
20: USHORT usMaxDepth_ = USHRT_MAX;
21:
22: IFrameDescription* pDepthFrameDescription_ = nullptr;
23: pDepthFrame_->get_FrameDescription(&pDepthFrameDescription_);
24: pDepthFrameDescription_->get_Width(&iDepthWidth_);
25: pDepthFrameDescription_->get_Height(&iDepthHeight_);
26: pDepthFrame_->get_DepthMinReliableDistance(&usMinDepth_);
27: pDepthFrame_->get_DepthMaxReliableDistance(&usMaxDepth_);
28: pDepthFrame_->AccessUnderlyingBuffer(&iDepthBufferSize_, &pDepthBuffer_);
29:
30: //Process depth infomation
31: ofPixels TmpDisplay_;
32: TmpDisplay_.allocate(iDepthWidth_, iDepthHeight_, ofImageType::OF_IMAGE_GRAYSCALE);
33: unsigned char * acDisplay_ = TmpDisplay_.getPixels();
34:
35: for(int iBufferIndex_ = 0; iBufferIndex_ < iDepthBufferSize_; iBufferIndex_++)
36: {
37: acDisplay_[iBufferIndex_] = 0xff * (float)pDepthBuffer_[iBufferIndex_] / usMaxDepth_; //Intensity
38: }
39:
40: _Display.setFromPixels(acDisplay_, iDepthWidth_, iDepthHeight_, OF_IMAGE_GRAYSCALE);
41: }
42: //Release frame
43: if(pDepthFrame_ != nullptr)
44: {
45: pDepthFrame_->Release();
46: }
47: }
(首先要先承認我偷懶,沒有每一個都用HRESULT去判斷是否成功XD)
14~28:取得資料
透過IFrameDescription*可以取得一個Frame的基本資訊
除了24, 25行的width與height外,還有像是Diagonal FOV等資訊,不過這裡用不到就是了
30~40:資料處裡:
DepthFrame的資料跟Kinect v1一樣,是儲存在unsigned short裡頭(0~65535)。
為了顯示為灰階圖,得將其降unsigned char的數值(0~255)。
方法很簡單,先轉為0.0~1.0在乘上255即可!因此就得取得他的最大最小值來將他轉為0.0~1.0。
(如果懶的話,最大值可以直接採用unsigned short的最大值65535)
唯一跟OF有關的部份就是如何存在ofImage當中了
由於ofImage無法直接更動每個byte,所以是由ofPixels存好值後,再透過setFromPixels轉存到為ofImage中
※不要忘記在exit()中要把_pKinectSensor以及_pDepthFrameReader做release喔
=============分隔線==============
以上就是這次的環境配置與第一支程式
其實絕大部分都跟Kinect v1時期差不多。(個人覺得比OpenNI 2.0包裝得更好)
下一篇的目標是Body Index Frame以及Body Frame
也到了長頸鹿該出現的時候了!!
作者已經移除這則留言。
回覆刪除哈囉,您好,我目前也在學KINECT V2體感程式設計,由於我專長不是寫程式這方面的,在書店、網路書城都找不到KINECT V2的參考書籍,請問您是否有KINECT V2的相關書籍可以推薦的,方便的話再請您推薦一下,由衷的謝謝您
回覆刪除Programming Kinect V2 For Windows
回覆刪除https://www.youtube.com/playlist?list=PL09RR9O9B-qVqPvNWXWcLxBe2oPrCswSZ