Find angle of head tilt from ARFaceAnchor in an ARFaceTracking session
Asked Answered
B

1

7

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?

Beamends answered 18/3, 2018 at 17:55 Comment(3)
you might have solved that one right? I just asked a similar question, i.e. how to get euler angles directly from ARFaceAnchor ?Manna
sorry I still don't know the answer @DavidTheryBeamends
I think I have solved it in the meantime, see here if interested: #66083408Manna
M
2

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)
           }
   }
}
Manna answered 8/2, 2021 at 23:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.