当前位置: 首页 > 科技观察

用AI“驯服”人类幼崽:这位爸爸找到了硬核养娃的乐趣

时间:2023-03-22 14:28:53 科技观察

,“爸爸”+“萌娃”一直是一个逆天的组合,甚至有人说,“父爱如山崩地裂”。如果您不相信,这就是证据:众所周知,人类幼崽看起来像永动机,一天24小时随时准备攻击您。让自己睡个好觉的方法似乎就是在白天消耗精力,所以人们想出了各种方法。当然,并不是所有的爸爸都这么不靠谱,也有一些人把孩子带得相当正常,AgustinusNalwan就是其中之一。AgustinusNalwan是Medium上的博主。曾从事计算机视觉、3D/动画、游戏开发等工作,目前就职于澳洲最大的汽车交易平台carsale.com.au。他有一个两岁半的儿子,名叫Dexie。Dexie很活泼,喜欢动物,尤其是老鹰。她经常像老鹰一样在房子周围飞来飞去。孩子的这种行为通常会引起家长“哈哈”的大笑(有的会被拍成短视频发到网上),但Nalwan可不是一般的家长。他一直在尝试用科技来增加养娃的乐趣。去年3月,Nalwan开发了一款具有玩具识别功能的系统,可以根据儿子手中的玩具与儿子互动,播放相关视频。这个项目帮助他赢得了Nvidia的“JetsonProjectoftheMonth:Qrio–aninteractiveAIbot”活动的大奖,奖品是NvidiaJetsonAGXXavier。JetsonAGXXavier的配置信息。这是一个具有强大计算能力的开发者工具包。已被京东、美团、菜鸟等无人快递车用作计算核心。鉴于JetsonAGXXavier的良好配置,Nalwan决定用它来帮助儿子制作一个新玩具,实现他“展翅高飞”的梦想。新玩具叫格里芬(神话中的格里芬),最终效果如下:当然爸爸们也可以陪着玩:或者自己玩:这么好的养娃经验当然要分享。在最近的一篇博客中,Nalwan完整的介绍了他打造Griffin的完整过程,有娃的可以参考一下。长着狮鹫头的传说中的狮鹫。GryffindorHouse在《哈利波特》的意思是金色的狮鹫。以下是Nalwan“从零开始”构建一个完整的手势识别游戏的过程。材料准备为实现上图效果,Griffin需要以下模块:3D游戏引擎:借助OpenGL编写的飞行模拟器,生成一个有山脉、天空和Griffin的3D魔法世界。HumanPoseEstimation:使用OpenPose姿态估计模型和SSD物体检测模型不断检测玩家的身体姿态作为系统的输入来控制Griffin。ActionMappingandGestureRecognition:将身体姿势转换为有意义的动作和手势,例如抬起左/右翅膀,左右滚动身体,起飞等通信系统:使用套接字将手势输入发送到3D游戏引擎。以下是整个系统所需的硬件:NVIDIAJetsonAGXXavier:这是一个运行上述所有模块的小型GPU驱动的嵌入式设备。它可以通过一个简单的HDMI接口支持音频和视频输出。此外,他还有一个以太网接口,方便联网。您甚至可以插入鼠标和键盘在设备上进行开发和调试,因为它具有功能齐全的Ubuntu18.04操作系统。电视(带HDMI输入和内置扬声器):作为游戏引擎的显示器。相机:我使用的是SonyIMX327。其实这里只需要224x224的图像分辨率,所以也可以选择低端的摄像头。Blu-Tack:将所有硬件拼接在一起。JetsonAGXXavier、IMX327相机和BluTack。实现构建3D游戏引擎为了更好地模拟飞行体验,Griffin系统会以第三人称视角渲染3D世界。想象一下,在格里芬的正后方有一个摄像头在注视着他正在看的地方。为什么不像飞行模拟器那样使用第一人称视角呢?因为看到老鹰的翅膀并同步移动她的手臂有助于Dexie快速学习如何控制游戏并获得更身临其境的体验。自己构建3D游戏引擎并不容易,可能需要数周时间。如今,大多数开发人员只使用专门的游戏引擎,例如Unity或Unreal。但不幸的是,我找不到可以在UbuntuOS/ARM芯片组上运行的游戏引擎。另一种方法是寻找在OpenGL上运行的开源飞行模拟器。这确保了游戏引擎将在AGX上运行,因为它支持OpenGLES(OpenGL的轻量级版本)并且是硬件加速的。如果您不希望游戏引擎以缓慢的速度运行,这是必要的。幸运的是,我找到了一个符合标准的C++开源飞行模拟器,并进行了以下修改:我用一个基于目标的系统取代了基于按钮的飞行控制系统。这让我可以不时地设置Griffin身体的目标旋转角度,然后这个旋转目标将由手势识别模块自行设置,映射Dexie手臂的方向。我增强了静态3D模型管理以支持层次结构。最初的飞机模型作为刚体运动,没有运动的身体部位。但是格里芬有两个翅膀需要独立于身体移动。为此,我在身体顶部添加了两个翅膀作为单独的3D模型。我可以单独旋转每个翅膀,或者我可以移动格里芬的身体,间接移动两个翅膀。实现此目标的适当方法是构建一个骨骼动画系统,将身体部位组织成树结构。但是,由于我只有三个身体部位要处理(身体和两个翅膀),所以我可以选择一个简单的方法。为了编辑老鹰和树木的3D模型,我使用了Blender,这是一款免费且易于使用的3D编辑工具。在Blender中编辑老鹰的3D模型。我为Griffin的起飞状态添加了一个树模型,并为在不重新启动应用程序的情况下重新启动游戏添加了一个游戏状态。格里芬有两种状态:站立(站在树枝上)和飞行。我使用libSFML添加音效来播放:当格里芬起飞时,有鹰鸣和风声。构建人体姿势估计模块该模块旨在从相机输入中检测人体姿势。具体来说,我们需要知道左/右手肘、左/右肩、脖子和鼻子的位置,以便操纵格里芬的翅膀和身体并触发特定姿势。OpenPose是一个流行的开源库,包含大量用于估计人体姿势、手部姿势和面部特征的AI模型。我正在使用带有resnet18的人体姿势估计COCO模型作为骨干特征提取器。该模型可以实时检测到18个关节点,包括上面我们需要的6个点。COCO关节点图。这里有一个很大的问题:OpenPose基于PyTorch框架构建,在NVIDIAAGXXavier中运行非常慢(4FPS),因为它无法利用高度优化的TensorRT框架。幸运的是,还有一个很棒的工具torch2trt可以自动将PyTorch模型移植到TensorRT框架!具体步骤为:安装OpenPose,PyTorch转TensorRT,下载预训练好的resnet18backbone模型。为了从摄像头获取视频内容,我使用了另一个库Jetcam。只需四行代码即可运行。人体姿态估计。这导致可以以100FPS运行的人体姿势估计模块!经过一些测试,我发现有时模型会将随机物体错误识别为关节(误报,如下图所示),这导致Griffin的运动控制出现问题。使用AmazonSageMakerJumpStart构建目标检测模型解决这个问题的一种方法是添加辅助AI模型,并使用目标检测模块提供人体的边界框,从而检测到人体的关节点可以排除边界框之外的内容。此外,这些边界框还可以帮助识别一群人中的主要玩家,距离摄像机最近的人应该是主要玩家。在之前的项目中,我手动训练了SSDMobileNetV2对象检测模型。这次我选择使用AmazonSageMakerJumpStart一键部署来自TensorFlowHub和PyTorchHub的AI模型。有超过150种模型可供选择,包括完全预训练的SSDMobileNetV2。从AmazonSageMakerStudio中启动JumpStart。在AmazonJumpStart中选择SSDMobileNetV2后,只需单击一下即可部署模型。有了目标检测模型,我可以为边界框外的关节点添加排除逻辑,这样误报就会少很多!排除人体边界框外的关节点。构建动作映射和手势识别模块该模块对于将人体姿势估计模块检测到的6个关节点运动转换为更有意义的输入至关重要。这包括三个直接运动映射:BodyTurnsWhileFlying:用于控制Griffin在飞行时的方向。可以根据水平轴与左右肘部矢量之间的角度计算身体旋转(下图)。在飞行过程中,两个机翼根据这个旋转角度同步运动。选择肘部而不是手腕是为了最大限度地提高可见度,因为手腕经常掉出相机的视野或被其他身体部位遮挡。站立时翅膀旋转:这纯粹是为了美观,让游戏更有趣,给人的印象是每个翅膀都可以在站立时单独控制。这是通过水平轴和肩肘矢量(下图底部)之间的角度计算的。最终机翼旋转角度会增加15度,以增加机翼动作,毕竟人长时间高举手臂会很累。身体转动和机翼旋转的运动映射。蹲伏:这是另一个不错的动作,给人一种在起飞前能够控制狮鹫蹲伏姿势的感觉。这是通过颈鼻向量和肩向量之间的长度比来计算的。蹲得越深,脖子到鼻子的距离越短,而左右肩的距离保持不变,所以长度比变小。蹲伏运动映射。起飞姿势:当左右肩之间的中心点在一秒内上下移动超过阈值时,该动作将被识别为起飞姿势。阈值是肩膀之间的长度。当这个动作被触发时,格里芬会跳下树枝开始飞行。游戏重置姿势:当左右肩的水平位置颠倒时,就是游戏重置姿势,比如玩家背对着镜头。游戏将重置,格里芬将回到树上位置,为下一次飞行做好准备。起飞并重置手势识别。通信系统现在我们已经完成了三个主要组件,接下来就是将它们粘合在一起的问题了。我们需要将姿态估计模块检测到的人体关节发送给手势识别模块,这是一个比较简单的工作。然而,将运动和姿势映射结果发送到3D游戏引擎并不是那么简单,因为游戏引擎是用C++编写的。您可能想知道为什么不用Python构建3D游戏引擎,因为没有可靠的方法从Python访问OpenGL。此外,我不想花费数周时间将C++转换为Python代码,即使可能也是如此。此时我需要以最小的开销在两者之间高效地传递信息。最小的开销对于游戏引擎来说是一个非常重要的因素,输入到控制器和动作发生之间的100毫秒延迟可能会导致玩家失去身临其境的体验。因此,两个独立应用程序之间最好的通信媒介是套接字。由于两个应用程序在同一台计算机上,因此延迟将在5毫秒以内。在C++中,我们只需使用sys/socket库,而在Python中,我们可以使用套接字框架。下面我将手势识别和姿态估计模块称为Pythonapp,客户端发送五种信息:roll_target、lwing_target、rwing_target、body_height、game_state。3D游戏引擎称为C++app,充当服务器,不断监听并接收上述信息。为了将这五种信息/变量从Python正确映射到C++,我们需要在发送它们之前将它们放置在类PythonC结构中。classPayload(Structure):_fields_=[("roll_target",c_int32),("lwing_target",c_int32),("rwing_target",c_int32),("body_height",c_int32),("game_state",c_int32)]在C++中应用程序,它们作为本机C结构接收。typedefstructpayload_t{int32_troll_target;int32_tlwing_target;int32_trwing_target;int32_tbody_height;int32_tgame_state;}有效载荷;从下面的架构图中可以看出,通信层由Python应用程序中的客户端模块和C++应用程序中的服务器模块组成。Griffin整体架构图。校准和测试准备就绪后,我设置了Griffin系统以执行校准和测试。这个系统的性能比我预想的要好得多。在执行所有实时3D渲染和姿态估计时,它一直保持着60FPS的帧率。看来NVIDIA的JetsonAGXXavier厉害了。在下面的视频中,您可以看到校准和测试过程。这个视频的帧率很低,因为我在Ubuntu桌面上以15FPS录制屏幕,以尽量减少对Griffin的影响。格里芬系统的校准和测试。最后,Dexie开始第一次驾驶Griffin飞行,这才是真正的考验。我在客厅设置好系统,儿子已经迫不及待地等待行动了。Dexie驾驶Griffin飞行的经历。我只演示了一次如何控制格里芬系统,跳跃起飞,张开双臂手势控制翅膀,德克希就学会了。由于游戏是第三人称视角,他很快就发现,画面中翅膀的动作,和他的姿势是直接同步的。然后他开始享受他的飞行体验。没有什么比您自己的游戏控制器更好的了——还记得乔布斯在宣布第一款iPhone时嘲笑手写笔时所说的话吗。有意思的是,德克希在要撞到一座山的时候,举起双臂做一个急转弯,但是因为我设置了最大旋转角度限制,格里芬没有让他飞出一个特别极端的角度,然后就撞到了山上......事情是这样的:Dexie在Griffin上的第一次飞行。他玩了半个小时,疯狂地挥舞着双臂,直到疲倦袭来。最重要的是,那天晚上他睡得很香,这对我们来说是一场胜利!我有更多时间看Netflix:)总之,我学到了很多东西,并且在构建这样一个系统时获得了很多乐趣。总的来说,我了解到:Torch2trt是一个强大的工具,可以自动将PyTorch模型转换为TensorRT版本,让AI模型在JetsonAGXXavier上运行得更快。许多最先进的AI模型都是使用PyTorch构建的,但手动将它们移植到TensorFlow并不是一个好的体验。NVIDIAJetsonAGXXavier非常强大!很多人说它可以实时处理30个1080p视频流的计算机视觉模型处理任务,这似乎是真的。AmazonSageMakerJumpStart提供了大量流行的AI模型,并使它们非常易于部署。构建3D游戏引擎让我回到了以前作为游戏和电影SFX开发人员的经历,带回了我生疏的OpenGL、C++和三角函数技能。说到动作识别游戏,人们自然会想到Xbox——我本可以在Xbox上用Unity引擎和Kinect传感器构建一个Griffin,但这不是很有道理吗?有时从头开始构建系统很有趣。玩老鹰是一项累人的工作,尤其是长时间举起双臂。但真正的老鹰会在上升气流的帮助下在空中滑翔。不知道这样的经历能不能给你一些启发呢?最后,笔者计划在近期将项目代码开源。