百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

ARKit实现人体动作捕捉功能(asoul动作捕捉设备)

cac55 2024-11-15 16:39 18 浏览 0 评论

Apple 已经成为动作捕捉行业的新玩家!可以说,其推出的 ARKit 将和移动设备 Kinect 相媲美。人物遮挡功能以及动作预测是 ARKit 框架的核心部分。本部分向你展示如何利用 iPhone 和 iPad 设备开发动作捕捉应用程序。

前提条件

因为我们开发的是 Apple 系统的应用,所以需要使用 Mac 计算机开发应用程序并利用 iOS 设备运行它们。

硬件

在硬件方面,你需要一个兼容 MacOS Catalina 系统的 MacOS 计算机。此外,动作捕捉应用程序需要 Apple A12 仿生处理器(Apple A12 Bionic processors)才能正常运行。以下 Mac 计算机和 iOS 设备都需要具备的开发条件:

对于这个指南,我使用的是一台 Mac Mini 主机和一个 11 寸 iPad Pro。

软件

为了运行顺利,您需要在您的 Mac 电脑中安装如下软件:

Unity3D 2019 mac 2019.1.5f1

MacOS Catalina 10.15 (Beta)

XCode 11 (Beta)

您的 IOS 设备需要更新至 iOS 13 (Beta)系统或者 iPadOS 13(Beta)系统。

正如你所看到的,在编写这篇文章时,大多数软件都是测试版(Beta)。请记住,设备可能会变得不稳定或无响应,因此要特别小心,不要丢失有价值的数据。新的文章将伴随着 ARKit3、iOS13 和 MacOS10.15 的公开发布。

