手势识别(HandGesture)使用指导:识别手势、数手指、石头剪刀布

« 返回

机器学习套件(ML Kit)组件在在线版和教育版中提供,离线版(含机房版)不包含。

它能做什么

手势识别找出画面里的手(最多 4 只),给出每只手是左手还是右手、21 个关键点(手腕和每根手指的指根、关节、指尖),以及 7 种内置手势:握拳、张开手掌、食指向上、拇指向下、点赞、剪刀手、我爱你。既能识别图片,也能打开摄像头实时识别,还能把贴图贴在手上。基于 Google MediaPipe,模型随 App 打包,完全离线。

它是 MIT 社区 HandPose 方案(TensorFlow.js + CustomWebView 拓展)和 MIT 石头剪刀布教程(用 Teachable Machine 训练手势)的本土化简化版(全程离线运行):内置组件,不用导入拓展、不依赖网页引擎和国外服务,常用手势不用训练直接认。

准备工作

  • 取数据:识别完成后调「手势」(英文代码,适合做判断)、「手势名称」(中文,适合显示)、「左右手」、「关键点」,手序号从 1 开始。「关键点」直接返回 [x, y, z] 列表,可用名字见「关键点名称」属性。
  • 实时识别:在设计器里放一个垂直布局当「预览容器」,「打开实时摄像头」后画面上直接画出手部骨架、标出手势。
  • 系统要求:Android 7.0 以上。
  • 联机调试:安卓上用 AI 伴侣调试需要安装 MLKit 版 AI 伴侣(应用宝,包名 cn.fun123.appinventor);普通版伴侣不含识别引擎,调用时会触发「屏幕.出现错误时」(错误码 4722)。直接打包 APK 安装测试不受影响。
  • 安装包体积:只有用到本组件的 App 才会打包它的识别引擎与模型,体积以编译结果为准。
  • 鸿蒙:暂不支持:鸿蒙系统没有开放手部关键点与手势识别接口,图片识别、实时摄像头都会触发「检测失败时」并说明原因。

案例一:识别照片里的手势

选图或拍照后调「识别图片文件」。「获得手势」事件给出手的数量,在事件里用「左右手」「手势名称」取每只手的结果:

procedure 识别(路径) {
  图像_原图.Picture = 路径
  标签_状态.Text = "识别中…"
  手势识别1.DetectFromFile(路径)
}
when 图像选择器_相册.AfterPicking() { 识别(图像选择器_相册.Selection) }
when 照相机1.AfterPicture(图像位址) { 识别(图像位址) }
when 手势识别1.GotHands(手数, 结果JSON) {
  标签_状态.Text = join("找到 ", 手数, " 只手")
  标签_结果.Text = join(手势识别1.Handedness(1), ":", 手势识别1.GestureName(1))
}
when 手势识别1.NoHandFound(操作) {
  标签_状态.Text = "没找到手"
}

案例二:用关键点数手指

手指竖起来时,指尖(_TIP)在中间关节(_PIP)上方,也就是 y 坐标更小。逐根比较食指、中指、无名指、小指,就能数出竖起几根(手要大致朝上;拇指是横着伸的,要另外比 x 坐标,这里不算):

global 手指数 = 0
procedure 数手指() {
  手指数 = 0
  foreach 手指 in split("INDEX_FINGER,MIDDLE_FINGER,RING_FINGER,PINKY", ",") {
    var 指尖 = 手势识别1.KeyPoint(join(手指, "_TIP"), 1)
    var 关节 = 手势识别1.KeyPoint(join(手指, "_PIP"), 1)
    if select(指尖, 2) < select(关节, 2) {
      手指数 = 手指数 + 1
    }
  }
}
when 手势识别1.GotHands(手数, 结果JSON) {
  数手指()
  标签_结果.Text = join(手势识别1.Handedness(1), ":", 手势识别1.GestureName(1), ",竖起 ", 手指数, " 根手指")
}

案例三:摄像头实时识别,和手机玩石头剪刀布

「打开实时摄像头」后,在「实时检测到手」事件里把手势代码换成石头、剪刀、布存进全局变量:石头 = Closed_Fist,布 = Open_Palm,剪刀 = Victory。点「出拳」时手机随机出一个,按规则判输赢:

