有不少朋友問到關於處理多個玩家的骨架資料的問題,其實透過Kinect for Windows SDK,搭配LINQ語法,要取得並顯示多個使用者的骨架資訊是非常簡單的喔!!
這篇文章就以KinectSkeletonApplication作為藍本,加上SoulSolutions.Kinect.Controls裡提供的SkeletonControl控制項,簡單的示範一下怎麼同時捕捉並顯示兩位玩家的骨架資訊吧!!
有不少朋友問到關於處理多個玩家的骨架資料的問題,其實透過Kinect for Windows SDK,搭配LINQ語法,要取得並顯示多個使用者的骨架資訊是非常簡單的喔!!
這篇文章就以KinectSkeletonApplication作為藍本,加上SoulSolutions.Kinect.Controls 裡提供的SkeletonControl控制項,簡單的示範一下怎麼同時捕捉並顯示兩位玩家的骨架資訊吧!!
首先我透過Blend來編輯KinectSkeletonApplication內建的MainWindow.xaml,把用來顯示頭和雙手的控制項移除,並且換上兩個SkeletonControl,如下圖:
完成後的MainWindow.xaml檔如下:
MainWindow.xaml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:SoulSolutions_Kinect_Controls_Skeleton="clr-namespace:SoulSolutions.Kinect.Controls.Skeleton;assembly=SoulSolutions.Kinect.Controls.Skeleton"
x:Class="Wpf_MultiUserSample.MainWindow" Title="MainWindow" Height="600" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.486*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Image x:Name="videoImage" Grid.ColumnSpan="2" />
<Border Margin="10" VerticalAlignment="Bottom" Background="#BF000000" Width="320" Height="240">
<Viewbox Height="274.826">
<SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl x:Name="skeletonPlayer1">
<SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl.Foreground>
<LinearGradientBrush EndPoint="1,1" MappingMode="RelativeToBoundingBox" StartPoint="0,0">
<GradientStop Color="Black" />
<GradientStop Color="Red" Offset="1" />
</LinearGradientBrush>
</SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl.Foreground>
</SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl>
</Viewbox>
</Border>
<Border Margin="10,0,10,10" VerticalAlignment="Bottom" Background="#BF000000" Grid.Column="1" Width="320"
Height="240">
<Viewbox Height="274.826">
<SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl x:Name="skeletonPlayer2">
<SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl.Foreground>
<LinearGradientBrush EndPoint="1,1" MappingMode="RelativeToBoundingBox" StartPoint="0,0">
<GradientStop Color="Black" />
<GradientStop Color="#FF0027FF" Offset="1" />
</LinearGradientBrush>
</SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl.Foreground>
</SoulSolutions_Kinect_Controls_Skeleton:SkeletonControl>
</Viewbox>
</Border>
</Grid>
</Window>
再來就是重頭戲的CodeBehind啦!!請直接看原始碼:
MainWindow.xaml.cs
using System;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Research.Kinect.Nui;
namespace Wpf_MultiUserSample
{
public partial class MainWindow : Window
{
Runtime runtime = new Runtime();
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler( MainWindow_Loaded );
this.Unloaded += new RoutedEventHandler( MainWindow_Unloaded );
runtime.VideoFrameReady += new EventHandler<Microsoft.Research.Kinect.Nui.ImageFrameReadyEventArgs>( runtime_VideoFrameReady );
runtime.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>( runtime_SkeletonFrameReady );
}
void runtime_SkeletonFrameReady( object sender , SkeletonFrameReadyEventArgs e )
{
SkeletonFrame skeletonSet = e.SkeletonFrame;
//取得Kinect捕捉到的玩家數量
int playersCount = ( from s in skeletonSet.Skeletons
where s.TrackingState == SkeletonTrackingState.Tracked
select s ).Count();
skeletonPlayer1.SkeletonData = ( from s in skeletonSet.Skeletons
where s.TrackingState == SkeletonTrackingState.Tracked
select s ).FirstOrDefault();
//如果捕捉到的玩家數是兩位,則顯示第二位玩家的骨架
if( playersCount == 2 )
{
//透過LINQ的ElementAt方法取得指定的元素(第二位玩家的SkeletonData)
skeletonPlayer2.SkeletonData = ( from s in skeletonSet.Skeletons
where s.TrackingState == SkeletonTrackingState.Tracked
select s ).ElementAt( 1 );
}
}
void MainWindow_Unloaded( object sender , RoutedEventArgs e )
{
runtime.Uninitialize();
}
void MainWindow_Loaded( object sender , RoutedEventArgs e )
{
//Since only a color video stream is needed, RuntimeOptions.UseColor is used.
runtime.Initialize( Microsoft.Research.Kinect.Nui.RuntimeOptions.UseColor | RuntimeOptions.UseSkeletalTracking );
//You can adjust the resolution here.
runtime.VideoStream.Open( ImageStreamType.Video , 2 , ImageResolution.Resolution640x480 , ImageType.Color );
}
void runtime_VideoFrameReady( object sender , Microsoft.Research.Kinect.Nui.ImageFrameReadyEventArgs e )
{
PlanarImage image = e.ImageFrame.Image;
BitmapSource source = BitmapSource.Create( image.Width , image.Height , 96 , 96 ,
PixelFormats.Bgr32 , null , image.Bits , image.Width * image.BytesPerPixel );
videoImage.Source = source;
}
}
}
當然,如果要處理更多玩家骨架的話也是做得到的喔!!只要輕鬆的透過LINQ語法就行啦(所以LINQ真的很重要!!)~
另外,也有朋友問到怎麼把特定的物件顯示在玩家的特定部位,關於這個需求,只要參考KinectSkeletonApplication中內建的玩家骨架轉為2D座標的程式碼,透過它來設定控制項的位置就行啦!! 就這麼簡單!!
這次的專案原始檔如下,請自行取用: