长期以来,「奶爸」+「萌娃」一贯是一个不被看好的组合,乃至有人说,「父爱如山体滑坡」。
不信的话,以下都是证据:

众所周知,人类幼崽彷佛是台永动机,在一天 24 小时任何韶光段里都有可能向你发难。
你能让自己睡个安稳觉的方法看来是在白天花费他们的精力,因此人们想出了各种各样的方法。

当然,并不是所有的奶爸都这么不靠谱,也有人带起娃来挺正常的,Agustinus Nalwan 便是个中之一。

用AI驯服人类幼崽这个奶爸找到了硬核带娃的乐趣

Agustinus Nalwan 是 Medium 上的一位博主,曾经从事打算机视觉、3D / 动画、游戏开拓等方面的事情,目前供职于澳洲最大的汽车交易平台 carsale.com.au。

他有一个两岁半的儿子,名叫 Dexie。
Dexie 非常活泼,喜好动物,尤其是老鹰,常常学老鹰在家里飞来飞去。

孩子的这种举动一样平常也就引起身长的「哈哈」一笑(有的会拍成短视频发网上),但 Nalwan 可不是一样平常的家长,他一贯在考试测验用技能增长带娃的乐趣。
去年三月份,Nalwan 就开拓过一款具有玩具识别能力的系统,可以和儿子互动并根据他手里的玩具播放干系视频。

这个项目帮他拿到了英伟达「Jetson Project of the Month: Qrio – an interactive AI bot」活动的大奖,奖品是一台英伟达 Jetson AGX Xavier。

Jetson AGX Xavier 的配置信息。

这是一种算力不小的开拓者套件,曾被京东、美团、菜鸟的无人快递车用作打算核心。
鉴于 Jetson AGX Xavier 配置还不错,Nalwan 决定用它来帮儿子做一个新玩具,实现他「展翅高飞」的梦想。

新玩具名叫 Griffin(神话中的狮鹫),终极实现效果是这样的:

当然,奶爸也可以随着一起玩:

或者自己玩:

这么好的带娃履历当然要分享出来。
在最近的一篇博客中,Nalwan 完全地先容了他打造 Griffin 的完全过程,手头有娃的可以参考一下。

传说中狮身鹰首的 griffin。
《哈利波特》中的 Gryffindor 学院意为金色的 griffin。

以下是 Nalwan「从零开始」构建整套姿态识别游戏的进程。

物料准备

要实现上图中的效果,Griffin 须要具备以下模块:

3D 游戏引擎:借助一个用 OpenGL 写成的翱翔仿照器天生带有山脉、天空和 Griffin 的 3D 魔幻天下。
人体姿态估计:利用 OpenPose 姿态估计模型和 SSD 目标检测模型来持续检测玩家的身体姿态,作为系统的输入,以掌握 Griffin。
动作映射和手势识别:将身体姿态转化为故意义的动作和手势,如抬起左 / 右翅膀、旁边翻滚身体、起飞等。
通信系统:利用 socket 将姿态输入送进 3D 游戏引擎。

以下是全体系统所须要的硬件:

NVIDIA Jetson AGX Xavier:这是一个 GPU 驱动的小型嵌入式设备,用来运行以上所有模块。
它可以通过一个大略的 HDMI 接口支持音视频输出。
此外,他还有一个以太网接口,方便联网。
你乃至可以插入鼠标和键盘在该设备上进行开拓和调试,由于它有一个功能完好的 Ubuntu 18.04 OS。
TV(带有 HDMI 输入和内置扬声器):作为游戏引擎的显示器。
摄像头:我用的是 Sony IMX327。
实在这里只须要 224x224 的图像分辨率,因此也可以选低端一点的摄像头。
Blu-Tack:把所有硬件拼接在一起。

Jetson AGX Xavier、 IMX327 摄像头和 Blu Tack。

实现

构建 3D 游戏引擎

为了更好地仿照翱翔体验,Griffin 系统将以第三人称视角渲染 3D 天下。
想象一下在 Griffin 正后方有一个摄像头看着他所看的地方。
为什么不用翱翔仿照器那样的第一人称视角呢?由于看到鹰的翅膀并同步移动自己的手臂,可以帮助 Dexie 快速学习如何掌握这个游戏,并拥有一个更沉浸式的体验。

自行构建 3D 游戏引擎并非易事,可能须要好几周的韶光。
现在大多数开拓者只利用专门的游戏引擎,如 Unity 或 Unreal。
但是很遗憾,我找不到可以在 Ubuntu OS/ARM 芯片组上运行的游戏引擎。
一种替代方法是找到在 OpenGL 上运行的开源翱翔仿照器。
这可以担保游戏引擎能在 AGX 上运行,由于它支持 OpenGL ES(OpenGL 的轻量级版本)并且得到硬件加速。
如果你不想游戏引擎以龟速运行的话,则这是必要的条件。

幸运的是,我找到了一个知足标准的 C++ 开源翱翔仿照器,并做了以下修正:

我用基于目标的系统更换了基于按键的翱翔掌握系统。
这样我就可以时时地设置 Griffin 身体的目标旋转角度,之后这一旋转目标将通过手势识别模块自行设置,该模块可以映射 Dexie 胳膊的方向。
我增强了静态 3D 模型管理,以支持层级构造。
原始的飞机模型是作为一个刚体移动的,它没有移动的身体部位。
但是 Griffin 有两个翅膀,须要独立于身体单独运动。
为此,我添加了两个翅膀,使之作为身体之上的单独 3D 模型。
我可以单独旋转每个翅膀,也可以移动 Griffin 的身体,间接移动两个翅膀。
实现该目标的一种恰当办法是构建骨骼动画系统,将身体部位组织为树构造的形式。
但是,由于我要处理的身体部位只有三个(身体和两个翅膀),因此我可以选择一种简便的办法。
为了编辑鹰和树 3D 模型,我利用了一个免费易用的 3D 编辑工具 Blender。

在 Blender 中编辑鹰的 3D 模型。

我添加了 Griffin 起飞状态的树模型,以及无需重启运用即可重启游戏的游戏状态。
Griffin 有两种状态:站立(站在树枝上)和飞行。
我利用 libSFML 添加音效播放:当 Griffin 起飞时,会涌现鹰的尖啸和风声。

构建人体姿态估计模块

该模块旨在检测来自摄像头输入的人体姿态。
详细而言,我们须要知道左 / 右手肘、左 / 右肩膀、脖子和鼻子的位置,才能驾驭 Griffin 的翅膀和身体,并触发特定的姿势。
OpenPose 是一个盛行的开源库,并具备大量估计人体姿态、手部姿势和面部特色的 AI 模型。
我利用的是人体姿态估计 COCO 模型,以 resnet18 作为骨干特色提取器。
该模型可以实时检测 18 个枢纽关头点,包括上述我们所需的 6 个点。

COCO 枢纽关头点图。

这里存在一个大问题:OpenPose 基于 PyTorch 框架构建,在 NVIDIA AGX Xavier 中运行速率很慢(4FPS),由于它无法利用重度优化的 TensorRT 框架。
幸运的是,还有一个厉害的工具 torch2trt,它可以自动将 PyTorch 模型移植到 TensorRT 框架中!
详细步骤是:安装 OpenPose,将 PyTorch 转换为 TensorRT,下载预演习 resnet18 骨干模型。

为了获取来自摄像头的视频内容,我利用另一个库 Jetcam。
只须要四行代码,就可以运行。

人体姿态估计。

这样就得到了可以 100FPS 速率运行的人体姿态估计模块!

经由一些测试后,我创造有时候这个模型会将随机工具缺点地识别为枢纽关头点(假正例,如下图所示),这会给 Griffin 的动作掌握带来麻烦。

利用 Amazon SageMaker JumpStart 构建目标检测模型

办理该问题的一种办法是添加一个赞助 AI 模型,用目标检测模块来供应人体边界框,这样就可以打消掉在边界框以外检测到的人体枢纽关头点了。
此外,这些边界框还可以帮助在一堆人中识别紧张玩家,间隔摄像头最近的人该当是紧张玩家。

