更新记录

1.0.0(2026-11-09)

  • 首个版本,仅支持 Android(minSdk 24)
  • 组件 <zy-face-liveness>:相机预览、人脸框绘制、实时检测、相机录入、抓拍、前后摄像头切换、缩放模式
  • 能力:多人检测、1:N 人脸库检索、1:1 比对、RGB 活体、动作活体(眨眼/张嘴/摇头/抬头)、年龄区间/性别/人种、口罩、睁闭眼、表情、人脸质量
  • 人脸库持久化到应用目录(特征库 + 名单表分离,名单表由插件自建,支持分页与重命名)

平台兼容性

uni-app(4.72)

Vue2 Vue2插件版本 Vue3 Vue3插件版本 Chrome Safari app-vue app-vue插件版本 app-nvue app-nvue插件版本 Android Android插件版本 iOS 鸿蒙
√ 1.0.0 √ 1.0.0 × × √ 1.0.0 √ 1.0.0 7.0 1.0.0 × ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × - × ×

uni-app x(4.72)

Chrome Safari Android Android插件版本 iOS 鸿蒙 微信小程序
- - 7.0 1.0.0 - - -

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
× × √ ×

zy-face-liveness 离线人脸识别 / 活体检测

Android 平台 UTS 插件(uni-app / uni-app x),基于开源引擎方案,全程离线,不依赖任何云服务。

能力 说明
人脸检测 单图 / 相机实时,支持同时识别多人,返回位置、角度、置信度、跟踪 ID
人脸识别 1:N 本地人脸库检索、1:1 两图比对(判断是否同一人)
活体检测 RGB 活体(静默)+ 动作活体(眨眼 / 张嘴 / 摇头 / 抬头)
人脸属性 年龄段、性别、人种、口罩、睁闭眼、表情、人脸质量
人脸库 注册(单/批量)、检索、删除、分页名单、重命名、总数,持久化到本机
相机组件 预览 + 人脸框 + 实时检测回调 + 相机录入 + 抓拍 + 前后摄切换
  • 支持平台:App-Android(uni-app Vue2/Vue3、uni-app x)
  • 最低系统:Android 7.0(API 24)

示例页面

示例 文件 内容
离线人脸识别(API) pages/face-liveness/face-liveness.vue 初始化/模型包切换、单图多人检测与全部属性、两图比对、人脸库注册/检索/名单/删除/改名、运行日志
人脸相机(nvue 组件) pages/face-liveness/face-liveness-camera.nvue <zy-face-liveness> 预览、人脸框、实时属性、开关热切换、相机录入、抓拍

组件用法要点:uts 组件不要 import、也不要写 components 注册,直接用插件 id 作为标签名(<zy-face-liveness>), 由编译器自动解析到 uni_modules/zy-face-liveness/utssdk/app-android/index.vue。 若用 import Xxx from '@/uni_modules/.../index.vue',该文件会被 vue-loader 当普通 vue 文件解析, 报 Module parse failed: Unexpected token(<script lang="uts"> 的类型标注无法识别)。

组件依赖 NVLoad / NVLoaded 生命周期,只能用在 nvue 页面(参考 zy-uvccamera 的用法)。


一、快速开始

import { init, detect, compare, register, search, count, listUsers, remove, release } from '@/uni_modules/zy-face-liveness'

// 1) 初始化(首次会解压模型,耗时数秒,必须在页面加载完成之后调用)
init({
  packName: 'Pikachu',
  thresholds: 0.48,      // 1:N 阈值,越大越严格
  maxDetectFaceNum: 5,   // 单帧最多人脸数
  success: (res) => {
    console.log('引擎就绪', res.version)
  },
  fail: (err) => {
    console.error('初始化失败', err.errCode, err.errMsg)
  }
})

1. 识别一张图片的人脸信息

detect({
  image: '/storage/emulated/0/DCIM/a.jpg',  // 本地路径 / file:// / content:// / http(s) / base64
  flags: {
    rgbLiveness: true,   // 默认 true
    quality: true,
    mask: true,
    eyeState: true,
    actions: true,
    attribute: true,
    emotion: true
  },
  success: (res) => {
    console.log('人脸数', res.faceNum)
    const face = res.faces[0]
    console.log('位置', face.rect, '角度', face.angle)
    console.log('活体', face.liveness, '质量', face.quality, '口罩', face.mask)
    console.log('年龄区间', face.ageBracket, '性别', face.gender, '人种', face.race)
    console.log('左眼睁', face.leftEyeOpen, '表情', face.emotion)
    console.log('动作', face.actions) // { blink, jawOpen, shake, headRaise, normal }
  }
})

