Kinect for Windows SDK v2.0 開發筆記 (二)彩色幀獲取

(轉載請註明出處)

使用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,簡直了...


本節範例下載

發佈了35 篇原創文章 · 獲贊 18 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章