如果你着急,请在 GitHub 上下载完整的源代码(代码地址:https://github.com/LightBuzz/Body-Tracking-ARKit )。

继续阅读,了解如何创建自己的动作捕捉应用程序!

详细步骤

说的足够多了…让我们驶入 ARKit 的魔法世界吧。在你的电脑上,打开 Unity3D 2019.1 并且创建一个新的工程文件。

步骤一:设置主要的场景

Unity3D 将从一个空场景开始。在添加任何视觉对象(visual objects)或编写任何代码之前,我们首先需要导入适当的资源包(dependencies)。骨架跟踪功能是 ARKit 工具包的一部分。因此,我们需要导入 ARKit 和 ARFoundation 依赖包。

现在,创建一个新场景并添加 AR Session 和 AR Session Origin 对象(在 Unity 中创造 AR 场景,首先做的都是这两件事情)。这些对象控制 iOS 相机的同时也会提供大量的 ARKit 其他体验功能。

另外,添加一个空的游戏对象,例如命名它为:Human Body Tracking,并附加一个新的 C#脚本(HumanBodyTracking.cs)。

场景的结构看起来是这样的:

步骤二:设置骨架

视觉元素已经到位,我们现在可以开始添加一些交互性。打开HumanBodyTracking.cs脚本,引用ARHumanBodyManager 类。ARHuman Body Manager 是分析摄像机数据以检测人体的主要脚本。代码如下:

[SerializeField] private ARHumanBodyManager humanBodyManager;

为了显示关节,我们将使用一些简单的 Unity3D 球体材质。每个球体将对应于特定的关节模式。添加一个 C# Dictionary 类,以逐帧(frame-by-frame)更新关节数据。代码如下:

private Dictionary<JointIndices3D, Transform> bodyJoints;

最后,添加对骨架的用户界面元素的引用。我们需要球体材质作为关节,线材质作为骨骼。代码如下:

[SerializeField] private GameObject jointPrefab;
[SerializeField] private GameObject lineRendererPrefab;
private LineRenderer[] lineRenderers;
private Transform[][] lineRendererTransforms;

你可以在 GitHub 上找到 HumanBodyTracking.cs 这个类完整的 C#代码。(GitHub 地址:https://github.com/LightBuzz/Body-Tracking-ARKit/blob/master/body-tracking-arkit/Assets/Scripts/HumanBodyTracking.cs )

步骤三:动作捕捉检测

这是教程中最重要的部分!ARKit 已经使动作捕捉变得非常容易实现。你所需要的就是用 ARHumanBodyManger 对象并且订阅到humanBidiesChanged 事件。

private void OnEnable()
{
    humanBodyManager.humanBodiesChanged += OnHumanBodiesChanged;
}
private void OnDisable()
{
    humanBodyManager.humanBodiesChanged -= OnHumanBodiesChanged;
}

humanBidiesChanged 事件就好像是实现动作捕捉功能的咒语。动作捕捉的信息是事件参数的一部分。下面将告诉您如何获取动作:


private void OnHumanBodiesChanged(ARHumanBodiesChangedEventArgs eventArgs)
{
    foreach (ARHumanBody humanBody in eventArgs.added)
    {
        UpdateBody(humanBody);
    }
    foreach (ARHumanBody humanBody in eventArgs.updated)
    {
        UpdateBody(humanBody);
    }
}

很简单,对不对?所以,让我们完成以上操作,并在先前创建的 Unity 用户界面中显示骨架。

注意:笔者在写这篇文章时,ARKit 仅仅支持单个人物的动作捕捉。

步骤四:展示骨架

以下的代码会更新相机中关节的位置。在 iOS 相机摄像头中,球体材质和线材质都会被覆盖(overlayed)。


private void UpdateBody(ARHumanBody arBody)
{
    if (jointPrefab == null) return;
    if (arBody == null) return;
    if (arBody.transform == null) return;
    InitializeObjects(arBody.transform);
    NativeArray<XRHumanBodyJoint> joints = arBody.joints;
    
    foreach (KeyValuePair<JointIndices3D, Transform> item in bodyJoints)
    {
        UpdateJointTransform(item.Value, joints[(int)item.Key]);
    }
    for (int i = 0; i < lineRenderers.Length; i++)
    {
        lineRenderers[i].SetPositions(lineRendererTransforms[i]);
    }
}

Apple 支持 92 种关联模式(指数)。然而,不是所有的关联模式都能被追踪到!大多数是根据它们相邻关节的位置推断出来的。为了您的方便,我选择了 14 种关联模式,这样能够和 Kinect 相机公平比较。下面是如何连接合适的关节并形成人体骨骼的代码:

private void InitializeObjects(Transform arBodyT)
{
    if (bodyJoints == null)
    {
        bodyJoints = new Dictionary<JointIndices3D, Transform>
        {
            { JointIndices3D.head_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.neck_1_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.left_arm_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.right_arm_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.left_forearm_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.right_forearm_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.left_hand_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.right_hand_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.left_upLeg_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.right_upLeg_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.left_leg_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.right_leg_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.left_foot_joint, Instantiate(jointPrefab, arBodyT).transform },
            { JointIndices3D.right_foot_joint, Instantiate(jointPrefab, arBodyT).transform }
        };
        lineRenderers = new LineRenderer[]
        {
            Instantiate(lineRendererPrefab).GetComponent<LineRenderer>(), // head neck
            Instantiate(lineRendererPrefab).GetComponent<LineRenderer>(), // upper
            Instantiate(lineRendererPrefab).GetComponent<LineRenderer>(), // lower
            Instantiate(lineRendererPrefab).GetComponent<LineRenderer>(), // right
            Instantiate(lineRendererPrefab).GetComponent<LineRenderer>() // left
        };
        lineRendererTransforms = new Transform[][]
        {
            new Transform[] { bodyJoints[JointIndices3D.head_joint], bodyJoints[JointIndices3D.neck_1_joint] },
            new Transform[] { bodyJoints[JointIndices3D.right_hand_joint], bodyJoints[JointIndices3D.right_forearm_joint], bodyJoints[JointIndices3D.right_arm_joint], bodyJoints[JointIndices3D.left_arm_joint], bodyJoints[JointIndices3D.left_forearm_joint], bodyJoints[JointIndices3D.left_hand_joint]},
            new Transform[] { bodyJoints[JointIndices3D.right_foot_joint], bodyJoints[JointIndices3D.right_leg_joint], bodyJoints[JointIndices3D.right_upLeg_joint], bodyJoints[JointIndices3D.left_upLeg_joint], bodyJoints[JointIndices3D.left_leg_joint], bodyJoints[JointIndices3D.left_foot_joint] },
            new Transform[] { bodyJoints[JointIndices3D.right_arm_joint], bodyJoints[JointIndices3D.right_upLeg_joint] },
            new Transform[] { bodyJoints[JointIndices3D.left_arm_joint], bodyJoints[JointIndices3D.left_upLeg_joint] }
        };
        for (int i = 0; i < lineRenderers.Length; i++)
        {
            lineRenderers[i].positionCount = lineRendererTransforms[i].Length;
        }
    }
}

ARKit 会给我们在 3D 空间中,关节的位置以及旋转度!下面代码中反映出在 2D 界面中是如何更新坐标,位置和球体的旋转:

private void UpdateJointTransform(Transform jointT, XRHumanBodyJoint bodyJoint)
{
    jointT.localScale = bodyJoint.anchorScale;
    jointT.localRotation = bodyJoint.anchorPose.rotation;
    jointT.localPosition = bodyJoint.anchorPose.position;
}

现在!就让我们建立并运行我们的工程在实际的 iOS 设备中吧!

步骤五:建立并部署应用

最后,我们需要在实际的设备中建立和运行工程。ARKit 是 IOS 和 IpadOS 的一部分,我们不能测试我们的代码在 MacOS 中(尽管我很想看到这样一款模拟器。

在 Unity 中,选择File->Build Settings。点击 iOS 建立目标并点击Build键。你将需要指定一个位置去存储所生成的工程,并耐心等待直到 Unity 完成搭建过程。

Unity 将创造一个 XCode 工程(.xcodeproj)。用 XCode 11 Beta 打开这个工程。如果您使用 XCode11 Beta 之前的版本,将会有一个错误提示并且工程无法正常运行。

当这个工程被发布后,需要提供你的 iOS 开发证书,连接你的 iOS 13 设备,并且点击 Run 键。这样,这个项目将会被部署在设备中。

相关推荐

Mac电脑强制删除任何软件方法-含自启动应用

对于打工者来说,进入企业上班使用的电脑大概率是会被监控起来,比如各种流行的数据防泄漏DLP,奇安信天擎,甚至360安全卫士,这些安全软件你想卸载是非常困难的,甚至卸载后它自己又安装回来了,并且还在你不...

Linux基础知识 | 文件与目录大全讲解

1.linux文件权限与目录配置1.文件属性Linux一般将文件可存取的身份分为三个类别,分别是owner/group/others,且三种身份各read/write/execute等权限文...

文件保护不妥协:2025 年 10 款顶级加密工具推荐

数据安全无小事,2025年这10款加密工具凭借独特功能脱颖而出,从个人到企业场景全覆盖,第一款为Ping32,其余为国外英文软件。1.Ping32企业级加密核心工具,支持200+文件格...

省心省力 一个软件搞定系统维护_省心安装在哪里能找到

◆系统类似于我们居住的房间,需要经常打理才能保持清洁、高效。虽然它本身也自带一些清理和优化的工具,但借助于好用的第三方工具来执行这方面的任务,会更让人省心省力。下面笔者就为大家介绍一款集多项功能于一身...

JAVA程序员常用的几个工具类_java程序员一般用什么软件写程序

好的工具做起事来常常事半功倍,下面介绍几个开发中常用到的工具类,收藏一下,也许后面真的会用到。字符串处理:org.apache.commons.lang.StringUtilsisBlank(Char...

手工解决Windows10的若干难题_windows10系统卡顿怎么解决

【电脑报在线】很多朋友已经开始使用Win10,估计还只是测试版本的原因,使用过程中难免会出现一些问题,这里介绍解决一些解决难题的技巧。技巧1:让ProjectSpartan“重归正途”从10074...

System32文件夹千万不能删除,看完这篇你就知道为什么了

C:\Windows\System32目录是Windows操作系统的关键部分,重要的系统文件存储在该目录中。网上的一些恶作剧者可能会告诉你删除它,但你不应该尝试去操作,如果你尝试的话,我们会告诉你会发...

Windows.old 文件夹:系统备份的解析与安全删除指南

Windows.old是Windows系统升级(如Win10升Win11)或重装时,系统自动在C盘创建的备份文件夹,其核心作用是保留旧系统的文件、程序与配置,为“回退旧系统”提供保...

遇到疑难杂症?Windows 10回收站问题巧解决

回收站是Windows10的一个重要组件。然而,我们在使用过程中,可能会遇到一些问题。例如,不论回收站里有没有文件,都显示同一个图标,让人无法判别回收站的空和满的真实情况;没有了像Windows7...

卸载软件怎么彻底删掉?简单几个步骤彻底卸载,电脑小白看过来

日常工作学习生活中,我们需要在安装一些软件程序,但随着软件的更新迭代速度,很多时候我们需要重新下载安装新的程序,这时就需要将旧的一些软件程序进行卸载。但是卸载软件虽然很简单,但是很多小伙伴们表示卸载不...

用不上就删!如何完全卸载OneDrive?

作为Windows10自带的云盘,OneDrive为资料的自动备份和同步提供了方便。然而,从隐私或其他方面考虑,有些人不愿意使用OneDrive。但Windows10本身不提供直接卸载OneDri...

【Linux知识】Linux下快速删除大量文件/文件夹方法

在Linux下,如果需要快速删除大量文件或文件夹,可以使用如下方法:使用rm命令删除文件:可以使用rm命令删除文件,例如:rm-rf/path/to/directory/*这个命令会递...

清理系统不用第三方工具_清理系统垃圾用什么软件

清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...

系统小技巧:软件卸载不了?这里办法多

在正常情况下,我们都是通过软件程序组中的卸载图标,或利用控制面板中的“程序和功能”模块来卸载软件的。但有时,我们也会发现利用卸载图标无法卸载软件或者卸载图标干脆丢失找不到了,甚至控制面板中卸载软件的功...

麒麟系统无法删除文件夹_麒麟系统删除文件权限不够

删除文件夹方法例:sudorm-rf文件夹名称。删除文件方法例:sudorm-r文件名包括扩展名。如果没有权限,给文件夹加一下权限再删。加最高权限chmod775文件名加可执行权限...

取消回复欢迎 发表评论: