[Kinect SDK] 獨樂樂不如眾樂樂 - 取得並顯示多個玩家的骨架資訊

  • 10790
  • 0
  • C#
  • 2013-07-15

有不少朋友問到關於處理多個玩家的骨架資料的問題,其實透過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,如下圖:

imageimage

完成後的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座標的程式碼,透過它來設定控制項的位置就行啦!! 就這麼簡單!!

 

這次的專案原始檔如下,請自行取用: