人脸识别演示
源码位置: demos/face_detect 查看源码
功能说明
本演示是一个完整的人脸识别应用,集成了摄像头图像采集、人脸检测、活体检测、特征提取、人脸识别和可视化显示等功能。用户可通过按键来体验人脸注册和人脸识别的功能。
系统架构
┌─────────────┐
│ 摄像头模块 │ GC0328 采集图像 (320x240)
└─────────────┘
│
├──────────────────────────────────┐
│ │
│ (实时图像) │ (部分图像)
▼ ▼
┌─────────────┐ ┌────────────────────────┐
│ 显示模块 │ │ 人脸识别算法模块 (AP) │
│ (ST7789 LCD) │◄────────────────│ 检测/对齐/活体/特征/对比 │
└─────────────┘ (人脸结果) └────────────────────────┘
▲ ▲
│ │
│ │ (控制命令)
│ (显示控制) │
│ │
┌─────────────┐ │
│ 按键模块 │───────────────────────────┘
│ (ADC 检测) │ K1:人脸注册
└─────────────┘
主要功能
1. 实时图像采集
GC0328 摄像头通过 DVP 接口连续采集 320x240 分辨率图像
支持输出 YUYV422彩色模式、YUYV422灰度模式(其中Cb=0, Cr=0)、RGB565模式,最大支持640*480分辨率
输出的每帧图片实时发给显示屏显示,同时部分图片也通过 IPC 自动发送到 AP 核进行算法处理
2. 人脸识别算法
人脸识别算法在 AP 核上运行,对每帧图像执行完整的人脸识别流程:
人脸检测:检测图像中的人脸位置和大小,输出人脸矩形框坐标和置信度得分
人脸对齐:定位 68 个人脸关键点(眼睛、鼻子、嘴巴、轮廓等),计算头部姿态角(yaw/pitch/roll)
活体检测:判断人脸是否为真人,输出活体检测结果(0、1)和得分,防止照片、视频攻击
特征提取:提取 384 维人脸特征向量,用于唯一标识一个人脸
特征比对:将提取的特征与已注册人脸进行相似度比对,输出比对得分( 阈值由用户决定,超过阈值则认为是同一人)
目前暂时支持注册最多 10 个人脸特征到内存库,可配置活体检测阈值以适应不同应用场景。
3. 交互式操作
K1 键:抓取当前检测到的人脸特征(需先检测到人脸),如果符合条件(比如活体检测通过、头部姿势正常),就把它存储下来,并且加载到算法对比库中。如果不满足条件,需要用户重新按K1键抓取
4. 可视化显示
LCD 显示字符来提示用户怎么操作
LCD 实时显示摄像头采集的画面
LCD 实时显示人脸检测算法的处理结果,包括检测到的人脸个数、人脸框、活体状态,活体得分等信息;
如果已注册有人脸,LCD也会显示检测到人脸的比对得分,超过对比阈值则人脸框显示为绿色(并且显示人脸ID),否则显示为红色
LCD 显示K1按键的人脸注册个数
硬件连接
开发板: ARCS-EVB开发板
摄像头: GC0328 摄像头模块,通过 DVP 接口连接
显示屏: ST7789 LCD 显示屏,通过 SPI 接口连接
按键: 通过 ADC 引脚检测,支持 2 个按键(目前仅K1按键可用)
K1: 注册人脸特征
K2: 人脸识别(与注册人脸比对)(需要CONFIG_ONLY_FACE_REGISTER=n才能生效)
调试串口:
CP 核 UART0 (PA3),波特率 921600
AP 核 UART1 (PA21),波特率 921600
使用说明
上电后系统自动初始化,LCD 显示摄像头实时画面
检测到人脸时,屏幕显示绿色矩形框
K1 键: 注册当前人脸特征(最多 10 个)
K2 键: 触发人脸识别,显示比对得分
K3 键: 切换摄像头彩色/灰度模式
编译运行
./build.sh -C -DBOARD=arcs_evb
烧录固件
1. 烧录 AP 核固件(Boot Core)
cskburn -s /dev/ttyACM0 -b 3000000 -C arcs 0x00 ./res/ap.bin
2. 烧录算法资源到 Flash
# 人脸检测模型
cskburn -s /dev/ttyACM0 -b 3000000 -C arcs 0x100000 ./res/algo/face_detect_thinker.bin
# 人脸对齐模型
cskburn -s /dev/ttyACM0 -b 3000000 -C arcs 0x170000 ./res/algo/face_align_thinker.bin
# 活体检测模型
cskburn -s /dev/ttyACM0 -b 3000000 -C arcs 0x300000 ./res/algo/face_nir_thinker_lineart_split.bin
# 人脸特征提取模型
cskburn -s /dev/ttyACM0 -b 3000000 -C arcs 0x410000 ./res/algo/face_verify_thinker.bin
3. 烧录 CP 核固件
cskburn -s /dev/ttyACM0 -b 3000000 -C arcs 0x800000 ./build/arcs.bin
预期输出
CP 核串口输出:
********Arcs SDK 0.1.1 @ v0.0.1-860-gd85bab268324********
Running on hart-id: 1
I/lisa_adc_arcs [00:00:00.035 1 none] ADC0 initialized successfully
I/lisa_i2c_arcs [00:00:00.037 1 none] I2C0 initialized successfully
I/lisa_pwm_arcs [00:00:00.037 1 none] PWM0 initialized successfully (max_channels=8)
I/lisa_touch_cst328 [00:00:00.039 1 none] CST328 touch device initialized successfully
I/lisa_dvp [00:00:00.040 1 none] DVP driver initialized
CP=======! Hard ID: 1
I/main [00:00:00.042 1 main] ic_message_init done!
I/acomp_ipc [00:00:02.044 1 rpc_client] [0]acomp remote dev index 1 name acomp.fd
I/acomp_fd [00:00:02.045 1 main] acomp fd init enter
I/acomp_fd [00:00:02.046 1 main] acomp fd dev index 1,name:acomp.fd
I/acomp_fd [00:00:02.047 1 main] acomp fd dev index 1,name:acomp.fd
I/acomp_fd [00:00:02.049 1 main] acomp fd init exit
I/acomp_fd [00:00:02.050 1 main] acomp fd prepare enter
I/acomp_fd [00:00:02.051 1 main] acomp fd prepare:0x2895ea60, size:128
I/acomp_fd [00:00:02.053 1 main] acomp fd prepare exit
I/acomp_fd [00:00:02.054 1 main] acomp fd start enter
I/acomp_fd [00:00:02.254 1 main] acomp fd start exit
I/acomp_fd [00:00:02.255 1 main] acomp fd add callback enter
I/acomp_fd [00:00:02.256 1 main] acomp fd add callback exit
I/acomp_fd [00:00:02.257 1 main] acomp_fd_live_detect_mode_set enter
I/acomp_fd [00:00:02.259 1 main] acomp_fd_live_detect_mode_set exit
INF:[acomp_stream_channel_create]Acomp stream channel 0x289fcbb4,0x2001b450,'stream.fd_image' created successfully ,vring phy addr=0x28966aa0, num_descs=4, buffer_size=153632, direction=M2R, role=Master
I/acomp_fd [00:00:02.272 1 main] acomp_fd_stream_ch_enable chn(stream.fd_image) index(0),desc(0x2892e280)
I/lvgl_heap [00:00:02.274 1 main] LVGL heap initialized: 1048576 bytes at 0x0x28825800
spi_set_bus_speed: sclk_div = 0 (sclk: 50000000), cs2sclk = 1
I/panel.st7789p3 [00:00:02.536 1 main] ST7789P3 initialized
I/lisa_i2c_arcs [00:00:02.540 1 main] I2C configured: speed=100000 Hz, mode=master
I/lisa_touch_cst328 [00:00:02.541 1 main] I2C auto-configured (speed: 100000 Hz)
I/lisa_touch_cst328 [00:00:02.762 1 main] CST328 hardware reset completed
I/lisa_touch_cst328 [00:00:02.763 1 main] CST328 interrupt pin configured
I/lisa_touch_cst328 [00:00:02.764 1 main] CST328 touch bus attached successfully
I/lisa_touch_cst328 [00:00:02.765 1 main] CST328 read task created with priority 2
I/lisa_touch_cst328 [00:00:02.766 1 main] CST328 interrupt mode enabled
I/lisa_touch_cst328 [00:00:02.767 1 main] CST328 touch device enabled
I/lvgl8_demo_widgets [00:00:02.774 1 task_ui] LVGL screen loaded and started
I/sample [00:00:02.788 1 main] === LISA ADC read example ===
I/sample [00:00:02.789 1 main] adc0 device ready
I/lisa_adc_arcs [00:00:02.790 1 main] Channel 4 configured: ref=1, 10-bit, vref_sel=0, vin_buf=1
I/sample [00:00:02.791 1 main] Channel 4 configured: 3.6V reference, 10-bit resolution
I/btn [00:00:02.793 1 btn] lisa_btn_task enter
I/btn [00:00:02.794 1 main] lisa btn init done
I/video_camera [00:00:02.795 1 main] camera config: w:320, h:240, format:2
I/video_camera [00:00:02.796 1 main] camera device ready
I/video_camera [00:00:02.797 1 main] Setting up camera...
I/lisa_camera [00:00:02.799 1 main] PWDN pin initialized (pin=7)
I/lisa_camera [00:00:02.800 1 main] Enabling XCLK output: 8000000 Hz
I/lisa_i2c_arcs [00:00:02.802 1 main] I2C configured: speed=400000 Hz, mode=master
I/lisa_camera [00:00:02.805 1 main] Sensor detected: PID=0x009D, addr=0x21
I/lisa_camera [00:00:03.308 1 main] Detected sensor frame size: 640x480
I/lisa_camera [00:00:03.311 1 main] Detected sensor pixel format: 0
I/lisa_camera [00:00:03.312 1 main] Frame buffers initialized: count=4, size=614400
I/lisa_camera [00:00:03.313 1 main] Camera setup completed
I/video_camera [00:00:03.314 1 main] Camera capabilities: max_width=640, max_height=480, supported_formats=0x00000005
I/video_camera [00:00:03.316 1 main] crop:x:160, y:120, w:320, h:240
I/lisa_camera [00:00:03.325 1 main] Frame buffers re-initialized: count=4, size=153600
I/lisa_camera [00:00:03.390 1 main] Frame buffers re-initialized: count=4, size=153600
I/video_camera [00:00:03.471 1 main] camera_set_gray on success
I/lisa_dvp [00:00:03.473 1 main] DVP initialized successfully with GPDMA channel 2
I/lisa_dvp [00:00:03.474 1 main] DVP clockout enabled successfully, freq: 8000000 Hz
I/video_camera [00:00:03.476 1 camera_task] Capture task started
I/video_camera [00:00:03.477 1 main] Camera capture started with internal task
I/video_camera [00:00:03.479 1 main] Frame callback registered
I/lisa_dvp [00:00:03.480 1 main] DVP capture started
I/camera_bus_dvp [00:00:03.481 1 main] DVP Normal capture started
I/lisa_camera [00:00:03.482 1 main] Camera started
I/camera_bus_dvp [00:00:03.754 1 isr] dvp_event_callback: event:1
I/camera_bus_dvp [00:00:03.881 1 isr] dvp_event_callback: event:1
I/camera_bus_dvp [00:00:04.008 1 isr] dvp_event_callback: event:1
I/main [00:00:04.102 1 rpc_client] fd result:2732,
I/camera_bus_dvp [00:00:04.135 1 isr] dvp_event_callback: event:1
I/camera_bus_dvp [00:00:04.261 1 isr] dvp_event_callback: event:1
I/main [00:00:04.361 1 rpc_client] fd result:2732,
LCD 屏幕显示:
实时显示摄像头采集的画面
实时显示检测到的人脸的黄色方框
屏幕左上方会实时显示检测到的人脸个数、活体状态和活体得分
按下K1键时,如果检测到人脸符合注册条件,会注册人脸特征,并在屏幕左下角显示”Registered: “个数会增加
如果已注册有人脸,LCD也会显示检测到人脸的比对得分,超过对比阈值则人脸框显示为绿色(并且显示人脸ID),否则显示为红色
核心 API
API |
说明 |
|---|---|
|
初始化人脸识别组件 |
|
准备人脸识别算法资源 |
|
启动人脸识别算法 |
|
注册人脸识别结果回调函数 |
|
配置活体检测模式 |
|
使能图像输入数据流通道 |
|
分配发送缓冲区 |
|
提交图像数据到算法 |
|
导入人脸特征到注册库 |
关键代码
/* 1. 初始化 */
acomp_init();
acomp_fd_init();
acomp_fd_prepare();
acomp_fd_start();
acomp_fd_add_callback(FD_CB_EVENT_ENGINE_RLT, fd_event_handler, NULL);
/* 2. 配置活体检测 */
acomp_fd_live_detect_mode_t mode = {.enable = true, .score_threshold = {0.51, 0.1}};
acomp_fd_live_detect_mode_set(&mode);
/* 3. 摄像头回调 - 发送图像到算法 */
void video_camera_cb(uint8_t *data, uint32_t len) {
uint8_t *buffer = acomp_fd_stream_tx_buffer_alloc(0, &buf_size, &desc_idx);
acomp_fd_input_frame_t *frame = (acomp_fd_input_frame_t *)buffer;
frame->format = PIX_FMT_YUV422_YUYV_PACKED;
frame->width = 320; frame->height = 240; frame->length = len;
memcpy(frame->data, data, len);
acomp_fd_stream_tx_buffer_submit(0, buffer, buf_size, desc_idx);
}
/* 4. 结果回调 - 更新显示 */
void fd_event_handler(uint32_t event, void *event_data, uint32_t 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) {
screen_update_fd_info(info, image_data, width, height, len);
}
}
}
配置说明
算法资源地址配置
在 prj.conf 中配置算法模型在 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
摄像头配置
CONFIG_IMAGE_WIDTH=320
CONFIG_IMAGE_HEIGHT=240
CONFIG_IMAGE_FORMAT=2 # YUYV422
CONFIG_FACE_LIVE_DETECT_ENABLE=y # 启用活体检测
CONFIG_FACE_LIVE_DETECT_THRESHOLD=50 # 活体检测阈值
CONFIG_FACE_COMPARE_SCORE_THRESHOLD=90 # 人脸比对得分阈值
CONFIG_ONLY_FACE_REGISTER=y # 只注册人脸,后续自动进行人脸识别(不需要用K2按键触发)
PSRAM 堆大小配置
CONFIG_PSRAM_HEAP_SIZE=0x680000
注意事项
算法资源烧录: 必须先烧录 AP 核固件和 4 个算法模型资源到 Flash,否则人脸识别算法无法正常运行
内存配置: 人脸识别算法需要较大的 PSRAM 空间,建议配置
CONFIG_PSRAM_HEAP_SIZE不小于 0x680000摄像头连接: 确保 GC0328 摄像头正确连接到 DVP 接口,否则无法采集图像
显示屏连接: 确保 ST7789 LCD 正确连接到 SPI 接口,否则无法显示画面
活体检测阈值: 活体得分阈值需要根据实际应用场景调整,阈值越高误识率越低但拒识率越高
双核协作: 本示例运行在 CP 核 (HARTID=1),需要 AP 核 (HARTID=0) 提供算法支持
特征注册: 最多支持 10 个注册人脸,每个人脸特征为 384 维浮点数
回调函数: 人脸识别结果通过回调函数异步返回,不要在回调中执行耗时操作