Kinect学习笔记四Body

项目管理 来源:hffhjh111 73℃ 0评论

Kinect学习笔记第四篇Body

C#

基础简述:

Kinect2.0的骨骼识别主要基于深度图像,与bodyIndex的识别相似,所以也会产生与BodyIndex相似的问题(详细查阅学习笔记Body篇)。感觉这是Kinect精髓所在,其实实现关键还是他那人体识别算法,谁提取了吗?开源吗?

 

Kinect里面,是通过25个关节点来表示一个骨架的,具体由下图可以看到。当你走进Kinect的视野范围的时候,Kinect就可以把你的25个关节点的位置找到(当然你得站着,不能遮挡),位置通过(x, y, z)坐标来表示。

 

Kinect V2.0是可以识别完整25个关节点,但是我只找到了一代的图。

增加的那几个点是双手的食指点、大拇指点与脖子(neck)。

 


 

 

25关节点(joint

Head Neck SpineShoulder (shoulder center) SpineMid(spine) SpineBasehip center)   

ShoulderRight ShoulderLeft

ElbowRight右胳膊肘 ElbowLeft

WristRight右腕 WristLeft

HandRight HandLeft

HandTipRight右手食指 HandTipLeft

ThumbRight右手拇指 ThumbLeft

HipRight右臀 HipLeft

KneeRight右膝 KneeLeft

AnkleRight右脚踝 AnkleLeft

FootLeft FootRight

 

玩家的各关节点位置用(x, y, z)坐标表示。坐标单位是米。坐标轴x,y, z是深度感应器实体的空间x, y, z坐标轴。这个坐标系是右手螺旋的,Kinect感应器处于原点上,z坐标轴则与Kinect感应的朝向一致。y轴正半轴向上延伸,x轴正半轴(从Kinect感应器的视角来看)暂称为骨架空间(坐标)。

       Kinect放置的位置会影响生成的图像。例如,Kinect可能被放置在非水平的表面上或者有可能在垂直方向上进行了旋转调整来优化视野范围。在这种情况下,y轴就往往不是相对地面垂直的,或者不与重力方向平行。最终得到的图像中,尽管人笔直地站立,在图像中也会显示出事倾斜的。

但是,骨骼坐标系和深度坐标及彩色影像坐标系不一样,甚至和UI界面上的坐标系不一样。在使用时一般会用到”世界线”(坐标映射)的改换,/*一切都是命运石之门的安排!*/,kinect提供了相应的方法。

坐标变换理解参考《Kinect应用开发实战用最自然的方式与机器对话第一代》中第四章P93、《kinect人机交互开发实践》。关于二代的书籍超少,谁知道的话请给我说啊!(值得注意的是,骨骼关节点的三维坐标中我们舍弃了Z值,只用了X,Y值。Kinect好不容易为我们提供了每一个节点的深度数据(Z值)而我们却没有使用,这看起来显得很浪费。其实不是这样的,我们使用了节点的Z值,只是没有直接使用,没有在UI界面上展现出来而已。在坐标空间转换中是需要深度数据的。试试在GetJointPoint方法中,将joint的Position中的Z值改为0,然后再调用MapSkeletonPointToDepth方法,你会发现返回的对象中x和y值均为0,可试试将图像以Z值进行等比缩放,可以发现图像的大小是和Z值(深度)成反的。也就是说,深度值越小,图像越大,即人物离Kinect越近,骨骼数据越大。)

 

 

 

