面部网格(FaceMesh)使用指导:468 个面部关键点,按区域画点

« 返回

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

它能做什么

面部网格检测人脸上 468 个关键点(带 x/y/z 坐标),可以按名字取单个关键点(额头、鼻尖、下巴、眼睛上下沿、嘴唇等),也可以按区域取一串点:脸廓、左右眼、眉毛、嘴唇上下沿、鼻梁。既能识别图片,也能打开摄像头实时检测,用于 AR 贴纸定位、美颜、面部特效、眨眼张嘴检测、跟着头动的小游戏。要求人脸离镜头较近(约 2 米内)。

准备工作

  • 用途:mesh(默认)输出 468 个点;boundingbox 只输出人脸框,快得多。
  • 取点:检测完成后在任意时候调「关键点」「关键点距离」「区域关键点」,结果已缓存,可反复取。「关键点」直接返回 [x, y, z] 列表,不用解析 JSON;可用名字见「关键点名称」属性。
  • 实时检测:在设计器里放一个垂直布局当「预览容器」,「打开实时摄像头」后画面上直接画出网格和五官轮廓。
  • AR 贴图:准备透明背景的 PNG(帽子、眼镜、胡子)上传为素材,用「添加贴图」贴到关键点上,戴眼镜用 BETWEEN_EYES。
  • 联机调试:安卓上用 AI 伴侣调试需要安装 MLKit 版 AI 伴侣(应用宝,包名 cn.fun123.appinventor);普通版伴侣不含识别引擎,调用时会触发「屏幕.出现错误时」(错误码 4722)。直接打包 APK 安装测试不受影响。
  • 安装包体积:只有用到本组件的 App 才会打包它的识别引擎与模型,体积以编译结果为准。
  • 鸿蒙:暂不支持:鸿蒙系统没有开放 468 点面部网格接口,图片检测与实时摄像头都会触发「检测失败时」并说明原因。

案例一:检测并显示人脸框

检测完成事件给出人脸数、点数和第一张脸的人脸框:

procedure 检测(路径) {
  画布_结果.BackgroundImage = 路径
  面部网格1.DetectFromFile(路径)
}
when 图像选择器_相册.AfterPicking() { 检测(图像选择器_相册.Selection) }
when 面部网格1.GotFaceMesh(人脸数, 关键点数量, 人脸框JSON) {
  标签_状态.Text = join("检测到 ", 人脸数, " 张脸,第一张 ", 关键点数量, " 个点")
  标签_结果.Text = 人脸框JSON
}
when 面部网格1.NoFaceFound(操作) {
  标签_状态.Text = "没找到人脸"
}

案例二:按区域取点画到画布上

「区域关键点」返回 JSON 数组;用「图片处理」读出原图宽高算缩放比例,逐点画小圆:

when 按钮_取点.Click() {
  var 横向比例 = 画布_结果.Width / 图片处理1.ImageWidth(图像选择器_相册.Selection)
  var 纵向比例 = 画布_结果.Height / 图片处理1.ImageHeight(图像选择器_相册.Selection)
  画布_结果.Clear()
  foreach 点 in Web客户端1.JsonTextDecodeWithDictionaries(面部网格1.RegionPoints(下拉框_区域.Selection, 1)) {
    画布_结果.DrawCircle(dictget(点, "x", 0) * 横向比例, dictget(点, "y", 0) * 纵向比例, 3, true)
  }
}

案例三:实时检测张嘴、眨眼

「打开实时摄像头」后,在「实时检测到面部网格」事件里用「关键点距离」算比例:内唇上下的距离除以脸宽(两颊距离)大于 0.1 算张嘴,眼睛上下沿距离除以脸宽小于 0.04 算闭眼。除以脸宽是为了不受离镜头远近影响;阈值因人而异,可以先把比例显示出来再调。「关键点」直接给出 [x, y, z],第 1、2 项就是像素坐标:

