(轉載請註明出處)
使用SDK: Kinect for Windows SDK v2.0 public preview
好了,真正正式進入SDK的學習當中。
同大多數Kinect相關的文章,第一個自然也是獲取它那1080P的彩色圖像。
值得說明的是,這次Kinect支持不同的程序使用同一個Kinect,至於有沒有壞處,
畢竟不是這方面的專家,不敢出狂言,只是隱約感覺到了一點蛋疼。
好了,可以使用上節給的模板創建項目了,需要簡單配置一下項目,選擇項目屬性後請按照圖中一樣設置
裏面的"KINECTSDK20_DIR"是一個環境變量,可以在系統屬性-高級-環境變量 裏邊查看/修改
再在stdafx.h裏面添加
#include <Kinect.h>
#pragma comment ( lib, "kinect20.lib" )
好了,COM組件是基於面向對象模型的接口,那麼Kinect的類是什麼呢,是KinectSensor,
比一代的NUISensor好點了。不過COM只提供了接口,於是叫做IKinectSensor。
使用
GetDefaultKinectSensor(IKinectSensor**)獲取一個默認的Kinect。如果有複數臺Kinect可以使用
GetKinectSensorCollection(IKinectSensorCollection** )進行枚舉,代碼大致如下
IKinectSensorCollection* pKinectCollection = nullptr;
IEnumKinectSensor* pEnumKinect = nullptr;
IKinectSensor* pKinect = nullptr;
// 獲取Kinect集合
HRESULT hr = ::GetKinectSensorCollection(&pKinectCollection);
// 獲取Kinect枚舉器
if (SUCCEEDED(hr)){
hr = pKinectCollection->get_Enumerator(&pEnumKinect);
}
// 枚舉Kinect
if (SUCCEEDED(hr)){
BOOLEAN available = false;
while (true){
// 獲取下一個
if (SUCCEEDED(pEnumKinect->GetNext(&pKinect))){
// 判斷有效性
pKinect->get_IsAvailable(&available);
if (available && YourJudgmentFunc(pKinect)){
break;
}
SafeRelease(pKinect);
}
else
break;
}
}
SafeRelease(pEnumKinect);
SafeRelease(pKinectCollection);
不過除了土豪和專家,誰用的起多臺
不過!等等!居然看到小寫的方法名:get_IsAvailable,夭壽啦,微軟居然有小寫開頭的方法,長這麼大第一次看到啊(筆者見識短,見諒)
是的,Kinect SDK中存在大量的get_開頭的方法,不過本人覺得Kinect的類太多了,雖然很好,但是效率與易用性會下降啊,
直接Kinect::GetColorFrameData也不錯,簡單粗暴。
IKinectSensor::Open() 紳士地打開傳感器
IKinectSensor::Close() 優雅地關閉傳感器
那麼怎麼獲取彩色幀呢,沒有一代那樣打開指定功能。
一代獲取彩色幀需要先說明“我要獲取彩色幀啦”,然後指定彩色幀格式。
二代設計上簡單了,直接獲取彩色幀相關對象幾個,目前還不能設置獲取分辨率。
本人估計爲了達到“多個程序使用一個Kinect”的效果,二代乾脆直接一股腦像扔垃圾一樣全扔過來了,
你要啥自己到地上撿,不需要像一代那樣開發票啦!
使用
IKinectSensor::get_ColorFrameSource(IColorFrameSource**)
獲取一個ColorFrameSource(彩色幀源)
再使用
IColorFrameSource::OpenReader(IColorFrameReader **)
打開一個ColorFrameReader(彩色幀讀取器)
再使用
IColorFrameReader::AcquireLatestFrame(IColorFrame**)
獲取彩色幀,有就返回S_OK,否則返回錯誤代碼
這個稱爲輪詢模式,有空的時候來問一下Kinect有沒有新的彩色幀,這個模式適合遊戲 ,
在每幀詢問一下,畢竟遊戲是每幀都要刷新的
還有一個稱爲事件模式,這個就適合其他一般程序啦。
Windows下使用WaitForSingleObject、WaitForMultipleObjects等待事件用於線程同步,
詳細可以參考其他文章,關鍵函數有CreatEvent, SetEvent, ResetEvent等。
這裏是用的是MsgWaitForMultipleObjects,這個函數不僅可以等待內核對象,還能對Windows消息進行響應,
當然,詳細的可以自行搜索一下。
MsgWaitForMultipleObjects(lengthof(events), events, FALSE, INFINITE, QS_ALLINPUT);
比如這裏用這個
event是個靜態數組,lengthof是個宏,定義如下,判斷靜態數組的長度
#define lengthof(a) (sizeof(a)/sizeof(*a))
當然,這裏事件只有一個,那就是彩色幀到達事件(下面簡稱彩色臨幀事件)
怎麼獲取呢?
在打開ColorFrameReader後不要急,IColorFrameReader::SubscribeFrameArrived(WAITABLE_HANDLE*)
獲取事件即可,使用時上邊的
events[0] = reinterpret_cast<HANDLE>(hColorFrameArrived)
強制轉換即可當彩色臨幀事件被觸發時,
IColorFrameReader::GetFrameArrivedEventData(WAITABLE_HANDLE, IColorFrameArrivedEventArgs**)
來獲取事件的數據
再使用
IColorFrameArrivedEventArgs::get_FrameReference(IColorFrameReference**)
獲取彩色幀引用
最後使用
IColorFrameReference::AcquireFrame(IColorFrame**)
獲取彩色幀
說到這裏,只想說: 我去,微軟你累不累。
這幾個類幾乎只有一個可用方法,完全可以合併啊
好了,這樣,事件與輪詢兩個模式終於同步了。
目前,彩色幀分辨率固定爲1920*1080,不過爲了保證以後能自行設置採樣分辨率,
所以應該獲取獲取的彩色幀分辨率
使用IColorFrame::get_FrameDescription獲取彩色幀描述,再利用這個描述獲取寬度與高度
自然還需要獲取源數據格式,我們需要的是BGRA格式,
使用IColorFrame::get_RawColorImageFormat檢查格式,如果是ColorImageFormat_Bgra後
可以直接使用
IColorFrame::AccessRawUnderlyingBuffer(UINT*, BYTE**)
獲取該幀數據地址與長度,BGRA順序的位圖。
如果不是BGRX格式的,可以用自帶的轉換方法進行轉換,不過這個方法需要自備緩衝區,
自己在構造函數裏面new[]一個就好了,記得在析構函數裏面釋放
自帶的方法是:
IColorFrame::CopyConvertedFrameDataToArray(UINT, BYTE*,ColorImageFormat)
然後就完事大吉,用自己想用的圖像接口顯示吧:
嗯,光線不是特別好,寢室很亂,見笑了
附加:
提供FPS顯示與鼠標縮放功能與顯示,詳細的請看範例,再根據例子講本工程補全吧。
還有就是不知道爲什麼有時15FPS,有時30FPS,簡直了...