This commit is contained in:
2026-04-13 15:02:57 +08:00
parent 8776f3e64d
commit 6eee922b7e

498
docs/arc_plugins.md Normal file
View File

@@ -0,0 +1,498 @@
# Arc Flutter 插件使用指南
## 简介
Arc 是一个封装虹软 (ArcSoft) Face SDK 的 Flutter 插件,提供 Android 平台的人脸检测、人脸识别、活体检测功能。本插件支持 1:1 人脸比对和 1:N 人脸搜索两种模式。
## 安装
### 1. 添加依赖
在您的 Flutter 项目 `pubspec.yaml` 中添加依赖:
```yaml
dependencies:
arc:
path: ../arc # 本地引用,或使用 git/path 方式
```
### 2. Android 配置
`android/app/build.gradle` 中确保最小 SDK 版本:
```gradle
android {
defaultConfig {
minSdkVersion 21 // 虹软 SDK 要求最低 Android 5.0
}
}
```
### 3. 获取虹软 SDK 密钥
访问 [虹软开放平台](https://ai.arcsoft.com.cn/) 注册账号,创建应用获取:
- `appId`: 应用 ID
- `sdkKey`: SDK 密钥
- `activeKey`: 激活密钥
## 快速开始
### 基础流程
```
激活 SDK → 初始化引擎 → 人脸检测 → 特征提取 → 特征比对/注册
```
### 示例代码
```dart
import 'package:arc/arc.dart';
final _arc = Arc();
// 1. 激活 SDK必须首先执行
await _arc.activeOnline(
appId: '您的AppId',
sdkKey: '您的SdkKey',
activeKey: '您的ActiveKey',
);
// 2. 初始化引擎
await _arc.init(
detectMode: 0, // 0=视频流模式, 1=图像模式
orient: 0, // 检测角度
maxFaceNum: 1, // 最大检测人脸数
combinedMask: 0x9D, // 功能组合掩码
);
// 3. 人脸检测(需要摄像头 NV21 数据)
final result = await _arc.detectFaces(
data: nv21Data,
width: width,
height: height,
);
// 4. 提取特征
final featureResult = await _arc.extractFaceFeature(
data: nv21Data,
width: width,
height: height,
rectLeft: faceInfo['rectLeft'],
rectTop: faceInfo['rectTop'],
rectRight: faceInfo['rectRight'],
rectBottom: faceInfo['rectBottom'],
faceData: faceInfo['faceData'], // 重要!必须传递
);
// 5. 比对特征
final compareResult = await _arc.compareFaceFeature(
featureData1: feature1,
featureData2: feature2,
);
```
## API 详细说明
### activeOnline - SDK 激活
在线激活虹软 SDK必须在使用其他功能前完成。
```dart
Future<Map<String, dynamic>?> activeOnline({
required String appId, // 虹软应用 ID
required String sdkKey, // SDK 密钥
required String activeKey, // 激活密钥
})
```
**返回值:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 是否成功 |
| `errorCode` | int | 错误码0=成功) |
| `message` | String | 结果描述 |
---
### init - 初始化引擎
初始化人脸识别引擎,配置检测模式和功能。
```dart
Future<Map<String, dynamic>?> init({
int? detectMode, // 检测模式
int? orient, // 检测角度
int? maxFaceNum, // 最大人脸数
int? combinedMask, // 功能掩码组合
})
```
**参数说明:**
| 参数 | 值 | 说明 |
|------|------|------|
| detectMode | 0 | VIDEO 模式(视频流,适合实时检测) |
| detectMode | 1 | IMAGE 模式(单张图片) |
| orient | 0/90/180/270/360 | 检测角度优先级 |
| maxFaceNum | 1-50 | 同时检测的最大人脸数量 |
**功能掩码组合:**
| 功能 | 值 | 说明 |
|------|------|------|
| ASF_FACE_DETECT | 0x00000001 | 人脸检测 |
| ASF_FACE_RECOGNITION | 0x00000004 | 人脸识别 |
| ASF_AGE | 0x00000008 | 年龄检测 |
| ASF_GENDER | 0x00000010 | 性别检测 |
| ASF_LIVENESS | 0x00000080 | RGB 活体检测 |
**推荐组合:**
```dart
combinedMask: 0x9D // 人脸检测 + 识别 + 年龄 + 性别 + 活体
// 计算方式: 0x01 | 0x04 | 0x08 | 0x10 | 0x80 = 0x9D
```
---
### detectFaces - 人脸检测
检测图像中的人脸,同时进行 RGB 活体检测。
```dart
Future<Map<String, dynamic>?> detectFaces({
required Uint8List data, // NV21 图像数据
required int width, // 图像宽度
required int height, // 图像高度
int format = 2050, // 图像格式(默认 NV21
})
```
**返回值:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 是否检测成功 |
| `errorCode` | int | 错误码 |
| `faceList` | List<Map> | 检测到的人脸列表 |
| `rgbLiveness` | int | RGB 活体结果(-1=未知, 0=非真人, 1=真人) |
| `isRgbAlive` | bool | 是否真人 |
**faceList 每项包含:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `rectLeft` | int | 人脸框左边界 |
| `rectTop` | int | 人脸框上边界 |
| `rectRight` | int | 人脸框右边界 |
| `rectBottom` | int | 人脸框下边界 |
| `faceOrientation` | int | 人脸角度 |
| `faceId` | int | 人脸 ID |
| `faceData` | Uint8List | **重要!特征提取必需的数据** |
---
### extractFaceFeature - 特征提取
从检测到的人脸中提取 512 字节的特征数据。
```dart
Future<Map<String, dynamic>?> extractFaceFeature({
required Uint8List data, // NV21 图像数据
required int width, // 图像宽度
required int height, // 图像高度
required int rectLeft, // 人脸框左边界(从 detectFaces 获取)
required int rectTop, // 人脸框上边界
required int rectRight, // 人脸框右边界
required int rectBottom, // 人脸框下边界
int format = 2050, // 图像格式
int faceOrientation = 0, // 人脸角度(从 detectFaces 获取)
int faceId = -1, // 人脸 ID
Uint8List? faceData, // **关键:人脸数据(从 detectFaces 获取)**
int extractType = 1, // 0=注册模式, 1=识别模式
int mask = 0, // 口罩状态
})
```
**参数说明:**
| 参数 | 值 | 说明 |
|------|------|------|
| extractType | 0 | REGISTER 模式(用于注册到人脸库) |
| extractType | 1 | RECOGNIZE 模式(用于比对验证) |
| mask | 0 | 未佩戴口罩 |
| mask | 1 | 已佩戴口罩 |
**返回值:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 是否成功 |
| `errorCode` | int | 错误码 |
| `featureData` | Uint8List | 512 字节特征数据 |
---
### compareFaceFeature - 特征比对 (1:1)
比对两个人脸特征的相似度。
```dart
Future<Map<String, dynamic>?> compareFaceFeature({
required Uint8List featureData1, // 第一个特征
required Uint8List featureData2, // 第二个特征
int compareModel = 0, // 比对模型
})
```
**compareModel 参数:**
| 值 | 说明 | 推荐阈值 |
|------|------|------|
| 0 | 生活照模型 | 0.8 |
| 1 | 证件照模型 | 0.82 |
**返回值:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 是否成功 |
| `similarity` | double | 相似度0-1 |
---
### registerFaceFeature - 注册到人脸库 (1:N)
将人脸特征注册到本地人脸库,用于后续 1:N 搜索。
```dart
Future<Map<String, dynamic>?> registerFaceFeature({
required int searchId, // 唯一标识符(建议使用用户 ID
required Uint8List featureData, // 特征数据
String? faceTag, // 附属信息(可选)
})
```
---
### registerFaceFeatureBatch - 批量注册
批量注册多张人脸特征。
```dart
Future<Map<String, dynamic>?> registerFaceFeatureBatch({
required List<Map<String, dynamic>> faceList,
})
// 示例:
await _arc.registerFaceFeatureBatch(
faceList: [
{'searchId': 1, 'featureData': feature1, 'faceTag': '张三'},
{'searchId': 2, 'featureData': feature2, 'faceTag': '李四'},
],
);
```
## 图像格式要求
### NV21 格式
- 虹软 SDK 使用 NV21 格式Android 摄像头默认格式)
- 格式代码:`2050`
- 宽度必须是 **4 的倍数**
- 高度必须是 **2 的倍数**
### 从 Camera 提取 NV21
使用 `camera` 插件获取 NV21 数据:
```dart
// 配置摄像头使用 NV21 格式
_cameraController = CameraController(
camera,
ResolutionPreset.medium,
enableAudio: false,
imageFormatGroup: ImageFormatGroup.nv21, // 关键配置
);
// 处理图像流
void _onImageAvailable(CameraImage image) {
final nv21Data = _extractNV21(image, image.width, image.height);
// 人脸检测
final result = await _arc.detectFaces(
data: nv21Data,
width: image.width,
height: image.height,
);
}
// NV21 数据提取函数
Uint8List _extractNV21(CameraImage image, int width, int height) {
final ySize = width * height;
final nv21Size = ySize * 3 ~/ 2;
// ... 根据 planes 结构提取数据
// 参考 example/lib/main.dart 中的完整实现
}
```
## 推荐阈值
| 功能 | 阈值 | 说明 |
|------|------|------|
| 人脸比对(生活照) | 0.8 | 相似度 >= 0.8 认为匹配 |
| 人脸比对(证件照) | 0.82 | 相似度 >= 0.82 认为匹配 |
| RGB 活体检测 | 0.5 | 活体分数 >= 0.5 认为真人 |
| IR 活体检测 | 0.5 | 活体分数 >= 0.5 认为真人 |
## 完整使用流程示例
### 1:1 人脸验证
```dart
// 1. 激活 SDK
final activeResult = await _arc.activeOnline(
appId: appId,
sdkKey: sdkKey,
activeKey: activeKey,
);
if (activeResult?['success'] != true) {
print('激活失败');
return;
}
// 2. 初始化引擎
final initResult = await _arc.init(
detectMode: 0,
orient: 0,
maxFaceNum: 1,
combinedMask: 0x9D,
);
// 3. 摄像头获取图像
// 使用 camera 插件获取 NV21 数据...
// 4. 人脸检测
final detectResult = await _arc.detectFaces(
data: nv21Data,
width: width,
height: height,
);
if (detectResult?['success'] == true) {
final faceList = detectResult!['faceList'] as List;
if (faceList.isNotEmpty) {
final faceInfo = faceList[0] as Map;
final rgbLiveness = detectResult['rgbLiveness'] as int;
// 检查活体
if (rgbLiveness != 1) {
print('非真人');
return;
}
// 5. 提取特征
final featureResult = await _arc.extractFaceFeature(
data: nv21Data,
width: width,
height: height,
rectLeft: faceInfo['rectLeft'],
rectTop: faceInfo['rectTop'],
rectRight: faceInfo['rectRight'],
rectBottom: faceInfo['rectBottom'],
faceData: faceInfo['faceData'], // 重要!
extractType: 1, // 识别模式
);
if (featureResult?['success'] == true) {
final currentFeature = featureResult!['featureData'] as Uint8List;
// 6. 比对(与已存储的特征)
final compareResult = await _arc.compareFaceFeature(
featureData1: currentFeature,
featureData2: storedFeature,
compareModel: 0,
);
final similarity = compareResult?['similarity'] as double ?? 0.0;
if (similarity >= 0.8) {
print('验证通过,相似度: ${similarity}');
} else {
print('验证失败,相似度: ${similarity}');
}
}
}
}
```
### 1:N 人脸搜索
```dart
// 注册阶段
// 提取特征(注册模式)
final registerFeature = await _arc.extractFaceFeature(
data: nv21Data,
width: width,
height: height,
rectLeft: faceInfo['rectLeft'],
rectTop: faceInfo['rectTop'],
rectRight: faceInfo['rectRight'],
rectBottom: faceInfo['rectBottom'],
faceData: faceInfo['faceData'],
extractType: 0, // 注册模式
);
// 注册到人脸库
await _arc.registerFaceFeature(
searchId: userId, // 如: 10001
featureData: registerFeature!['featureData'],
faceTag: '张三',
);
// 搜索阶段SDK 会自动搜索匹配)
// 使用 extractType=1 提取特征后SDK 会自动进行 1:N 搜索
```
## 错误处理
所有 API 返回统一的错误格式:
```dart
{
'success': false,
'errorCode': 81929, // 具体错误码
'message': '特征提取失败',
}
```
常见错误码:
- `0`: 成功
- `81929`: 特征提取失败(通常是因为未传递 faceData
- `其他`: 参考 `android/src/.../FaceErrorCode.java` 中的 586 个错误码定义
## 注意事项
1. **必须先激活再初始化**:使用顺序为 `activeOnline``init` → 其他功能
2. **faceData 必须传递**`extractFaceFeature``faceData` 参数是从 `detectFaces` 获取的关键数据,不传递会导致特征提取失败
3. **图像尺寸限制**:宽度必须为 4 的倍数,高度必须为 2 的倍数
4. **单设备激活**:虹软 SDK 激活与设备绑定,同一 AppId 在不同设备上需要重新激活
5. **特征存储**:特征数据为 512 字节,建议使用 Base64 编码后存储
## 依赖插件推荐
实现完整人脸识别功能通常需要配合:
```yaml
dependencies:
arc: ^0.0.1 # 人脸识别
camera: ^0.11.0 # 摄像头访问
shared_preferences: ^2.0.0 # 特征存储
```
## 参考资源
- [虹软开放平台](https://ai.arcsoft.com.cn/)
- [虹软人脸识别 SDK 文档](https://ai.arcsoft.com.cn/manual/)
- 本插件示例代码:`example/lib/main.dart`
- 虹软接口文档:`docs/虹软人脸识别接口文档.md`