2. 判断两张图片是否同一人

compare({
  image1: '/sdcard/a.jpg',
  image2: '/sdcard/b.jpg',
  thresholds: 0.48,
  success: (res) => {
    console.log('相似度', res.similarity, res.percentage + '%', '是否同一人', res.same)
  },
  fail: (err) => {
    // 9280005 表示某张图没检测到人脸
  }
})

3. 录入人脸库 + 检索

// 录入(可批量,多张一起提交)
register({
  images: ['/sdcard/a.jpg', '/sdcard/b.jpg'],
  names: ['张三', '李四'],
  success: (res) => {
    res.items.forEach(item => {
      console.log(item.success, item.id, item.name, item.message)
    })
  }
})

// 从人脸库找人
search({
  image: '/sdcard/c.jpg',
  topK: 3,
  success: (res) => {
    if (res.matched) {
      console.log('命中', res.items[0].id, res.items[0].name, res.items[0].similarity)
    }
  }
})

// 名单管理
count({ success: (res) => console.log('人脸库总数', res.count) })
listUsers({ page: 1, pageSize: 20, success: (res) => console.log(res.total, res.users) })
remove({ ids: [3, 4], success: (res) => console.log(res.removed) })

4. 页面卸载时释放

onUnload(() => {
  release({})
})

二、相机组件

<template>
  <view style="flex:1">
    <zy-face-liveness
      ref="faceRef"
      style="width:100%;height:500px;"
      :front="true"
      :auto-start="true"
      :detect-flags="flags"
      @onEvent="onFaceEvent"></zy-face-liveness>

    <button @tap="startRegister">录入当前人脸</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      // 初始开关(JSON 字符串),也可运行时用 setDetectFlags 修改
      flags: '{"rgbLiveness":true,"recognize":true,"attribute":true}'
    }
  },
  methods: {
    onFaceEvent(e) {
      const detail = e.detail
      // type: loaded / started / stopped / detect / recognize / register / capture / error / flags / scaleType / switchCamera
      if (detail.type === 'detect') {
        const data = JSON.parse(detail.dataJson)
        // data.faceNum / data.faces[]
      }
      if (detail.type === 'recognize') {
        const data = JSON.parse(detail.dataJson)
        console.log('命中', data.faces[0].name)
      }
      if (detail.type === 'register') {
        const data = JSON.parse(detail.dataJson)
        console.log('录入', data.success, data.id, data.name, data.path)
      }
      if (detail.type === 'error') {
        console.warn('相机/引擎错误', detail.code, detail.msg)
      }
    },
    startRegister() {
      this.$refs.faceRef.registerFace({ name: '张三', needBase64: false })
    }
  }
}
</script>

组件 props

属性 类型 默认 说明
front Boolean true 是否前置摄像头
auto-start Boolean true 视图就绪并拿到相机权限后自动开始预览
detect-flags String "" 初始检测开关(JSON 字符串)

组件方法

方法 参数 说明
start { front?, cameraId?, physicalCameraId? } 开始预览(cameraId / physicalCameraId 当前版本预留未生效)
stop - 停止预览
switchCamera - 前后摄切换
setDetectFlags { rgbLiveness?, quality?, mask?, eyeState?, actions?, attribute?, emotion?, recognize? } 运行时更新开关
registerFace { name?, savePath?, needBase64? } 请求录入:下一帧若恰好 1 张人脸则写入人脸库,结果经 onEvent(type=register)
capture { savePath?, needBase64? } 抓拍当前帧,结果经 onEvent(type=capture)
setScaleType 'FILL_CENTER' \| 'FIT_CENTER' 画面缩放模式
release - 释放相机

组件事件 onEvent(e)

e.detail = { type, code, msg, dataJson },dataJson 需自行 JSON.parse。

type dataJson
loaded {}
started / switchCamera { front }
stopped {}
detect { faceNum, width, height, faces:[FaceInfo] }(每帧回调)
recognize { faceNum, width, height, faces:[FaceInfo] }(仅命中人脸库的人脸)
register { success, id, name, code, message, path?, base64? }
capture { path, base64, width, height }
error {}(看 detail.code / detail.msg)

三、module API