Body代码分析:(C#)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using Microsoft.Kinect;

 

 

 

namespace myBodyViewer

{

    /// <summary>

    /// MainWindow.xaml 的交互逻辑

    /// </summary>

    public partial class MainWindow : Window

    {

        //绘制手圈时的半径

        private const double HandSize = 30;

        //接缝厚度?

        private const double JointThickness = 3;

        //夹边矩形的厚度?

        private const double ClipBoundsThickness = 10;

        //常数为夹紧Z值的相机空间点负面

        private const float InferredZPositionClamp = 0.1f;

        //用于绘制正在闭合的手的刷子

        private readonly Brush handClosedBrush = new SolidColorBrush(Color.FromArgb(12825500));

        //用于绘制正在打开的手的刷子

        private readonly Brush handOpenBrush = new SolidColorBrush(Color.FromArgb(12802550));

        //用于绘制正在跟踪识别的手的刷子?

        private readonly Brush handLassoBrush = new SolidColorBrush(Color.FromArgb(12800255));

        //用于绘制正在跟踪的关节的刷子

        private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(2556819268));

        //用于绘制正在跟踪推断的关节的刷子

        private readonly Brush inferredJointBrush = Brushes.Yellow;

        //用于画目前推断的骨头的笔

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

        //画出一组身体用于渲染输出

        private DrawingGroup drawingGroup;//DrawingGroup表示可以作为单个绘图进行运算的绘图集合

        //图源

        private DrawingImage imageSource;

        //坐标映射器(将一种类型的点映射到另一个地方)

        private CoordinateMapper coordinateMapper = null;

 

        private KinectSensor kinectSensor = null;

        private BodyFrameReader bodyFrameReader = null;

        private Body[] bodies = null;//身体数组

        private List<Tuple<JointTypeJointType>> bones;

        private int displayWidth;//展示的宽度(纵深空间)

        private int displayHeight;//展示的高度(纵深空间)

        private List<Pen> bodyColors;//人体跟踪的颜色列表(泛型)

 

以上定义了各种不同识别情况时的画笔工具、属性与坐标变换时的参数等等,鉴于我对画笔并不熟悉,就不再过多的解释。仅指明他们在程序中的作用(唐大仕老师住院了,没法再网易上学他的C#进阶啦,愿安好!)。

 

 

以下主要与之前不同的是增加了25个关节点的定义,其中采用了泛型。以及6种人体色彩(最大支持6个人的识别)

 

        public MainWindow()

        {

            this.kinectSensor = KinectSensor.GetDefault();

            this.coordinateMapper = this.kinectSensor.CoordinateMapper;//获得Kinect的坐标映射器

            FrameDescription frameDescription = this.kinectSensor.DepthFrameSource.FrameDescription;

            this.bodyFrameReader = this.kinectSensor.BodyFrameSource.OpenReader();

 

            this.displayWidth = frameDescription.Width;

            this.displayHeight = frameDescription.Height;

 

            //关节之间的线定义为Bone

            this.bones = new List<Tuple<JointTypeJointType>>();

            //Torso(躯干)

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.Head, JointType.Neck));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.Neck, JointType.SpineShoulder));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.SpineShoulder, JointType.SpineMid));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.SpineMid, JointType.SpineBase));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.SpineShoulder, JointType.ShoulderRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.SpineShoulder, JointType.ShoulderLeft));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.SpineBase, JointType.HipRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.SpineBase, JointType.HipLeft));

            // Right Arm

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.ShoulderRight, JointType.ElbowRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.ElbowRight, JointType.WristRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.WristRight, JointType.HandRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.HandRight, JointType.HandTipRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.WristRight, JointType.ThumbRight));

            // Left Arm

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.ShoulderLeft, JointType.ElbowLeft));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.ElbowLeft, JointType.WristLeft));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.WristLeft, JointType.HandLeft));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.HandLeft, JointType.HandTipLeft));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.WristLeft, JointType.ThumbLeft));

            // Right Leg

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.HipRight, JointType.KneeRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.KneeRight, JointType.AnkleRight));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.AnkleRight, JointType.FootRight));

            // Left Leg

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.HipLeft, JointType.KneeLeft));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.KneeLeft, JointType.AnkleLeft));

            this.bones.Add(new Tuple<JointTypeJointType>(JointType.AnkleLeft, JointType.FootLeft));

 

            //每个BodyIndex一个填充颜色,

            this.bodyColors = new List<Pen>();

            

            this.bodyColors.Add(new Pen(Brushes.Red, 6));

            this.bodyColors.Add(new Pen(Brushes.Orange, 6));

            this.bodyColors.Add(new Pen(Brushes.Green, 6));

            this.bodyColors.Add(new Pen(Brushes.Blue, 6));

            this.bodyColors.Add(new Pen(Brushes.Indigo, 6));

            this.bodyColors.Add(new Pen(Brushes.Violet, 6));

 

            this.kinectSensor.Open();

            this.drawingGroup = new DrawingGroup();

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

            this.DataContext = this;

            InitializeComponent();

        }

 

 

