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

13 KiB
Raw Blame History

Arc Flutter 插件使用指南

简介

Arc 是一个封装虹软 (ArcSoft) Face SDK 的 Flutter 插件,提供 Android 平台的人脸检测、人脸识别、活体检测功能。本插件支持 1:1 人脸比对和 1:N 人脸搜索两种模式。

安装

1. 添加依赖

在您的 Flutter 项目 pubspec.yaml 中添加依赖:

dependencies:
  arc:
    path: ../arc  # 本地引用,或使用 git/path 方式

2. Android 配置

android/app/build.gradle 中确保最小 SDK 版本:

android {
    defaultConfig {
        minSdkVersion 21  // 虹软 SDK 要求最低 Android 5.0
    }
}

3. 获取虹软 SDK 密钥

访问 虹软开放平台 注册账号,创建应用获取:

  • appId: 应用 ID
  • sdkKey: SDK 密钥
  • activeKey: 激活密钥

快速开始

基础流程

激活 SDK → 初始化引擎 → 人脸检测 → 特征提取 → 特征比对/注册

示例代码

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必须在使用其他功能前完成。

Future<Map<String, dynamic>?> activeOnline({
  required String appId,      // 虹软应用 ID
  required String sdkKey,     // SDK 密钥
  required String activeKey,  // 激活密钥
})

返回值:

字段 类型 说明
success bool 是否成功
errorCode int 错误码0=成功)
message String 结果描述

init - 初始化引擎

初始化人脸识别引擎,配置检测模式和功能。

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 活体检测

推荐组合:

combinedMask: 0x9D  // 人脸检测 + 识别 + 年龄 + 性别 + 活体
// 计算方式: 0x01 | 0x04 | 0x08 | 0x10 | 0x80 = 0x9D

detectFaces - 人脸检测

检测图像中的人脸,同时进行 RGB 活体检测。

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 检测到的人脸列表
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 字节的特征数据。

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)

比对两个人脸特征的相似度。

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 搜索。

Future<Map<String, dynamic>?> registerFaceFeature({
  required int searchId,         // 唯一标识符(建议使用用户 ID
  required Uint8List featureData, // 特征数据
  String? faceTag,               // 附属信息(可选)
})

registerFaceFeatureBatch - 批量注册

批量注册多张人脸特征。

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 数据:

// 配置摄像头使用 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 人脸验证

// 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 人脸搜索

// 注册阶段
// 提取特征(注册模式)
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 返回统一的错误格式:

{
  'success': false,
  'errorCode': 81929,  // 具体错误码
  'message': '特征提取失败',
}

常见错误码:

  • 0: 成功
  • 81929: 特征提取失败(通常是因为未传递 faceData
  • 其他: 参考 android/src/.../FaceErrorCode.java 中的 586 个错误码定义

注意事项

  1. 必须先激活再初始化:使用顺序为 activeOnlineinit → 其他功能
  2. faceData 必须传递extractFaceFeaturefaceData 参数是从 detectFaces 获取的关键数据,不传递会导致特征提取失败
  3. 图像尺寸限制:宽度必须为 4 的倍数,高度必须为 2 的倍数
  4. 单设备激活:虹软 SDK 激活与设备绑定,同一 AppId 在不同设备上需要重新激活
  5. 特征存储:特征数据为 512 字节,建议使用 Base64 编码后存储

依赖插件推荐

实现完整人脸识别功能通常需要配合:

dependencies:
  arc: ^0.0.1               # 人脸识别
  camera: ^0.11.0           # 摄像头访问
  shared_preferences: ^2.0.0 # 特征存储

参考资源