MLKitFaceMesh 拓展:面部网格(468 个关键点)

« 返回首页

logo MLKitFaceMesh 拓展

检测 468 个面部关键点(带 x/y/z 坐标),用于 AR 贴纸定位、美颜、面部特效。

为什么选它:

  • 完全离线。模型随 .aix 打包,设备不需要 Google Play 服务,断网也能用。
  • 不把 468 个点塞进事件。全序列化有几十 KB,而大多数场景只要某几个区域 —— 所以事件只给摘要,要点时按需调「区域点」(12 个区域任选)或「全部点」。 结果缓存在组件里,检测一次可以反复取不同区域,不用重新识别。
  • 可以只要人脸框(boundingbox 模式)——比出网格快得多。

限制:这是 ML Kit 的 beta 功能;要求人脸离镜头较近(约 2 米内)且基本正面。 远景、大角度侧脸检测不到。

与 MLKitFaceDetector 的区别:那个给的是人脸框 + 微笑/睁眼概率 + 头部转角(约 10 项信息); 本拓展给的是 468 个点的几何网格,用来贴图和变形。

  • .aix 拓展下载:

cn.fun123.MLKit.FaceMesh.aix


快速上手

一、检测并取左眼的点

when 图像选择器1.AfterPicking() {
  标签1.Text = "检测中…"
  FaceMesh1.DetectFromFile(图像选择器1.Selection)
}
when FaceMesh1.GotFaceMesh(faceCount, pointCount, boundsJson) {
  标签1.Text = join("检测到 ", faceCount, " 张脸,", pointCount, " 个点")
  标签_眼睛.Text = FaceMesh1.RegionPoints("LEFT_EYE", 1)
}
when FaceMesh1.NoFaceFound(operation) {
  标签1.Text = "没检测到人脸,请让脸离镜头近一些、正对镜头"
}
when FaceMesh1.DetectFailed(operation, errorMessage) {
  标签1.Text = errorMessage
}

点的 JSON 形状(用「JSON 文本解码」块解析):

[{"index":33,"x":123.4,"y":56.7,"z":-12.3},
 {"index":34,"x":126.1,"y":57.2,"z":-12.0}]

x/y 是原图像素坐标,z 是相对深度(越小越靠近镜头)。

二、同一次检测取多个区域(不用重新识别)

when FaceMesh1.GotFaceMesh(faceCount, pointCount, boundsJson) {
  标签_左眼.Text = FaceMesh1.RegionPoints("LEFT_EYE", 1)
  标签_右眼.Text = FaceMesh1.RegionPoints("RIGHT_EYE", 1)
  标签_嘴唇.Text = FaceMesh1.RegionPoints("UPPER_LIP_TOP", 1)
  标签_脸部轮廓.Text = FaceMesh1.RegionPoints("FACE_OVAL", 1)
}

三、只要人脸框(快得多)

when Screen1.Initialize() {
  FaceMesh1.UseCase = "boundingbox"
}
when FaceMesh1.GotFaceMesh(faceCount, pointCount, boundsJson) {
  标签1.Text = boundsJson
}

四、把可用区域做成下拉框

when Screen1.Initialize() {
  列表选择器_区域.ElementsFromString = FaceMesh1.AvailableRegions
}
when 列表选择器_区域.AfterPicking() {
  标签1.Text = FaceMesh1.RegionPoints(列表选择器_区域.Selection, 1)
}

12 个可用区域

FACE_OVAL(脸廓)、LEFT_EYEBROW_TOP / LEFT_EYEBROW_BOTTOM(左眉上/下沿)、 RIGHT_EYEBROW_TOP / RIGHT_EYEBROW_BOTTOM(右眉上/下沿)、 LEFT_EYE / RIGHT_EYE(左/右眼)、 UPPER_LIP_TOP / UPPER_LIP_BOTTOM(上唇上/下沿)、 LOWER_LIP_TOP / LOWER_LIP_BOTTOM(下唇上/下沿)、NOSE_BRIDGE(鼻梁)。

左右以被拍摄者为准(不是画面左右)—— 自拍时会和直觉相反。


属性

UseCase
检测模式。mesh(默认)= 输出 468 个网格点;boundingbox = 只输出人脸边界框(快得多,不给点)。 填了认不出的值会回退到 mesh。改这个属性会重建检测器,立即生效。
AvailableRegions
只读。可用的区域名,英文逗号分隔。可以直接喂给列表选择框的 ElementsFromString。
Busy
只读。是否正在检测。

事件

GotFaceMesh(faceCount,pointCount,boundsJson)
检测完成(只给摘要)。pointCount 在 mesh 模式下是 468、boundingbox 模式下是 0; boundsJson 是第一张脸的边界框。 要拿点请在这个事件里调「区域点」或「全部点」方法 —— 结果已缓存,可反复取不同区域。
NoFaceFound(operation)
图里没检测到人脸。这不是错误 —— 面部网格要求人脸离镜头较近且基本正面。
DetectFailed(operation,errorMessage)
检测失败。

方法

DetectFromFile(path)
检测图片文件。path 可以是素材文件名、设备路径、file:// 或 content:// 地址。
DetectFromBase64(base64)
检测 Base64 图片。支持带 data:image/...;base64, 前缀的写法。
RegionPoints(regionName,faceIndex)
取上一次检测结果里某个区域的点,返回 JSON 数组。faceIndex 从 1 开始。 没有结果或区域名不对时返回 [](不会报错)。
AllPointsJson(faceIndex)
取全部 468 个点。⚠️ 数据量大(几十 KB),一般用「区域点」就够了。
BoundsJson(faceIndex)
取某张脸的边界框 JSON。没有结果时返回 {}。

运行环境:AI 伴侣联机需要 Android 11 及以上

本拓展的识别模型放在依赖库自带的 assets 里,AI 伴侣联机调试要把它挂进 AssetManager,用的是 Android 11(API 30)才有的 ResourcesLoader —— 这是系统提供的 唯一公开办法,更低版本没有等价 API。所以:

运行方式 Android 6 ~ 10 Android 11 及以上
打包 APK ✅ 正常 ✅ 正常
AI 伴侣联机 ❌ 模型加载不了 ✅ 正常

打包 APK 之所以不受限制,是因为模型在编译时就被并进了 APK 的 assets,装到手机上 就是 App 自己的资源,与系统版本无关。伴侣的 APK 是提前编好装在手机上的,运行时没法 往自己已安装的包里加文件,只能靠系统的运行时挂载 API。

低版本设备上想验证功能,直接打包 APK 测即可;要用伴侣边改边调,请换 Android 11+ 的设备。

常见问题

总是触发「没检测到人脸」。 面部网格对距离很敏感 —— 要求人脸离镜头约 2 米内且基本正面。 远景合照、大角度侧脸、严重遮挡都检测不到。先用 MLKitFaceDetector(普通人脸检测)确认图里有脸, 那个的检测范围宽得多。

取点的方法返回 []。 三种可能:① 还没检测成功就调了(要在 GotFaceMesh 事件里调); ② 区域名拼错了(用 可用区域 属性对一下);③ 检测模式 设成了 boundingbox(那个模式不产生点)。

点画到画布上位置不对。 x/y 是原图像素坐标,画布是显示尺寸,要按 画布宽 / 原图宽 换算。

为什么 .aix 有 26 MB? 除了 2.9 MB 的网格模型,还有 21.6 MB 的 mediapipe 推理引擎(4 个 CPU 架构的原生库)。 这是「完全离线、不依赖 Google Play 服务」的代价。

文档反馈