以下代码可放在MainWindows中,只是执行顺序略不同

        private void Body_Loaded(object sender, RoutedEventArgs e)

        {

            if (this.bodyFrameReader != null)

            {

                this.bodyFrameReader.FrameArrived += this.Reader_FrameArrived;

            }

        }

 

 

 

 

帧到达事件。若有骨骼帧到达,则以其中的人体骨架数量来初始化bodies数组的大小,并将数据带入此数组。数据在传入数组后,初始化画布与笔,进行坐标的变换(从色彩到深度),然后将数据交由其他画身体的子方法处理。处理完一帧重开画布。

        private void Reader_FrameArrived(object sender, BodyFrameArrivedEventArgs e)

        {

            bool dataReceived = false;

            using (BodyFrame bodyFrame = e.FrameReference.AcquireFrame())

            {

                if (bodyFrame != null)

                {

                    if (this.bodies == null)

                    {

                        this.bodies = new Body[bodyFrame.BodyCount];//BodyFrame中的人体总数

                    }

                    bodyFrame.GetAndRefreshBodyData(this.bodies);//数据带入

                    dataReceived = true;

                }

            }

            if(dataReceived)

            {

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

                {

                    // 画一个透明背景设置渲染的大小(绘制矩形,黑色背景)

                    dc.DrawRectangle(Brushes.Black, nullnew Rect(0.00.0this.displayWidth, this.displayHeight));

                    int penIndex = 0;

                    foreach (Body body in this.bodies)

                    {

                        Pen drawPen = this.bodyColors[penIndex++];

                        if (body.IsTracked)

                        {

                            this.DrawClippedEdges(body, dc);

                            IReadOnlyDictionary<JointTypeJoint> joints = body.Joints;

                            // 关节点转换为深度(显示)空间

                            Dictionary<JointTypePoint> jointPoints = new Dictionary<JointTypePoint>();

                            foreach (JointType jointType in joints.Keys)

                            {

                                // 有时推断的关节点的深度(Z)可能显示为负

                                //夹到0.1f,以防止coordinatemapper返回(无限大,无限)

                                CameraSpacePoint position = joints[jointType].Position;

                                if (position.< 0)

                                {

                                    position.= InferredZPositionCl

                                }

                                //点从色彩空间映射到深度空间,position貌似可以改变骨骼显示器的大小,

                                DepthSpacePoint depthSpacePoint = this.coordinateMapper.MapCameraPointToDepthSpace(position);

                                jointPoints[jointType] = new Point(depthSpacePoint.X, depthSpacePoint.Y);//映射完的坐标替换旧坐标

                            }

                            this.DrawBody(joints, jointPoints, dc, drawPen);

                            this.DrawHand(body.HandLeftState, jointPoints[JointType.HandLeft], dc);

                            this.DrawHand(body.HandRightState, jointPoints[JointType.HandRight], dc);

                        }

                    }

                    // 新建矩形渲染区(画布),防止渲染我们图纸以外的区域

                    this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.00.0this.displayWidth, this.displayHeight));

                }

            }

        }

 

 

 

 

