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 measure the orientation of a joint around each axis (X, Y, Z).
Measuring the orientation values is not trivial because it requires some good knowledge of Mathematics. Do not be afraid, though! After reading this article, you’ll be able to calculate the orientation of each joint using one line of C# code!
Sounds good? Let’s get started.
Prerequisites
To run the code and samples provided in this guide, you’ll need the following:
- Kinect for XBOX v2 sensor with an adapter (or Kinect for Windows v2 sensor)
- Kinect for Windows v2 SDK
- Windows 8.1 or higher
- Visual Studio 2013 or higher
- A dedicated USB 3 port
Let’s do the Math…
Kinect is reading the joint orientation values as a quaternion. A quaternion is a set of 4 values: X, Y, Z, and W.
The Kinect SDK is encapsulating the quaternion into a structure called Vector4. We need to transform this quaternion (Vector4) into a set of 3 numeric values.
Using the Orientation quaternion, we can calculate the rotation of the joint around the X, Y, and Z axis.
Pitch: rotating around the X-axis
The rotation around the X axis is called Pitch. Here is how to measure it:
public static double Pitch(this Vector4 quaternion)
{
double value1 = 2.0 * (quaternion.W * quaternion.X + quaternion.Y * quaternion.Z);
double value2 = 1.0 - 2.0 * (quaternion.X * quaternion.X + quaternion.Y * quaternion.Y);
double roll = Math.Atan2(value1, value2);
return roll * (180.0 / Math.PI);
}
Yaw: rotating around the Y-axis
The rotation around the Y axis is called Yaw. Here is how to measure it:
public static double Yaw(this Vector4 quaternion)
{
double value = 2.0 * (quaternion.W * quaternion.Y - quaternion.Z * quaternion.X);
value = value > 1.0 ? 1.0 : value;
value = value < -1.0 ? -1.0 : value;
double pitch = Math.Asin(value);
return pitch * (180.0 / Math.PI);
}
Roll: rotating around the Z-axis
The rotation around the Z axis is called Roll. Here is how to measure it:
public static double Roll(this Vector4 quaternion)
{
double value1 = 2.0 * (quaternion.W * quaternion.Z + quaternion.X * quaternion.Y);
double value2 = 1.0 - 2.0 * (quaternion.Y * quaternion.Y + quaternion.Z * quaternion.Z);
double yaw = Math.Atan2(value1, value2);
return yaw * (180.0 / Math.PI);
}
Using the code
Here is the complete code. All you have to do is import the following C# file into your Kinect project.
using System;
using Microsoft.Kinect;
namespace LightBuzz.Vitruvius
{
/// <summary>
/// Provides extension methods for transforming quaternions to rotations.
/// </summary>
public static class JointOrientationExtensions
{
/// <summary>
/// Rotates the specified quaternion around the X axis.
/// </summary>
/// <param name="quaternion">The orientation quaternion.</param>
/// <returns>The rotation in degrees.</returns>
public static double Pitch(this Vector4 quaternion)
{
double value1 = 2.0 * (quaternion.W * quaternion.X + quaternion.Y * quaternion.Z);
double value2 = 1.0 - 2.0 * (quaternion.X * quaternion.X + quaternion.Y * quaternion.Y);
double roll = Math.Atan2(value1, value2);
return roll * (180.0 / Math.PI);
}
/// <summary>
/// Rotates the specified quaternion around the Y axis.
/// </summary>
/// <param name="quaternion">The orientation quaternion.</param>
/// <returns>The rotation in degrees.</returns>
public static double Yaw(this Vector4 quaternion)
{
double value = 2.0 * (quaternion.W * quaternion.Y - quaternion.Z * quaternion.X);
value = value > 1.0 ? 1.0 : value;
value = value < -1.0 ? -1.0 : value;
double pitch = Math.Asin(value);
return pitch * (180.0 / Math.PI);
}
/// <summary>
/// Rotates the specified quaternion around the Z axis.
/// </summary>
/// <param name="quaternion">The orientation quaternion.</param>
/// <returns>The rotation in degrees.</returns>
public static double Roll(this Vector4 quaternion)
{
double value1 = 2.0 * (quaternion.W * quaternion.Z + quaternion.X * quaternion.Y);
double value2 = 1.0 - 2.0 * (quaternion.Y * quaternion.Y + quaternion.Z * quaternion.Z);
double yaw = Math.Atan2(value1, value2);
return yaw * (180.0 / Math.PI);
}
}
}
Then, in your main C# file, import the following namespace:
using LightBuzz.Vitruvius;
And, finally, specify the joint you would like to measure the orientation for and call the Roll, Pitch, and Yaw methods:
var orientation = body.JointOrientations[JointType.ElbowLeft].Orientation;
var rotationX = orientation.Pitch();
var rotationY = orientation.Yaw();
var rotationZ = orientation.Roll();
Download the code on GitHub
Supported joints
Measuring the rotation of the human body joints is not a trivial job. Unfortunately, Kinect does not provide us with Orientation values for the Head, Hands, and Feet. These joints do not have a “parent” joint, so it’s extremely difficult to accurately measure their orientation. The orientation accuracy regarding the rest of the joints is pretty good. The supported joints are the following:
- Neck
- SpineShoulder
- SpineBase
- ShoulderLeft/ShoulderRight
- ElbowLeft/ElbowRight
- WristLeft/WristRight
- HipLeft/HipRight
- KneeLeft/KneeRight
The method described in this post will help you in most use-case scenarios, such as simple games. In case you would like to have increased accuracy (e.g. healthcare apps), you’ll need to use more complex algorithms, which involve a lot of custom coding. LightBuzz has a lot of experience with this kind of algorithms and could help you with your project.
Summary
In this blog post, you’ve learnt how to easily measure the rotation of the human body joints around the X, Y, and Z axis.
PS: Vitruvius
If you liked this post, then you’ll love Vitruvius. Vitruvius is the result of our Kinect research during the past 5 years. Vitruvius will help you minimize the development time and create tough applications with just a few lines of code! Includes advanced Mathematics, Avateering, Video Recording, Face Tracking, and more.
‘Til the next time, keep Kinecting!
Hi,
I used this code to calculate my angles from kinect. But I have a problem, I put this angles into my avatar in Unity but it doesn’t work well, like the coordinate systems are not the same. How can I fix it? What coordinate system it is used here?
Tranks,
Albert
Hello. Some of the Kinect joints do not have any rotation values (e.g. the Head joint). So, it won’t be possible to have a one-on-one mapping with Unity. For avateering, I would strongly recommend Vitruvius.
Hi Vagnos,
i recently buy Vitruvius it works perfectly
but i want to calculate the wrist and the hips rotation,is this possible using vitruvius ?
Thank you very much, David! I’m glad you enjoy the product. The rotation of the wrist is tricky because Kinect does not provide reliable orientation information for the end joints (head, wrists, feet).
However, you could estimate the rotation in terms of other joints.
For example, to measure the rotation of the hip, you could check the angle between the hip, the spine, and the knee. To measure the rotation of the wrist, you could measure the angle between the wrist, the hand, and the Z axis. You can do this with the help of the Angle() method.
This a lot for this project.
please, I need a reference to the calculations used to convert from quaternion to Roll, Pitch, and Yaw angles.
You can check this reference.