A lot of Kinect developers need to create apps that calculate a lot of complex human body measurements. Today I’ll show you how to use Vitruvius to measure angles in the 3D and 2D space.

{ Reasonably, Vitruvius is featured in the official Microsoft Kinect Website and Channel9 }

This is what you’ll be able to do after reading the following tutorial:

What is an angle?

An angle is a combination of two lines. To measure an angle, all you need is 3 points in the 3D or 2D space: a starting point, a middle point, and an end point.

The official Kinect SDK includes the following built-in types of points, so, first, let me give you some background information:

1) CameraSpacePoint

A CameraSpacePoint is a set of coordinates in the 3D space. It has X, Y, and Z values, all measured in meters. The X value represents the horizontal distance of the point, measured from the left side of the field-of-view. The Y value represents the vertical distance of the point, measured from the top of the field-of-view. The Z value represents the distance between the point and the sensor plane. The CameraSpacePoint is the only Kinect point that gives us information about the 3D world.

2) ColorSpacePoint

A ColorSpacePoint is a set of coordinates in the 2D Color space. The Color space is a 1920×1080 frame. A ColorSpacePoint only has two coordinates: the X coordinate defines the distance from the left edge of the frame, and the Y coordinate defines the distance from the top of the frame.

3) DepthSpacePoint

A DepthSpacePoint is, again, a set of coordinates in the 2D Depth space. The Depth space is a 512×424 frame. A depth point has X and Y values, just like the color points. The Depth space is equivalent to the Infrared space, so you can use the same type of points for both.

What about the joints?

You already know that Kinect’s power is the ability to calculate the positions of 25 human body joints. A Joint is a structure that includes:

  • The position in the 3D space
  • The type/name of the joint
  • The tracking accuracy

The position of a joint in the 3D space is expressed as a CameraSpacePoint. To properly map the 3D-position into the 2D-position, you need to use Coordinate Mapping.

Measuring an angle with Vitruvius

Vitruvius contains some handy extension methods that will help you measure an angle using CameraSpacePoints, ColorSpacePoints, or DepthSpacePoints. First, you need to include the proper namespace in your C# file:

using LightBuzz.Vitruvius;

We assume that you already know how to get a Body object from a BodyFrame. Let’s say that you want to measure the angle on your elbow. This angle is formed by 3 joints — the shoulder, the elbow, and the wrist:

Joint shoulder = body.Joints[JointType.ShoulderLeft];
Joint elbow = body.Joints[JointType.ElbowLeft];
Joint wrist = body.Joints[JointType.WristLeft];

The middle point of the angle is, of course, the elbow. The starting point of the angle is the shoulder. The end point of the angle is the wrist. So, here you are:

double angle = elbow.Angle(shoulder, wrist);

The Angle method is an extension method, included in Vitruvius. This way, you can calculate any angle for any human body joint!

The above code is equivalent to the following:

double angle = elbow.Position.Angle(shoulder.Position, wrist.Position);

Need to measure the same angle in the Color or Depth space? No problem! Vitruvius includes another handy extension method, called ToPoint. Here’s how you can use it:

var shoulderColor = shoulder.ToPoint(Viualization.Color);
var elbowColor = elbow.ToPoint(Viualization.Color);
var wristColor = wrist.ToPoint(Viualization.Color);

double angle = elbowColor.Angle(shoulderColor, wristColor);

Similarly, you can calculate the angle in the Depth/Infrared space:

var shoulderDepth = shoulder.ToPoint(Viualization.Depth);
var elbowDepth = elbow.ToPoint(Viualization.Depth);
var wristDepth = wrist.ToPoint(Viualization.Depth);

double angle = elbowColor.Angle(shoulderColor, wristColor);

Simple, huh?

Same principles apply to HD Face points, too!

CameraSpacePoint nose = face.Nose;
CameraSpacePoint cheekLeft = face.CheekLeft;
CameraSpacePoint cheekRight = face.CheekRight;