函数 说明
init(options) 初始化引擎(首次解压模型,耗时数秒)
detect(options) 单图人脸信息
compare(options) 两图比对
register(options) 批量注册人脸
search(options) 1:N 检索
remove(options) 按 ID 删除
count(options) 人脸库特征总数
listUsers(options) 分页名单(id + name)
rename(options) 修改姓名
setThreshold(options) 修改 1:N 阈值(0~1)
version(options) 引擎版本(同步回调)
release(options) 释放引擎

所有函数统一 { success, fail, complete } 回调,失败为 UniError(errSubject = 'zy-face-liveness')。

init 参数

字段 默认 说明
packName 'Pikachu' 模型包:Pikachu(17MB,快)/ Megatron(61MB,准)
thresholds 0.48 1:N 检索阈值
maxDetectFaceNum 5 单帧最多人脸数
searchMode 0 0 EAGER(快)/ 1 EXHAUSTIVE(准)
videoDetectMode 2 视频:0 每帧检测 / 1 轻量跟踪 / 2 检测+跟踪
imageDetectMode 0 图片:0 每帧检测
detectPixelLevel -1 检测像素级别,-1 自动

FaceInfo 字段

字段 说明
index 本帧序号
trackId 跟踪 ID(视频稳定,图片为 -1)
confidence 检测置信度
rect { x, y, width, height } 像素坐标
angle { pitch, roll, yaw } 欧拉角(度)
faceId 命中的人脸库 ID(>0 命中;-1 未命中/未开启识别)
liveness RGB 活体 0~1,>0.5 判为活体
quality 人脸质量 0~1,>0.5 判为清晰
mask 口罩置信度 0~1,>0.5 判为戴口罩
leftEyeOpen / rightEyeOpen 1 睁 / 0 闭
emotion 0 无表情 1 开心 2 伤心 3 吃惊 4 恐惧 5 厌恶 6 愤怒
ageBracket 0:0~2 1:3~9 2:10~19 3:20~29 4:30~39 5:40~49 6:50~59 7:60~67 8:>70
gender 0 女 / 1 男
race 0 黑人 1 亚洲人 2 拉丁裔 3 中东 4 白人
actions { blink, jawOpen, shake, headRaise, normal },0 未发生 / 1 发生

四、错误码

码 含义
9280001 参数错误
9280002 引擎未初始化,请先调用 init
9280003 引擎初始化失败(模型包缺失 / 设备不支持)
9280004 图片读取失败(路径不存在 / 下载失败 / base64 非法)
9280005 未检测到人脸
9280006 检测到多张人脸(注册要求单张)
9280007 特征提取失败
9280008 人脸库操作失败
9280009 相机不可用
9280010 未获得相机权限
9280011 无法获取应用上下文(请在页面 onLoad 之后调用)
9280012 引擎已初始化(重复 init 会按成功返回,此码保留)
9280013 文件保存失败
9280014 操作失败(含异常信息)

五、性能与最佳实践

  1. 只开需要的开关:quality / mask / eyeState / actions / attribute / emotion 每开一项都会增加单帧耗时; 相机实时识别默认只开 rgbLiveness,需要属性时再开。recognize: true 会额外做特征提取 + 检索,最耗性能。
  2. 动作活体:不要只看单帧 actions,建议统计 2~3 秒内连续帧(如 blink 命中 ≥1 且 liveness > 0.5 的帧数占比)。
  3. RGB 活体:建议连续采集多帧,活体帧数 > 非活体帧数时判定为真人(单帧容易误判)。
  4. 注册质量:录入图不要戴口罩 / 墨镜,人脸尽量正对、光线均匀;detect 先看 quality > 0.5 再注册。
  5. init 时机:首次 init 会解压模型(Pikachu 约 17MB),务必在页面可交互后再调用并给 loading。

六、存储与已知限制

  • 特征库:Android/data/<包名>/files/zy_face_liveness/face_feature.db(由引擎持久化)
  • 名单表:Android/data/<包名>/files/zy_face_liveness/face_names.db(插件自建,id → name)
  • 卸载应用或清除数据会丢失人脸库,请按需导出备份
  • 若通过其他途径(直接操作引擎)增删特征,名单表不会同步;以 count() 返回的特征数为准
  • cameraId / physicalCameraId(多摄指定)当前版本预留未生效,仅支持前后摄像头切换
  • 仅支持 Android

隐私、权限声明

1. 本插件需要申请的系统权限列表:

android.permission.CAMERA(相机预览与录入)、android.permission.INTERNET(仅远程图片下载)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

全部推理在本机完成,不上传任何人脸数据;仅在传入 http(s) 图片地址时才会请求该地址

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。