//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace Microsoft.Samples.Kinect.SkeletonBasics { using System.IO; using System.Windows; using System.Windows.Media; using Microsoft.Kinect; /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { /// /// Width of output drawing /// private const float RenderWidth = 640.0f; /// /// Height of our output drawing /// private const float RenderHeight = 480.0f; /// /// Thickness of drawn joint lines /// private const double JointThickness = 3; /// /// Thickness of body center ellipse /// private const double BodyCenterThickness = 10; /// /// Thickness of clip edge rectangles /// private const double ClipBoundsThickness = 10; /// /// Brush used to draw skeleton center point /// private readonly Brush centerPointBrush = Brushes.Blue; /// /// Brush used for drawing joints that are currently tracked /// private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68)); /// /// Brush used for drawing joints that are currently inferred /// private readonly Brush inferredJointBrush = Brushes.Yellow; /// /// Pen used for drawing bones that are currently tracked /// private readonly Pen trackedBonePen = new Pen(Brushes.Green, 6); /// /// Pen used for drawing bones that are currently inferred /// private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1); /// /// Active Kinect sensor /// private KinectSensor sensor; /// /// Drawing group for skeleton rendering output /// private DrawingGroup drawingGroup; /// /// Drawing image that we will display /// private DrawingImage imageSource; /// /// Initializes a new instance of the MainWindow class. /// public MainWindow() { InitializeComponent(); } /// /// Draws indicators to show which edges are clipping skeleton data /// /// skeleton to draw clipping information for /// drawing context to draw to private static void RenderClippedEdges(Skeleton skeleton, DrawingContext drawingContext) { if (skeleton.ClippedEdges.HasFlag(FrameEdges.Bottom)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(0, RenderHeight - ClipBoundsThickness, RenderWidth, ClipBoundsThickness)); } if (skeleton.ClippedEdges.HasFlag(FrameEdges.Top)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(0, 0, RenderWidth, ClipBoundsThickness)); } if (skeleton.ClippedEdges.HasFlag(FrameEdges.Left)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(0, 0, ClipBoundsThickness, RenderHeight)); } if (skeleton.ClippedEdges.HasFlag(FrameEdges.Right)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(RenderWidth - ClipBoundsThickness, 0, ClipBoundsThickness, RenderHeight)); } } /// /// Execute startup tasks /// /// object sending the event /// event arguments private void WindowLoaded(object sender, RoutedEventArgs e) { // Create the drawing group we'll use for drawing this.drawingGroup = new DrawingGroup(); // Create an image source that we can use in our image control this.imageSource = new DrawingImage(this.drawingGroup); // Display the drawing using our image control Image.Source = this.imageSource; // Look through all sensors and start the first connected one. // This requires that a Kinect is connected at the time of app startup. // To make your app robust against plug/unplug, // it is recommended to use KinectSensorChooser provided in Microsoft.Kinect.Toolkit (See components in Toolkit Browser). foreach (var potentialSensor in KinectSensor.KinectSensors) { if (potentialSensor.Status == KinectStatus.Connected) { this.sensor = potentialSensor; break; } } if (null != this.sensor) { // Turn on the skeleton stream to receive skeleton frames this.sensor.SkeletonStream.Enable(); // Add an event handler to be called whenever there is new color frame data this.sensor.SkeletonFrameReady += this.SensorSkeletonFrameReady; // Start the sensor! try { this.sensor.Start(); } catch (IOException) { this.sensor = null; } } if (null == this.sensor) { this.statusBarText.Text = Properties.Resources.NoKinectReady; } } /// /// Execute shutdown tasks /// /// object sending the event /// event arguments private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e) { if (null != this.sensor) { this.sensor.Stop(); } } /// /// Event handler for Kinect sensor's SkeletonFrameReady event /// /// object sending the event /// event arguments private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { Skeleton[] skeletons = new Skeleton[0]; using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame()) { if (skeletonFrame != null) { skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength]; skeletonFrame.CopySkeletonDataTo(skeletons); } } using (DrawingContext dc = this.drawingGroup.Open()) { // Draw a transparent background to set the render size dc.DrawRectangle(Brushes.Black, null, new Rect(0.0, 0.0, RenderWidth, RenderHeight)); if (skeletons.Length != 0) { foreach (Skeleton skel in skeletons) { RenderClippedEdges(skel, dc); if (skel.TrackingState == SkeletonTrackingState.Tracked) { this.DrawBonesAndJoints(skel, dc); } else if (skel.TrackingState == SkeletonTrackingState.PositionOnly) { dc.DrawEllipse( this.centerPointBrush, null, this.SkeletonPointToScreen(skel.Position), BodyCenterThickness, BodyCenterThickness); } } } // prevent drawing outside of our render area this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight)); } } /// /// Draws a skeleton's bones and joints /// /// skeleton to draw /// drawing context to draw to private void DrawBonesAndJoints(Skeleton skeleton, DrawingContext drawingContext) { // Render Torso this.DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter); this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderLeft); this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderRight); this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.Spine); this.DrawBone(skeleton, drawingContext, JointType.Spine, JointType.HipCenter); this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipLeft); this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipRight); // Left Arm this.DrawBone(skeleton, drawingContext, JointType.ShoulderLeft, JointType.ElbowLeft); this.DrawBone(skeleton, drawingContext, JointType.ElbowLeft, JointType.WristLeft); this.DrawBone(skeleton, drawingContext, JointType.WristLeft, JointType.HandLeft); // Right Arm this.DrawBone(skeleton, drawingContext, JointType.ShoulderRight, JointType.ElbowRight); this.DrawBone(skeleton, drawingContext, JointType.ElbowRight, JointType.WristRight); this.DrawBone(skeleton, drawingContext, JointType.WristRight, JointType.HandRight); // Left Leg this.DrawBone(skeleton, drawingContext, JointType.HipLeft, JointType.KneeLeft); this.DrawBone(skeleton, drawingContext, JointType.KneeLeft, JointType.AnkleLeft); this.DrawBone(skeleton, drawingContext, JointType.AnkleLeft, JointType.FootLeft); // Right Leg this.DrawBone(skeleton, drawingContext, JointType.HipRight, JointType.KneeRight); this.DrawBone(skeleton, drawingContext, JointType.KneeRight, JointType.AnkleRight); this.DrawBone(skeleton, drawingContext, JointType.AnkleRight, JointType.FootRight); // Render Joints foreach (Joint joint in skeleton.Joints) { Brush drawBrush = null; if (joint.TrackingState == JointTrackingState.Tracked) { drawBrush = this.trackedJointBrush; } else if (joint.TrackingState == JointTrackingState.Inferred) { drawBrush = this.inferredJointBrush; } if (drawBrush != null) { drawingContext.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(joint.Position), JointThickness, JointThickness); } } } /// /// Maps a SkeletonPoint to lie within our render space and converts to Point /// /// point to map /// mapped point private Point SkeletonPointToScreen(SkeletonPoint skelpoint) { // Convert point to depth space. // We are not using depth directly, but we do want the points in our 640x480 output resolution. DepthImagePoint depthPoint = this.sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(skelpoint, DepthImageFormat.Resolution640x480Fps30); return new Point(depthPoint.X, depthPoint.Y); } /// /// Draws a bone line between two joints /// /// skeleton to draw bones from /// drawing context to draw to /// joint to start drawing from /// joint to end drawing at private void DrawBone(Skeleton skeleton, DrawingContext drawingContext, JointType jointType0, JointType jointType1) { Joint joint0 = skeleton.Joints[jointType0]; Joint joint1 = skeleton.Joints[jointType1]; // If we can't find either of these joints, exit if (joint0.TrackingState == JointTrackingState.NotTracked || joint1.TrackingState == JointTrackingState.NotTracked) { return; } // Don't draw if both points are inferred if (joint0.TrackingState == JointTrackingState.Inferred && joint1.TrackingState == JointTrackingState.Inferred) { return; } // We assume all drawn bones are inferred unless BOTH joints are tracked Pen drawPen = this.inferredBonePen; if (joint0.TrackingState == JointTrackingState.Tracked && joint1.TrackingState == JointTrackingState.Tracked) { drawPen = this.trackedBonePen; } drawingContext.DrawLine(drawPen, this.SkeletonPointToScreen(joint0.Position), this.SkeletonPointToScreen(joint1.Position)); } /// /// Handles the checking or unchecking of the seated mode combo box /// /// object sending the event /// event arguments private void CheckBoxSeatedModeChanged(object sender, RoutedEventArgs e) { if (null != this.sensor) { if (this.checkBoxSeatedMode.IsChecked.GetValueOrDefault()) { this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated; } else { this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default; } } } } }