调用方法画出骨骼,就是两点连线,并根据Kinect追踪情况来选用表示不同情况的画笔与刷子。我在这并不熟悉画笔工具,不多谈论。

        private void DrawBody(IReadOnlyDictionary<JointTypeJoint> joints, IDictionary<JointTypePoint> jointPoints, DrawingContext drawingContext, Pen drawingPen)

        {

            // Draw the bones

            foreach (var bone in this.bones)

            {

                this.DrawBone(joints, jointPoints, bone.Item1, bone.Item2, drawingContext, drawingPen);

            }

            // Draw the joints

            foreach (JointType jointType in joints.Keys)

            {

                Brush drawBrush = null;

                //根据追踪情况选择画笔

                TrackingState trackingState = joints[jointType].TrackingState;

                if (trackingState == TrackingState.Tracked)

                {

                    drawBrush = this.trackedJointBrush;

                }

                else if (trackingState == TrackingState.Inferred)

                {

                    drawBrush = this.inferredJointBrush;

                }

                if (drawBrush != null)

                {

                    drawingContext.DrawEllipse(drawBrush, null, jointPoints[jointType], JointThickness, JointThickness);

                }

            }

        }

画骨头(据骨骼的追踪情况(Tracked/UnTracked/Inferred)选用不同画笔参数)

        private void DrawBone(IReadOnlyDictionary<JointTypeJoint> joints, IDictionary<JointTypePoint> jointPoints, JointType jointType0, JointType jointType1, DrawingContext drawingContext, Pen drawingPen)

        {

            Joint joint0 = joints[jointType0];

            Joint joint1 = joints[jointType1];

            // 据跟踪情况解释,若找不到这些关节点,退出

            if (joint0.TrackingState == TrackingState.NotTracked ||

                joint1.TrackingState == TrackingState.NotTracked)

            {

                return;

            }

            // 除非关节已跟踪,我们假定所有骨头都推断,画笔为推断默认色

            Pen drawPen = this.inferredBonePen;

            if ((joint0.TrackingState == TrackingState.Tracked) && (joint1.TrackingState == TrackingState.Tracked))

            {

                drawPen = drawingPen;//笔换色

            }

            drawingContext.DrawLine(drawPen, jointPoints[jointType0], jointPoints[jointType1]);

        }

画手(据手的开合选用不同画笔参数)

        private void DrawHand(HandState handState, Point handPosition, DrawingContext drawingContext)

        {

            //画手(其实是圈)

            switch (handState)

            {

                case HandState.Closed:

                    drawingContext.DrawEllipse(this.handClosedBrush, null, handPosition, HandSize, HandSize);

                    break;

                case HandState.Open:

                    drawingContext.DrawEllipse(this.handOpenBrush, null, handPosition, HandSize, HandSize);

                    break;

                case HandState.Lasso:

                    drawingContext.DrawEllipse(this.handLassoBrush, null, handPosition, HandSize, HandSize);

                    break;

            }

        }

 

 

 

对人体不在或不全在Kinect摄像头范围内的处理

 

        private void DrawClippedEdges(Body body, DrawingContext drawingContext)

        {

            FrameEdges clippedEdges = body.ClippedEdges;

            if (clippedEdges.HasFlag(FrameEdges.Bottom))

            {

                drawingContext.DrawRectangle(

                    Brushes.Red,

                    null,

                    new Rect(0this.displayHeight - ClipBoundsThickness, this.displayWidth, ClipBoundsThickness));

            }

            if (clippedEdges.HasFlag(FrameEdges.Top))

            {

                drawingContext.DrawRectangle(

                    Brushes.Red,

                    null,

                    new Rect(00this.displayWidth, ClipBoundsThickness));

            }

            if (clippedEdges.HasFlag(FrameEdges.Left))

            {

                drawingContext.DrawRectangle( 

                    Brushes.Red,

                    null,

                    new Rect(00, ClipBoundsThickness, this.displayHeight));

            }

            if (clippedEdges.HasFlag(FrameEdges.Right))

            {

                drawingContext.DrawRectangle(

                    Brushes.Red,

                    null,

                    new Rect(this.displayWidth - ClipBoundsThickness, 0, ClipBoundsThickness, this.displayHeight));

            }

        }

 

 

 

 

 

        public ImageSource BodyImageSource

        {

            get

            {

                return this.imageSource;

            }

        }

 

        private void Body_Closed(object sender, EventArgs e)

        {

            if(this.bodyFrameReader!=null)

            {

                this.bodyFrameReader.Dispose();

                this.bodyFrameReader = null;

            }

            if(this.kinectSensor!=null)

            {

                this.kinectSensor.Close();

                this.kinectSensor = null;

            }

        }

        

    }

}

 

 

 

 

