跳到教程内容
教程首页
App Inventor 2 教程 AI跳舞
准备开始
动手创造 · PROJECT LAB

AI跳舞

准备探索你的新作品
0%
★★★ 项目难度每一步,都离作品更近

先了解你将做出什么

应用介绍

舞蹈看起来很有机、很复杂,但人体动作可以用关键点的位置和距离来描述。本教程使用 PoseNet 把摄像头中的人体转换成骨骼模型,再用坐标关系判断“手举过头顶”“抬膝”“T 形站姿”等动作,并自动累计舞蹈分数。

PoseNet 需要摄像头和手机算力,模拟器不能运行这个扩展。请用真机和 AI2 Companion 测试,并保持光线均匀、背景简单、整个人都在画面中。

舞者姿态

PoseNet 演示

AI 跳舞导览

设置电脑和手机

先安装 AI2 Companion,让电脑和手机连接到同一个网络。打开“硬件测试工程”,通过“连接”菜单扫描二维码;如果测试工程没有显示“模型已就绪”或错误信息,请先更换设备,再开始制作完整应用。

AI跳舞教程

1. 认识项目和界面

打开起始工程,先观察它提供的界面和预置组件。你可以调整颜色和布局,但不要重命名组件,因为后续步骤会使用这些名称。

AI跳舞界面

SwapCameraButton 切换前后摄像头,CanvasLiveButton 切换 Canvas 的黑色背景和实时画面,ResetButton 把舞蹈分数归零。WebViewer1 显示摄像头画面,Canvas1 绘制人体骨骼,PosenetExtension1 负责追踪人体关键点。

2. 认识 PoseNet 关键点

PoseNet 会追踪眼睛、耳朵、鼻子、肩膀、手肘、手腕、臀部、膝盖和脚踝。每个能识别到的关键点会返回一个包含 [x, y] 的列表;暂时识别不到时返回空列表。

PoseNet 人体关键点

Canvas 左上角是坐标原点,向右 x 增大,向下 y 增大。因此“手腕在耳朵上方”应比较为 手腕的 y < 耳朵的 y。光线不足、背景凌乱和宽松衣物都可能让某些关键点暂时为空。

3. 检查模型准备状态

起始工程已经提供了界面状态代码。保留 PosenetExtension1.ModelReady 事件,在模型准备好时显示“模型已就绪”;保留 PosenetExtension1.Error 事件,在出错时显示错误信息。

开始追踪前可以让开始按钮保持禁用,收到 ModelReady 后再启用。这样用户不会在扩展尚未加载时触发空数据。

模型就绪和错误事件

4. 检查预置的界面代码

工程还提供了三个基础事件:ResetButton.被点击时 把舞蹈分数设为 0SwapCameraButton.被点击时 在前置和后置摄像头之间切换,CanvasLiveButton.被点击时 修改一个布尔变量,用来决定 Canvas 显示实时背景还是纯黑背景。

重置按钮

切换摄像头按钮

实时 Canvas 按钮

5. 创建 getX 和 getY 辅助过程

PoseNet 的点是包含两个元素的列表。创建 getX(point)getY(point) 两个过程,分别返回点列表的第 1 项和第 2 项。之后比较坐标时使用过程名,代码会比到处写 选择列表项 更容易阅读。

getX 和 getY

6. 创建 defined 和 allDefined

创建 defined(point) 布尔过程:当 point 是包含两个元素的列表时返回 true,否则返回 false

再创建 allDefined(points):遍历一组关键点,只要有一个点未定义就返回 false,全部定义才返回 true。姿态规则在访问坐标前必须先检查关键点,这样模型暂时看不清人时不会因空列表报错。

defined 过程

allDefined 过程

7. 创建 distance 辅助过程

创建 distance(point1, point2),用勾股定理计算两个点在 Canvas 上的欧氏距离:

距离 = √((x2 - x1)² + (y2 - y1)²)

只有两个点都定义时才计算距离。这个过程之后会用于判断手臂是否伸直,以及 T 形姿势中手腕到肩膀的距离。

距离公式

distance 过程

8. 创建绘制关键点和骨骼的过程

创建 drawPoint(point),在定义好的点位置画一个半径约 4 像素的小圆;创建 drawLine(point1, point2),在两个定义好的点之间画线。

这两个过程是绘制骨骼的基础:关键点可以用醒目的红色,骨骼可以用另一种颜色,方便观察 PoseNet 的追踪效果。

drawPoint 过程

drawLine 过程

9. 处理 PoseUpdated 事件

当人体位置发生变化时,PosenetExtension1.PoseUpdated 会触发。起始工程已经准备好事件外壳;其中的条件会根据 CanvasLiveButton 的状态决定是否把摄像头实时画面显示在 Canvas 背景上。

