前言

最近我使用USB摄像头、电脑、ESP32-S3和一块64×64的P2.5 HUB75灯板,实现了一个AI视觉流体灯板。

没有检测到手时,ESP32-S3会持续运行自动流体动画;当手出现在摄像头画面中后,张手、握拳、移动和捏合会被转换成不同的流体作用力。

本文重点解释手势识别链路、关键点计算、动作判断、串口数据设计,以及ESP32-S3如何把手势转换成灯板效果。

请添加图片描述

一、系统结构

整个系统分为电脑视觉端和ESP32-S3显示端。

USB摄像头
    ↓
MediaPipe Hand Landmarker
    ↓
21个手部关键点
    ↓
动作、位置和速度计算
    ↓ USB串口,230400 baud
ESP32-S3
    ↓
流体粒子与力场计算
    ↓
64×64 P2.5 HUB75灯板

电脑负责视觉推理,ESP32-S3负责实时灯效。串口中只传输控制参数,不传输视频帧,也不传输完整的4096像素画面。

二、MediaPipe输出了什么

项目使用MediaPipe Hand Landmarker。每检测到一只手,模型会输出21个关键点:

  • 1个手腕点;
  • 拇指4个点;
  • 食指、中指、无名指、小指各4个点。

每个关键点包含归一化坐标。x=0.5、y=0.5表示该点位于画面中心,因此后续算法不依赖摄像头的具体分辨率。

MediaPipe并没有直接替我们完成全部动作分类。项目会根据这些关键点进一步计算:

  • 手掌中心位置;
  • 每根手指是否伸展;
  • 拇指与食指的相对距离;
  • 相邻帧之间的位移和速度;
  • 当前动作的稳定状态。

三、四种手势的判断方法

1. 张开手掌

程序比较指尖、指关节和掌心的位置。如果检测到至少4根手指伸展,就判断为张开手掌。

张手对应排斥力,手掌附近的粒子会向外散开。

2. 握拳

当大部分指尖收回掌心附近,伸展手指数量不超过1根时,判断为握拳。

握拳对应吸引力,粒子会向手掌映射到的灯板位置聚拢。

3. 拇指与食指捏合

不能只使用两指之间的像素距离,因为手靠近摄像头时会整体变大。

项目使用归一化比例:

pinch_ratio = 拇指尖到食指尖的距离 / 手掌参考尺度

pinch_ratio <= 0.42时,判断为捏合。捏合会触发一次粒子爆发,而不是持续施加作用力。

4. 手掌移动

程序记录手掌中心在相邻两帧中的位置:

vx = current_x - previous_x
vy = current_y - previous_y
speed = sqrt(vx² + vy²)

vxvy决定推动方向,speed决定推动强度。

四、为什么必须做滤波

手部关键点会受到光线、遮挡、运动模糊和模型误差影响。如果直接使用每一帧的结果,灯板会出现抖动,动作也可能在两个状态之间快速切换。

本项目主要采用以下处理:

  1. 对手掌坐标进行低通平滑;
  2. 对速度单独平滑,避免单帧定位误差变成强冲击;
  3. 为手势设置阈值,减少临界状态反复切换;
  4. 设置丢失超时,避免手离开后保留上一次作用力。

ESP32-S3超过约500ms没有收到有效手势数据时,会清除手势力,但自动流体动画仍然继续运行。

五、串口为什么只发送控制参数

如果发送完整64×64 RGB画面,一帧至少需要:

64 × 64 × 3 = 12288 bytes

以30FPS计算,仅像素数据就接近369KB/s,还没有计算帧头、校验和转义开销。普通串口很难稳定承担这种数据量。

因此电脑只发送类似下面的控制数据:

{
  "seq": 1032,
  "visible": true,
  "gesture": "open",
  "x": 0.63,
  "y": 0.41,
  "vx": 0.08,
  "vy": -0.03,
  "speed": 0.086
}

这类数据通常只有几十到几百字节。ESP32-S3收到后,将归一化坐标映射到灯板:

int panelX = constrain(static_cast<int>(x * 63.0f), 0, 63);
int panelY = constrain(static_cast<int>(y * 63.0f), 0, 63);

然后根据动作类型选择吸引、排斥、推动或爆发力。

六、流体效果怎样响应手势

视觉端和流体端是两个独立模块。

视觉端只负责输出:

手是否可见
手掌坐标
动作类型
移动方向
移动速度

ESP32-S3端根据这些数据修改粒子速度:

张手:粒子远离手掌中心
握拳:粒子靠近手掌中心
移动:沿手掌移动方向增加速度
捏合:瞬间施加径向冲击力

这样的分层设计便于扩展。视觉端可以换成人体姿态、物体追踪或面部方向,显示端也可以换成火焰、粒子喷泉、光点或小游戏。

七、常见问题

摄像头打开错了

电脑同时存在内置摄像头和USB摄像头时,需要枚举摄像头编号,并在配置中选择正确设备。

串口无法连接

关闭PlatformIO Monitor、Arduino串口监视器等占用串口的软件,再启动视觉程序。

手势识别抖动

增加位置平滑,适当提高动作阈值,并避免强逆光。手掌尽量完整出现在画面中。

灯板闪烁或重启

64×64 P2.5灯板需要独立、稳定的5V电源。ESP32-S3与灯板必须共地,不能依靠开发板USB口给整块灯板供电。

总结

这个项目的核心不是让AI直接生成4096个像素,而是让AI把现实动作翻译成少量、稳定的控制参数。

电脑负责从画面中提取21个关键点,并判断位置、速度和动作;ESP32-S3负责把这些数据转换成灯板上的流体力场。两部分通过轻量串口协议连接,既减少通信压力,也保留了嵌入式端实时生成灯效的能力。

我是阿白,感谢您的观看。

更多推荐