使用Xamarin和C#的ARKit身体跟踪不准确 [英] ARKit Body Tracking using Xamarin and C# Inaccurate

查看:117
本文介绍了使用Xamarin和C#的ARKit身体跟踪不准确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试翻译一些Swift示例(例如,这个

 使用ARKit;使用基金会;使用OpenTK;使用SceneKit;使用系统;使用System.Collections.Generic;使用UIKit;命名空间XamarinArkitSample{公共局部类BodyDetectionViewController:UIViewController{私有只读ARSCNView sceneView;公共BodyDetectionViewController(){this.sceneView =新的ARSCNView{AutoenablesDefaultLighting = true,委托=新的SceneViewDelegate()};this.View.AddSubview(this.sceneView);}公共重写void ViewDidLoad(){base.ViewDidLoad();this.sceneView.Frame = this.View.Frame;}公共重写void ViewDidAppear(布尔动画){base.ViewDidAppear(动画);var bodyTrackingConfiguration = new ARBodyTrackingConfiguration(){WorldAlignment = ARWorldAlignment.Gravity};this.sceneView.Session.Run(bodyTrackingConfiguration,ARSessionRunOptions.ResetTracking |ARSessionRunOptions.RemoveExistingAnchors);}公共替代无效ViewDidDisappear(布尔动画){base.ViewDidDisappear(动画);this.sceneView.Session.Pause();}公共重写void DidReceiveMemoryWarning(){base.DidReceiveMemoryWarning();}公共类SceneViewDelegate:ARSCNViewDelegate{字典< string,JointNode>joints = new Dictionary< string,JointNode>();浮动关节半径= 0.02f;UIColor jointColour = UIColor.Green;公共重写void DidAddNode(ISCNSceneRenderer渲染器,SCNNode节点,ARAnchor锚点){如果(锚定为ARBodyAnchor bodyAnchor){foreach(ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames中的var jointName){var jointNode = MakeJoint(jointRadius,jointColour);尝试{var jointPosition = GetJointPosition(bodyAnchor,jointName);jointNode.Position = jointPosition;//System.Diagnostics.Debug.WriteLine($将{jointName}节点添加到位置{jointPosition.X},{jointPosition.Y},{jointPosition.Z}");如果(!joints.ContainsKey(jointName)){node.AddChildNode(jointNode);joints.Add(jointName,jointNode);}}抓住(前例外){System.Diagnostics.Debug.WriteLine($" {ex.Message}");}}}}公共重写void DidUpdateNode(ISCNSceneRenderer渲染器,SCNNode节点,ARAnchor锚点){如果(锚定为ARBodyAnchor bodyAnchor){foreach(ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames中的var jointName){尝试{var jointPosition = GetJointPosition(bodyAnchor,jointName);如果(joints.ContainsKey(jointName)){joints [jointName] .Update(jointPosition);//System.Diagnostics.Debug.WriteLine($将{jointName}节点更新到位置{jointPosition.X},{jointPosition.Y},{jointPosition.Z}");}}抓住(前例外){System.Diagnostics.Debug.WriteLine($" {ex.Message}");}}}}私有SCNVector3 GetJointPosition(ARBodyAnchor bodyAnchor,字符串jointName){//https://github.com/iamfine/ARSkeletonNMatrix4 jointTransform = bodyAnchor.Skeleton.GetModelTransform((NSString)jointName);//方法1SCNMatrix4矩阵= jointTransform.ToSCNMatrix4();SCNMatrix4 bodyAnchorTransform = bodyAnchor.Transform.ToSCNMatrix4();SCNMatrix4.Mult(参考矩阵,ref bodyAnchorTransform,输出矩阵);返回新的SCNVector3(matrix.M41,matrix.M42,matrix.M43);//方法2/*var结果= bodyAnchor.Transform.Column3 + jointTransform.Column3;返回新的SCNVector3(result);*/}私有JointNode MakeJoint(float jointRadius,UIColor jointColour){var jointNode = new JointNode();var material = new SCNMaterial();material.Diffuse.Contents = jointColour;var jointGeometry = SCNSphere.Create(jointRadius);jointGeometry.FirstMaterial =材料;jointNode.Geometry = jointGeometry;返回jointNode;}}公共类JointNode:SCNNode{公共无效更新(SCNVector3位置){this.Position =位置;}}}公共静态类扩展{公共静态SCNMatrix4 ToSCNMatrix4(此NMatrix4自已){var newMatrix =新的SCNMatrix4(自我M11,自我M21,自我M31,自我M41,self.M12,self.M22,self.M32,self.M42,self.M13,self.M23,self.M33,self.M43,self.M14,self.M24,self.M34,self.M44);返回newMatrix;}}} 

解决方案

这样我就可以了.似乎我使如何确定每个关节节点的X,Y,Z位置过于复杂.我要做的就是这个.

  private SCNVector3 GetJointPosition(ARBodyAnchor bodyAnchor,字符串jointName){NMatrix4 jointTransform = bodyAnchor.Skeleton.GetModelTransform((NSString)jointName);返回新的SCNVector3(jointTransform.Column3);} 

这是完整的清单.

 使用ARKit;使用基金会;使用OpenTK;使用SceneKit;使用系统;使用System.Collections.Generic;使用UIKit;命名空间XamarinArkitSample{公共局部类BodyDetectionViewController:UIViewController{私有只读ARSCNView sceneView;公共BodyDetectionViewController(){this.sceneView =新的ARSCNView{AutoenablesDefaultLighting = true,委托=新的SceneViewDelegate()};this.View.AddSubview(this.sceneView);}公共重写void ViewDidLoad(){base.ViewDidLoad();this.sceneView.Frame = this.View.Frame;}公共重写void ViewDidAppear(布尔动画){base.ViewDidAppear(动画);var bodyTrackingConfiguration = new ARBodyTrackingConfiguration(){WorldAlignment = ARWorldAlignment.Gravity};this.sceneView.Session.Run(bodyTrackingConfiguration);}公共替代无效ViewDidDisappear(布尔动画){base.ViewDidDisappear(动画);this.sceneView.Session.Pause();}公共重写void DidReceiveMemoryWarning(){base.DidReceiveMemoryWarning();}公共类SceneViewDelegate:ARSCNViewDelegate{字典< string,JointNode>joints = new Dictionary< string,JointNode>();浮动关节半径= 0.04f;UIColor jointColour = UIColor.Yellow;公共重写void DidAddNode(ISCNSceneRenderer渲染器,SCNNode节点,ARAnchor锚点){如果(!(锚是ARBodyAnchor bodyAnchor))返回;foreach(ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames中的var jointName){JointNode jointNode = MakeJoint(jointRadius,jointColour);var jointPosition = GetJointPosition(bodyAnchor,jointName);jointNode.Position = jointPosition;如果(!joints.ContainsKey(jointName)){node.AddChildNode(jointNode);joints.Add(jointName,jointNode);}}}公共重写void DidUpdateNode(ISCNSceneRenderer渲染器,SCNNode节点,ARAnchor锚点){如果(!(锚是ARBodyAnchor bodyAnchor))返回;foreach(ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames中的var jointName){var jointPosition = GetJointPosition(bodyAnchor,jointName);如果(joints.ContainsKey(jointName)){joints [jointName] .Update(jointPosition);}}}私有SCNVector3 GetJointPosition(ARBodyAnchor bodyAnchor,字符串jointName){NMatrix4 jointTransform = bodyAnchor.Skeleton.GetModelTransform((NSString)jointName);返回新的SCNVector3(jointTransform.Column3);}私有JointNode MakeJoint(float jointRadius,UIColor jointColour){var jointNode = new JointNode();var material = new SCNMaterial();material.Diffuse.Contents = jointColour;var jointGeometry = SCNSphere.Create(jointRadius);jointGeometry.FirstMaterial =材料;jointNode.Geometry = jointGeometry;返回jointNode;}}公共类JointNode:SCNNode{公共无效更新(SCNVector3位置){this.Position =位置;}}}公共静态类扩展{公共静态SCNMatrix4 ToSCNMatrix4(此NMatrix4自已){var row0 =新的SCNVector4(self.M11,self.M12,self.M13,self.M14);var row1 = new SCNVector4(self.M21,self.M22,self.M23,self.M24);var row2 = new SCNVector4(self.M31,self.M32,self.M33,self.M34);var row3 = new SCNVector4(self.M41,self.M42,self.M43,self.M44);返回新的SCNMatrix4(row0,row1,row2,row3);}}} 

有些微调整看起来像这样.

还有一个视频在这里工作.

https://www.youtube.com/watch?v=VxM1RMlYdAo

I am trying to translate some Swift examples (such as this one https://github.com/iamfine/ARSkeleton) to C# that show how to use ARKit Body Tracking.

But I don't quite seem able to position the joint nodes correctly over the corresponding joints. They follow my body movements, but the position of the nodes seem to be incorrect.

Can anyone familiar with ARKit Body Tracking see what I am doing wrong?

Thanks

using ARKit;
using Foundation;
using OpenTK;
using SceneKit;
using System;
using System.Collections.Generic;
using UIKit;

namespace XamarinArkitSample
{
    public partial class BodyDetectionViewController : UIViewController
    {
        private readonly ARSCNView sceneView;

        public BodyDetectionViewController()
        {
            this.sceneView = new ARSCNView
            {
                AutoenablesDefaultLighting = true,
                Delegate = new SceneViewDelegate()
            };

            this.View.AddSubview(this.sceneView);
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            this.sceneView.Frame = this.View.Frame;
        }

        public override void ViewDidAppear(bool animated)
        {
            base.ViewDidAppear(animated);

            var bodyTrackingConfiguration = new ARBodyTrackingConfiguration()
            {
                WorldAlignment = ARWorldAlignment.Gravity
            };

            this.sceneView.Session.Run(bodyTrackingConfiguration,
                ARSessionRunOptions.ResetTracking | ARSessionRunOptions.RemoveExistingAnchors);
        }

        public override void ViewDidDisappear(bool animated)
        {
            base.ViewDidDisappear(animated);
            this.sceneView.Session.Pause();
        }

        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
        }

        public class SceneViewDelegate : ARSCNViewDelegate
        {
            Dictionary<string, JointNode> joints = new Dictionary<string, JointNode>();
            float jointRadius = 0.02f;
            UIColor jointColour = UIColor.Green;

            public override void DidAddNode(ISCNSceneRenderer renderer, SCNNode node, ARAnchor anchor)
            {
                if (anchor is ARBodyAnchor bodyAnchor)
                {
                    foreach (var jointName in ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames)
                    {
                        var jointNode = MakeJoint(jointRadius, jointColour);

                        try
                        {
                            var jointPosition = GetJointPosition(bodyAnchor, jointName);
                            jointNode.Position = jointPosition;
                           
                            //System.Diagnostics.Debug.WriteLine($"Adding {jointName} node to position {jointPosition.X},{jointPosition.Y},{jointPosition.Z}");

                            if (!joints.ContainsKey(jointName))
                            {
                                node.AddChildNode(jointNode);
                                joints.Add(jointName, jointNode);
                            }
                        }
                        catch (Exception ex)
                        {
                            System.Diagnostics.Debug.WriteLine($"{ex.Message}");
                        }
                    }
                }
            }

            public override void DidUpdateNode(ISCNSceneRenderer renderer, SCNNode node, ARAnchor anchor)
            {
                if (anchor is ARBodyAnchor bodyAnchor)
                {
                    foreach (var jointName in ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames)
                    {
                        try
                        {
                            var jointPosition = GetJointPosition(bodyAnchor, jointName);

                            if (joints.ContainsKey(jointName))
                            {
                                joints[jointName].Update(jointPosition);
                                //System.Diagnostics.Debug.WriteLine($"Updating {jointName} node to position {jointPosition.X},{jointPosition.Y},{jointPosition.Z}");
                            }
                        }
                        catch (Exception ex)
                        {
                            System.Diagnostics.Debug.WriteLine($"{ex.Message}");

                        }
                    }
                }
            }

            private SCNVector3 GetJointPosition(ARBodyAnchor bodyAnchor, string jointName)
            {
                // https://github.com/iamfine/ARSkeleton
                
                NMatrix4 jointTransform = bodyAnchor.Skeleton.GetModelTransform((NSString)jointName);

                // Approach 1
                SCNMatrix4 matrix = jointTransform.ToSCNMatrix4();
                SCNMatrix4 bodyAnchorTransform = bodyAnchor.Transform.ToSCNMatrix4();
                SCNMatrix4.Mult(ref matrix, ref bodyAnchorTransform, out matrix);
                return new SCNVector3(matrix.M41, matrix.M42, matrix.M43);

                // Approach 2
                /*
                var result = bodyAnchor.Transform.Column3 + jointTransform.Column3;
                return new SCNVector3(result);
                */
            }

            private JointNode MakeJoint(float jointRadius, UIColor jointColour)
            {
                var jointNode = new JointNode();

                var material = new SCNMaterial();
                material.Diffuse.Contents = jointColour;

                var jointGeometry = SCNSphere.Create(jointRadius);
                jointGeometry.FirstMaterial = material;
                jointNode.Geometry = jointGeometry;

                return jointNode;
            }
        }

        public class JointNode : SCNNode
        {
            public void Update(SCNVector3 position)
            {
                this.Position = position;
            }
        }
    }

    
    public static class Extensions
    {
        public static SCNMatrix4 ToSCNMatrix4(this NMatrix4 self)
        {
            var newMatrix = new SCNMatrix4(
                self.M11, self.M21, self.M31, self.M41,
                self.M12, self.M22, self.M32, self.M42,
                self.M13, self.M23, self.M33, self.M43,
                self.M14, self.M24, self.M34, self.M44
            );

            return newMatrix;
        }
    }
    
}

解决方案

So I got it working. It seems I was overcomplicating how to determine the X,Y,Z position of each joint node.. all I needed to do was this..

private SCNVector3 GetJointPosition(ARBodyAnchor bodyAnchor, string jointName)
{
   NMatrix4 jointTransform = bodyAnchor.Skeleton.GetModelTransform((NSString)jointName);
   return new SCNVector3(jointTransform.Column3);
}

Here is the full listing..

using ARKit;
using Foundation;
using OpenTK;
using SceneKit;
using System;
using System.Collections.Generic;
using UIKit;

namespace XamarinArkitSample
{
    public partial class BodyDetectionViewController : UIViewController
    {
        private readonly ARSCNView sceneView;

        public BodyDetectionViewController()
        {
            this.sceneView = new ARSCNView
            {
                AutoenablesDefaultLighting = true,
                Delegate = new SceneViewDelegate()
            };

            this.View.AddSubview(this.sceneView);
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            this.sceneView.Frame = this.View.Frame;
        }

        public override void ViewDidAppear(bool animated)
        {
            base.ViewDidAppear(animated);

            var bodyTrackingConfiguration = new ARBodyTrackingConfiguration()
            {
                WorldAlignment = ARWorldAlignment.Gravity
            };

            this.sceneView.Session.Run(bodyTrackingConfiguration);
        }

        public override void ViewDidDisappear(bool animated)
        {
            base.ViewDidDisappear(animated);
            this.sceneView.Session.Pause();
        }

        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
        }

        public class SceneViewDelegate : ARSCNViewDelegate
        { 
            Dictionary<string, JointNode> joints = new Dictionary<string, JointNode>();
            float jointRadius = 0.04f;
            UIColor jointColour = UIColor.Yellow;

            public override void DidAddNode(ISCNSceneRenderer renderer, SCNNode node, ARAnchor anchor)
            {
                if (!(anchor is ARBodyAnchor bodyAnchor))
                    return;

                foreach (var jointName in ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames)
                {
                    JointNode jointNode = MakeJoint(jointRadius, jointColour);

                    var jointPosition = GetJointPosition(bodyAnchor, jointName);
                    jointNode.Position = jointPosition;
                           
                    if (!joints.ContainsKey(jointName))
                    {
                        node.AddChildNode(jointNode);
                        joints.Add(jointName, jointNode);
                    }
                }
            }

            public override void DidUpdateNode(ISCNSceneRenderer renderer, SCNNode node, ARAnchor anchor)
            {
                if (!(anchor is ARBodyAnchor bodyAnchor))
                    return;

                foreach (var jointName in ARSkeletonDefinition.DefaultBody3DSkeletonDefinition.JointNames)
                {       
                    var jointPosition = GetJointPosition(bodyAnchor, jointName);

                    if (joints.ContainsKey(jointName))
                    {
                        joints[jointName].Update(jointPosition);
                    }   
                }
            }

            private SCNVector3 GetJointPosition(ARBodyAnchor bodyAnchor, string jointName)
            {
                NMatrix4 jointTransform = bodyAnchor.Skeleton.GetModelTransform((NSString)jointName);
                return new SCNVector3(jointTransform.Column3);
            }

            private JointNode MakeJoint(float jointRadius, UIColor jointColour)
            {
                var jointNode = new JointNode();

                var material = new SCNMaterial();
                material.Diffuse.Contents = jointColour;

                var jointGeometry = SCNSphere.Create(jointRadius);
                jointGeometry.FirstMaterial = material;
                jointNode.Geometry = jointGeometry;

                return jointNode;
            }
        }

        public class JointNode : SCNNode
        {
            public void Update(SCNVector3 position)
            {
                this.Position = position;
            }
        }
    }

    
    public static class Extensions
    {
        public static SCNMatrix4 ToSCNMatrix4(this NMatrix4 self)
        {
            var row0 = new SCNVector4(self.M11, self.M12, self.M13, self.M14);
            var row1 = new SCNVector4(self.M21, self.M22, self.M23, self.M24);
            var row2 = new SCNVector4(self.M31, self.M32, self.M33, self.M34);
            var row3 = new SCNVector4(self.M41, self.M42, self.M43, self.M44);
            return new SCNMatrix4(row0, row1, row2, row3);
        }
    }
}

Which with a bit of tweaking looks like this..

And a video of it working here..

https://www.youtube.com/watch?v=VxM1RMlYdAo

这篇关于使用Xamarin和C#的ARKit身体跟踪不准确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