上篇文章介紹了Kinect開發的環境配置,這篇文章和下一篇文章將介紹Kinect開發的基本知識,為深入研究Kinect for Windows SDK做好基礎。
每一個Kinect應用都有一些基本元素。應用程式必須探測和發現連結到裝置上的Kinect感應器。在使用這些感應器之前,必須進行初始化,一旦初始化成功後,就能產生資料,我們的程式就能處理這些資料。最後當應用程式關閉是,必須合理的釋放這些感應器。
本文第一部分將會介紹如何探測初始化幾釋放感應器,這是非常基礎的話題,但是對於基於Kinect開發的應用程式非常重要。一旦初始化好了之後,Kinect的各種感應器就能夠產生資料。我們的程式可以讀取這些資料流。Kinect產生的資料流類類似於System.IO命名空間下面的IO資料流。
第二部分將詳細介紹資料流的基礎,並示範如何從Kinect中使用ColorImageStream擷取彩色網路攝影機產生的資料。資料流能夠生產基於像素的資料,使得能夠像從相機或者基本的相片那樣生產彩色映像。可以對這些資料進行各種有趣的處理。
本文是整個Kinect SDK開發的基礎部分,瞭解了這些之後,對於熟悉SDK中其他部分比較有協助。
1. Kinect感應器
基於Kinect開發的應用程式最開始需要用到的對象就是KinectSensor對象,該對象直接表示Kinect硬體裝置。KinectSensor對象是我們想要擷取資料,包括彩色影像資料,景深資料和骨骼追蹤資料的源頭。本文將詳細介紹ColorImageStream,後面的文章將詳細討論DepthImageStream和SkeletonStream。
從KinectSensor擷取資料最常用的方式是通過監聽該對象的一系列事件。每一種資料流都有對應的事件,當改類型資料流可用時,就會觸發改時間。每一個資料流以幀(frame)為單位。例如:ColorImageStream當擷取到了新的資料時就會觸發ColorFrameReady事件。當在討論各個具體的感應器資料流是我們將會詳細討論這些事件。
每一種資料流(Color,Depth,Skeleton)都是以資料點的方式在不同的座標系中顯示的,在後面的討論中我們能夠清楚的看到這一點。將一個資料流中的點資料轉換到另一個資料流中是一個很常見的操作,在本文的後面將會討論如何轉換以及為什麼這種轉換很有必要。KinectSensor對象有一些列的方法能夠進行資料流到資料點陣的轉換,他們是MapDepthToColorImagePoint,MapDepthToSkeletonPoint以及MapSkeletonPointToDepth。在擷取Kinect資料前,我們必須先發現串連的Kinect裝置。發現Kinect裝置很簡單,但是也有需要主注意的地方。
1.1 發現串連的Kinect裝置
KinectObject對象沒有公用的構造器,應用程式不能直接建立它。相反,該對象是SDK在探測到有串連的Kinect裝置時建立的。當有Kinect裝置串連到電腦上時,應用程式應該得到通知或者提醒。KinectSeneor對象有一個靜態屬性KinectSensors,該屬性是一個KinectSensorCollection集合,該集合繼承自ReadOnlyCollection,ReadOnlyCollection集合很簡單,他只有一個索引器和一個稱之為StatusChanged的事件。
使用集合中的索引器來擷取KinectSensor對象。集合中元素的個數就是Kinect裝置的個數。也就是說,一台電腦上可以串連多個Kinect裝置來從不同的方向擷取資料。應用程式可以使用多個Kinect裝置來擷取多方面的資料,Kinect個數的限制 只有電腦配置的限制。由於每個Kinect是通過USB來進行資料轉送的,所以每一個Kinect裝置需要一條USB線與電腦相連。此外,更多的Kinect裝置需要更多的CPU和記憶體消耗。
尋找Kinect裝置可以通過簡單的遍曆集合找到;但是KinectSensor集合中的裝置不是都能直接使用,所以KinectSensor對象有一個Status屬性,他是一個枚舉類型,標識了當前Kinect裝置的狀態。下表中列出了感應器的狀態及其含義:
只有裝置在Connected狀態下時,KinectSensor對象才能初始化。在應用的整個生命週期中,感應器的狀態可能會發生變化,這意味著我們開發的應用程式必須監控裝置的串連狀態,並且在裝置串連狀態發生變化時能夠採取相應的措施來提高使用者體驗。例如,如果串連Kinect的USB線從電腦拔出,那麼感應器的串連狀態就會變為Disconnected,通常,應用程式在這種情況下應該暫停,並提示使用者將Kinect裝置插入到電腦上。應用程式不應該假定在一開始時Kinect裝置就處於可用狀態,也不應該假定在整個程式啟動並執行過程中,Kinect裝置會一直與電腦串連。
下面,首先建立一個WPF應用程式來展示如何發現,擷取Kinect感應器的狀態。先建按一個WPF項目,並添加Microsoft.Kinect.dll。在MainWindows.xaml.cs中寫下如下代碼:
public partial class MainWindow : Window{ //私人Kinectsensor對象 private KinectSensor kinect; public KinectSensor Kinect { get { return this.kinect;} set { //如果帶賦值的感應器和目前的不一樣 if (this.kinect!=value) { //如果當前的感測對象不為null if (this.kinect!=null) { //uninitailize當前對象 this.kinect=null; } //如果傳入的對象不為空白,且狀態為串連狀態 if (value!=null&&value.Status==KinectStatus.Connected) { this.kinect=value; } } } } public MainWindow() { InitializeComponent(); this.Loaded += (s, e) => DiscoverKinectSensor(); this.Unloaded += (s, e) => this.kinect = null; } private void DiscoverKinectSensor() { KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged; this.Kinect = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected); } private void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e) { switch (e.Status) { case KinectStatus.Connected: if (this.kinect == null) this.kinect = e.Sensor; break; case KinectStatus.Disconnected: if (this.kinect == e.Sensor) { this.kinect = null; this.kinect = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected); if (this.kinect == null) { //TODO:通知用於Kinect已拔出 } } break; //TODO:處理其他情況下的狀態 } }}