与基于屏幕空间的 2D人体姿态估计不同,3D人体姿态估计是尝试还原人体在三维世界中的形状与姿态,包括深度信息。绝大多数的现有3D人体姿态估计方法依赖2D人体姿态估计,通过获取 2D人体姿态后再构建神经网络算法,实现从 2D 到 3D人体姿态的映射。
在 ARKit中,由于是采用计算机视觉的方式估计人体姿态,与2D人体姿态估计一样,3D人体姿态估计也受到遮挡、光照、姿态、视角的影响,并且相比于2D人体姿态估计,3D人体姿态估计计算量要大得多,也要复杂得多。但幸运的是,我们并不需要去关注底层的算法实现,ARKit会在检测到人体时直接提供一个ARBodyAnchor 类型对象,该对象包含一个 ARSkeleton3D类型的人体骨骼类型,通过这个类型可以获取所有检测到的人体骨骼关节点信息。ARBodyAnchor 描述了检测到的3D人形结构信息,其结构如下图所示。
对比图2D结构,可以看到,在 ARKit 中,2D与3D人体关节结构层次基本一致,唯一不同的是,在3D 人体结构中,多了一个表示 3D 人体空间位置信息的 Transform(ARBodyAnchor 下的Transform)。在使用上,这两者使用方法完全一样,只是代表3D 人体骨骼的Skeleton 结构比2D更复杂。
描述 3D人体骨骼结构的类为 ARSkeleton3D,也继承自 ARSkeleton 类,ARSkeleton3D 描述了3D空间中的人体骨骼节点结构。由于描述的人体结构是在三维空间中的层次结构,该类包含两个表示位置信息的数组 jointLocalTransforms 和 jointModelTransforms,其中jointLocalTransforms 描述的位置信息是某个节点相对其父节点的位置,而jointModelTransforms 描述的位置信息是相对检测到的ARBodyAnchor 位置。jointLocalTransforms 和 jointModelTransforms 包含的是3D空间中各关节点的位置信息矩阵。
在使用中,可以通过 ARSkeleton3D 的 localTransform(for: ARSkeleton. JointName)方法得到某个关节点相对其父节点的位置,此方法需要传递关节点的原始名称(rawValue)而不是ARSkeleton 预定义的关节点名(预定义关节点名可以通过其.rawValue 获取原始名称)。同样,我们也可以通过 modelTransform(for: ARSkeleton. JointName)方法得到某个关节点相对 ARBodyAnchor 的位置。
jointLocalTransforms 和 jointModelTransforms都是simd_float4x4 类型数组,因此我们也可以直接通过下标取到特定的关节点位置信息,下标方法取值比使用localTransform() 和 modelTransform()方法快得多,特别是对每次 ARAnchor update 都要执行的循环操作,可以节省很多时间。获取特定节点名称的索引值可以通过 definition.index (for:)方法实现。除此之外,还可以通过 ARSkeleton3D 的 isJointTracked(_:)方法查询每一个关节点在当前帧的检测跟踪情况,也可以获取每一个关节点的父节点。
得到姿态信息是一个仿射变换矩阵 在仿射变换矩阵中,每一列都代表了不同的变换元素。具体到 simd_float4x4 中,这四列分别对应于平移(Translation)、缩放(Scale)、旋转(Rotation)和透视(Perspective)的变换。
- 第一列 (columns.0): X 轴方向的基向量,它包含了 X 轴上的缩放比例。
- 第二列 (columns.1): Y 轴方向的基向量,它包含了 Y 轴上的缩放比例。
- 第三列 (columns.2): Z 轴方向的基向量,它包含了 Z 轴上的缩放比例。
- 第四列 (columns.3): 位移(Translation)向量,它包含了平移信息。
对于旋转矩阵来说,它是正交矩阵,因此其中的这三列(columns.0、columns.1、columns.2)是互相垂直的单位向量,表示了旋转的方向。而平移向量则描述了物体在空间中的位置。在 ARKit 中的 jointModelTransforms 中,这些矩阵描述了每个关节相对于整个人体坐标系的变换,因此你可以使用其中的这些信息来实现例如骨骼动画、渲染等效果。
3D人体姿态估计基础
3D人体姿态估计在娱乐电玩、体育科学、人机交互、教育培训、工业制造等领域都有着广泛的应用。在ARKit 中,我们可以很简单方便地从底层 API 中获取检测到的3D人体姿态估计数据信息,但应用这些数据却需要详细了解3D人体姿态估计数据结构。本节先从原理技术上阐述应用数据的机制,然后学习 ARKit中对3D人体骨骼节点的结构描述。
在2D人体姿态估计中,ARKit 使用了17个人体骨骼关节点对姿态信息进行描述,在3D人体姿态估计中,这个数量要大得多,共使用了91个人体骨骼关节点进行描述,并且这91个关节点并不在一个平面内,而是以三维的形式分布在3D空间中,与2D人体骨骼关节点一样,这些骨骼关节点对应真实人体骨骼位置,它们的分布与相互连接关系如图所示。
在图中,我们也可以看到,定义人体根骨骼的Root 节点不在脚底位置,而是在尾椎骨位置,所有其他骨骼都以 Root 节点为根。详细的骨骼节点关联关系如下表所示。
肢体部位 | 骨骼关节点名称 | 索引 | 父节点名称 | 索引 |
尾椎骨 | root | 0 | 无 | 一1 |
臀部 | hips_joint | 1 | root | 0 |
左腿 | left_upLeg_joint | 2 | hips_joint | 1 |
left_leg joint | 3 | left_upLeg_joint | 2 | |
left_foot_joint | 4 | left_leg_joint | 3 | |
left_toes_joint | 5 | left_foot_joint | 4 | |
left_toesEnd_joint | 6 | left_toes_joint | 5 | |
右腿 | right_upLeg_joint | 7 | hips_joint | 7 |
right_leg_joint | 8 | right_upLeg_joint | 7 | |
right_foot_joint | 9 | right_leg joint | 8 | |
right_toes _joint | 10 | right_foot_joint | 9 | |
right_toesEnd_joint | 11 | right_toes _joint | 10 | |
脊柱 | spine_1 _joint | 12 | hips_joint | 1 |
spine_2_joint | 13 | spine_ 1 joint | 12 | |
spine_3_joint | 14 | spine_2_joint | 13 | |
spine_4_joint | 15 | spine_3 _joint | 14 | |
spine_5 _joint | 16 | spine_4_joint | 15 | |
spine_6 _joint | 17 | spine_5_joint | 16 | |
spine_7_joint | 18 | spine_6_joint | 17 | |
左臂 | left_shoulder_1_joint | 19 | spine_? joint | 18 |
left_arm_joint | 20 | left_ shoulder_1_joint | 19 | |
left_forearm_ joint | 21 | left_arm_joint | 20 | |
左手 | left_hand_joint | 22 | left_forearm_joint | 21 |
左手食指 | left_handIndexStart_joint | 23 | left_hand_joint | 22 |
left_handIndex_ 1_joint | 24 | left_handIndexStart_joint | 23 | |
left_handIndex_2 _joint | 25 | left_handIndex_1 joint | 24 | |
left_handIndex_3_joint | 26 | left_handIndex_2_joint | 25 | |
left_handIndexEnd joint | 27 | left_handIndex_3 joint | 26 | |
左手中指 | left_handMidStart_joint | 28 | left_hand_joint | 22 |
left_handMid_1_ joint | 29 | left_handMidStart_joint | 28 | |
left_handMid_ 2_joint | 30 | left_handMid_1 _joint | 29 | |
left _handMid_3_joint | 31 | left_handMid_2 _joint | 30 | |
left_handMidEnd joint | 32 | left_handMid_3_joint | 31 | |
左手无名指 | left_handPinkyStart_joint | 33 | left_hand_joint | 22 |
left_handPinky_1_ joint | 34 | left_handPinkyStart_joint | 33 | |
left_handPinky_2 joint | 35 | left_handPinky_1 joint | 34 | |
left_handPinky_3 _joint | 36 | left_handPinky_ 2 joint | 35 | |
left_handPinkyEnd_joint | 37 | left_handPinky_3_joint | 36 |
肢体部位 | 骨骼关节点名称 | 索引 | 父节点名称 | 索引 |
左手小指 | left_handRingStart_joint | 38 | left_hand_joint | 22 |
left_handRing_1_joint | 39 | left_ handRingStart_joint | 38 | |
left_handRing_2 joint | 40 | left_handRing_ 1_joint | 39 | |
left handRing_3_joint | 41 | left_handRing_2_ joint | 40 | |
left_handRingEnd_joint | 42 | left_ handRing_3_joint | 41 | |
左手母指 | left_handThumbStart_ joint | 43 | lleft_hand_joint | 22 |
left handThumb_1_joint | 44 | left_handThumbStart_ joint | 43 | |
left_handThumb_2 _joint | 45 | left_handThumb_1_joint | 44 | |
left handThumbEnd_joint | 46 | left_handThumb_2_joint | 45 | |
颈椎 | neck_1 _joint | 47 | spine_7_ joint | 18 |
neck 2 joint | 48 | neck_1 _joint | 47 | |
neck_3_joint | 49 | neck_2 joint | 48 | |
neck_4 joint | 50 | neck_3 _joint | 49 | |
头部 | head_joint | 51 | neck_4 _joint | 50 |
下巴 | jaw_joint | 52 | head_ joint | 51 |
chin_ joint | 53 | jaw_ joint | 52 | |
左眼 | left_eye _joint | 54 | head_joint | 51 |
left_eyeLowerLid_joint | 55 | left_eye_joint | 54 | |
left_eyeUpperLid_joint | 56 | left_eye_joint | 54 | |
left_ eyeball_joint | 57 | left_eye_joint | 54 | |
鼻子 | nose_joint | 58 | head joint | 51 |
右眼 | right_eye joint | 59 | head_joint | 51 |
right_ eyeLowerLid_joint | 60 | right_eye_joint | 59 | |
right_eyeUpperLid joint | 61 | right_eye_joint | 59 | |
right_eyeball_joint | 62 | right_eye_ joint | 59 | |
右臂 | right_shoulder_1 _joint | 63 | spine_7_joint | 18 |
right_arm_joint | 64 | right_shoulder_1_joint | 63 | |
right_forearm_joint | 65 | right_arm_ joint | 64 | |
右手 | right_hand_joint | 66 | right_forearm_joint | 65 |
右手食指 | right_handIndexStart_ joint | 67 | right_hand_joint | 66 |
right_handindex_ 1_joint | 68 | right_handIndexStart_joint | 67 | |
right_ handIndex_2 joint | 69 | right_handIndex_ 1_joint | 68 | |
right_handIndex_3_joint | 70 | right_handIndex_2_ joint | 69 | |
right_handIndexEnd_joint | 71 | right_handIndex_3_joint | 70 | |
右手中指 | right_ handMidStart_joint | 72 | right_hand_joint | 66 |
right_handMid_1_ joint | 73 | right_handMidStart_joint | 72 | |
right_handMid_2_joint | 74 | right_handMid_1_joint | 73 | |
right_handMid_3 _joint | 75 | right_ handMid_ 2 joint | 74 | |
right_ handMidEnd_joint | 76 | right_handMid_3 _joint | 75 |
肢体部位 | 骨骼关节点名称 | 索引 | 父节点名称 | 索引 |
右手无名指 | right_handPinkyStart_ joint | 77 | right_hand_joint | 66 |
right_ handPinky_1_joint | 78 | right_handPinkyStart _joint | 77 | |
right_handPinky_2_ joint | 79 | right_handPinky_1_joint | 78 | |
right_handPinky_3_ joint | 80 | right_handPinky_2 _joint | 79 | |
right_ handPinkyEnd_joint | 81 | right_handPinky_3_joint | 80 | |
右手小指 | right_handRingStart_joint | 82 | right_hand_joint | 66 |
right_handRing_ 1_joint | 83 | right_handRingStart_joint | 82 | |
right_ handRing_2_joint | 84 | right_handRing_ 1_joint | 83 | |
right_handRing_3 joint | 85 | right_handRing_2 joint | 84 | |
right_handRingEnd _joint | 86 | right_handRing_3_joint | 85 | |
右手母指 | right_handThumbStart_ joint | 87 | right_hand_joint | 66 |
right_handThumb_1_joint | 88 | right_handThumbStart_joint | 87 | |
right_handThumb_2_joint | 89 | right_handThumb_1_joint | 88 | |
right_handThumbEnd_joint | 90 | right_handThumb_2 _joint | 89 |
人体骨骼关节点名称开发者可以自行定义,但关节点数量、序号、关联关系必须与表中一致。如果用于驱动三维模型,人体骨骼关节点命名建议应与模型骨骼命名完全一致以减少错误和降低程序绑定压力。