更新记录
1.0.6(2026-07-29)
-优化uniappx
1.0.5(2026-07-27)
-新增相机实时人脸识别
1.0.4(2026-07-27)
-优化
查看更多平台兼容性
uni-app(4.18)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | √ | √ | 5.0 | √ | 4.18 |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | - | × | - | - | - | - |
uni-app x(4.18)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | × | √ |
ly028-OffFace 离线人脸检测识别特真提取
真实案例体验
门禁 / 考勤类真实项目落地(ly028-reg):人脸注册、人脸库管理、拍照识别、实时相机流识别。
全功能 Demo 体验
插件官方全功能演示 App,覆盖检测、追踪、流式识别、活体、模型管理等全部 API 与示例页面。
鸿蒙实测图
iOS 实测图
基于 SeetaFace6 的人脸检测 UTS 原生插件,Android / iOS / HarmonyOS Next 三端完美支持,导出函数完全一致,一套代码三端运行。全离线运行,无需网络连接,数据不出设备。
特性
- 🔒 全离线 — 本地推理,无需联网,人脸数据不出设备
- 📱 三端完美一致 — Android / iOS / HarmonyOS Next 导出 API 完全相同,调用端无平台差异
- 🎯 30+ 个导出函数 — 检测、关键点、特征提取、活体、年龄、性别、口罩、眼睛、姿态、质量、1:1 比对、1:N 识别、人脸库管理
- 🧩 UTS 插件 — uni-app/uni-app x 原生插件,按需集成
平台兼容
| 平台 | 最低版本 | 架构 |
|---|---|---|
| Android | 7.0 (API 21) | arm64-v8a, armeabi-v7a |
| iOS | 12.0 | arm64 |
| HarmonyOS Next | API 9+ | arm64-v8a |
集成与调试
HBuilderX 自定义基座运行
- 插件市场购买插件后,在
manifest.json→ App 原生插件配置中选择ly028-OffFace - 选择需要使用的模块
- 自定义调试基座:菜单栏 → 运行 → 运行到手机或模拟器 → 制作自定义调试基座
- 制作完成后,选择自定义基座运行到真机即可调试所有功能
首次使用请确保已关联 uni-app 开发者证书,自定义基座有效期为 7 天,过期后需重新制作。
离线打包
插件为原生代码插件,离线打包需自行集成原生依赖。
插件包体积优化
本插件将模型文件从插件包移出,插件市场包体积从 89MB 降至 38MB。
| 方案 | 体积 |
|---|---|
| 插件市场包(不含模型) | ~38 MB |
| 完整功能(含模型) | 模型放入项目 static/models/ 后自动加载 |
方式一:自动发现(推荐)
在项目 static/ 目录下创建 models/ 文件夹,放入 .csta 模型文件,插件初始化时自动发现并加载:
YourProject/
├── static/
│ └── models/ ← 放入 .csta 模型文件
│ ├── face_detector.csta
│ ├── face_recognizer_light.csta
│ ├── face_landmarker_pts5.csta
│ ├── ...
│ └── quality_lbn.csta
├── uni_modules/
│ └── ly028-OffFace/ ← 插件包(不含模型)
import * as OffFace from '@/uni_modules/ly028-OffFace'
// 自动发现 static/models/ 下的模型
OffFace.initFaceEngineAsync(null, null, (res) => {
const initResult = JSON.parse(res)
if (initResult.code === 0) {
console.log('引擎初始化成功')
}
})
方式二:自定义目录名
模型放在不同目录时,通过 modelAssetDir 参数指定:
OffFace.initFaceEngineAsync(null, null, (res) => {
// ...
}, 'offface_models') // 模型放在 static/offface_models/ 下
方式三:远程下载
不放置模型文件,通过 CDN 下载缺失模型(需要 modelBaseUrl 参数):
OffFace.initFaceEngineAsync('https://your-cdn.com/models/', null, (res) => {
// ...
})
注意:引擎初始化时不下载模型,仅扫描已存在的文件。缺失的大模型需调用
downloadModelAsync()单独下载:
OffFace.downloadModelAsync(
'face_recognizer.csta',
'https://your-cdn.com/models/',
(progressJson) => {
const p = JSON.parse(progressJson)
console.log(p.name, p.pct) // 持续进度(@UTSJS.keepAlive)
},
(resultJson) => {
const r = JSON.parse(resultJson)
console.log('download done', r.code)
}
)
// 2. 异步检测人脸 OffFace.detectFileAsync('/path/to/image.jpg', (res) => { const result = JSON.parse(res) if (result.code === 0 && result.data.faceCount > 0) { console.log('检测到', result.data.faceCount, '张人脸') console.log('第一个人脸:', result.data.faces[0]) } })
// 3. 释放引擎 OffFace.releaseEngine()
## 全量 API 参考
### 引擎生命周期
| API | 说明 |
|-----|------|
| `initFaceEngineAsync(modelBaseUrl?, modelPath?, callback, modelAssetDir?)` | 初始化引擎,结果通过 callback 返回。`modelAssetDir` 指定 `static/` 下的模型目录名,默认自动发现 `models/` |
| `releaseEngine()` | 释放引擎 |
| `setAppLanguage(language)` | 设置语言(`zh-Hans` / `en`) |
### 人脸检测
| API | 说明 |
|-----|------|
| `detectFace(imageData, width, height, channels)` | 从 RGBA 像素数组检测 |
| `detectWithOptions(imageData, w, h, ch, minSize, threshold, flags)` | 全功能检测(flags 按位组合) |
| `detectFileAsync(filePath, callback)` | 异步文件检测,结果通过 callback 返回 |
| `detectFileWithOptionsAsync(filePath, options, callback)` | 带选项异步文件检测 |
| `detectTestImage(width, height)` | 测试图像检测 |
**flags 位定义**:
| 位 | 功能 |
|----|------|
| 1 | 关键点 |
| 2 | 年龄(需额外模型) |
| 4 | 性别 |
| 8 | 口罩 |
| 16 | 眼睛状态 |
| 32 | 姿态角 |
| 64 | 活体 |
| 128 | 质量评估 |
### 活体检测
| API | 说明 |
|-----|------|
| `detectFileLivenessAsync(filePath, callback)` | 异步活体检测 |
| `checkLivenessReadyAsync(callback)` | 异步检查活体模型是否就绪 |
返回 `liveness` 值:`real`(真实)、`spoof`(伪造)、`fuzzy`(模糊)、`detecting`(检测中)
### 人脸跟踪(FaceTracker)
基于 SeetaFace6 `FaceTracker` 的视频流人脸跟踪,适用于摄像头逐帧场景。三端(Android / iOS / HarmonyOS)API 完全一致。
| API | 说明 |
|-----|------|
| `initTracker(width, height, minFaceSize?, threshold?)` | 初始化跟踪器 |
| `trackAsync(options, callback)` | 异步逐帧跟踪(推荐),详见下方 |
`trackAsync` 接收 `TrackFrameOptions` 参数,通过 callback 返回跟踪结果:
```typescript
import { trackAsync } from '@/uni_modules/ly028-OffFace'
trackAsync({
data: base64ImageData, // Base64 帧数据
width: 1920, // 图像宽度
height: 1080, // 图像高度
frameNo: frameNo, // 帧序号(递增)
format: 'nv12', // 'nv12'(默认)|'rgba'|'nv21'|'i420'|'bgr'
detailMode: 1, // 0=基础跟踪|1=含详细属性
}, (result: string) => {
const data = JSON.parse(result)
console.log('人脸数:', data.faceCount)
})
TrackFrameOptions:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
data |
string |
是 | — | 每帧图像的像素缓冲区,Base64 编码字符串。来源:由 ly028-Camera 插件或其他摄像头方案采集到的一帧完整像素数据,编码为 Base64 后传入 |
width |
number |
是 | — | 图像宽度(像素) |
height |
number |
是 | — | 图像高度(像素) |
frameNo |
number |
是 | — | 帧序号(逐帧递增) |
format |
string |
否 | "nv12" |
像素格式,应与 data 解码前的原始像素格式一致(nv12 / rgba / nv21 / i420 / bgr)。推荐 NV12,iOS 摄像头原生输出格式,无需额外转换 |
detailMode |
number |
否 | 0 |
0=基础跟踪 1=含详细属性 |
data的原始像素格式由format参数描述,解码时需要匹配。例如format: "nv12"时,Base64 解码后的字节应为 NV12 排列的 YUV 数据。三端统一由ly028-Camera插件提供 Base64 帧数据,调用方无需关心内部编码细节。
跟踪配置:
| API | 说明 |
|---|---|
trackerSetMinFaceSize(size) |
最小人脸尺寸(默认 80) |
trackerSetThreshold(th) |
检测阈值(默认 0.9) |
trackerSetVideoStable(stable) |
视频稳定模式,减少 PID 跳变 |
trackerReset() |
重置跟踪器(PID 重新分配) |
stopTrackAsync() |
解除 trackAsync 背压 |
流式人脸库识别(Stream Identify)
相机逐帧喂入 → 与人脸库比对 → 命中时回调一次。相机开/关由应用自行控制。
| API | 说明 |
|---|---|
startStreamIdentifyAsync(options, onHit, ?) |
开始识别会话 |
streamIdentifyFrameAsync(frame) |
喂入一帧(fire-and-forget,禁止 await) |
stopStreamIdentify() |
结束会话 |
StreamIdentifyOptions:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
threshold |
number | 0.6 | 相似度阈值 |
topN |
number | 1 | Top-N,范围 1..10 |
skipEvery |
number | 1 | 每 N 帧识别 1 次 |
minFaceSize |
number | 引擎默认 | 最小人脸尺寸 |
detectThreshold |
number | 0.9 | 检测阈值 |
StreamIdentifyFrame:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
data |
string | — | Base64 帧数据(配合 ly028-Camera) |
width |
number | — | 图像宽度 |
height |
number | — | 图像高度 |
frameNo |
number | — | 可选,帧序号 |
format |
string | "nv12" |
nv12 / rgba / nv21 / i420 / bgr |
回调说明:
onHit(result)— 识别命中时回调一次,JSON 信封内data含userId、similarity等onProgress(rectsJson)(可选)— 人脸框数组 JSON,可传给updateFaceRects绘制 overlay- 未命中时不触发
onHit
import {
startStreamIdentifyAsync,
streamIdentifyFrameAsync,
stopStreamIdentify
} from '@/uni_modules/ly028-OffFace'
// 1. 开始会话
startStreamIdentifyAsync(
{ threshold: 0.6, topN: 1, skipEvery: 1 },
(result) => {
const env = JSON.parse(result)
// 命中:处理 userId / similarity,然后结束
stopStreamIdentify()
},
(rectsJson) => {
// 可选:更新相机人脸框 overlay
const rects = JSON.parse(rectsJson)
// updateFaceRects(rects)
}
)
// 2. 相机 onFrame 内喂帧(不要 await)
streamIdentifyFrameAsync({
data: base64Frame,
width,
height,
format: 'nv12'
})
// 3. 用户关闭相机或离开页面时
stopStreamIdentify()
使用须知:
- 需先初始化引擎与人脸库,并至少注册一张脸
streamIdentifyFrameAsync为 fire-and-forget,不要在回调里 await- 推荐相机参数:
format: 'nv12',maxFps: 5(与跟踪示例一致) - 命中后请调用
stopStreamIdentify()并关闭相机
流式识别用于实时查人脸库;
trackAsync用于实时跟踪出框与属性,两者可独立使用。
跟踪结果(detailMode: 1 时)
{
"faceCount": 2,
"faces": [{
"PID": 1,
"rect": {"x": 100, "y": 200, "width": 150, "height": 180},
"score": 0.95,
"frameNo": 42,
"step": 3,
"landmarks": [{"x": 120, "y": 250}, {"x": 180, "y": 250}],
"age": 25,
"gender": "male",
"mask": false,
"maskScore": 0.02,
"eyeLeft": "open",
"eyeRight": "open",
"yaw": 5.2, "pitch": 3.1, "roll": -1.8,
"quality": {
"brightness": {"level": "high", "score": 0.92},
"clarity": {"level": "high", "score": 0.88},
"integrity": {"level": "high", "score": 0.95},
"pose": {"level": "high", "score": 0.90},
"resolution": {"level": "medium", "score": 0.65},
"pose_ex": {"level": "high", "score": 0.91}
}
}]
}
智能降频:
detailMode: 1时属性检测每 3 帧执行一次完整管道,中间帧按 PID 合并最近属性结果,避免逐帧全量推理的性能开销。 空闲复位:距上次 track 超过 5 秒自动重置跟踪器状态。 反压:上一帧未处理完时新帧直接丢弃,避免队列积压。
模块管理
| API | 说明 |
|---|---|
getModelStatusAsync(callback) |
异步获取模型下载状态 |
getMissingModels() |
获取缺失模型列表 |
downloadModelAsync(name, baseUrl, , onComplete) |
异步下载模型(@UTSJS.keepAlive 持续进度回调) |
getLoadStatus() |
获取模块加载状态 |
getModelLoadStatusByFilesAsync(callback) |
异步按文件查加载状态 |
ensureModuleLoaded(moduleName) |
确保模块已加载 |
ensureModulesLoaded(names) |
批量确保加载 |
loadModule(name, modelDir) |
手动加载模块 |
人脸识别(FaceDatabase)
| API | 说明 |
|---|---|
initFaceDatabaseAsync(modelType, callback) |
异步初始化人脸库(light / std) |
switchFaceDatabaseAsync(modelType, callback) |
异步切换活跃模型 |
getFaceDatabaseStatusAsync(callback) |
异步获取双库状态 |
特征提取
| API | 说明 |
|---|---|
extractFeatureAsync(imageData, width, height, landmarks, callback) |
异步提取人脸特征向量 |
人脸注册
| API | 说明 |
|---|---|
registerFaceAsync(imageData, w, h, landmarks, userId, callback) |
异步注册人脸 |
registerFaceByFileAsync(filePath, landmarks, userId?, callback) |
从文件注册(空 userId 自动生成) |
updateFaceByFileAsync(filePath, landmarks, userId, callback) |
更新已注册人脸 |
1:N 识别
| API | 说明 |
|---|---|
identifyFaceAsync(imageData, w, h, landmarks, callback) |
异步最佳匹配识别 |
identifyFaceByFileAsync(filePath, landmarks, callback) |
从文件识别 |
identifyTopNAsync(imageData, w, h, landmarks, n, callback) |
异步 Top-N 识别 |
identifyTopNByFileAsync(filePath, landmarks, topN, callback) |
从文件 Top-N |
人脸管理
| API | 说明 |
|---|---|
deleteFaceAsync(userId, callback) |
异步删除人脸 |
clearFacesAsync(callback) |
异步清空所有人脸 |
getFaceCountAsync(callback) |
异步获取人脸数 |
exportFeaturesAsync(callback) |
异步导出所有人脸特征 |
compareFacesAsync(feature1, feature2, callback) |
异步 1:1 特征比对 |
配置
| API | 说明 |
|---|---|
setMinFaceSize(size) |
最小人脸像素(默认 40) |
setDetectThreshold(threshold) |
检测阈值(默认 0.9) |
返回值格式
所有 API 返回统一 JSON 信封:
// 成功
{"code": 0, "data": {...}}
// 失败
{"code": 1, "subCode": 500, "msg": "错误描述"}
检测结果结构
{
"code": 0,
"data": {
"faceCount": 1,
"imageWidth": 1920,
"imageHeight": 1080,
"faces": [{
"rect": {"x": 100, "y": 200, "width": 300, "height": 400},
"score": 0.98,
"landmarks": [{"x": 150, "y": 250}, ...],
"age": 25,
"gender": "male",
"mask": false,
"maskScore": 0.02,
"eyeLeft": "open",
"eyeRight": "open",
"yaw": -5.3, "pitch": 2.1, "roll": 1.0,
"liveness": "real",
"quality": {
"brightness": {"level": "high", "score": 0.95},
"clarity": {"level": "medium", "score": 0.65},
"integrity": {"level": "high", "score": 0.90}
}
}]
}
}
识别结果结构
{"code": 0, "data": {"found": true, "userId": "user_abc123", "similarity": 0.87}}
Top-N 结果结构
{"code": 0, "data": {"count": 3, "topN": 5, "results": [
{"userId": "user_abc", "similarity": 0.87},
{"userId": "user_def", "similarity": 0.72}
], "duplicates": [], "duplicateThreshold": 0.6}}
注意事项
- 插件包不包含模型文件,需将
.csta文件放入项目static/models/(或其他指定目录),初始化时自动加载 - 引擎只能初始化一次,释放后可再次初始化
- 人脸库初始化选择:
light(512 维,轻量)、std(1024 维,需下载face_recognizer.csta约 98MB) - 活体检测需要
fas_first.csta和fas_second.csta两个模型 - 年龄检测为热加载模块,需额外下载
age_predictor.csta(约 32MB) - 并发检测内部有互斥锁,同一时间只允许一次检测
- 建议图片最大尺寸 1280px,超尺寸自动缩放
隐私声明
- 本插件不采集任何用户数据
- 所有人脸检测与识别在设备端离线完成
- 无需网络权限,不上传任何图像或特征数据
许可
- 插件市场购买后获得使用授权
- 禁止反编译、二次分发

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 924
赞赏 0
下载 12480799
赞赏 1937
赞赏
京公网安备:11010802035340号