How to Track Skeleton Joins using Kinect

In this article I will demonstrate to you on how to track the Skeleton in Kinect.
Download

  Download source code for How to Track Skeleton Joins using Kinect

Introduction

This is the 3rd article that I have written this year about Kinect. In this article I’m going to introduce you to skeleton tracking.

Objective

The objective of this article is to demonstrate to you on how to track the skeleton in Kinect.

 

Types of Skeleton Tracking Modes

 

Standing (Default)

·       This is the default tracking mode, it tracks all the joints.

·       This mode tracks 20 skeleton joints, reporting their position as "tracked" or "inferred"     


Seated

·       The seated mode only tracks the ten upper-body joints (shoulders, elbows, wrists, arms and head).


Where do I Start

Create a WPF application as I have explained in the previous articles and make sure your xaml looks like this 

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:Toolbox="clr-namespace:Kinect.Toolbox;assembly=Kinect.Toolbox"x:Class="WpfApplication1.MainWindow"

        Title="MainWindow" Height="514.656" Width="782.122">

 

 

    <Grid>

        <TextBlock x:Name="Message"  HorizontalAlignment="Center" VerticalAlignment="Top" Height="30" Background="Green" Foreground="Red" Margin="0,0,0,462.8" />

 

        <Image Name="Image" Margin="68,27,72,2.8"/>

    </Grid>

 

</Window>

And your code should look like this, I have commented the code, to explain each part or line what it is responsible for. 

This avoids the part that I need to explain between the codes.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows;

using System.Windows.Media;

using Microsoft.Kinect;

 

namespace WpfApplication1

{

    /// <summary>

    /// Interaction logic for MainWindow.xaml

    /// </summary>

    public partial class MainWindow : Window

    { 

      /// There can be more than one sensors connected, for now take the first one

        KinectSensor sensor = KinectSensor.KinectSensors[0];

 

        #region "Variables"

        /// <summary>

        /// Thickness of body center ellipse

        /// </summary>

        private const double BodyCenterThickness = 10;

 

        /// <summary>

        /// Thickness of clip edge rectangles

        /// </summary>

        private const double ClipBoundsThickness = 10;

 

        /// <summary>

        /// Brush used to draw skeleton center point

        /// </summary>

        private readonly Brush centerPointBrush = Brushes.Blue;

 

        /// <summary>

        /// Brush used for drawing joints that are currently tracked

        /// </summary>