double angle = nose.Angle(cheekLeft, cheekRight);

Note: the sample projects included with Vitruvius also contain a handy Arc control. Using the Arc control, you can visualize the angle on top of a body very easily.

Why do you need this?

Except the obvious reason (measuring an angle), such Mathematical calculations are extremely helpful when you need to compare the relative positions between a few points. Gesture detection, sign language identification, or even facial expressions!

Supported Platforms

The above code (including angle measurements and Arc controls) is supported in the following platforms, frameworks, and engines:

  • Unity3D
  • Windows Presentation Foundation (.NET 4.5+)
  • Windows Store (WinRT)

Get Vitruvius

As you see, Vitruvius is helping innovative companies create Kinect apps fast. Vitruvius simplifies Kinect development, so you can now focus on what’s really important: your app, your research, and your customers.

Author Vangos Pterneas

Vangos Pterneas is a Microsoft Most Valuable Professional in the Kinect technology. He helps companies from all over the world grow their revenue by creating profitable software products. Vangos is the owner of LightBuzz Software agency and author of The Dark Art Of Freelancing. Read more

More posts by Vangos Pterneas

Join the discussion 52 Comments

  • Justin Pando says:

    Where are your tutorials/videos for getting started with Vitruvius? Right now, the only code samples I can find are on your front page advertisements and they’re missing context.

  • Brian Hewitt says:

    This seems like a very promising tool, but there’s no documentation. The included ‘Documentation’ in the free version is empty, and no documentation is provided online.

  • Suzanne says:

    Hai Vango…

    May I ask about this code :

    var shoulderColor = shoulder.ToPoint(Viualization.Color);
    var elbowColor = elbow.ToPoint(Viualization.Color);
    var wristColor = wrist.ToPoint(Viualization.Color);

    double angle = elbowColor.Angle(shoulderColor, wristColor);

    From where Viualization comes?

    • Hi Suzanne. Visualization is an enumeration that is part of Vitruvius. It is used as a flag to determine the output type. If you use Visualization.Color, the points will be created for a 1920×1080 canvas. If you use Visualization.Depth or Visualization.Infrared, the points will be created for a 512×424 resolution.

      Let me know if that information helped you 🙂

  • Klara says:

    Hello,

    i hope you can help me. You need this code for skelattracking:

    using (var frame = reference.BodyFrameReference.AcquireFrame())
    {
    if (frame != null)
    {
    var bodies = frame.Bodies();

    _userReporter.Update(bodies);

    Body body = bodies.Closest();

    if (body != null)
    {
    viewer.DrawBody(body);
    angle.Update(body.Joints[_start], body.Joints[_center], body.Joints[_end], 60);
    tblAngle.Text = ((int)angle.Angle).ToString();
    }
    }
    }

    and calculate the angle.

    My question is: Can i will track a part of the body(ShoulderRight, ElbowRight,WristRight) and not the complete body? If yes, how i do it?

    • Hello Klara. Kinect can only track the whole body. However, you can draw only the joints and lines you need. It’s not required to draw everything. For example, if you only need to display 3 joints, you can use the following code:

      XAML:

      <Viewbox>
      <Grid Width="1920" Height="1080">
      <Image Name="camera" />
      <Canvas Name="canvas">
      <Ellipse Name="ellipseShoulder" Width="10" Height="10" Fill="Blue" />
      <Ellipse Name="ellipseElbow" Width="10" Height="10" Fill="Blue" />
      <Ellipse Name="ellipseWrist" Width="10" Height="10" Fill="Blue" />
      <Line Name="line1" Stroke="Blue" StrokeThickness="5" />
      <Line Name="line2" Stroke="Blue" StrokeThickness="5" />
      </Canvas>
      </Grid>
      </Viewbox>

      C#

      if (body != null)
      {
      var shoulder = body.Joints[JointType.ShoulderRight].Position.ToPoint(Visualization.Color);
      var elbow = body.Joints[JointType.ElbowRight].Position.ToPoint(Visualization.Color);
      var wrist = body.Joints[JointType.WristRight].Position.ToPoint(Visualization.Color);
      if (!float.IsInfinity(shoulder.X) && !float.IsInfinity(shoulder.Y) &&
      !float.IsInfinity(elbow.X) && !float.IsInfinity(elbow.Y) &&
      !float.IsInfinity(wrist.X) && !float.IsInfinity(wrist.Y))
      {
      Canvas.SetLeft(ellipseShoulder, shoulder.X - ellipseShoulder.Width / 2);
      Canvas.SetTop(ellipseShoulder, shoulder.Y - ellipseShoulder.Height / 2);
      Canvas.SetLeft(ellipseElbow, elbow.X - ellipseElbow.Width / 2);
      Canvas.SetTop(ellipseElbow, elbow.Y - ellipseElbow.Height / 2);
      Canvas.SetLeft(ellipseWrist, wrist.X - ellipseWrist.Width / 2);
      Canvas.SetTop(ellipseWrist, wrist.Y - ellipseWrist.Height / 2);
      line1.X1 = shoulder.X;
      line1.Y1 = shoulder.Y;
      line1.X2 = elbow.X;
      line1.Y2 = elbow.Y;
      line2.X1 = elbow.X;
      line2.Y1 = elbow.Y;
      line2.X2 = wrist.X;
      line2.Y2 = wrist.Y;
      }
      }

      Let me know if that information helped you 🙂

      • Klara says:

        Hey,

        thanks it works. But it is less accurate than viewer.DrawBody(body) and there is a fault in the if-function (double can’t convert in to double).

        Otherwise it is ok 🙂

        • Thank you. Please check the updated code in my previous comment.

          • Klara says:

            Yes, i had the same idea. 🙂

            but,

            if (!float.IsInfinity(shoulder.X) && !float.IsInfinity(shoulder.Y) &&
            !float.IsInfinity(elbow.X) && !float.IsInfinity(elbow.Y) &&
            !float.IsInfinity(wrist.X) && !float.IsInfinity(wrist.Y))
            {
            ….
            }

            Have the Error : CS1503

            Argument ‘1’: cannot convert from “double” in “float”

          • That code should work in WPF and Unity. In case you are using WinRT, replace “float.IsInfinity” with “double.IsInfinity” and it should be OK.

          • Klara says:

            Super 🙂

          • Klara says:

            Hey,

            i have one question for calculate the angle.

            Can you tell me what formula you use it to calculate the angle ?
            Vector3D: a (x,y,z) = Elbow – Shoulder
            Vector3D: b(x,y,z)=Wrist – Shoulder

            angle =arccos (a x b)/(|a|*|b|)

            Use you this one?

          • Klara says:

            b*= Wrist-Elbow

          • Hi Klara,

            You can simply use the Angle method:


            var start = body.Joints[JointType.ShoulderLeft];
            var center = body.Joints[JointType.ElbowLeft];
            var end = body.Joints[JointType.WristLeft];

            var angle = center.Angle(start, end);

            Source code

          • Klara says:

            Yes , it was , but behind it? Which calculation ?

          • Hi Klara. You mean this code? Source.

  • Hannnan says:

    I have a question if you don’t mind

    Can I used the angle calculation to figure out if the hand ( arm) is up near to mouth or far from the mouth??

    • Hello Hanan. Sure, you can check whether the hand is near to or far from the mouth by using the following Vitruvius code:


      const float threshold = 0.1f; // 10 cm - change this
      var hand = body.Joints[JointType.Hand].Position;
      var mouth = face.Mouth;
      var distance = hand.Length(mouth);
      if (distance < threshold) // Hand is close to the mouth. if (distance > threshold) // Hand is far from the mouth.

      Let me know if that helped you (you can check the Face sample to learn how to acquire the Face object).

  • arunraj says:

    Can somebody help me, how to find the angles between in the Right Elbow and Right Knee?
    Anybody provide me the sample code…
    I don’t know which extensions to use.. need a proper tutorial…

    • Hello. We can definitely help you. An angle needs 3 points:
      – Right Elbow
      – Right Knee

      What is the third one? Could you probably send a picture of the angle?

      • arunraj says:

        I got the code MathExtensions.cs from you……
        Now my doubt is how to start coding in C#.net..
        My objective is to find the Angle using the joints as follows..
        1. Right Wrist, Right Elbow, Right Shoulder.. Elbow Angle
        2. Right Hip, Right Knee, Right Angle.. Knee Angle
        How to include the extensions in Visual Studio?
        Please give a complete tutorial..

        • Here’s how you can include Vitruvius in your Project:
          1) Open the downloaded Vitruvius folder and navigate to the Assemblies folder.
          2) Open the WPF or WinRT folder, based on the type of project you want to create. If you don’t know what type of project you have, it’s most probably WinRT.
          3) Open Visual Studio and create a new WPF or WinRT project, targeting .NET 4.5+.
          4) Right-click the References item and select “Add new reference”.
          5) Browse to the folder you opened in Step #2.
          6) Select LightBuzz.Vitruvius.dll.
          7) In your .cs file, include the following reference:


          using LightBuzz.Vitruvius;

          That’s it. You can now access all of the Vitruvius extensions.

          For example:


          var shoulder = body.Joints[JointType.ShoulderRight];
          var elbow = body.Joints[JointType.ElbowRight];
          var wrist = body.Joints[JointType.WristRight];
          var hip = body.Joints[JointType.HipRight];
          var knee = body.Joints[JointType.KneeRight];
          var ankle = body.Joints[JointType.AnkleRight];

          var angle1 = elbow.Angle(shoulder, wrist);
          var angle2 = knee.Angle(hip, ankle);

  • arunraj says:

    using System.Windows;
    using LightBuzz.Vitruvius;
    using Microsoft.Kinect;

    namespace AngleMeasurement
    {
    ///
    /// Interaction logic for MainWindow.xaml
    ///
    ///

    public partial class MainWindow : Window
    {

    public MainWindow()
    {

    InitializeComponent();
    var shoulder = body.Joints[JointType.ShoulderRight];
    var elbow = body.Joints[JointType.ElbowRight];
    var wrist = body.Joints[JointType.WristRight];
    var hip = body.Joints[JointType.HipRight];
    var knee = body.Joints[JointType.KneeRight];
    var ankle = body.Joints[JointType.AnkleRight];

    var angle1 = elbow.Angle(shoulder, wrist);
    var angle2 = knee.Angle(hip, ankle);

    }
    }
    }

    Getting the following error: The Name ‘body’ doesn’t exist in the current context..

    I want to use the arc tool to display the above two angles in live mode…
    What’s the code? I’ve to type..

    Thanks in advance..

    • Hello. What you asked is into the Samples folder.

      1) Open the downloaded Vitruvius folder and navigate to the *Samples* folder.
      2) Open the WPF or WinRT folder, based on the type of project you want to create.
      3) Open the .sln file using Visual Studio.
      4) Check the AnglePage.xaml.cs.

      It’s a complete example, using the Arc control and the Angle extension method.

      • arunraj says:

        Dear sir, I know what you mean? i’ve already explored the code of AnglePage.xaml.cs..
        but the code you have given and the code inside AnglePage.xaml.cs is totally different..
        Please tell me the reason for this error
        Getting the following error: The Name ‘body’ doesn’t exist in the current context..

        using System.Windows;
        using LightBuzz.Vitruvius;
        using Microsoft.Kinect;
        namespace AngleMeasurement
        {
        ///
        /// Interaction logic for MainWindow.xaml
        ///
        ///
        public partial class MainWindow : Window
        {
        public MainWindow()
        {
        InitializeComponent();
        var shoulder = body.Joints[JointType.ShoulderRight];
        var elbow = body.Joints[JointType.ElbowRight];
        var wrist = body.Joints[JointType.WristRight];
        var hip = body.Joints[JointType.HipRight];
        var knee = body.Joints[JointType.KneeRight];
        var ankle = body.Joints[JointType.AnkleRight];
        var angle1 = elbow.Angle(shoulder, wrist);
        var angle2 = knee.Angle(hip, ankle);
        }
        }
        }

  • arunraj says:

    Dear sir, thanks for your help, but now I’ve one final doubt..
    Please help me..

    using (var frame = reference.BodyFrameReference.AcquireFrame())
    {
    if (frame != null)
    {
    var bodies = frame.Bodies();

    _userReporter.Update(bodies);

    Body body = bodies.Closest();

    if (body != null)
    {

    var shoulder = body.Joints[JointType.ShoulderRight];
    var elbow = body.Joints[JointType.ElbowRight];
    var wrist = body.Joints[JointType.WristRight];
    var hip = body.Joints[JointType.HipRight];
    var knee = body.Joints[JointType.KneeRight];
    var ankle = body.Joints[JointType.AnkleRight];

    var angle1 = elbow.Angle(shoulder, wrist);
    var angle2 = knee.Angle(hip, ankle);

    viewer.DrawBody(body);

    angle.Update(body.Joints[JointType.ShoulderRight], body.Joints[JointType.ElbowRight], body.Joints[JointType.WristRight], 100);
    angle.Update(body.Joints[JointType.HipRight], body.Joints[JointType.KneeRight], body.Joints[JointType.AnkleRight], 100);
    tblAngle.Text = ((int)angle.Angle).ToString();
    //viewer.DrawBody(body);
    //angle.Update(body.Joints[_start], body.Joints[_center], body.Joints[_end], 100);

    //tblAngle.Text = ((int)angle.Angle).ToString();
    }
    }
    }
    }

    void UserReporter_BodyEntered(object sender, PlayersControllerEventArgs e)
    {
    }

    void UserReporter_BodyLeft(object sender, PlayersControllerEventArgs e)
    {
    viewer.Clear();
    angle.Clear();

    tblAngle.Text = “-“;
    }
    }
    }

    With the code above, i was able to get only the Knee angle.. The code to show elbow angle get overwritten..
    Whether i need to create separate method for elbow angle as well?
    How can i get both angles simultaneously?

    • Hello. You’ll simply need to add a second Arc control in your XAML file.


      <controls:KinectAngle x:Name="angle1" Opacity="0.5" />
      <controls:KinectAngle x:Name="angle2" Opacity="0.5" />

      …and update both controls accordingly:


      angle1.Update(body.Joints[JointType.ShoulderRight], body.Joints[JointType.ElbowRight], body.Joints[JointType.WristRight], 100);
      angle2.Update(body.Joints[JointType.HipRight], body.Joints[JointType.KneeRight], body.Joints[JointType.AnkleRight], 100);

  • arunraj says:

    While Displaying the various angles in the screen at the same time, is there any better way we can do from the code below?
    Please suggest how to store those values in real-time in .csv format..

  • Klara says:

    Hey, can you tell me

    How big is the error/ deviation of Kinect 2?

    If you calculate a angle from 90 degree –> error? or standard deviation? for example at a distance of 2 m

  • Muthug says:

    Hi Vangos, can you please tell me how to include my ankle angle ? currently all other joint angles are captured except ankle (I’m using Unity + Virtuvius pack + kinect V2). Also would like to capture 2 eyes

    • Hello Muthug. Thanks for using Vitruvius! What ankle angle do you need? You can use the Angle extension method to measure the angle between 3 points. If you need the rotation information, then use the joint orientation property:

      var orientation = body.Joints[JointType.AnkleLeft].Orientation;

      This is a quaternion actually.

      To get the position of the eyes, simply use the Face extension methods (check the Face sample inside the Avateering Unity scene):

      var eyeLeft = face.EyeLeft;

      All of the Face properties (like EyeLeft, EyeRight, Jaw, etc) are CameraSpacePoints, just like the original joint positions.

      Let me know if you need any additional help.

      • Muthug says:

        Vangos, I’m using your sample unity project. Edited Avateering Sample scene and calling only skeleton model, the skeleton is mirroring what ever action I do, showing all joint angles except ankle angle. Which file to edit for me to see the skeleton model to show the ankle angle too. (only 6 angles are shown in your sample scene file, please help me to display the 7th angle -marked yellow in the uploaded image:

        http://pictub.club/image/HAPZm

        • Hello Muthug,

          You can display whichever angle you need. Here’s how:
          * Launch the Unity editor and open the Angle scene.
          * From your Hierarchy view, select the “Angle Sample”.
          * Navigate to the Inspector window and find the Joint Peaks array.
          * Modify the start/center/end joints of an array element or add a new one.

          Done! (I have sent a picture to your email, too).

          Vangos

  • Argie says:

    Hello Vangos, I would like to ask you whether it is possible to use vitruvius not live, but using it to parse depth videos from datasets, and calculate the angles among joints within each frame and store them?

    • Hello, Argie. Sure! Using the Video Recording and Playback of Vitruvius, you can replay the 3D data, acquire every single frame, and calculate the angles without connecting a Kinect sensor.

  • Aisha says:

    hello
    thanks for ur support
    I have some questions:
    1. Is there an optimal way to choose a specific skeletal angles to detect a gesture?
    2. how many angles i need to measure… to detect an exact gesture? is there a limit?
    3. is it possible to find the angle of rightsoulder, spinbase and rightknee? i try it but it did’t work… (i want to detect the angle of a bending human back… “bowing”)
    4. i couldn’t understand the “arc” clearly.. is it only for displaying purpose,,, or does it count in calculations? i always put it 50!!

    thannks again

    • Hello, Aisha. Thank you for your message. Check my comments below:

      1) It depends on the gesture. The more complex a gesture, the more angles you’ll need to consider. What gesture are you trying to measure?
      2) You can measure as many angles as you like, depending on the gesture.
      3) You can do the following:


      var chest = body.Joints[JointType.SpineShoulder].Position;
      var waist = body.Joints[JointType.SpineBase].Position;
      var verticalAxis = new CameraSpacePoint { X = waist.X, Y = 0f, Z = waist.Z };
      var angle = waist.Angle(chest, verticalAxis);

      4) The Arc control is for display purposes. You can specify the points, as well as its radius. So, if you set it to 50, the radius of the arc would be 50 points.

  • Ben says:

    Hi Vangos,
    thanks for this great tool! I have been playing around with it and I tried to display the different angles of the joints right next to actual joints in the life picture (like the picture of the athlete here on your webpage 😉 )
    Unfortunately, I do not know this can be achieved. Right know I can only show the angles on a canvas on top of the picture like in your sample code….do you have an idea to help me out?
    Cheers,
    Ben

  • […] one of my previous blog posts, I showed you how to measure joint angles using Kinect and C#. Today, we’ll dive into a more complex topic: in this article, you are going to learn how to […]

  • […] one of my previous blog posts, I showed you how to measure joint angles using Kinect and C#. Today, we’ll dive into a more complex topic: in this article, you are going to learn how to […]

  • […] Pterneas May 28, 2017 In one of my previous blog posts, I showed you how to measure joint angles using Kinect and C#. Today, we’ll dive into a more complex topic: in this article, you are going to learn how to […]

Leave a Reply