效果图:

 

从上图可看见增加的五个关节点,Kinect studio播放时内存占用超大,原因应该是那号称色彩一秒120M数据量造成的吧,录了10S左右就1.5G了。

 

 

程序流程:

1.声明各种画笔,刷子等参数,初始化25关节点,人体色彩。

2.开启KinectSensor,注册事件....(同于其他帧的使用)初始化不同识别模式下的参数。

3.事件方法,获得骨骼帧,坐标变换,更新,开画(分类分情况使用各种画图小方法)。

4.画完显示后更新画布。

5.清空,初始,收尾。

 

 

附加小改程序:

作用:只显示人体关节点(不连起来),并实时显示某一个人的头部关节点坐标及转换后坐标(只可有一个人,否则将不知显示的是谁),SaveAll可以将某一骨骼帧所有的关节点的三维坐标保存至D\\SaveAllJoint.txt。可以在此基础上了解关节点。

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using System.IO;

using Microsoft.Kinect;

 

namespace myPositionOfBody

{

    /// <summary>

    /// MainWindow.xaml 的交互逻辑

    /// </summary>

    public partial class MainWindow : Window

    {

 

 

        //剪切矩形的厚度

        private const double ClipBoundsThickness = 10;

        //常数为夹紧Z值的相机空间点负面

        private const float InferredZPositionClamp = 0.1f;

        //用于绘制正在跟踪的关节的刷子

        private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(2556819268));

        //用于绘制推断的关节的刷子

        private readonly Brush inferredJointBrush = Brushes.Yellow;

        //画出一组身体用于渲染输出

        private DrawingGroup drawingGroup;//DrawingGroup表示可以作为单个绘图进行运算的绘图集合

        //图源

        private DrawingImage imageSource;

        //坐标映射器(将一种类型的点映射到另一个地方)

        private CoordinateMapper coordinateMapper = null;

 

 

        private KinectSensor kinectSensor = null;

        private BodyFrameReader bodyFrameReader = null;

        private Body[] bodies = null;//身体数组

        private int displayWidth;//展示的宽度(纵深空间)

        private int displayHeight;//展示的高度(纵深空间)

        private List<Pen> bodyColors;//人体跟踪的颜色列表(泛型)

 

        public bool Savejudge;//JudgeForSave

        

        public MainWindow()

        {

            this.kinectSensor = KinectSensor.GetDefault();

            this.coordinateMapper = this.kinectSensor.CoordinateMapper;//获得Kinect的坐标映射器

            FrameDescription frameDescription = this.kinectSensor.DepthFrameSource.FrameDescription;

            this.bodyFrameReader = this.kinectSensor.BodyFrameSource.OpenReader();

 

            this.displayWidth = frameDescription.Width;

            this.displayHeight = frameDescription.Height;

 

            //每个BodyIndex一个填充颜色,

            this.bodyColors = new List<Pen>();

            this.bodyColors.Add(new Pen(Brushes.Red, 6));

            this.bodyColors.Add(new Pen(Brushes.Orange, 6));

            this.bodyColors.Add(new Pen(Brushes.Green, 6));

            this.bodyColors.Add(new Pen(Brushes.Blue, 6));

            this.bodyColors.Add(new Pen(Brushes.Indigo, 6));

            this.bodyColors.Add(new Pen(Brushes.Violet, 6));

 

 

            this.kinectSensor.Open();

            this.drawingGroup = new DrawingGroup();

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

            this.DataContext = this;

            this.Savejudge = false;

            if (this.bodyFrameReader != null)

            {

                this.bodyFrameReader.FrameArrived += this.Reader_FrameArrived;

            }

 

            InitializeComponent();

        }