        private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68));

 

        /// <summary>

        /// Brush used for drawing joints that are currently inferred

        /// </summary>       

        private readonly Brush inferredJointBrush = Brushes.Yellow;

 

        /// <summary>

        /// Pen used for drawing bones that are currently tracked

        /// </summary>

        private readonly Pen trackedBonePen = new Pen(Brushes.Green, 6);

 

        /// <summary>

        /// Pen used for drawing bones that are currently inferred

        /// </summary>       

        private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1);

 

        /// <summary>

        /// Drawing image that we will display

        /// </summary>

        private DrawingImage imageSource;

 

        /// <summary>

        /// Thickness of drawn joint lines

        /// </summary>

        private const double JointThickness = 3;

 

 

        /// <summary>

        /// Drawing group for skeleton rendering output

        /// </summary>

        private DrawingGroup drawingGroup;

        /// <summary>

        /// Width of output drawing

        /// </summary>

        private const float RenderWidth = 640.0f;

 

        /// <summary>

        /// Height of our output drawing

        /// </summary>

        private const float RenderHeight = 480.0f;

        #endregion

 

 

        public MainWindow()

        {

            InitializeComponent();

            //After Initialization subscribe to the loaded event of the form

            Loaded += MainWindow_Loaded;

 

            //After Initialization subscribe to the unloaded event of the form

            //We use this event to stop the sensor when the application is being closed.

            Unloaded += MainWindow_Unloaded;

 

           

        }

 

        void MainWindow_Unloaded(object sender, RoutedEventArgs e)

        {

            //stop the Sestor

            sensor.Stop();

 

        }

 

    

        void MainWindow_Loaded(object sender, RoutedEventArgs e)

        {

 

            //Create a Drawing Group that will be used for Drawing

            this.drawingGroup = new DrawingGroup();

 

            //Create an image Source that will display our skeleton

            this.imageSource = new DrawingImage(this.drawingGroup);

 

            //Display the Image in our Image control

            Image.Source = imageSource;

 

            try

            {

                //Check if the Sensor is Connected

                if (sensor.Status == KinectStatus.Connected)

                {

                    //Start the Sensor

                    sensor.Start();

//Tell Kinect Sensor to use the Default Mode(Human Skeleton Standing) || Seated(Human Skeleton Sitting Down)

                    sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default;

//Subscribe to te  Sensor's SkeletonFrameready event to track the joins and create the joins to display on our image control

                    sensor.SkeletonFrameReady += sensor_SkeletonFrameReady;

                //nice message with Colors to alert you if your sensor is working or not

                    Message.Text = "Kinect Ready";

                    Message.Background = new SolidColorBrush(Colors.Green);

                    Message.Foreground = new SolidColorBrush(Colors.White);

 

                    // Turn on the skeleton stream to receive skeleton frames

                    this.sensor.SkeletonStream.Enable();

                }

                else if (sensor.Status == KinectStatus.Disconnected)

                {

               //nice message with Colors to alert you if your sensor is working or not

                    Message.Text = "Kinect Sensor is not Connected";

                    Message.Background = new SolidColorBrush(Colors.Orange);

                    Message.Foreground = new SolidColorBrush(Colors.Black);

                    

                }

                else if (sensor.Status == KinectStatus.NotPowered)

                {

//nice message with Colors to alert you if your sensor is working or not

                    Message.Text = "Kinect Sensor is not Powered";

                    Message.Background = new SolidColorBrush(Colors.Red);

                    Message.Foreground = new SolidColorBrush(Colors.Black);

                }

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

 

            }

        }

 

        /// <summary>

        //When the Skeleton is Ready it must draw the Skeleton

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        void sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)

        {

            //declare an array of Skeletons

            Skeleton[] skeletons = new Skeleton[1];

 

             //Opens a SkeletonFrame object, which contains one frame of skeleton data.

                using (SkeletonFrame skeletonframe = e.OpenSkeletonFrame())

                {

                    //Check if the Frame is Indeed open

                    if (skeletonframe != null)

                    {

 

                       skeletons = new Skeleton[skeletonframe.SkeletonArrayLength];

                        

// Copies skeleton data to an array of Skeletons, where each Skeleton contains a collection of the joints.

                        skeletonframe.CopySkeletonDataTo(skeletons);

 

                        //draw the Skeleton based on the Default Mode(Standing), "Seated"

 if (sensor.SkeletonStream.TrackingMode == SkeletonTrackingMode.Default)

  {

                            //Draw standing Skeleton

                            DrawStandingSkeletons(skeletons);

 }

 else if (sensor.SkeletonStream.TrackingMode == SkeletonTrackingMode.Seated)

                        {

                            //Draw a Seated Skeleton with 10 joints

                            DrawSeatedSkeletons(skeletons);

                        }

                    }

              

            }

           

 

        }

 

 

  

        //Thi Function Draws the Standing  or Default Skeleton

        private void DrawStandingSkeletons(Skeleton[] skeletons)

        {

 

            using (DrawingContext dc = this.drawingGroup.Open())

            {

                //Draw a Transparent background to set the render size or our Canvas

                dc.DrawRectangle(Brushes.Black, nullnew Rect(0.0, 0.0, RenderWidth, RenderHeight));

 

                //If the skeleton Array has items

                if (skeletons.Length != 0)

                {

                    //Loop through the Skeleton joins

                    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 the canvas

this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight));

 

            }

        }

 

 

        private void DrawSeatedSkeletons(Skeleton[] skeletons)

        {

 

            using (DrawingContext dc = this.drawingGroup.Open())

            {

                //Draw a Transparent background to set the render size

 dc.DrawRectangle(Brushes.Black, nullnew 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,  nullthis.SkeletonPointToScreen(skel.Position), BodyCenterThickness, BodyCenterThickness);

 

                        }

 

                    }

 

 

                }

 

                //Prevent Drawing outside the canvas

                this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight));

 

            }

        }

 

 

        /// <summary>

        /// Draws indicators to show which edges are clipping skeleton data

        /// </summary>

        /// <param name="skeleton">skeleton to draw clipping information for</param>

        /// <param name="drawingContext">drawing context to draw to</param>

        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));

            }

        }

 

        /// <summary>

        /// Draws a skeleton's bones and joints

        /// </summary>

        /// <param name="skeleton">skeleton to draw</param>

        /// <param name="drawingContext">drawing context to draw to</param>

        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, nullthis.SkeletonPointToScreen(joint.Position), JointThickness, JointThickness);

                }

            }

        }

 

        /// <summary>

        /// Draws a bone line between two joints

        /// </summary>

        /// <param name="skeleton">skeleton to draw bones from</param>

        /// <param name="drawingContext">drawing context to draw to</param>

        /// <param name="jointType0">joint to start drawing from</param>

        /// <param name="jointType1">joint to end drawing at</param>

        private void DrawBone(Skeleton skeleton, DrawingContext drawingContext, JointType jointType0, JointTypejointType1)

        {

            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));

        }

 

 

        /// <summary>

        /// Maps a SkeletonPoint to lie within our render space and converts to Point

        /// </summary>

        /// <param name="skelpoint">point to map</param>

        /// <returns>mapped point</returns>

        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);

        }

 

    }

}


Reference
Conclusion

Currently we see a Skeleton, in one of my next articles, I will show you how to cover this skeleton with an avatar. Thank you again for visiting DotNetFunda.com. 



转自:http://www.dotnetfunda.com/articles/article2069-how-to-track-skeleton-joins-using-kinect.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Halcon中的skeleton算子用于提取图像中的骨架。骨架的构造方式是将图像中的每个点看作是一个半径最大的圆的中心点,并且仍然完全包含在这个区域内。通过使用skeleton算子,可以将一个区域进行骨架化处理,最终形成一条分裂的线。这种操作类似于沼泽地被太阳烤干后形成的裂口。骨架化操作适用于对地图中的江河和道路进行线化处理的典型例子。\[1\]\[3\] #### 引用[.reference_title] - *1* [Halcon 算子 skeleton](https://blog.csdn.net/weixin_39829336/article/details/113074704)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [halcon 二值图像处理 区域的细化 skeleton](https://blog.csdn.net/weixin_39926429/article/details/124700413)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [halcon skelton 骨骼处理](https://blog.csdn.net/weixin_39926429/article/details/123356538)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值