Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find angle of head tilt from ARFaceAnchor in an ARFaceTracking session

I am trying to find the angle of the head with regards to the y axis in a ARFaceAnchor. My starting example is Apple's sample code: creating face-based AR experiences.

Given this image, I am basically searching for the angle of the green marker (from the coordinateOrigin node) relative to the vertical axis.

enter image description here

The ARFaceAnchor object inherits from ARAnchor , providing atransform` property:

A matrix encoding the position, orientation, and scale of the anchor relative to the world coordinate space of the AR session the anchor is placed in.

The type of such transform is as follows: var transform: matrix_float4x4 { get }

How do I derive angle information such as the one described from this matrix?

like image 371
atineoSE Avatar asked Mar 18 '18 17:03

atineoSE


1 Answers

As Apple does not provide a quaternion to euler conversion for this class, in my case I had to compute them by hand as shown below.

Please find the reference here, which is inspired by this mathematical resource.

extension matrix_float4x4 {
   // Function to convert rad to deg
   func radiansToDegress(radians: Float32) -> Float32 {
       return radians * 180 / (Float32.pi)
   }
   var translation: SCNVector3 {
      get {
          return SCNVector3Make(columns.3.x, columns.3.y, columns.3.z)
      }
   }
   // Retrieve euler angles from a quaternion matrix
   var eulerAngles: SCNVector3 {
       get {
           // Get quaternions
           // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
           let qw = sqrt(1 + self.columns.0.x + self.columns.1.y + self.columns.2.z) / 2.0
           let qx = (self.columns.2.y - self.columns.1.z) / (qw * 4.0)
           let qy = (self.columns.0.z - self.columns.2.x) / (qw * 4.0)
           let qz = (self.columns.1.x - self.columns.0.y) / (qw * 4.0)

           // Deduce euler angles with some cosines
           // https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
           /// yaw (z-axis rotation)
           let siny = +2.0 * (qw * qz + qx * qy)
           let cosy = +1.0 - 2.0 * (qy * qy + qz * qz)
           let yaw = radiansToDegress(radians:atan2(siny, cosy))
           // pitch (y-axis rotation)
           let sinp = +2.0 * (qw * qy - qz * qx)
           var pitch: Float
           if abs(sinp) >= 1 {
               pitch = radiansToDegress(radians:copysign(Float.pi / 2, sinp))
           } else {
               pitch = radiansToDegress(radians:asin(sinp))
           }
           /// roll (x-axis rotation)
           let sinr = +2.0 * (qw * qx + qy * qz)
           let cosr = +1.0 - 2.0 * (qx * qx + qy * qy)
           let roll = radiansToDegress(radians:atan2(sinr, cosr))
           
           /// return array containing ypr values
           return SCNVector3(yaw, pitch, roll)
           }
   }
}
like image 122
David Thery Avatar answered Nov 15 '22 00:11

David Thery