文章目錄
- Kinect開發環境
- 擷取RGB Camera資料
- 擷取Depth資訊
- 寫到最後
作者:馬寧
Kinect SDK出來之後,不到24小時,很多Geek們已經將自己的樣本發布到網上去了。可見,好東西肯定會被大家認可的,不好的東西投入再多的宣傳也沒用。
這一篇我們就要正式進入Kinect的編程世界了,介紹我們如何從Camera擷取映像資訊。先來介紹一下Kinect的整體結構,省得大家在後邊的介紹中被某些名詞弄暈。
Kinect一共有三個Camera,其中中間的一個是RGB Camera,用來擷取640x480的彩色映像,每秒鐘最多擷取30幀映像;兩側是兩個景深(3D Depth)感應器,用來檢測玩家的相對位置,原理和人眼立體成像是一樣的,不過這兩個感應器使用的是紅外線,所以說奧巴馬玩不了Kinect的人一定是居心叵測。Kinect兩側是麥克風,下邊還有一個可移動底座,用來調整Kinect的仰角。
Kinect開發環境
今天我們主要是操作RGB Camera和Depth Sensor,首先,我們要完成Kinect開發環境的配置:
第一步,建立WPF工程
開啟Visual Studio 2010,建立一個WPF工程,名叫KinectWpfDemo:
當然,由於Kinect SDK中包含基於.NET的程式集,除了WPF外,我們使用.NET WinForm或XNA架構都可以,目前還沒有人在Silverlight平台上實驗成功。
第二步,添加Kinect程式集的引用
在Solution Explorer中,按右鍵KinectWpfDemo,在右鍵菜單中選擇“Add Reference…”。在彈出的對話方塊中,我們在.NET標籤頁裡,選擇“Microsoft.Research.Kinect”程式集。如所示:
第三步,添加Coding4Fun Kinect Toolkit
這是一個可選項,不過為了之後的編程方便,建議大家添加一個。Coding4Fun Kinect Toolkit的:
http://c4fkinect.codeplex.com/
解壓縮後,一共有五個檔案,針對WinForm、WPF平台,還有一個Microsoft.Expression.Drawing.dll。我們通過Add Reference,將Coding4Fun.Kinect.Wpf.dll添加進來。
擷取RGB Camera資料
第四步,添加控制項
雙擊開啟MainWindow.xaml,在設計器中添加兩個Image控制項,一個用於顯示RGB映像,另一個用於顯示Depth資訊。
第五步,引用命名空間
開啟MainWindow.xaml.cs檔案,在檔案頭部添加對於Kinect對象的引用:
using Microsoft.Research.Kinect.Nui;using Microsoft.Research.Kinect.Audio;using Coding4Fun.Kinect.Wpf;
回到MainWindow.xaml的設計器中,在屬性視窗中選擇Event,找到Loaded和Closed兩個方法,分別雙擊,添加兩個事件的處理函數:
在MainWindow.xaml.cs檔案的MainWindow類中,聲明Runtime的變數:
Runtime nui;
然後,在Loaded事件的處理函數中添加Runtime初始化的代碼:
private void Window_Loaded(object sender, RoutedEventArgs e){nui = new Runtime();nui.Initialize(RuntimeOptions.UseColor| RuntimeOptions.UseDepth | RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);}
接下來是Closed事件中關閉Runtime的代碼:
private void Window_Closed(object sender, EventArgs e){nui.Uninitialize();}
Runtime對象是Kinect SDK中最主要的一個類,所有針對Kinect的操作都由Runtime類進行了封裝。Runtime的建構函式沒有接受任何參數,但有一個顯式的初始化函數Initialize,接受RuntimeOptions參數,指定調用Kinect的哪些功能。其中RuntimeOptions.UseColor表示使用RGB Camera,而RuntimeOptions.UseDepth則表示使用Depth感應器。
初始化工作完成之後,我們要通過RGB Camera來擷取即時的映像資料了。我們首先要聲明一個事件處理方法,來接收視頻資料的資訊:
nui.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_VideoFrameReady);
然後是事件處理函數:
void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e){PlanarImage imageData = e.ImageFrame.Image;image1.Source = BitmapSource.Create(imageData.Width, imageData.Height, 96, 96,PixelFormats.Bgr32, null, imageData.Bits, imageData.Width * imageData.BytesPerPixel);//image1.Source = e.ImageFrame.ToBitmapSource();}
提示:Getting Started上提供的Sample Code有誤,需要將最後一個參數中的data.Width改為imageData.Width才可以正常運行。
VideoFrameReady事件會傳遞一個ImageFrameReadyEventArgs參數給事件處理函數,其中的ImageFrame會包含關於圖片的各種資訊,比如Type變數指定了映像是來自RGB還是Depth,Resolution變數指定了解析度,而Image中以byte[]數組的方式儲存了映像的真實資料。
然後的工作就是根據PlanarImage中包括的資料來建立一個Bitmap對象,然後將其傳遞給Image控制項,顯示到WPF程式的介面上。
最後,我們還要在建構函式裡開啟視頻流,來擷取視頻資料:
nui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
第一個參數是ImageStreamType,用來指定開啟的裝置流類型;第二個參數是PoolSize,指定緩衝區的數量,至少為2,保證一個Buffer進行繪製,另一個Buffer進行資料填充;第三個參數指定Camera的解析度;第四個參數則是擷取的圖片類型。
顯示效果如所示:
上面的範例程式碼,沒有使用Coding4Fun的Helper類,如果使用的話,則代碼如下:
void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e){image1.Source = e.ImageFrame.ToBitmapSource();e.ImageFrame.ToBitmapSource().Save("catpure.jpg", ImageFormat.Jpeg);}
Helper類使用了C#的Extension Methods,為ImageFrame增加了一些轉換方法。我們還可以將映像儲存為檔案,考慮到檔案系統儲存的效率檔案,建議大家不用每張都存。
擷取Depth資訊
接下來我們要擷取Depth資訊了,過程與RGB Camera類似。首先要確保Runtime對象被初始化時,已經添加了RuntimeOptions.UseDepth的屬性,否則裝置無法正常開啟。
然後,添加擷取Depth資料的事件處理,並開啟Depth的資料流,這次的解析度是320x240:
nui.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_DepthFrameReady);nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.Depth);
下面是事件處理函數,在另外一個Image函數裡,顯示Depth映像:
void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e){image2.Source = e.ImageFrame.ToBitmapSource(); }
偷懶,所以使用了Coding4Fun的Helper類。程式啟動並執行效果如下:
寫到最後
這一篇中,我們完成了Kinect開發環境的配置、添加了Coding4Fun Kinect Toolkit、從RGB Camera和Depth Sensor中擷取了映像資訊。
接下來,我們就要進入Kinect動作捕捉部分了。