1036 lines
34 KiB
ReStructuredText
1036 lines
34 KiB
ReStructuredText
人脸识别组件
|
||
==============
|
||
|
||
简介
|
||
----
|
||
|
||
ACOMP FD (Face Detection) 是 ARCS SDK 的人脸识别组件,提供基于图像流的人脸检测、对齐、活体检测和特征提取功能。该组件支持多种图像格式输入,提供灵活的参数配置和事件回调机制。
|
||
|
||
主要特性
|
||
--------
|
||
|
||
- **完整人脸识别流程**:支持人脸检测、对齐、活体检测、特征提取和特征比对
|
||
- **多格式图像输入**:支持 YUYV422、RGB565、BGR888 等多种图像格式,最大支持640*480分辨率
|
||
- **活体检测**:支持活体检测功能,可配置活体检测阈值
|
||
- **人脸特征管理**:支持人脸特征导入和比对,最多支持 10 个注册人脸
|
||
- **事件回调机制**:支持人脸识别结果、错误事件等多种事件通知
|
||
- **图像流管理**:提供完整的图像流通道管理和缓冲区操作接口
|
||
- **状态管理**:支持初始化、就绪、启动、停止等完整的生命周期管理
|
||
- **跨核通信**:基于 IPC 机制实现图像流的跨核传输
|
||
|
||
人脸识别基本流程
|
||
----------------
|
||
|
||
人脸识别基本流程如下图所示,实际根据业务需求,流程可能会有所不同:
|
||
|
||
.. image:: assets/face_detect_flow.png
|
||
:alt: 人脸识别基本流程
|
||
|
||
组件架构
|
||
--------
|
||
|
||
ACOMP FD 组件采用双核异构架构,CP 核(应用核)通过 ACOMP IPC 框架与 AP 核(算法核)进行通信,实现人脸识别功能。
|
||
|
||
.. code-block:: text
|
||
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ CP 核 (Application Core) │
|
||
│ │
|
||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||
│ │ 用户应用层 │ │
|
||
│ │ ┌────────────────────────────────────────────────────────┐ │ │
|
||
│ │ │ • 人脸识别事件回调处理 (检测结果/特征/活体) │ │ │
|
||
│ │ │ • 图像数据采集 (摄像头/图像文件) │ │ │
|
||
│ │ │ • 人脸特征管理 (注册/比对) │ │ │
|
||
│ │ └────────────────────┬───────────────────────────────────┘ │ │
|
||
│ └───────────────────────┼──────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌───────────────────────▼──────────────────────────────────────┐ │
|
||
│ │ ACOMP FD 组件 (CP 侧) │ │
|
||
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
|
||
│ │ │ 生命周期管理 │ │ 事件回调管理 │ │ 参数配置接口 │ │ │
|
||
│ │ │ init/prepare │ │ add_callback │ │ params_set/ │ │ │
|
||
│ │ │ start/stop │ │ remove_cb │ │ live_detect │ │ │
|
||
│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │
|
||
│ │ │ │ │ │ │
|
||
│ │ ┌──────▼─────────────────▼─────────────────▼───────┐ │ │
|
||
│ │ │ 图像流管理 (Stream API) │ │ │
|
||
│ │ │ • M2R 流: 图像输入 (camera → 算法) │ │ │
|
||
│ │ │ • tx_alloc/submit │ │ │
|
||
│ │ └──────────────────────┬───────────────────────────┘ │ │
|
||
│ └─────────────────────────┼──────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌─────────────────────────▼─────────────────────────────────────┐ │
|
||
│ │ ACOMP IPC 层 (CP 侧) │ │
|
||
│ │ • IPC 消息封装 (NEW/FREE/CONTROL/NOTIFY) │ │
|
||
│ │ • 设备查询和管理 │ │
|
||
│ │ • 同步/异步命令处理 │ │
|
||
│ └─────────────────────────┬─────────────────────────────────────┘ │
|
||
└────────────────────────────┼────────────────────────────────────────┘
|
||
│
|
||
│ IC Message (IPC 消息通道)
|
||
│
|
||
┌────────────────────────────▼────────────────────────────────────────┐
|
||
│ AP 核 (Algorithm Core) │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||
│ │ ACOMP Framework (AP 侧) │ │
|
||
│ │ │ │
|
||
│ │ • 接收 CP 核的 IPC 命令 (prepare/start/stop/control) │ │
|
||
│ │ • 处理图像流数据 (M2R 接收) │ │
|
||
│ │ • 执行人脸识别算法引擎 │ │
|
||
│ │ • 推送识别结果到 CP 核 (检测框/特征/活体) │ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||
│ │ 人脸识别算法引擎 (FD Engine) │ │
|
||
│ │ │ │
|
||
│ │ • 人脸检测 (Face Detection) │ │
|
||
│ │ • 人脸对齐 (Face Alignment) - 68个关键点 │ │
|
||
│ │ • 活体检测 (Liveness Detection) │ │
|
||
│ │ • 特征提取 (Feature Extraction) - 384维特征 │ │
|
||
│ │ • 特征比对 (Feature Comparison) │ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
|
||
┌─────────────────────────┐
|
||
│ 共享内存 (Shared Mem) │
|
||
│ ┌────────────────────┐ │
|
||
│ │ VirtQueue 环形缓冲 │ │
|
||
│ │ (Stream IPC 数据) │ │
|
||
│ └────────────────────┘ │
|
||
└─────────────────────────┘
|
||
|
||
架构说明
|
||
~~~~~~~~
|
||
|
||
1. CP 核 (应用核) - 开放接口层
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
- **用户应用层**: 处理人脸识别事件,采集图像数据,管理人脸特征
|
||
- **ACOMP FD 组件**: 提供生命周期管理、事件回调、参数配置等 API
|
||
- **图像流管理**: 管理 M2R(Master to Remote) 图像数据流
|
||
- **ACOMP IPC 层**: 封装 IPC 消息,与 AP 核通信
|
||
|
||
2. AP 核 (算法核) - 算法实现层
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
- **ACOMP Framework**: 接收 IPC 命令,管理算法生命周期,处理图像流数据
|
||
- **人脸识别算法引擎**: 执行人脸检测、对齐、活体检测、特征提取和比对
|
||
|
||
.. note::
|
||
|
||
AP 核的具体实现为闭源算法库,开发者只需关注 CP 核的 API 使用即可。
|
||
|
||
3. 通信机制
|
||
^^^^^^^^^^^
|
||
|
||
- **控制通道**: 通过 IC Message 传递控制命令 (prepare/start/stop/control)
|
||
- **数据通道**: 通过 VirtQueue 共享内存实现零拷贝图像流传输
|
||
- **事件通知**: AP 核通过 NOTIFY 消息主动推送识别结果到 CP 核
|
||
|
||
4. 数据流向
|
||
^^^^^^^^^^^
|
||
|
||
- **M2R 流**: CP 核采集的图像数据 (摄像头/文件) → AP 核算法引擎
|
||
- **事件流**: AP 核识别结果(检测框/特征/活体) → CP 核回调函数
|
||
|
||
图像数据结构
|
||
------------
|
||
|
||
输入图像数据结构
|
||
~~~~~~~~~~~~~~~~
|
||
|
||
.. code-block:: c
|
||
|
||
typedef struct{
|
||
acomp_fd_pixel_format format; /* 像素格式 */
|
||
uint32_t index; /* 帧索引号 */
|
||
uint16_t width; /* 图像宽度(像素) */
|
||
uint16_t height; /* 图像高度(像素) */
|
||
uint32_t length; /* 图像数据长度(字节) */
|
||
uint32_t resv[4]; /* 保留字段 */
|
||
uint8_t data[0]; /* 图像数据 */
|
||
} acomp_fd_input_frame_t;
|
||
|
||
支持的图像格式
|
||
~~~~~~~~~~~~~~
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 30 30 40
|
||
|
||
* - 格式
|
||
- 说明
|
||
- 数据大小 (320x240)
|
||
* - ``PIX_FMT_BGR888``
|
||
- BGR 24位真彩色
|
||
- 230400 字节
|
||
* - ``PIX_FMT_YUV422_YUYV_PACKED``
|
||
- YUYV422 交织格式
|
||
- 153600 字节
|
||
* - ``PIX_FMT_RGB565``
|
||
- RGB 16位高彩色
|
||
- 153600 字节
|
||
|
||
人脸识别结果结构
|
||
~~~~~~~~~~~~~~~~
|
||
|
||
.. code-block:: c
|
||
|
||
typedef struct {
|
||
acomp_fd_rect_t face_rect; /* 人脸检测矩形框 */
|
||
float face_score; /* 人脸检测得分 */
|
||
acomp_fd_align_point_t align_points[68]; /* 68个人脸关键点 */
|
||
int n_align_point; /* 关键点个数 */
|
||
acomp_fd_head_pose_t pose; /* 头部姿态角度 */
|
||
acomp_fd_live_detect_result_t live_result; /* 活体检测结果 */
|
||
int face_id; /* 人脸ID */
|
||
float features[384]; /* 384维人脸特征 */
|
||
int feature_cnt; /* 特征维度 */
|
||
float compare_scores[10]; /* 与注册人脸的比对得分 */
|
||
int compare_cnt; /* 已注册人脸数量 */
|
||
} acomp_fd_result_t;
|
||
|
||
配置选项
|
||
--------
|
||
|
||
基本配置
|
||
~~~~~~~~
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 40 40 20
|
||
|
||
* - 配置项
|
||
- 说明
|
||
- 默认值
|
||
* - ``CONFIG_ACOMP``
|
||
- 启用ACOMP组件
|
||
- n
|
||
* - ``CONFIG_ACOMP_FD``
|
||
- 启用ACOMP组件的人脸识别组件
|
||
- n
|
||
|
||
资源配置
|
||
~~~~~~~~
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 50 30 20
|
||
|
||
* - 配置项
|
||
- 说明
|
||
- 默认值
|
||
* - ``CONFIG_ACOMP_FD_RES_FACE_DETECT_ADDRESS``
|
||
- 人脸检测模型地址(Flash)
|
||
- 0x30100000
|
||
* - ``CONFIG_ACOMP_FD_RES_FACE_DETECT_LENGTH``
|
||
- 人脸检测模型长度
|
||
- 450936
|
||
* - ``CONFIG_ACOMP_FD_RES_FACE_ALIGN_ADDRESS``
|
||
- 人脸对齐模型地址(Flash)
|
||
- 0x30170000
|
||
* - ``CONFIG_ACOMP_FD_RES_FACE_ALIGN_LENGTH``
|
||
- 人脸对齐模型长度
|
||
- 1588664
|
||
* - ``CONFIG_ACOMP_FD_RES_FACE_LIVE_ADDRESS``
|
||
- 活体检测模型地址(Flash)
|
||
- 0x30300000
|
||
* - ``CONFIG_ACOMP_FD_RES_FACE_LIVE_LENGTH``
|
||
- 活体检测模型长度
|
||
- 1095288
|
||
* - ``CONFIG_ACOMP_FD_FACE_VERIFY_ADDRESS``
|
||
- 特征提取模型地址(Flash)
|
||
- 0x30410000
|
||
* - ``CONFIG_ACOMP_FD_FACE_VERIFY_LENGTH``
|
||
- 特征提取模型长度
|
||
- 2953752
|
||
|
||
快速开始
|
||
--------
|
||
|
||
1. 启用组件
|
||
~~~~~~~~~~~
|
||
|
||
在项目的 ``prj.conf`` 文件中添加:
|
||
|
||
.. code-block:: kconfig
|
||
|
||
# 启用 ACOMP 组件
|
||
CONFIG_ACOMP=y
|
||
|
||
# 启用ACOMP组件的FD组件
|
||
CONFIG_ACOMP_FD=y
|
||
|
||
# 配置人脸识别组件所需资源在flash的位置和大小
|
||
CONFIG_ACOMP_FD_RES_FACE_DETECT_ADDRESS=0x30100000
|
||
CONFIG_ACOMP_FD_RES_FACE_DETECT_LENGTH=450936
|
||
CONFIG_ACOMP_FD_RES_FACE_ALIGN_ADDRESS=0x30170000
|
||
CONFIG_ACOMP_FD_RES_FACE_ALIGN_LENGTH=1588664
|
||
CONFIG_ACOMP_FD_RES_FACE_LIVE_ADDRESS=0x30300000
|
||
CONFIG_ACOMP_FD_RES_FACE_LIVE_LENGTH=1095288
|
||
CONFIG_ACOMP_FD_FACE_VERIFY_ADDRESS=0x30410000
|
||
CONFIG_ACOMP_FD_FACE_VERIFY_LENGTH=2953752
|
||
|
||
2. 初始化人脸识别组件
|
||
~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
在应用程序中初始化人脸识别组件:
|
||
|
||
.. code-block:: c
|
||
|
||
#include "acomp.h"
|
||
#include "fd/acomp_fd.h"
|
||
|
||
int main(int argc, char **argv)
|
||
{
|
||
// 初始化 ACOMP 框架
|
||
acomp_init();
|
||
|
||
// 初始化人脸识别组件
|
||
int ret = acomp_fd_init();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("FD init failed: %d\n", ret);
|
||
return -1;
|
||
}
|
||
|
||
// 你的应用代码
|
||
return 0;
|
||
}
|
||
|
||
3. 注册事件回调
|
||
~~~~~~~~~~~~~~~
|
||
|
||
使用事件回调函数接收人脸识别结果:
|
||
|
||
.. code-block:: c
|
||
|
||
#include "fd/acomp_fd.h"
|
||
|
||
void fd_event_handler(uint32_t event, void *event_data,
|
||
uint32_t event_data_len, void *priv)
|
||
{
|
||
if (event & FD_CB_EVENT_ENGINE_RLT) {
|
||
// 人脸识别结果
|
||
acomp_fd_result_info_t *info = (acomp_fd_result_info_t *)event_data;
|
||
|
||
if (info->results_cnt > 0) {
|
||
uint32_t max_idx = info->max_area_results_index;
|
||
acomp_fd_result_t *result = &info->results[max_idx];
|
||
|
||
printf("Face detected: [%d,%d,%d,%d], score: %.2f\n",
|
||
result->face_rect.x, result->face_rect.y,
|
||
result->face_rect.w, result->face_rect.h,
|
||
result->face_score);
|
||
|
||
printf("Head pose: yaw=%.1f, pitch=%.1f, roll=%.1f\n",
|
||
result->pose.yaw, result->pose.pitch, result->pose.roll);
|
||
|
||
printf("Live detect: status=%d, score=%.2f\n",
|
||
result->live_result.status,
|
||
result->live_result.scores[1]);
|
||
} else {
|
||
printf("No face detected\n");
|
||
}
|
||
} else if (event & FD_CB_EVENT_ENGINE_WR_ERR) {
|
||
// 写入错误
|
||
printf("FD write error\n");
|
||
}
|
||
}
|
||
|
||
// 注册回调
|
||
int ret = acomp_fd_add_callback(
|
||
FD_CB_EVENT_ENGINE_RLT | FD_CB_EVENT_ENGINE_WR_ERR,
|
||
fd_event_handler,
|
||
NULL
|
||
);
|
||
|
||
4. 启动人脸识别服务
|
||
~~~~~~~~~~~~~~~~~~~
|
||
|
||
完整的启动流程:
|
||
|
||
.. code-block:: c
|
||
|
||
#include "fd/acomp_fd.h"
|
||
|
||
void start_fd_service(void)
|
||
{
|
||
int ret;
|
||
|
||
// 1. 就绪组件(分配资源)
|
||
ret = acomp_fd_prepare();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("FD prepare failed: %d\n", ret);
|
||
return;
|
||
}
|
||
|
||
// 2. 启动人脸识别
|
||
ret = acomp_fd_start();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("FD start failed: %d\n", ret);
|
||
return;
|
||
}
|
||
|
||
printf("FD service started\n");
|
||
}
|
||
|
||
void stop_fd_service(void)
|
||
{
|
||
int ret;
|
||
|
||
// 1. 停止人脸识别
|
||
ret = acomp_fd_stop();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("FD stop failed: %d\n", ret);
|
||
return;
|
||
}
|
||
|
||
// 2. 清理资源
|
||
ret = acomp_fd_cleanup();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("FD cleanup failed: %d\n", ret);
|
||
return;
|
||
}
|
||
|
||
printf("FD service stopped\n");
|
||
}
|
||
|
||
5. 配置活体检测参数
|
||
~~~~~~~~~~~~~~~~~~~
|
||
|
||
设置活体检测模式和阈值:
|
||
|
||
.. code-block:: c
|
||
|
||
#include "fd/acomp_fd.h"
|
||
|
||
void configure_live_detect(void)
|
||
{
|
||
// 配置活体检测
|
||
acomp_fd_live_detect_mode_t mode = {
|
||
.enable = true, // 启用活体检测
|
||
.score_threshold = {
|
||
0.51, // 假人阈值(未使用)
|
||
0.1, // 真人阈值(活体得分 >= 0.1 才进行特征提取)
|
||
},
|
||
};
|
||
|
||
int ret = acomp_fd_live_detect_mode_set(&mode);
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("Set live detect mode failed: %d\n", ret);
|
||
}
|
||
}
|
||
|
||
6. 创建图像输入流并发送图像数据
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
使能 M2R (Master to Remote) 流通道,用于将图像数据发送给 AP 核:
|
||
|
||
.. code-block:: c
|
||
|
||
#include "fd/acomp_fd.h"
|
||
|
||
#define TX_STREAM_CH_INDEX 0
|
||
#define TX_STREAM_CH_NAME "stream.fd_image"
|
||
|
||
void setup_tx_stream(void)
|
||
{
|
||
// 1. 创建 M2R 流通道描述符
|
||
acomp_stream_chn_create_desc_t desc = {
|
||
.cname = TX_STREAM_CH_NAME,
|
||
.direction = ACOMP_STREAM_DIRECTION_M2R, // Master to Remote
|
||
.index = TX_STREAM_CH_INDEX,
|
||
.buffer_size = 320 * 240 * 2 + sizeof(acomp_fd_input_frame_t),
|
||
.num_descs = 4, // 缓冲区描述符数量
|
||
.kick_policy = 1, // 自动触发
|
||
};
|
||
|
||
// 2. 使能流通道
|
||
int ret = acomp_fd_stream_ch_enable(TX_STREAM_CH_INDEX, &desc);
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("Failed to enable tx stream: %d\n", ret);
|
||
}
|
||
}
|
||
|
||
void send_image_to_fd(uint8_t *image_data, int width, int height,
|
||
acomp_fd_pixel_format format)
|
||
{
|
||
uint8_t *buffer;
|
||
uint32_t buf_size;
|
||
uint16_t desc_idx;
|
||
|
||
// 1. 分配发送缓冲区
|
||
buffer = acomp_fd_stream_tx_buffer_alloc(TX_STREAM_CH_INDEX,
|
||
&buf_size, &desc_idx);
|
||
if (buffer && buf_size > 0) {
|
||
// 2. 填充图像帧数据
|
||
acomp_fd_input_frame_t *frame = (acomp_fd_input_frame_t *)buffer;
|
||
frame->format = format;
|
||
frame->index = 0;
|
||
frame->width = width;
|
||
frame->height = height;
|
||
frame->length = width * height * 2; // YUYV422
|
||
memcpy(frame->data, image_data, frame->length);
|
||
|
||
// 3. 提交缓冲区发送
|
||
acomp_fd_stream_tx_buffer_submit(TX_STREAM_CH_INDEX,
|
||
buffer, buf_size, desc_idx);
|
||
}
|
||
}
|
||
|
||
7. 人脸特征管理
|
||
~~~~~~~~~~~~~~~
|
||
|
||
导入人脸特征用于识别:
|
||
|
||
.. code-block:: c
|
||
|
||
#include "fd/acomp_fd.h"
|
||
|
||
void load_face_features(void)
|
||
{
|
||
// 准备人脸特征数据(特征可从人脸识别组件识别结果或文件或数据库读取)
|
||
acomp_fd_feature_result_t features[3]; // 最多10个
|
||
|
||
// 假设已经从某处获取了特征数据(特征可从人脸识别组件识别结果或文件或数据库读取)
|
||
// load_features_from_storage(features, 3);
|
||
|
||
// 导入特征到人脸识别组件
|
||
int ret = acomp_fd_features_load(features, 3);
|
||
if (ret != ACOMP_ERR_OK) {
|
||
printf("Load features failed: %d\n", ret);
|
||
} else {
|
||
printf("Loaded 3 face features\n");
|
||
}
|
||
}
|
||
|
||
API 参考
|
||
--------
|
||
|
||
生命周期管理
|
||
~~~~~~~~~~~~
|
||
|
||
acomp_fd_init
|
||
^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_init(void);
|
||
|
||
**功能**:初始化人脸识别组件
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_NO_MEM``:内存不足
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
- ``ACOMP_ERR_NOT_FOUND``:设备未找到
|
||
|
||
acomp_fd_prepare
|
||
^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_prepare(void);
|
||
|
||
**功能**:就绪人脸识别组件,初始化内存块及算法资源
|
||
|
||
**说明**:在调用 ``acomp_fd_start()`` 之前必须调用此函数
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_NO_MEM``:内存不足
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
acomp_fd_cleanup
|
||
^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_cleanup(void);
|
||
|
||
**功能**:复位人脸识别组件,释放内存块及算法资源
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
acomp_fd_start
|
||
^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_start(void);
|
||
|
||
**功能**:启动人脸识别组件,开始处理图像流
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_NO_MEM``:内存不足
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
acomp_fd_stop
|
||
^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_stop(void);
|
||
|
||
**功能**:停止人脸识别组件,停止处理图像流
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
参数配置
|
||
~~~~~~~~
|
||
|
||
acomp_fd_params_set
|
||
^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_params_set(const acomp_fd_param_t *params, uint32_t params_cnt);
|
||
|
||
**功能**:设置组件参数
|
||
|
||
**参数**:
|
||
|
||
- ``params``:参数数组指针
|
||
- ``params_cnt``:参数个数
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
acomp_fd_live_detect_mode_set
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_live_detect_mode_set(const acomp_fd_live_detect_mode_t *mode);
|
||
|
||
**功能**:设置活体检测模式
|
||
|
||
**参数**:
|
||
|
||
- ``mode``:活体检测配置
|
||
|
||
- ``enable``:是否启用活体检测
|
||
- ``score_threshold[1]``:真人得分阈值(活体得分 >= 此值才进行特征提取)
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
acomp_fd_align_threshold_set
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_align_threshold_set(const acomp_fd_head_pose_t *threshold);
|
||
|
||
**功能**:设置人脸对齐的头部姿态阈值
|
||
|
||
**说明**:如果头部姿态角度超过阈值,将不进行活体检测和特征提取
|
||
|
||
**参数**:
|
||
|
||
- ``threshold``:头部姿态阈值
|
||
|
||
- ``yaw``:偏航角阈值
|
||
- ``pitch``:俯仰角阈值
|
||
- ``roll``:翻滚角阈值
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
acomp_fd_features_load
|
||
^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_features_load(const acomp_fd_feature_result_t *features, uint32_t count);
|
||
|
||
**功能**:从外部导入人脸特征到注册库
|
||
|
||
**参数**:
|
||
|
||
- ``features``:人脸特征数组指针
|
||
- ``count``:特征个数(最多10个)
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_NO_MEM``:内存不足
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
事件回调
|
||
~~~~~~~~
|
||
|
||
acomp_fd_add_callback
|
||
^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_add_callback(uint32_t events, fd_event_cb_t cb, void *priv);
|
||
|
||
**功能**:添加事件回调函数
|
||
|
||
**参数**:
|
||
|
||
- ``events``:事件位掩码,可同时注册多个事件
|
||
|
||
- ``FD_CB_EVENT_ENGINE_RLT``:人脸识别结果返回
|
||
- ``FD_CB_EVENT_ENGINE_WR_ERR``:算法引擎写入错误
|
||
|
||
- ``cb``:回调函数指针
|
||
- ``priv``:回调函数的私有数据指针
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_NO_MEM``:内存不足
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
|
||
acomp_fd_remove_callback
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_remove_callback(fd_event_cb_t cb);
|
||
|
||
**功能**:移除回调函数
|
||
|
||
**参数**:
|
||
|
||
- ``cb``:待移除的回调函数
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
- ``ACOMP_ERR_NOT_SUPPORTED``:不支持的操作
|
||
|
||
图像流管理
|
||
~~~~~~~~~~
|
||
|
||
acomp_fd_stream_ch_enable
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_stream_ch_enable(int chn, acomp_stream_chn_create_desc_t *desc);
|
||
|
||
**功能**:使能图像流通道
|
||
|
||
**参数**:
|
||
|
||
- ``chn``:通道索引
|
||
- ``desc``:通道描述符指针
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
- ``ACOMP_ERR_CREATE_STREAM_FAILED``:创建流失败
|
||
|
||
acomp_fd_stream_ch_disable
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_stream_ch_disable(int chn);
|
||
|
||
**功能**:禁用图像流通道
|
||
|
||
**参数**:
|
||
|
||
- ``chn``:通道索引
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
|
||
acomp_fd_stream_tx_buffer_alloc
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
void* acomp_fd_stream_tx_buffer_alloc(int chn, uint32_t* len, uint16_t* desc_idx);
|
||
|
||
**功能**:分配 TX 流缓冲区用于向 AP 核发送图像数据
|
||
|
||
**参数**:
|
||
|
||
- ``chn``:通道索引
|
||
- ``len``:可用缓冲区长度指针(输出)
|
||
- ``desc_idx``:描述符索引指针(输出)
|
||
|
||
**返回值**:缓冲区指针,失败返回 NULL
|
||
|
||
acomp_fd_stream_tx_buffer_submit
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
.. code-block:: c
|
||
|
||
int acomp_fd_stream_tx_buffer_submit(int chn, void* buffer,
|
||
uint32_t len, uint16_t desc_idx);
|
||
|
||
**功能**:提交 TX 流缓冲区发送图像数据到 AP 核
|
||
|
||
**参数**:
|
||
|
||
- ``chn``:通道索引
|
||
- ``buffer``:缓冲区指针
|
||
- ``len``:数据长度
|
||
- ``desc_idx``:描述符索引
|
||
|
||
**返回值**:
|
||
|
||
- ``ACOMP_ERR_OK``:成功
|
||
- ``ACOMP_ERR_INVALID_STATE``:无效状态
|
||
- ``ACOMP_ERR_INVALID_ARG``:参数错误
|
||
|
||
使用示例
|
||
--------
|
||
|
||
完整示例
|
||
~~~~~~~~
|
||
|
||
.. code-block:: c
|
||
|
||
#include "acomp.h"
|
||
#include "fd/acomp_fd.h"
|
||
#include "lisa_log.h"
|
||
|
||
#define TAG "fd_demo"
|
||
|
||
// 事件回调函数
|
||
void fd_event_handler(uint32_t event, void *event_data,
|
||
uint32_t event_data_len, void *priv)
|
||
{
|
||
if (event & FD_CB_EVENT_ENGINE_RLT) {
|
||
acomp_fd_result_info_t *info = (acomp_fd_result_info_t *)event_data;
|
||
|
||
LISA_LOGI(TAG, "FD result: count=%d", info->results_cnt);
|
||
|
||
if (info->results_cnt > 0) {
|
||
uint32_t idx = info->max_area_results_index;
|
||
acomp_fd_result_t *result = &info->results[idx];
|
||
|
||
LISA_LOGI(TAG, "Face rect: [%d,%d,%d,%d], score: %.2f",
|
||
result->face_rect.x, result->face_rect.y,
|
||
result->face_rect.w, result->face_rect.h,
|
||
result->face_score);
|
||
|
||
LISA_LOGI(TAG, "Head pose: yaw=%.1f, pitch=%.1f, roll=%.1f",
|
||
result->pose.yaw, result->pose.pitch, result->pose.roll);
|
||
|
||
LISA_LOGI(TAG, "Live: status=%d, score=%.2f",
|
||
result->live_result.status,
|
||
result->live_result.scores[1]);
|
||
|
||
if (result->compare_cnt > 0) {
|
||
LISA_LOGI(TAG, "Compare scores: [%.2f, %.2f]",
|
||
result->compare_scores[0],
|
||
result->compare_scores[1]);
|
||
}
|
||
}
|
||
} else if (event & FD_CB_EVENT_ENGINE_WR_ERR) {
|
||
LISA_LOGE(TAG, "FD write error");
|
||
}
|
||
}
|
||
|
||
void fd_demo(void)
|
||
{
|
||
int ret;
|
||
|
||
// 1. 初始化 ACOMP 框架
|
||
acomp_init();
|
||
|
||
// 2. 初始化人脸识别组件
|
||
ret = acomp_fd_init();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
LISA_LOGE(TAG, "FD init failed: %d", ret);
|
||
return;
|
||
}
|
||
|
||
// 3. 注册事件回调
|
||
ret = acomp_fd_add_callback(
|
||
FD_CB_EVENT_ENGINE_RLT | FD_CB_EVENT_ENGINE_WR_ERR,
|
||
fd_event_handler,
|
||
NULL
|
||
);
|
||
if (ret != ACOMP_ERR_OK) {
|
||
LISA_LOGE(TAG, "Add callback failed: %d", ret);
|
||
return;
|
||
}
|
||
|
||
// 4. 就绪组件
|
||
ret = acomp_fd_prepare();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
LISA_LOGE(TAG, "FD prepare failed: %d", ret);
|
||
return;
|
||
}
|
||
LISA_LOGI(TAG, "FD prepared");
|
||
|
||
// 5. 启动人脸识别
|
||
ret = acomp_fd_start();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
LISA_LOGE(TAG, "FD start failed: %d", ret);
|
||
return;
|
||
}
|
||
LISA_LOGI(TAG, "FD started");
|
||
|
||
// 6. 配置活体检测
|
||
acomp_fd_live_detect_mode_t mode = {
|
||
.enable = true,
|
||
.score_threshold = {0.51, 0.1},
|
||
};
|
||
acomp_fd_live_detect_mode_set(&mode);
|
||
|
||
// 7. 创建图像输入流
|
||
acomp_stream_chn_create_desc_t desc = {
|
||
.cname = "stream.fd_image",
|
||
.direction = ACOMP_STREAM_DIRECTION_M2R,
|
||
.index = 0,
|
||
.buffer_size = 320 * 240 * 2 + sizeof(acomp_fd_input_frame_t),
|
||
.num_descs = 4,
|
||
.kick_policy = 1,
|
||
};
|
||
acomp_fd_stream_ch_enable(0, &desc);
|
||
|
||
// 8. 发送图像数据(示例)
|
||
// send_image_to_fd(...);
|
||
|
||
// 9. 运行一段时间
|
||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||
|
||
// 10. 停止人脸识别
|
||
ret = acomp_fd_stop();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
LISA_LOGE(TAG, "FD stop failed: %d", ret);
|
||
}
|
||
LISA_LOGI(TAG, "FD stopped");
|
||
|
||
// 11. 清理资源
|
||
ret = acomp_fd_cleanup();
|
||
if (ret != ACOMP_ERR_OK) {
|
||
LISA_LOGE(TAG, "FD cleanup failed: %d", ret);
|
||
}
|
||
LISA_LOGI(TAG, "FD cleaned up");
|
||
}
|
||
|
||
图像流处理示例
|
||
~~~~~~~~~~~~~~
|
||
|
||
.. code-block:: c
|
||
|
||
#include "fd/acomp_fd.h"
|
||
|
||
void image_stream_tx_example(uint8_t *image_data, int width, int height)
|
||
{
|
||
int chn = 0;
|
||
uint32_t len;
|
||
uint16_t desc_idx;
|
||
void *buffer;
|
||
|
||
// 分配发送缓冲区
|
||
buffer = acomp_fd_stream_tx_buffer_alloc(chn, &len, &desc_idx);
|
||
if (buffer) {
|
||
// 填充图像帧数据
|
||
acomp_fd_input_frame_t *frame = (acomp_fd_input_frame_t *)buffer;
|
||
frame->format = PIX_FMT_YUV422_YUYV_PACKED;
|
||
frame->index = 0;
|
||
frame->width = width;
|
||
frame->height = height;
|
||
frame->length = width * height * 2;
|
||
memcpy(frame->data, image_data, frame->length);
|
||
|
||
// 提交发送
|
||
acomp_fd_stream_tx_buffer_submit(chn, buffer, len, desc_idx);
|
||
}
|
||
}
|
||
|
||
注意事项
|
||
--------
|
||
|
||
1. **初始化顺序**:必须先调用 ``acomp_init()`` 初始化 ACOMP 框架,再调用 ``acomp_fd_init()``
|
||
2. **生命周期管理**:启动前必须调用 ``acomp_fd_prepare()``,停止后应调用 ``acomp_fd_cleanup()`` 释放资源
|
||
3. **状态检查**:所有 API 都会进行状态检查,确保在正确的状态下调用相应的函数
|
||
4. **事件回调**:回调函数在组件内部线程中执行,应避免长时间阻塞操作
|
||
5. **内存管理**:组件使用动态内存分配,确保系统有足够的堆内存
|
||
6. **资源配置**:确保配置的模型地址和长度与实际烧录的模型匹配
|
||
7. **图像格式**:支持 YUYV422、RGB565、BGR888 等格式,推荐使用 YUYV422或RGB565 以节省内存
|
||
8. **活体检测阈值**:根据实际应用场景调整活体检测阈值,平衡误识率和拒识率
|
||
9. **特征管理**:最多支持 10 个注册人脸特征,每个特征为 384 维浮点数
|
||
10. **跨核通信**:图像流基于 IPC 机制,注意跨核数据传输的延迟和同步问题
|
||
11. **双核协作**:本组件运行在 CP 核,需要 AP 核提供算法支持,确保 AP 核固件正确烧录
|
||
|
||
常见问题
|
||
--------
|
||
|
||
**Q: 人脸识别组件初始化失败怎么办?**
|
||
|
||
A: 检查以下几点:
|
||
|
||
- 确保 ACOMP 框架已正确初始化
|
||
- 检查系统是否有足够的堆内存
|
||
- 确认 AP 核固件和算法模型已正确烧录到 Flash
|
||
|
||
**Q: 为什么没有检测到人脸?**
|
||
|
||
A: 可能的原因:
|
||
|
||
- 图像质量不佳(光线不足、模糊等)
|
||
- 人脸角度过大或遮挡严重
|
||
- 图像格式或尺寸不正确
|
||
- 检查回调函数是否正确注册
|
||
|
||
**Q: 活体检测总是失败怎么办?**
|
||
|
||
A: 建议:
|
||
|
||
- 调整活体检测阈值 ``score_threshold[1]`` (降低阈值更容易通过)
|
||
- 确保图像质量良好,光线充足
|
||
- 检查人脸是否正对摄像头,角度不要过大
|
||
|
||
**Q: 特征比对得分很低怎么办?**
|
||
|
||
A: 建议:
|
||
|
||
- 确保注册和识别时的图像质量一致
|
||
- 检查人脸角度和光线条件
|
||
- 特征比对阈值通常设置为 0.7-0.9,根据实际情况调整
|
||
|
||
**Q: 如何提高识别准确率?**
|
||
|
||
A: 建议:
|
||
|
||
- 使用高质量的图像输入(清晰、光线充足)
|
||
- 确保人脸正对摄像头,角度不要过大
|
||
- 注册多个角度的人脸特征
|
||
- 调整活体检测和特征比对阈值
|