using Microsoft.Kinect; 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.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace KinectConnection { public class BodyImageStream : KinectStream { private BodyFrameReader bodyFrameReader = null; private Body[] bodies = null; private DrawingGroup drawingGroup = new DrawingGroup(); private List bodyColors = new List(); private CoordinateMapper coordinateMapper = null; private List> bones = new List>(); private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68)); private readonly Brush inferredJointBrush = Brushes.Yellow; private const double HandSize = 30; private const double JointThickness = 3; private readonly Brush handClosedBrush = new SolidColorBrush(Color.FromArgb(128, 255, 0, 0)); private readonly Brush handOpenBrush = new SolidColorBrush(Color.FromArgb(128, 0, 255, 0)); private readonly Brush handLassoBrush = new SolidColorBrush(Color.FromArgb(128, 0, 0, 255)); private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1); private const double ClipBoundsThickness = 10; private DrawingImage imageSource = new DrawingImage(); private FrameDescription frameDescription; private int displayHeight; private int displayWidth; public override ImageSource Source { get { return this.imageSource; } } public BodyImageStream() : base() { this.coordinateMapper = this.KinectSensor.CoordinateMapper; frameDescription = this.KinectSensor.DepthFrameSource.FrameDescription; displayHeight = frameDescription.Height; displayWidth = frameDescription.Width; // Torso this.bones.Add(new Tuple(JointType.Head, JointType.Neck)); this.bones.Add(new Tuple(JointType.Neck, JointType.SpineShoulder)); this.bones.Add(new Tuple(JointType.SpineShoulder, JointType.SpineMid)); this.bones.Add(new Tuple(JointType.SpineMid, JointType.SpineBase)); this.bones.Add(new Tuple(JointType.SpineShoulder, JointType.ShoulderRight)); this.bones.Add(new Tuple(JointType.SpineShoulder, JointType.ShoulderLeft)); this.bones.Add(new Tuple(JointType.SpineBase, JointType.HipRight)); this.bones.Add(new Tuple(JointType.SpineBase, JointType.HipLeft)); // Right Arm this.bones.Add(new Tuple(JointType.ShoulderRight, JointType.ElbowRight)); this.bones.Add(new Tuple(JointType.ElbowRight, JointType.WristRight)); this.bones.Add(new Tuple(JointType.WristRight, JointType.HandRight)); this.bones.Add(new Tuple(JointType.HandRight, JointType.HandTipRight)); this.bones.Add(new Tuple(JointType.WristRight, JointType.ThumbRight)); // Left Arm this.bones.Add(new Tuple(JointType.ShoulderLeft, JointType.ElbowLeft)); this.bones.Add(new Tuple(JointType.ElbowLeft, JointType.WristLeft)); this.bones.Add(new Tuple(JointType.WristLeft, JointType.HandLeft)); this.bones.Add(new Tuple(JointType.HandLeft, JointType.HandTipLeft)); this.bones.Add(new Tuple(JointType.WristLeft, JointType.ThumbLeft)); // Right Leg this.bones.Add(new Tuple(JointType.HipRight, JointType.KneeRight)); this.bones.Add(new Tuple(JointType.KneeRight, JointType.AnkleRight)); this.bones.Add(new Tuple(JointType.AnkleRight, JointType.FootRight)); // Left Leg this.bones.Add(new Tuple(JointType.HipLeft, JointType.KneeLeft)); this.bones.Add(new Tuple(JointType.KneeLeft, JointType.AnkleLeft)); this.bones.Add(new Tuple(JointType.AnkleLeft, JointType.FootLeft)); 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.imageSource = new DrawingImage(this.drawingGroup); } public override void Start() { if (this.KinectSensor != null) { this.bodyFrameReader = this.KinectSensor.BodyFrameSource.OpenReader(); if (this.bodyFrameReader != null) { this.bodyFrameReader.FrameArrived += this.Reader_BodyFrameArrived; } } } public override void Stop() { if (this.bodyFrameReader != null) { this.bodyFrameReader.FrameArrived -= this.Reader_BodyFrameArrived; // Dispose the reader to free resources. // If we don't dispose manualy, the gc will do it for us, but we don't know when. this.bodyFrameReader.Dispose(); this.bodyFrameReader = null; } } private void Reader_BodyFrameArrived(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]; } // The first time GetAndRefreshBodyData is called, Kinect will allocate each Body in the array. // As long as those body objects are not disposed and not set to null in the array, // those body objects will be re-used. bodyFrame.GetAndRefreshBodyData(this.bodies); dataReceived = true; } } if (dataReceived) { 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, displayWidth, displayHeight)); int penIndex = 0; foreach (Body body in this.bodies) { Pen drawPen = this.bodyColors[penIndex++]; if (body.IsTracked) { this.DrawClippedEdges(body, dc); IReadOnlyDictionary joints = body.Joints; // convert the joint points to depth (display) space Dictionary jointPoints = new Dictionary(); foreach (JointType jointType in joints.Keys) { // sometimes the depth(Z) of an inferred joint may show as negative // clamp down to 0.1f to prevent coordinatemapper from returning (-Infinity, -Infinity) CameraSpacePoint position = joints[jointType].Position; if (position.Z < 0) { position.Z = 0.1f; } 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); } } // prevent drawing outside of our render area this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, displayWidth, displayHeight)); } } } private void DrawBody(IReadOnlyDictionary joints, IDictionary 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); } } } 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; } } private void DrawBone(IReadOnlyDictionary joints, IDictionary jointPoints, JointType jointType0, JointType jointType1, DrawingContext drawingContext, Pen drawingPen) { Joint joint0 = joints[jointType0]; Joint joint1 = joints[jointType1]; // If we can't find either of these joints, exit if (joint0.TrackingState == TrackingState.NotTracked || joint1.TrackingState == TrackingState.NotTracked) { return; } // We assume all drawn bones are inferred unless BOTH joints are tracked Pen drawPen = this.inferredBonePen; if ((joint0.TrackingState == TrackingState.Tracked) && (joint1.TrackingState == TrackingState.Tracked)) { drawPen = drawingPen; } drawingContext.DrawLine(drawPen, jointPoints[jointType0], jointPoints[jointType1]); } private void DrawClippedEdges(Body body, DrawingContext drawingContext) { FrameEdges clippedEdges = body.ClippedEdges; if (clippedEdges.HasFlag(FrameEdges.Bottom)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(0, displayHeight - ClipBoundsThickness, displayWidth, ClipBoundsThickness)); } if (clippedEdges.HasFlag(FrameEdges.Top)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(0, 0, displayWidth, ClipBoundsThickness)); } if (clippedEdges.HasFlag(FrameEdges.Left)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(0, 0, ClipBoundsThickness, displayHeight)); } if (clippedEdges.HasFlag(FrameEdges.Right)) { drawingContext.DrawRectangle( Brushes.Red, null, new Rect(displayWidth - ClipBoundsThickness, 0, ClipBoundsThickness, displayHeight)); } } } }