Files
arc/docs/arc_plugins.md
2026-04-13 15:03:00 +08:00

498 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`