        private void Reader_FrameArrived(object sender, BodyFrameArrivedEventArgs e)

        {

            bool dataReceived = false;

            using (BodyFrame bodyFrame = e.FrameReference.AcquireFrame())

            {

                if (bodyFrame != null)

                {

                    if (this.bodies == null)

                    {

                        this.bodies = new Body[bodyFrame.BodyCount];//BodyFrame中的人体总数

                    }

                    bodyFrame.GetAndRefreshBodyData(this.bodies);//数据带入

                    dataReceived = true;

                    //显示识别的未转换前一人体头部骨骼点坐标,镜头前仅能一个人,否则不知是谁的。

                    foreach (var x in this.bodies)

                    {

                        if (x.Joints[(JointType)3].Position.!= 0 && x.Joints[(JointType)3].Position.!= 0 && x.Joints[(JointType)3].Position.!= 0)

                        {

                            string pointPosition = "X=" + x.Joints[(JointType)3].Position.+ "Y=" + x.Joints[(JointType)3].Position.+ "Z=" + x.Joints[(JointType)3].Position.Z;

                            this.headPosition.Content = "Position Of Head:" + pointPosition;

                        }

 

                    }

                    if(this.Savejudge)

                    {

                        SaveAllJoints(this.bodies);

                        this.Savejudge = false;

                    }

 

                }

            }

            if (dataReceived)

            {

 

 

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

                {

                    // 画一个透明背景设置渲染的大小(绘制矩形,黑色背景)

                    dc.DrawRectangle(Brushes.Black, nullnew Rect(0.00.0this.displayWidth, this.displayHeight));

 

                    int penIndex = 0;

                    foreach (Body body in this.bodies)

                    {

                        Pen drawPen = this.bodyColors[penIndex++];

 

                        if (body.IsTracked)

                        {

                            this.DrawClippedEdges(body, dc);

                            IReadOnlyDictionary<JointTypeJoint> joints = body.Joints;

 

 

                            // 关节点转换为深度(显示)空间

                            Dictionary<JointTypePoint> jointPoints = new Dictionary<JointTypePoint>();

                            foreach (JointType jointType in joints.Keys)

                            {

                                // 有时推断的关节点的深度(Z)可能显示为负

                                //夹到0.1f,以防止coordinatemapper返回(无限大,无限)

                                CameraSpacePoint position = joints[jointType].Position;

                                if (position.< 0)

                                {

                                    position.= InferredZPositionCl

                                }

                                //点从色彩空间映射到深度空间,position貌似可以改变骨骼据显示器的大小,

                                DepthSpacePoint depthSpacePoint = this.coordinateMapper.MapCameraPointToDepthSpace(position);

                                jointPoints[jointType] = new Point(depthSpacePoint.X, depthSpacePoint.Y);//映射完的坐标替换旧坐标

 

                            }

                            //显示识别的转换后一人体头部骨骼点坐标(相对显示框),镜头前仅能一个人,否则不知是谁的。

                            string PositionAfterTransform = "X=" + jointPoints[(JointType)3].+ " Y=" + jointPoints[(JointType)3].Y;

                            this.afterTransform.Content ="AfterTransform"+ PositionAfterTransform;

                            this.DrawBodyJoint(joints, jointPoints, dc, drawPen);

                        }

                    }

 

                    // 新建矩形渲染区(画布),防止渲染我们图纸以外的区域

                    this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.00.0this.displayWidth, this.displayHeight));

                }

            }

        }

 

        private void DrawBodyJoint(IReadOnlyDictionary<JointTypeJoint> joints, IDictionary<JointTypePoint> jointPoints, DrawingContext drawingContext, Pen drawingPen)

        {

            // Draw the joints

            foreach (JointType jointType in joints.Keys)

            {

                Brush drawBrush = null;

                //根据追踪情况选择画笔

                TrackingState trackingState = joints[jointType].TrackingState;

 

                if (trackingState == TrackingState.Tracked)

                {

                    drawBrush = this.trackedJointBrush;

                }

                else if (trackingState == TrackingState.Inferred)

                {

                    drawBrush = this.inferredJointBrush;

                }

 

                if (drawBrush != null)

                {

                    drawingContext.DrawEllipse(drawBrush, null, jointPoints[jointType], 3.03.0);

                }

            }

        }

        private void DrawClippedEdges(Body body, DrawingContext drawingContext)

        {

            FrameEdges clippedEdges = body.ClippedEdges;

 

            if (clippedEdges.HasFlag(FrameEdges.Bottom))

            {

                drawingContext.DrawRectangle(

                    Brushes.Red,

                    null,

                    new Rect(0this.displayHeight - ClipBoundsThickness, this.displayWidth, ClipBoundsThickness));

            }

 

            if (clippedEdges.HasFlag(FrameEdges.Top))

            {

                drawingContext.DrawRectangle(

                    Brushes.Red,

                    null,

                    new Rect(00this.displayWidth, ClipBoundsThickness));

            }

 

            if (clippedEdges.HasFlag(FrameEdges.Left))

            {

                drawingContext.DrawRectangle(

                    Brushes.Red,

                    null,

                    new Rect(00, ClipBoundsThickness, this.displayHeight));

            }

 

            if (clippedEdges.HasFlag(FrameEdges.Right))

            {

                drawingContext.DrawRectangle(

                    Brushes.Red,

                    null,

                    new Rect(this.displayWidth - ClipBoundsThickness, 0, ClipBoundsThickness, this.displayHeight));

            }

        }

        public ImageSource BodyImageSource

        {

            get

            {

                return this.imageSource;

            }

        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)

        {

            if (this.bodyFrameReader != null)

            {

                this.bodyFrameReader.Dispose();

                this.bodyFrameReader = null;

 

            }

            if (this.kinectSensor != null)

            {

                this.kinectSensor.Close();

                this.kinectSensor = null;

            }

        }

 

        public void SaveAllJoints(Body[] bodies)

        {

            FileStream fs = new FileStream("D:\\SaveAllJoints.txt"FileMode.OpenOrCreate);

            StreamWriter sw = new StreamWriter(fs);

            foreach(Body x in bodies)

            {

                for(int i=0;i<25;i++)

                {

                    sw.WriteLine("{0}[{1},{2},{3}]", (JointType)i, x.Joints[(JointType)i].Position.X, x.Joints[(JointType)i].Position.Y,x.Joints[(JointType)i].Position.Z);

                }

                sw.Write("\r\n");

            }

            sw.Flush();

            sw.Close();

            fs.Close();

        }

        private void SaveAll_Click(object sender, RoutedEventArgs e)

        {

            this.Savejudge = true;

        }

        

    }

}

 

 

 

 

附:

参考地址:http://blog.csdn.net/zouxy09/article/details/8161617

http://www.cnblogs.com/yangecnu/archive/2012/04/06/KinectSDK_Skeleton_Tracking_Part1.html

第一个程序Xaml添加代码:

<Image HorizontalAlignment="Left"   Source="{Binding BodyImageSource}" Stretch="UniformToFill" VerticalAlignment="Top" />

 

第二个程序xaml添加代码:

<Image HorizontalAlignment="Left" Source="{Binding BodyImageSource}"  Stretch="UniformToFill" VerticalAlignment="Top" />