1

I am trying to get real-world human body height from ARBodyAnchor. I understand that I can get real-world distance between body joints. For example hip to foot-joint as in code below. But how do I get distance from top of head to bottom of foot?

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    if anchor is ARBodyAnchor {
        let footIndex = ARSkeletonDefinition.defaultBody3D.index(for: .leftFoot)
        let footTransform = ARSkeletonDefinition.defaultBody3D.neutralBodySkeleton3D!.jointModelTransforms[footIndex]
        let distanceFromHipOnY = abs(footTransform.columns.3.y)
        print(distanceFromHipOnY)
    }
}
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Kashif
  • 4,642
  • 7
  • 44
  • 97

1 Answers1

2

enter image description here

The default height of ARSkeleton3D from right_toes_joint (or if you wish left_toes_joint) to head_joint is 1.71 meters. And since head_joint in Apple's skeletal system's definition is the upmost skeleton's point, you can use the common skull's height – from eye line to crown.

In other words, the distance from neck_3_joint to head_joint in virtual model's skeleton is approximately the same as from head_joint to crown.

enter image description here

There are 91 joint in ARSkeleton3D:

print(bodyAnchor.skeleton.jointModelTransforms.count)      // 91

Code:

extension ViewController: ARSessionDelegate {

    func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
    
        for anchor in anchors {
        
            guard let bodyAnchor = anchor as? ARBodyAnchor
            else { return }

            let skeleton = bodyAnchor.skeleton

            for (i, joint) in skeleton.definition.jointNames.enumerated() {
                print(i, joint)

                // [10] right_toes_joint
                // [51] head_joint
            }
        
            let toesJointPos = skeleton.jointModelTransforms[10].columns.3.y
            let headJointPos = skeleton.jointModelTransforms[51].columns.3.y

            print(headJointPos - toesJointPos)       // 1.6570237 m
        }
    }
}

However, we have a compensator:

bodyAnchor.estimatedScaleFactor

ARKit must know the height of a person in the camera feed to estimate an accurate world position for the person's body anchor. ARKit uses the value of estimatedScaleFactor to correct the body anchor's position in the physical environment.

The default real-world body is 1.8 meters tall. (some kind of mismatch...)

The default value of estimatedScaleFactor is 1.0.

If you set:

let config = ARBodyTrackingConfiguration()
config.automaticSkeletonScaleEstimationEnabled = true
arView.session.run(config, options: [])

ARKit sets this property to a value between 0.0 and 1.0.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    Thanks @Andy for the answer. Apple is doing body height measurement in its stock MEASURE app. Do you think they do it the same way or they a better more precise way of doing it? – Kashif Mar 01 '22 at 17:20
  • Hi @Kashif, it's hard to say, because they are real keepers of iOS MoCap )) I've updated my answer... – Andy Jazz Mar 01 '22 at 19:50
  • 1
    Thanks @AndyJazz. However, since the default height of the skeleton is always 1.71m, when we compute the height using the above formula, do we not always get the same value? How would one arrive at the “actual” / “real world” height of a human in the scene using this information? Do you suggest multiplying 1.71 with the estimatedScaleFactor? (which Apple says will be between 0 and 1 only, implying that the human can never be taller than 1.71m?) I am probably missing something trivial here, any guidance will truly help. Thanks – entropy.maximum May 02 '22 at 18:55
  • 1
    @AndyJazz apologies, I don’t follow. If I need to estimate height of a user in frame, I would love to know how I can use `.scale` to do so. – entropy.maximum May 03 '22 at 06:09
  • Sorry, @entropy.maximum, I misread your question. Yes, I totally agree with you, there are enough inconsistencies... But you've said: "...a parameter's value will be between 0 and 1 only, implying that the human can never be taller than 1.71 m...". This is not true. A distance from `toes_joint` to `head_joint` is 1.71 meter. Plus a distance from `head_joint` to a `crown`... Look at the second paragraph of my answer. – Andy Jazz May 03 '22 at 20:25
  • 1
    @AndyJazz Yup, agreed. Also, I ran some experiments and realised that the estimated scale factor can indeed be greater than 1 under some circumstances. I've seen it produce a value of 1.2 in some scenarios. And the added height from crown to head is probably the reason why the documentation refers to the default height as 1.8 in some scenarios and 1.71 in others. Either way, I think we can agree on the fact that it needs some rework. Thanks again! :) – entropy.maximum May 05 '22 at 06:32
  • @AndyJazz I did quite a bit of experimentation with this code, taking average of multiple measurements and average of measurements from right and left toes. Yet the results are inconsistent. Any other ideas how to make the results more realistic/consistent? – Kashif Jan 29 '23 at 20:36
  • @Kashif, Yes, I agree that multiple measurements' results are inconsistent, but unfortunately I have nothing more to add to the posted code. – Andy Jazz Jan 29 '23 at 21:23
  • 1
    Not sure If it will work or not but can we get the bounding box of the body anchor and calculate the Y axis to get height. Just a wild guess. – Jaswant Singh Feb 07 '23 at 11:24
  • @JaswantSingh, I'll publish your guess )). – Andy Jazz Feb 07 '23 at 11:29