在之前的项目中,我手动演习过 SSDMobileNetV2 目标检测模型。
这次我选择利用 Amazon SageMaker JumpStart,只需一键操作就可以从 TensorFlowHub 和 PyTorchHub 支配 AI 模型。
这里有 150 多个可选的模型,个中就有经由完备预演习的 SSDMobileNetV2。

从 Amazon SageMaker Studio 中启动 JumpStart。

在 Amazon JumpStart 中选择 SSDMobileNetV2 后,只需一键操作就可以支配模型。
有了目标检测模型后,我可以为边界框以外的枢纽关头点添加 exclusion logic,这样假正例就会少很多!

在人体边界框以外的枢纽关头点被打消在外。

构建动作映射和手势识别模块

该模块对付将人体姿态估计模块检测到的 6 个枢纽关头点动作转换为更具意义的输入至关主要。
这包括三种直接的动作映射:

翱翔时的身体迁徙改变:用于掌握 Griffin 翱翔时的方向。
身体迁徙改变可以通过横轴和旁边手肘向量之间的夹角进行打算(下图上)。
在翱翔时,两只翅膀基于这一迁徙改变角度同步移动。
选择手肘而不是手腕是为了最大化可见度,由于手腕常常会掉出摄像头视角或被其他身体部位隐瞒住。
站立时的翅膀旋转:这纯粹是出于都雅,为了让游戏更具意见意义性,给人一种站立的时候可以单独掌握每个翅膀的印象。
这通过横轴与肩膀 - 手肘向量之间的夹角进行打算(下图下)。
终极的翅膀旋转角度会添加 15 度,以加大翅膀的动作,毕竟人永劫光举高胳膊会很累。

身体迁徙改变和翅膀旋转时的动作映射。

蹲伏:这是另一个都雅动作,可以让人感想熏染到能够掌握 Griffin 起飞前的蹲伏姿势。
这通过脖子 - 鼻子向量和肩膀向量之间的长度比进行打算。
蹲伏得越深,脖子和鼻子之间的间隔越短,而旁边肩膀之间的间隔保持不变,因此长度比变小。

蹲伏动作映射。

起飞姿势:当旁边肩膀之间的中央点在一秒内高下移动的幅度超过阈值时,则该动作会被识别为起飞姿势。
阈值是肩膀之间的长度。
当这一动作被触发时,Griffin 会跳下树枝,开始飞行。
游戏复位姿势:当旁边肩膀的水平位置反转时则为游戏复位姿势,如玩家背对摄像头。
游戏将复位,Griffin 回到站在树上的姿势,准备下一次翱翔。

起飞和复位手势识别。

通信系统

现在,我们完成了三个紧张组件,只须要将它们粘合在一起就行了。
我们须要将姿态估计模块检测到的人体枢纽关头点发送至手势识别模块,这个任务比较大略。
但是,将动作和姿势映射结果发送至 3D 游戏引擎就不那么大略了,由于游戏引擎是用 C++ 写的。
你可能会迷惑为什么不用 Python 构建 3D 游戏引擎,缘故原由在于没有靠谱的办法来利用 Python 访问 OpenGL。
此外,纵然可能,我也不想花费好几周韶光将 C++ 转换为 Python 代码。

此时我须要以最小花销高效地在这二者之间通报信息。
对付游戏引擎而言,最小花销是非常主要的成分,输入掌握器和动作发生之间涌现 100ms 的延迟都会导致玩家失落去沉浸式体验。
因此,两个单独运用之间的最好通信媒介是 socket。
由于这两个运用在同一台打算机内,因此延迟会在 5ms 以内。

在 C++ 中,我们大略地利用 sys/socket 库,而在 Python 中,我们可以利用 socket 框架。
从现在开始,我把手势识别和姿态估计模块称作 Python app,该客户端发送五种信息:roll_target、lwing_target、rwing_target、body_height 和 game_state。
把 3D 游戏引擎称为 C++ app,充当监听并不断吸收上述信息的做事器。

