← 全部笔记

COMPUTER VISION · 12 MIN READ

Gesture:把在线会议
变成隔空白板

从捏合画线,到抓取、缩放与击掌清屏:一次基于 OpenCV 与 MediaPipe 的实时手势交互实验。

在在线会议中用捏合手势圈出演示图表的概念场景
在线会议中的隔空标注概念图。

这是未来使用场景的概念示意,并非当前版本截图。现在的程序已经能在白板或摄像头画面上绘图,但还没有接入 PPT、屏幕采集或虚拟摄像头。

在线会议里,我们已经很习惯共享屏幕、播放 PPT、打开摄像头。但到了真正需要“指一下”的时候,交互仍然有些笨重:先把注意力从讲述切到鼠标,找到批注工具,再在屏幕上画圈。

我做 Gesture 的起点,就是想试试另一种方式:如果摄像头能够理解手势,我能不能在讲话的同时,直接抬手、捏合手指,在画面上圈出重点?如果背景不是摄像头,而是正在演示的 PPT 或共享屏幕,再把合成后的画面作为虚拟摄像头送进 Zoom、Teams 或 Meet,它就会像一块悬在镜头前的虚拟白板。

当前实现与设想的边界:项目现在完成的是摄像头手势识别、白板/AR 绘图和轨迹操作;PPT/屏幕采集、人物抠像、虚拟摄像头及会议软件集成仍是下一步。

查看 GitHub 源码 ↗

现在已经能做什么

当前版本是一个 Python 桌面程序,使用 OpenCV 读取摄像头,用 MediaPipe Hand Landmarker 检测最多两只手。白板模式只展示白色画布与轨迹;AR 模式则把指针、轨迹与提示叠加到实时摄像头画面。

  • 拇指与食指捏合绘制,分开后结束一条独立轨迹;
  • 在轨迹附近握拳,将整条轨迹抓起并移动;
  • 保持握拳,让画面中的手掌变大或变小,从而缩放轨迹;
  • 把轨迹拖到任一角落,张手删除;
  • 两只手从画面两侧向中央移动,以“击掌”清空画布。

从 21 个关键点里,找出真正需要的信息

MediaPipe 手部关键点与 Gesture 使用方式示意
蓝线帮助理解骨架;交互逻辑只取其中几组信息。

绘图主要关注拇指指尖(4)和食指指尖(8)。两点中点是屏幕指针,两点距离决定是否捏合。掌心由手腕与四个掌指关节(0、5、9、13、17)取平均得到;食指根部(5)到小指根部(17)的距离被视作掌宽。

代码不直接拿固定像素判断捏合,而是计算:

pinch_ratio = 两个指尖的像素距离 / 画面短边像素数

比例小于等于 0.04 时进入绘制,大于等于 0.06 时退出。两个阈值故意不相等,手指在临界位置轻微抖动时,状态不会在“开始”和“结束”间疯狂切换。

拇指和食指捏合后绘制轨迹的动画
两指中点由红变绿,程序开始记录归一化轨迹点。

每帧记录的坐标是 0 到 1 之间的归一化值,显示时再乘以当前画面宽高。手指分开后,当前点列被封装成一条独立的 Trajectory。如果绘制时手突然离开画面,程序也会结束并保留当前轨迹,避免录制状态一直悬着。

握拳以后,轨迹不再只是一条死线

程序判断握拳时,会检查四根手指的指尖是否比各自近端关节更靠近手腕,同时检查拇指是否收进掌心附近。握拳刚开始时,它在掌心周围约 80 像素内寻找最近轨迹并锁定。

scale = 当前掌宽 / 抓取瞬间的掌宽
新点 = 当前掌心 +(原始点 - 抓取起点)× scale

掌心移动负责平移,摄像头画面中的掌宽变化负责缩放。这里并没有测量真实三维深度;“手靠近或远离镜头”只是通过掌宽变化获得的直观效果。

握拳抓取轨迹并平移缩放的动画
轨迹始终从抓取时的原始点重新计算变换,避免累计误差。

删除沿用同一动作:抓住轨迹,拖到四角之一,再张开手。角落区边长取“画面短边的 18%”和 120 像素中的较小值;删除后还有 1.5 秒冷却,避免残余姿态误触。

为什么击掌清屏不是“两只手靠近就算”

如果只判断两手距离,日常动作很容易误触。代码因此先等待两只手分别出现在左右两侧,再要求它们同时向中央移动;水平间距缩小、高度接近并通过 1.5 秒冷却后,才真正清空画布。它识别的不是一张静态手势照片,而是一段带上下文的运动。

从摄像头涂鸦到会议里的虚拟白板

目前的 AR 模式很直接:OpenCV 读入摄像头帧,MediaPipe 从同一帧提取关键点,程序再叠加轨迹。它证明了实时识别与画面叠加可以工作,但真正的会议形态还需补上两端。

摄像头 ──→ 手势识别 ──────────────┐ ├─→ 画面合成 ─→ 虚拟摄像头 ─→ 会议软件 PPT / 屏幕采集 ─→ 背景画面 ────────┘

一种用法,是把 AR 模式里的摄像头背景换成 PPT 或桌面采集画面;另一种是保留人物,把标注层与摄像头合成后作为虚拟摄像头输出。这样发言者不必在讲述和鼠标操作之间来回切换。

当前版本的局限

这个原型已经能表达交互方向,但离日常会议工具还有距离:

  • 识别、合成与显示在单个实时循环里完成,性能直接受设备配置影响;
  • 轨迹采用逐帧指尖中点,没有额外平滑、抽稀或曲线拟合;
  • 绘制与抓取默认使用检测结果中的第一只手,两手主要用于击掌;
  • 抓取命中范围约 80 像素,轨迹很多时选择不够可控;
  • CSV 保存函数虽然保留在代码中,但调用当前被注释,退出后不会自动保存。

接下来,先把链路做完整

  1. 把输入源抽象成摄像头、窗口、屏幕或 PPT;
  2. 拆分识别、轨迹状态与画面渲染;
  3. 接入虚拟摄像头,让会议软件能够选择合成画面;
  4. 为轨迹增加平滑和抽稀,并测量端到端延迟;
  5. 根据真实会议使用设计颜色、撤销、工具选择与防误触。

Gesture 现在更像一个交互原型:它验证了“捏合去画、握拳去抓、击掌去清空”这套动作语言。下一步的关键,是让它从摄像头窗口里的实验,变成可以自然进入会议工作流的一层工具。

如果我能在讲到图表拐点时直接抬手把它圈出来,然后不间断地继续讲下去——那就是我最初想做这个项目的原因。

项目使用 Python、OpenCV 与 MediaPipe。本文依据仓库实际代码撰写,并将尚未实现的会议场景明确标为下一步。