when 按钮_实时.Click() {
  面部网格1.PreviewContainer = 垂直布局_预览
  面部网格1.StartLiveCamera()
}
when 按钮_停止.Click() { 面部网格1.StopLiveCamera() }
when 面部网格1.LiveFaceMesh(人脸数, 图片宽度, 图片高度) {
  if 人脸数 > 0 {
    var 脸宽 = 面部网格1.KeyPointDistance("LEFT_CHEEK", "RIGHT_CHEEK", 1)
    var 张嘴比 = 面部网格1.KeyPointDistance("UPPER_LIP_INNER", "LOWER_LIP_INNER", 1) / 脸宽
    var 左眼比 = 面部网格1.KeyPointDistance("LEFT_EYE_TOP", "LEFT_EYE_BOTTOM", 1) / 脸宽
    var 右眼比 = 面部网格1.KeyPointDistance("RIGHT_EYE_TOP", "RIGHT_EYE_BOTTOM", 1) / 脸宽
    var 鼻尖 = 面部网格1.KeyPoint("NOSE_TIP", 1)
    标签_状态.Text = join(choose(张嘴比 > 0.1, "张嘴", "闭嘴"), " ", choose(左眼比 < 0.04 and 右眼比 < 0.04, "闭眼", "睁眼"))
    标签_结果.Text = join("鼻尖 (", round(select(鼻尖, 1)), ", ", round(select(鼻尖, 2)), ")")
  }
}

案例四:面部滤镜:戴眼镜、戴帽子、加胡子

「添加贴图(名称, 图片, 锚点, 宽度比例, 横向偏移, 纵向偏移)」把透明背景的 PNG 贴到关键点上:宽度 = 脸宽 × 宽度比例,偏移也按脸宽计(纵向为负往上),贴图会跟着头移动、随歪头旋转。同名再加就是替换,「清空贴图」全部摘下。做滤镜时把「显示标注」关掉只留贴图;「保存当前画面」连贴图一起存成 PNG,完成后触发「画面已保存」:

when 按钮_眼镜.Click() { 面部网格1.AddSticker("眼镜", "glasses.png", "BETWEEN_EYES", 1, 0, 0.05) }
when 按钮_帽子.Click() { 面部网格1.AddSticker("帽子", "tophat.png", "FOREHEAD", 1.4, 0, -0.55) }
when 按钮_胡子.Click() { 面部网格1.AddSticker("胡子", "mustache.png", "NOSE_BOTTOM", 0.65, 0, 0.02) }
when 按钮_摘下.Click() { 面部网格1.ClearStickers() }
when 复选框_网格.Changed() { 面部网格1.ShowOverlay = 复选框_网格.Checked }
when 按钮_保存.Click() { 面部网格1.CaptureLiveFrame() }
when 面部网格1.LiveFrameCaptured(图片地址) {
  图像_照片.Picture = 图片地址
}

结果数据说明

区域名:FACE_OVAL 脸廓、LEFT_EYE/RIGHT_EYE 眼、LEFT_EYEBROW_TOP 等眉毛、UPPER_LIP_TOP/LOWER_LIP_BOTTOM 等嘴唇、NOSE_BRIDGE 鼻梁,完整列表看「可用区域」属性。每个点含 index、x、y、z,人脸序号从 1 开始。

常见问题

现象 原因与处理
检测不到脸 脸离镜头太远或太侧;用正脸近照
区域关键点返回 [] 还没检测成功,或区域名拼错(要大写)
点画偏了 要按原图与画布的宽高比例换算
实时预览黑屏、看不到画面 「预览容器」要选布局组件并给明确宽高(如宽度充满、高度 300 像素);第一次打开要允许摄像头权限
实时检测时界面卡 调大「实时事件间隔」,事件里少做事;画面上的标注不受间隔影响

完整 .aia 源码与操作指导

下载 .aia 源码

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

功能 操作 预期结果
检测人脸 选一张正脸近照 显示人脸数、点数和人脸框,画出脸廓点
切换区域 下拉框选 LEFT_EYE 等,点「画出该区域」 画布上只画出该区域的点
无人脸 选风景照 提示没找到人脸
实时检测 点「实时检测」,对着前置摄像头张嘴、眨眼 预览区画出网格;状态栏实时显示张嘴/闭嘴、睁眼/闭眼和鼻尖坐标
面部滤镜 实时检测时点「戴眼镜」「戴帽子」「加胡子」,取消「显示网格」 贴图跟着脸动、随歪头旋转;「全摘下」清掉
保存照片 戴上贴图后点「保存照片」 下方显示刚才的画面(含贴图),前置摄像头与预览一样是镜像

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

文档反馈