为了将这五种信息 / 变量精确地从 Python 映射到 C++ 上,在发送之前我们须要将其放置在 Python C-like 构造中。

class Payload(Structure): _fields_ = [(“roll_target”, c_int32), (“lwing_target”, c_int32), ("rwing_target", c_int32), ("body_height", c_int32), ("game_state", c_int32)]

在 C++ app 中,它们以本机 C 构造形式吸收。

typedef struct payload_t { int32_t roll_target; int32_t lwing_target; int32_t rwing_target; int32_t body_height; int32_t game_state;} payload;

从下面的架构图可以看出,通信层由一个位于 Python app 中的客户端模块和一个位于 C ++ app 中的做事器模块组成。

Griffin 的整体架构图。

校准与测试

准备就绪后,我设置了 Griffin 系统以实行校准和测试。
这套系统的性能要比我预测的好很多,在实行所有实时 3D 渲染和姿态估计时一贯都保持在 60FPS 的帧率,看来英伟达的 Jetson AGX Xavier 性能强大不是说说而已。
不才面的视频中,你可以看到校准和测试的过程。
这个视频帧率较低,是由于我在 Ubuntu 桌面上以 15FPS 录屏,只管即便减少对 Griffin 的影响。

Griffin 系统的校准与测试。

起飞

末了,是时候让 Dexie 用 Griffin 考试测验第一次翱翔了,这才是真正的大考。
我在客厅里架设好了系统,我儿子一贯在不耐烦地等待行动。

Dexie 利用 Griffin 翱翔的经历。

我只演示了一遍如何掌握 Griffin 系统,跳一下便是起飞,展开手臂依赖姿势掌握翅膀,Dexie 就学会了。
由于游戏是第三人称视角,以是他很快就创造画面中翅膀的运动是直接和自己姿势同步的。
随后他就开始享受自己的翱翔体验了。
没有什么是比你自己更好的游戏掌握器了——记住乔布斯在发布第一代 iPhone 时嘲笑手写笔时所说的话。

故意思的是,Dexie 有次快要撞山时,他奋力扬起手臂想要来个急转弯,但由于我设置了最大旋转角度限定,Griffin 不许可他飞特殊极限的角度,随后他就撞了山…… 当时是这个样子:

Dexie 在 Griffin 上的首飞。

他上来就玩了半小时,发疯似地摆荡动手臂,直到疲倦袭来。
最主要的是,那天晚上他睡得很喷鼻香,对我们来说这是一次胜利!
我有更多韶光看 Netflix 了 :)

总结

构建这样一套系统让我学到了很多,同时得到的乐趣大概多。
总体来说我学到了:

Torch2trt 是一个很强大的工具,可以自动将 PyTorch 模型转化为 TensorRT 版,让 AI 模型在 Jetson AGX Xavier 上运行地更快。
很多最前辈的 AI 模型都是用 PyTorch 构建起来的,但手动将它们移植到 TensorFlow 上可不是好的体验。
英伟达 Jetson AGX Xavier 的性能非常强大!
很多人说它可以实时处理 30 个 1080p 视频流的打算机视觉模型处理任务,看来的确是这样。
亚马逊 SageMaker JumpStart 供应了大量盛行的 AI 模型,并让它们非常易于支配。
构建 3D 游戏引擎的经历让我重拾之前作为游戏和电影 SFX 开拓职员的经历,再次用起了生疏的 OpenGL、C++ 和三角学方面的技能。
说到动作识别游戏,人们自然会想到 Xbox——我本可以用 Unity 引擎和 Kinect 传感器在 Xbox 上构建一个 Griffin,但是这样不就没有太大意义了吗?有时从头构建一套系统才是乐趣所在。
扮演老鹰是一个很累的事情,尤其是永劫光抬起手臂这件事。
不过真正的老鹰是通过上升气流得到帮助并滑翔在天空中的。

不知这样的一段经历,是否能给你一些启示?

末了,作者操持在近期将项目代码开源出来。

参考内容:

https://agustinus-nalwan.medium.com/making-my-toddlers-dream-of-flying-come-true-with-ai-tech-85e40d7144a2