在这个事件中调用 drawKeyPointsdrawBodydrawHead。先让事件正常触发,再逐个完成这些过程,排错会更容易。

PoseUpdated 事件

10. 绘制人体关键点和骨骼

drawKeyPoints 中把 Canvas 的 PaintColor 设为醒目的颜色,然后遍历 PosenetExtension1.KeyPoints 列表,对每个定义好的点调用 drawPoint

drawBody 中遍历 PosenetExtension1.Skeleton。列表中的每一项是一根由两个端点组成的骨骼,取出两个端点后调用 drawLine。例如小腿骨骼的两个端点就是脚踝和膝盖。

绘制关键点提示

绘制关键点示例

小腿骨骼

绘制骨骼示例

11. 可选:绘制圆形头部

如果希望骨骼模型有一个圆形头部,可以完成 drawHead

  1. 检查 LeftEarRightEar 都已定义。
  2. 用两只耳朵的中点作为圆心,使用中点公式计算圆心。
  3. 用两耳之间距离的一半作为半径,让圆经过两只耳朵。

如果只画耳朵、眼睛和鼻子的关键点而不画圆形头部,程序仍然可以正常工作。

头部中点公式

构造圆形头部

drawHead 过程

12. 第一次测试应用

用 AI2 Companion 在真机上测试:确认人体关键点能出现,骨骼线段能连接正确,Canvas 和 WebViewer 的宽高完全一致。

手机屏幕较小时,可以滚动屏幕;也可以隐藏显示舞者图片的 HorizontalArrangement1。如果隐藏 WebViewer1,仍必须让 Canvas1 保持和 WebViewer 原来相同的尺寸,否则坐标会错位。

13. 认识待检测的舞步

本教程用四类动作练习规则:双手举过头顶、抬膝、特拉沃尔塔式动作和 T 形姿势。每个动作都可以拆成“关键点定义检查 + 坐标或距离比较 + 得分”的流程。

双手举起

抬膝

Travolta 动作

T-Pose

14. 检测双手举起

创建 checkForHandsintheAirMove

  1. 检查左右手腕和左右耳都已定义。
  2. 比较右手腕 y 与右耳 y、左手腕 y 与左耳 y。
  3. 两只手腕都在各自耳朵上方时,增加舞蹈分数。

由于 y 越小表示位置越高,所以判断条件是两个手腕的 y 坐标分别小于对应耳朵的 y 坐标。

双手举起判断提示

双手举起判断示例

15. 检测抬膝

创建 checkForKneeUpMove

  1. 检查左右膝和左右臀都已定义。
  2. 判断右膝是否高于右臀,或左膝是否高于左臀。
  3. 任意一侧满足条件时增加舞蹈分数。

抬膝判断提示

抬膝判断示例

16. 检测 Travolta 动作

自己尝试创建 checkForTravoltaMove:右手腕高于右耳且左手腕低于左肩,或左手腕高于左耳且右手腕低于右肩。任意一种姿势成立时就增加分数。

先写出判断条件,再用 allDefined 确认需要的手腕、耳朵和肩膀都存在。不要在关键点为空时直接比较坐标。

Travolta 判断示例

17. 检测 T 形姿势

T 形姿势要求左右手臂水平伸展,身体看起来像字母 T。可以从下面两类条件入手:

  • 左右手腕和肩膀的 y 坐标要足够接近,保证手臂大致水平。
  • 手腕到肩膀的直线距离要接近“手腕到手肘距离 + 手肘到肩膀距离”,保证手臂大致伸直。

使用 distance 计算这些长度,并为“足够接近”设置合理误差,不要要求浮点数完全相等。

手臂伸展

T-Pose 判断示例

18. 再次测试并观察得分

分别测试四种舞步,确认每个动作只有在条件满足时增加舞蹈分数。保持动作不动时,如果分数持续快速增加,说明程序需要增加“上一帧未达成、这一帧达成”的边沿判断,让同一个动作只奖励一次。

最佳测试条件是光线均匀、背景单色、衣服贴身,并让整个人保持在摄像头范围内。也可以用背景清楚的独舞视频测试 PoseNet 对画面中舞者的追踪效果。

舞步演示

扩展应用

  • 为每个舞步增加去重机制,动作保持时只奖励一次,检测到新动作后才允许再次得分。
  • 为动作不标准的情况设计扣分规则,例如手臂接近 T 形姿势但没有保持水平。
  • 把舞步换成瑜伽姿势,正确姿势加分,偏离姿势时给出提示。
  • 在不改变关键点安全检查的前提下,设计并实现更多可以用坐标和距离描述的动作。