文章目錄
作者:馬寧
我們的Kinect SDK開發開始漸入佳境了,Skeleton Tracking(骨骼追蹤)是Kinect的核心技術,正因為有了這項技術,很多有趣的功能才得以實現。
首先,我們來看一下骨骼追蹤的具體實現。Kinect最多可以追蹤20個骨骼點,而且目前只能追蹤人體,其他的物體或者動物就無能為力了。介紹了Kinect骨骼點的分布情況:
初始化代碼
接下來,我們來看一下骨骼追蹤的代碼是如何編寫的。首先,我們要建立一個新的Visual C#的工程,叫做“SkeletonTracking”,添加Kinect程式集和Coding4Fun程式集的工作,可以參考上一篇“Kinect for Windows SDK開發初體驗(二)操作Camera”的內容,在這裡不再重複。
首先我們還是建立Runtime對象,在初始化時,指定UseSkeletalTracking的RuntimeOptions,然後在SkeletonFrameReady事件中添加處理函數。
Runtime nui; private void Window_Loaded(object sender, RoutedEventArgs e){nui = new Runtime();nui.Initialize(RuntimeOptions.UseSkeletalTracking); nui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(nui_SkeletonFrameReady);}
接下來,表單關閉時的事件處理函數:
private void Window_Closed(object sender, EventArgs e){nui.Uninitialize();}
如果這個時候,我們在空的nui_SkeletonFrameReady事件處理函數中,添加一個斷點:
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) {}
正確串連Kinect裝置,並且站在Kinect前,讓Kinect能夠正確識別人體時,SkeletonFrameReady事件將被觸發。
我們可以通過看到返回的事件處理參數,其中比較重要的是SkeletonFrame和Skeletons兩個對象。
添加代碼
接下來,我們要準備WPF的介面,在介面上添加五個小球,來跟蹤頭部、雙手和膝蓋的位置。在MainPage.xaml中,添加下列代碼:
<Canvas Name="MainCanvas"><Ellipse Canvas.Left="0" Canvas.Top="0" Height="50" Name="headEllipse" Stroke="Black" Width="50" Fill="Orange" /><Ellipse Canvas.Left="50" Canvas.Top="0" Height="50" Name="rightEllipse" Stroke="Black" Width="50" Fill="SlateGray" /><Ellipse Canvas.Left="100" Canvas.Top="0" Fill="SpringGreen" Height="50" Name="leftEllipse" Stroke="Black" Width="50" /><Ellipse Canvas.Left="150" Canvas.Top="0" Height="50" Name="KneeRightEllipse" Stroke="Black" Width="50" Fill="Salmon" /><Ellipse Canvas.Left="200" Canvas.Top="0" Fill="Navy" Height="50" Name="KneeLeftEllipse" Stroke="Black" Width="50" /></Canvas>
然後,我們在SkeletonFrameReady事件處理函數中添加捕捉SkeletonData的方法:
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) {SkeletonFrame allSkeletons = e.SkeletonFrame;//get the first tracked skeletonSkeletonData skeleton = (from s in allSkeletons.Skeletonswhere s.TrackingState == SkeletonTrackingState.Trackedselect s).FirstOrDefault();}
我們使用了LINQ來擷取TrackingState等於Tracked的SkeletonData資料。在SkeletonData對象的Joints屬性集合中儲存了所有骨骼點的資訊。每個骨骼點的資訊都是一個Joint對象,其中的Position的X、Y、Z表示了三維位置。其中X和Y的範圍都是-1到1,而Z是Kinect到識別物體的距離。
我們可以用下面的代碼,將Joint的位置縮放到合適的比例:
Joint j = skeleton.Joints[JointID.HandRight].ScaleTo(640, 480, .5f, .5f);
最後兩個參數為原始大小的最大值和最小值,上面的語句相當於將-0.5到0.5的範圍擴大為0到640的範圍。
我們封裝了一個函數,將擷取到的SkeletonData資料,轉換為螢幕上的某一個圓圈:
private void SetEllipsePosition(FrameworkElement ellipse, Joint joint) { var scaledJoint = joint.ScaleTo(640, 480, .5f, .5f);Canvas.SetLeft(ellipse, scaledJoint.Position.X);Canvas.SetTop(ellipse, scaledJoint.Position.Y); }
最後,我們SkeletonFrameReady事件的處理方法會是這樣的:
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) {SkeletonFrame allSkeletons = e.SkeletonFrame;//get the first tracked skeletonSkeletonData skeleton = (from s in allSkeletons.Skeletonswhere s.TrackingState == SkeletonTrackingState.Trackedselect s).FirstOrDefault();SetEllipsePosition(headEllipse, skeleton.Joints[JointID.Head]); SetEllipsePosition(leftEllipse, skeleton.Joints[JointID.HandLeft]); SetEllipsePosition(rightEllipse, skeleton.Joints[JointID.HandRight]);SetEllipsePosition(KneeLeftEllipse, skeleton.Joints[JointID.KneeLeft]);SetEllipsePosition(KneeRightEllipse, skeleton.Joints[JointID.KneeRight]);}
最後,程式啟動並執行效果如下,貌似膝蓋的識別還是有些問題:
程式運行時,我們會發現小球運動時會有跳動的問題,為了減少這種情況,我們要設定SkeletonEngine引擎的TransformSmooth屬性為true,並指定TransformSmoothParameters參數,根據應用的具體情況,該參數也應該被適當微調。
添加代碼後的Load函數,代碼如下:
private void Window_Loaded(object sender, RoutedEventArgs e){nui = new Runtime();nui.Initialize(RuntimeOptions.UseSkeletalTracking); //Must set to true and set after call to Initializenui.SkeletonEngine.TransformSmooth = true;//Use to transform and reduce jittervar parameters = new TransformSmoothParameters{Smoothing = 0.75f,Correction = 0.0f,Prediction = 0.0f,JitterRadius = 0.05f,MaxDeviationRadius = 0.04f};nui.SkeletonEngine.SmoothParameters = parameters;nui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(nui_SkeletonFrameReady);}
寫到最後
到這裡, Kinect最精華的部分“骨骼追蹤”已經介紹給大家了,大家可以去寫一些有趣的應用了。接下來,我們會介紹另外一個Kinect的核心功能——Depth Data,景深資料。
OpenXLive杯Windows Phone遊戲開發大賽
OpenXLive杯Windows Phone遊戲開發大賽,是由OpenXLive聯合國內知名的開發人員社區:DevDiv、智機網、WPMind、Silverlight銀光中國和XNA遊戲世界,一起舉辦的針對Windows Phone遊戲開發的比賽。
http://www.openxlive.net/posts/news/40