global 我出 = ""
when 按钮_实时.Click() {
  手势识别1.PreviewContainer = 垂直布局_预览
  手势识别1.StartLiveCamera()
}
when 手势识别1.LiveHands(手数, 图片宽度, 图片高度, 结果JSON) {
  if 手数 == 0 {
    我出 = ""
  } else {
    var 手势 = 手势识别1.Gesture(1)
    我出 = choose(手势 == "Closed_Fist", "石头", choose(手势 == "Open_Palm", "布", choose(手势 == "Victory", "剪刀", "")))
  }
}
when 按钮_出拳.Click() {
  if 我出 == "" {
    标签_结果.Text = "先对着镜头比出石头、剪刀或布"
  } else {
    var 手机出 = randomItem(split("石头,剪刀,布", ","))
    if 我出 == 手机出 {
      标签_结果.Text = "平局"
    } else if (我出 == "石头" and 手机出 == "剪刀") or (我出 == "剪刀" and 手机出 == "布") or (我出 == "布" and 手机出 == "石头") {
      标签_结果.Text = join("手机出", 手机出, ",你赢了")
    } else {
      标签_结果.Text = join("手机出", 手机出, ",手机赢了")
    }
  }
}

案例四:指尖星星:把贴图贴在手上

锚点用手部关键点名(如 INDEX_FINGER_TIP 食指尖、WRIST 手腕、MIDDLE_FINGER_MCP 掌心附近),宽度和偏移按手掌宽度(食指根到小指根的距离)计,贴图随手的方向旋转(手指朝上时不转)。纵向偏移为负往指尖方向挪:

when 按钮_星星.Click() { 手势识别1.AddSticker("星星", "star.png", "INDEX_FINGER_TIP", 0.8, 0, -0.3) }
when 按钮_摘下.Click() { 手势识别1.ClearStickers() }
when 按钮_保存.Click() { 手势识别1.CaptureLiveFrame() }
when 手势识别1.LiveFrameCaptured(图片地址) {
  图像_照片.Picture = 图片地址
}

结果数据说明

手势代码:Closed_Fist 握拳、Open_Palm 张开手掌、Pointing_Up 食指向上、Thumb_Down 拇指向下、Thumb_Up 点赞、Victory 剪刀手、ILoveYou 我爱你,没认出是 None。关键点坐标是图片像素,z 是相对手腕的深度(越小越靠近镜头)。「结果JSON」里每只手含 handedness、gesture、gestureName、gestureScore 和 21 个 landmarks(index、name、x、y、z)。左右手是被拍人自己的左右。

常见问题

现象 原因与处理
找不到手 手太小、太暗或被挡住;让手占画面三分之一左右,光线充足
手势一直是「无」 手势要做到位、手掌对着镜头;7 种以外的手势都返回 None,可以用关键点自己判断
手指数不对 数手指的方法要求手指朝上;手横着或倒着时改为比较 x 坐标
普通版伴侣里调用报错 4722 请安装 MLKit 版 AI 伴侣,或直接打包 APK 测试
实时预览黑屏、看不到画面 「预览容器」要选布局组件并给明确宽高(如宽度充满、高度 300 像素);第一次打开要允许摄像头权限
实时检测时界面卡 调大「实时事件间隔」,事件里少做事;画面上的标注不受间隔影响

完整 .aia 源码与操作指导

下载 .aia 源码

导入 HandGestureDemo.aia 后可以直接打包 APK 运行;用 AI 伴侣联机调试请安装 MLKit 版 AI 伴侣。源码文件已通过正式编辑器载入、后台导入和 APK 编译校验;真机识别效果请以实际设备为准。

功能 操作 预期结果
识别照片 从相册选一张有手的照片或拍照 显示左右手、手势名称和竖起的手指数;两只手时下方显示第二只
无手 选风景照 提示没找到手
实时识别 点「实时识别」,对着前置摄像头比手势 预览区画出手部骨架、左上角标出手势;状态栏实时显示左右手和手势
石头剪刀布 实时识别时比出石头、剪刀或布,点「出拳」 手机随机出拳并判定输赢,比分累加
指尖星星 实时识别时点「指尖星星」,移动食指 星星跟着食指尖移动,随手的方向转动;「摘下」清掉
保存照片 贴上星星后点「保存照片」 下方显示刚才的画面(含贴图),前置摄像头与预览一样是镜像

案例界面与积木源码在仓库 docs/markdown/reference/components/guide/examples/HandGestureDemo/,SHA-256:713b8f351a60db068fd5ede9df2e1475c2ed2fd31245636108d25b3ec318ea0c。

文档反馈