从 ARKit 中的 faceAnchor 中提取 yaw/pitch/roll

问题描述

使用 ARKit 进行面部跟踪,一旦检测到面部,我就会得到 faceAnchor (ARFaceAnchor),它提供了一个 simd_float4x4 矩阵。我了解变换矩阵,并且我也知道该主题已部分解决(此处:How to get values from simd_float4 in objective-c 和此处:simd_float4x4 Columns),但是是否有一种直接的方法来获取 yaw/pitch/rool 值从面锚? (为了在下面的代码中输入我的 y/p/r 值)。

    func renderer(_ renderer: SCNSceneRenderer,didUpdate node: SCNNode,for anchor: ARAnchor) {
        let faceAnchor = anchor as? ARFaceAnchor
        let data = faceAnchor?.transform
        print(data!)
        let message = OSCMessage(
            OSCAddressPattern("/orientation"),yawValue,pitchValue,rollValue
        )
        client.send(message)
        print(message)
        
    }

仅供参考,OSCMessage 来自嵌入在我的项目中的 SwiftOSC 框架。

解决方法

由于 Apple 显然(还)没有为此目的提供函数,因此需要先验地实现四元数到欧拉角的计算。使用 these mathematical resources 和弧度到度数的转换函数,这可以作为扩展实现,如下所示:

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
            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
            /// 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)
            }
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...