首页
商城
  • English
  • 简体中文
首页
商城
  • English
  • 简体中文
  • 产品系列

    • FPGA+ARM

      • GM-3568JHF

        • 一、简介

          • GM-3568JHF 简介
        • 二、快速开始

          • 00 前言
          • 01 环境搭建
          • 02 编译说明
          • 03 烧录指南
          • 04 调试工具
          • 05 软件更新
          • 06 查看信息
          • 07 测试命令
          • 08 应用编译
          • 09 源码获取
        • 三、外设与接口

          • 01 USB
          • 02 显示与触摸
          • 03 以太网
          • 04 WIFI
          • 05 蓝牙
          • 06 TF-Card
          • 07 音频
          • 08 串口
          • 09 CAN
          • 10 RTC
        • 四、应用开发

          • 01 UART读写案例
          • 02 按键检测案例
          • 03 LED灯闪烁案例
          • 04 MIPI屏幕检测案例
          • 05 读取 USB 设备信息案例
          • 06 FAN 检测案例
          • 07 FPGA FSPI 通信案例
          • 08 FPGA DMA 读写案例
          • 09 GPS调试案例
          • 10 以太网测试案例
          • 11 RS485读写案例
          • 12 FPGA IIC 读写案例
          • 13 PN532 NFC读卡案例
          • 14 TF卡读写案例
        • 五、QT开发

          • 01 ARM64交叉编译器环境搭建
          • 02 QT 程序加入开机自启服务
        • 六、RKNN_NPU开发

          • 01 RK3568 NPU 概述
          • 02 开发环境搭建
          • 运行官方 YOLOv5 示例
        • 七、FPGA开发

          • ARM与FPGA通讯
          • FPGA开发手册
        • 八、其他

          • 01 根目录文件系统的修改
          • 02 系统自启服务
        • 九、资料下载

          • 资料下载
    • ShimetaPi

      • M4-R1

        • 一、简介

          • M4-R1简介
        • 二、快速上手

          • 01 OpenHarmony概述
          • 02 镜像烧录
          • 03 应用开发快速上手
          • 04 设备开发快速上手
        • 三、应用开发

          • 01 ArkUI

            • 1 ArkTS语言简介
            • 2 UI 组件-Row 容器介绍
            • 3 UI 组件-Column 容器介绍
            • 4 UI 组件-Text 组件
            • 5 UI 组件-Toggle 组件
            • 6 UI 组件-Slider 组件
            • 7 UI 组件-Animation 组件&Transition 组件
          • 02 资料获取

            • 1 OpenHarmony 官方资料
          • 03 开发须知

            • 1 Full-SDK替换教程
            • 2 引入和使用三方库
            • 3 HDC调试
            • 4 命令行恢复出厂模式
            • 5 升级App为system权限
          • 04 构建第一个应用

            • 1 构建第一个ArkTs应用-HelloWorld
          • 05 案例

            • 01 串口调试助手应用案例
            • 02 手写板应用案例
            • 03 数字时钟应用案例
            • 04 WIFI 信息获取应用案例
        • 四、设备开发

          • 1 Ubuntu环境开发

            • 01 环境搭建
            • 02 下载源码
            • 03 编译源码
          • 2 使用DevEco Device Tool 工具

            • 01 工具简介
            • 02 开发环境的搭建
            • 03 导入SDK
            • 04 HUAWEI DevEco Tool 功能介绍
        • 五、内核外设与接口

          • 01 指南
          • 02 设备树介绍
          • 03 NAPI 入门
          • 04 ArkTS入门
          • 05 NAPI开发实战演示
          • 06 GPIO介绍
          • 07 I2C通讯
          • 08 SPI通信
          • 09 PWM 控制
          • 10 串口通讯
          • 11 TF卡
          • 12 屏幕
          • 13 触摸
          • 14 Ethernet(以太网)
          • 15 M.2 硬盘
          • 16 音频
          • 17 WIFI & BT
          • 18 摄像头
        • 六、资料下载

          • 资料下载
      • M4-R2

        • 一、产品简介

          • M4-R2 产品简介
        • 二、快速上手

          • 快速上手
        • 三、Android 系统

          • 1 快速上手

            • Android系统烧录与启动
            • 开发环境搭建
            • ADB调试与日志分析
            • SDK下载与编译环境搭建
            • Android系统基础操作
          • 2 SDK 编译

            • Android_SDK编译
            • Android构建系统与增量编译
          • 3 系统开发

            • Android系统定制
          • 4 应用开发

            • Android应用开发入门
            • Android JNI开发
          • 5 驱动与 HAL

            • Android HAL开发
          • 6 AI 与 NPU

            • Android NPU使用指南
        • 四、硬件参考

          • 核心板参数
          • 底板接口定义
          • 40PIN引脚定义
          • 电源管理
        • 五、常见问题与故障排除

          • 系统启动问题
          • 外设驱动问题
          • 网络连接问题
          • 显示问题
          • 常见编译错误
        • 六、应用方案参考

          • 智能显示终端方案
          • 边缘AI计算方案
          • 工业控制方案
          • NVR安防监控方案
          • 智能家居网关方案
        • 七、资料下载

          • 资料下载
      • M5-R2A

        • 一、产品简介

          • M5-R2A 产品简介
        • 二、快速上手

          • 系统烧录指南
          • 开发环境搭建
          • 快速上手
          • SDK下载与编译环境搭建
        • 四、Debian/Ubuntu 系统

          • 1 快速上手

            • 系统启动与基础操作
            • 网络配置与SSH
            • 软件包管理与更新
            • Debian 与 Ubuntu 镜像差异
          • 2 系统开发

            • Linux SDK编译
            • 内核配置与裁剪
            • 设备树详解与实践
            • 根文件系统构建
          • 3 外设驱动开发

            • GPIO驱动与控制
            • I2C驱动开发
            • SPI驱动开发
            • UART串口驱动
            • PWM驱动
            • ADC驱动
            • CAN/CAN-FD驱动
            • USB主机与设备驱动
            • SDMMC/eMMC驱动
            • 以太网GMAC驱动
            • 音频驱动
            • 摄像头Camera驱动
            • 触摸屏驱动
            • 显示DRM驱动
            • HDMI显示驱动
            • PCIe驱动
            • WiFi/蓝牙驱动
            • 看门狗WDT驱动
            • 热敏传感器THERMAL驱动
          • 4 应用开发

            • C/C++应用开发入门
            • Python应用开发
            • Qt嵌入式开发实战
            • GStreamer多媒体开发
            • 网络编程与应用
            • 文件系统与存储
          • 5 AI 与 NPU

            • NPU架构与性能概览
            • RKNN Toolkit2安装与使用
            • 模型转换与量化
            • 分类模型部署(LeNet/ResNet)
            • 目标检测部署(YOLOv5/v7/v8)
            • 语义分割部署
            • 人脸检测与识别
            • OCR文字识别
            • NPU性能调优与调试
          • 6 多媒体

            • 显示框架
            • 摄像头应用
            • 视频编解码(MPP)
            • 音频开发与ALSA
            • RGA图像处理
          • 7 性能优化与调试

            • 系统启动时间优化
            • CPU/GPU/NPU调优
            • 内存与存储优化
            • 功耗分析与优化
            • 调试工具使用指南
          • 8 高级主题

            • 安全启动与加密
            • OTA远程升级
            • Docker容器部署
            • ROS/ROS2机器人开发
            • RTOS与Linux协同
        • 五、Android 系统

          • 1 快速上手

            • Android系统烧录与启动
            • Android系统基础操作
            • ADB调试与日志分析
          • 2 SDK 编译

            • Android SDK编译
            • Android构建系统与增量编译
          • 3 系统开发

            • Android系统定制
          • 4 应用开发

            • Android应用开发入门
            • Android JNI开发
          • 5 驱动与 HAL

            • Android HAL开发
          • 6 AI 与 NPU

            • Android NPU使用指南
        • 六、硬件参考

          • 核心板参数
          • 底板接口定义
          • 40PIN引脚定义
          • 电源管理
        • 七、资料下载

          • 资料下载
      • Pico-G1

        • 一、产品概述

          • 01 产品介绍
          • 02 SDK版本基本信息
        • 二、快速入门

          • 01 开发环境搭建
          • 02 镜像编译
          • 03 镜像烧录
          • 04 系统登录
          • 05 网络配置
          • 06 文件传输
          • 07 SDK目录结构
          • 08 部署第一个应用程序
          • 09 部署第一个驱动程序
          • 10 SD卡挂载
        • 三、外设与接口

          • 01 GPIO控制
          • 02 UART串口通信
          • 03 I2C 通信
          • 04 SPI 通信
        • 四、MPP媒体开发

          • 01 MPP媒体处理软件
          • 02 图像处理链路
          • 03 视频输入
          • 04 图像编码
        • 五、NPU与AI

          • 01 NPU驱动与运行库架构
          • 02 .xmm 模型加载
          • 03 SVP视频处理
          • 04 AI降噪 (AI_NR)
        • 六、应用程序示例

          • 01 加解密接口应用
          • 02 ADC 采集应用
          • 03 低功耗应用
          • 04 音频处理应用
          • 05 视频编码应用
          • 06 视频输入应用
          • 07 视频图形子系统应用
          • 08 区域叠加应用
          • 09 智能视频引擎应用
          • 10 UVC 网络摄像头应用
          • 11 综合快速演示应用
          • 12 FPN 校正应用
          • 13 区域运动检测应用
          • 14 MTCNN 人脸检测应用
        • 七、扩展板外设功能例程

          • 00 - Pico 扩展板外设功能例程总览
          • 01 - OLED 显示应用
          • 02 - TFT 显示应用
          • 03 - MPU6050 陀螺仪应用
          • 04 - ADC 采集应用
          • 05 - 无源蜂鸣器应用
          • 06 - MQ 气体传感器应用
          • 07 - GPS 定位应用
          • 08 - SHT20 温湿度应用
          • 09 - 超声波测距应用
          • 10 - SPO2 血氧传感器应用
          • 11 - 电机控制应用
          • 12 - 舵机控制应用
    • 开源鸿蒙

      • SC-3568HA

        • 一、简介

          • SC-3568HA简介
        • 二、快速上手

          • OpenHarmony概述
          • 镜像烧录
          • 开发环境准备
          • Hello World应用以及部署
        • 三、应用开发

          • ArkUI

            • 第一章 ArkTS语言简介
            • 第二章 UI组件介绍和实际应用(上)
            • 第三章 UI组件介绍和实际应用(中)
            • 第四章 UI组件介绍和实际应用(下)
          • 拓展

            • 第一章 入门指引
            • 第二章 三方库的引用和使用
            • 第三章 应用编译以及部署
            • 第四章 命令行恢复出厂设置
            • 第五章 系统调试--HDC调试
            • 第六章 APP 稳定性测试
            • 第七章 应用测试
        • 四、设备开发

          • 第一章 环境搭建
          • 第二章 下载源码
          • 第三章 编译源码
        • 五、内核的外设与接口

          • 树莓派接口
          • GPIO 接口
          • I2C 接口
          • SPI通信
          • PWM控制
          • 串口通讯
          • TF Card
          • 屏幕
          • 触摸
          • 音频
          • RTC
          • Ethernet
          • M.2
          • MINI-PCIE
          • Camera
          • WIFI&BT
          • 树莓派拓展板
        • 六、资料下载

          • 资料下载
      • M-K1HSE

        • 一、简介

          • M-K1HSE 简介
        • 二、快速开始

          • 开发环境搭建
          • 源码获取
          • 编译说明
          • 烧录指南
        • 三、应用开发

          • 00 应用开发环境搭建
          • 01 第一个应用-Hello World
        • 四、外设与接口

          • 01 Audio
          • 02 RS485
          • 03 Display
        • 五、系统定制开发

          • 系统移植
          • 系统定制
          • 驱动开发
          • 系统调试
          • OTA升级
        • 六、资料下载

          • 资料下载
    • HVS视觉融合相机

      • 快速开始

        • 01 SDK 介绍
        • 02 资料下载
        • 03 设备固件烧录
        • 04 第一个 C++ 程序
        • 05 第一个 Python 程序
        • 06 Python 数据分析
        • 07 MultiVision Studio
        • 08 版本介绍
      • 二次开发

        • 01 编程指引

          • 01 打开相机
          • 02 读取事件
          • 03 录制与回放
          • 04 事件处理
          • 05 显示与可视化
          • 06 调参
          • 07 采集 APS 图像
          • 08 帧率切换
          • 09 时间戳同步
        • 02 Toolkit SDK

          • 01 Hybrid Vision Toolkit
          • 02 快速上手
          • 03 C++ API
          • 04 Python API
        • 03 Algo SDK

          • 01 Hybrid Vision Algo
          • 02 Algo API
          • 03 Windows Algo SDK
        • 04 USB数据协议
        • 05 示例程序总览
        • 06 应用场景
      • 基础知识

        • 01 事件相机基础原理
        • 02 HVS 融合视觉
        • 03 事件可视化
        • 04 数据格式参考
        • 05 术语表
        • 06 偏置与调参
        • 07 视频教程
      • HVS 相机

        • 01 HVS 相机快速上手
        • 02 网络化能力

          • 01 HVS 相机系统架构
          • 2 EVS Network Server
          • 3 EVS Time Sync
          • 4 Web Window
        • 03 HVS 相机兼容性矩阵
        • 04 常见问题解决指南
        • 05 产品

          • CF-NRS1(灵光一号视觉融合相机)
      • HVS 模块

        • 01 MIPI 模块快速上手
        • 02 载板适配

          • RDK X5 载板适配
          • RDK S100 载板适配
          • 树莓派载板适配
          • shimetapi 板载板适配
        • 03 MIPI 模块兼容性矩阵
        • 04 产品

          • EVS_003 传感器模块
    • AI硬件

      • 1684XB-32T

        • 一、简介

          • AIBOX-1684XB-32简介
        • 二、快速上手

          • 初次使用
          • 网络配置
          • 磁盘使用
          • 内存分配
          • 风扇策略
          • 固件升级
          • 交叉编译
          • 模型量化
        • 三、应用开发

          • 开发简介

            • Sophgo SDK开发
            • SOPHON-DEMO简介
          • 大语言模型

            • 部署Llama3示例
            • Sophon LLM_api_server开发
            • 部署MiniCPM-V-2_6
            • Qwen-2-5-VL图片视频识别DEMO
            • Qwen3-chat-DEMO
            • Qwen3-Qwen Agent-MCP开发
            • Qwen3-langchain-AI Agent
          • 深度学习

            • ResNet(图像分类)
            • LPRNet(车牌识别)
            • SAM(通用图像分割基础模型)
            • YOLOv5(目标检测)
            • OpenPose(人体关键点检测)
            • PP-OCR(光学字符识别)
        • 四、资料下载

          • 资料下载
      • 1684X-416T

        • 简介

          • AIBOX-1684X-416简介
        • Demo简单操作指引

          • shimeta智慧监控demo的简单使用说明
      • RDK-X5

        • 简介

          • RDK-X5 硬件简介
        • 快速开始

          • RDK-X5 快速开始
        • 应用开发

          • AI在线模型开发

            • 实验01-接入火山引擎豆包 AI
            • 实验02-图片分析
            • 实验03-多模态视觉分析定位
            • 实验04-多模态图文比较分析
            • 实验05-多模态文档表格分析
            • 实验06-摄像头运用-AI视觉分析
          • 大语言模型

            • 实验01-语音识别
            • 实验02-语音对话
            • 实验03-多模态图片分析-语音对话
            • 实验04-多模态图片比较-语音对话
            • 实验05-多模态文档分析-语音对话
            • 实验06-多模态视觉运用-语音对话
          • ROS2基础开发

            • 实验01-搭建环境
            • 实验02-工作包的创建及编译
            • 实验03-运行 ROS2 话题通信节点
            • 实验04-ROS2 相机应用
          • 40pin-IO开发

            • 实验01-GPIO 输出(LED闪烁)
            • 实验02-GPIO 输入
            • 实验03-按键控制 LED
            • 实验04-PWM 输出
            • 实验05-串口输出
            • 实验06-IIC 实验
            • 实验07-SPI 实验
          • USB模块开发使用

            • 实验01-USB 语音模块使用
            • 实验02-声源定位模块使用
          • 机器视觉技术实战

            • 实验01-打开 USB 摄像头
            • 实验02-颜色识别检测
            • 实验03-手势识别体验
            • 实验04-YOLOv5物体检测
      • RDK-S100

        • 简介

          • RDK-S100 硬件简介
        • 快速开始

          • RDK-S100 硬件简介
        • 应用开发

          • AI在线模型开发

            • 实验01-接入火山引擎豆包 AI
            • 实验02-图片分析
            • 实验03-多模态视觉分析定位
            • 实验04-多模态图文比较分析
            • 实验05-多模态文档表格分析
            • 实验06-摄像头运用-AI视觉分析
          • 大语言模型

            • 实验01-语音识别
            • 实验02-语音对话
            • 实验03-多模态图片分析-语音对话
            • 实验04-多模态图片比较-语音对话
            • 实验05-多模态文档分析-语音对话
            • 实验06-多模态视觉运用-语音对话
          • ROS2基础开发

            • 实验01-搭建环境
            • 实验02-工作包的创建及编译
            • 实验03-运行 ROS2 话题通信节点
            • 实验04-ROS2 相机应用
          • 40pin-IO开发

            • 实验01-GPIO 输出(LED闪烁)
            • 实验02-GPIO 输入
            • 实验03-按键控制 LED
            • 实验04-PWM 输出
            • 实验05-串口输出
            • 实验06-IIC 实验
            • 实验07-SPI 实验
          • USB模块开发使用

            • 实验01-USB 语音模块使用
            • 实验02-声源定位模块使用
          • 机器视觉技术实战

            • 实验01-打开 USB 摄像头
            • 实验02-图像处理基础
            • 实验03-目标检测
            • 实验04-图像分割
      • AIBOX-M88(RK1828)

        • 一、简介

          • AIBOX-M88(RK1828) - 产品介绍
          • AIBOX-M88(RK1828) 硬件规格
          • AIBOX-M88(RK1828) 使用与安全
        • 二、快速开始

          • AIBOX-M88(RK1828) 镜像烧录
          • RK182X 硬件安装与验证
          • RK182X 开发环境快速搭建
          • RK182X SDK 总览
          • RK182X 环境搭建详解
          • RK182X 快速开始
          • 原厂 SDK 资料抽取记录
        • 三、开发指南

          • ClawChips 架构与原理
          • SKILL 使用手册
          • RK182X系列LLM推理(RK1828型号)
          • RK182X系列CNN推理(RK1828型号)
          • 模型转换
          • RK182X AI Agent 应用开发指南
          • RK182X 工业异常检测应用
        • 四、SDK 参考

          • RKNN3-SDK 概述

            • RKNN3 SDK 概述
          • RKNN3-Toolkit

            • RKNN3 Toolkit 安装与使用
          • RKLLM

            • RKLLM 设备端 LLM 推理
          • RK182X系列 NPU 概述与架构(RK1828型号)
          • RK182X INT8 量化推理部署
          • RK182X MPP 多媒体处理框架
          • MPP 详解

            • RK182X 视频解码
            • RK182X 视频编码
          • NPU 详解

            • RKNN 模型转换
            • RK182X NPU INT8 量化推理
            • RK182X 多模型并行推理
          • RGA 详解

            • RK182X RGA 2D 图形加速
          • VPU 详解

            • RK182X VPU 编解码
        • 五、硬件参考

          • RK182X系列 硬件架构概述(RK1828型号)
          • RK182X 引脚定义与复用配置
          • RK182X 引脚定义
          • RK182X 电源管理
          • RK182X 时钟与 PLL 配置
          • RK182X 时钟与频率配置
        • 六、实战教程

          • Hello World
          • Hello RK1828 - 第一个程序
          • RTSP 推流
          • RTSP 推流 + AI 分析
          • 视美泰AI龙虾一键部署
          • PaddleOCR-VL 文字识别
          • Qwen3-1.7B LLM 文本对话
          • AI 巡检多视角(Qwen3-VL 包装)
          • YOLOv5 目标检测
        • 七、资料下载

          • 资料下载
        • 八、常见问题

          • 常见问题
    • 核心板

      • C-3568BQ

        • 简介

          • C-3568BQ 简介
      • C-3588LQ

        • 简介

          • C-3588LQ 简介
      • GC-3568JBAF

        • 简介

          • GC-3568JBAF 简介
      • C-K1BA

        • 简介

          • C-K1BA 简介
    • 软件平台

      • ShiMetaPi Workbench

        • 一、产品简介

          • 产品概述
          • 核心架构
          • 功能入口
          • 支持的硬件
          • 版本说明
        • 二、快速入门

          • 安装与登录
          • 连接设备
          • 配置环境
          • 接入 AIHub
          • 首次调用模型
        • 三、用户指南

          • 工作区总览
          • 设备管理
          • 模型广场
          • 一键部署
          • 视觉 - SVP
          • 视觉 - 自定义模型
          • shimeta-py IDE
          • 终端
          • Agent 调试助手
          • 设置与资源
        • 四、常见问题

          • 安装与登录
          • 设备连接
          • 模型与部署
          • 视觉与运行时
          • 设置与其他
      • ShimetaPi软件源

        • 简介

          • ShimetaPi 软件源
        • Pico G1 (GK7206)

          • 快速开始

            • 安装与首次推理
            • shimeta_infer — 图片推理
            • shimeta_camera — 摄像头实时推理
            • SVP 场景检测
            • 文件传输与内置模型参考
            • 常见问题
          • HTTP API & Python SDK

            • HTTP API 参考
      • 模型微调训练平台

        • 一、平台介绍

          • 模型训练平台
        • 二、快速上手

          • 注册与登录
          • 创建第一个模型(30 分钟快速体验)
        • 三、训练指南

          • 数据准备与标注
          • 训练参数配置
          • 启动与监控训练
          • 模型评估与测试
        • 四、模型部署

          • 导出模型
          • 部署到边缘设备

人脸检测与识别

目标平台: RK3576 | NPU 算力: 6 TOPS | 文档版本: V1.0
适用板型: C-3576BQ 核心板 + M4-R2 底板
最后更新: 2026-10-23


1. 概述

1.1 功能简介

人脸检测与识别是智能安防、门禁考勤、身份核验等场景的核心 AI 能力。RK3576 搭载 6 TOPS 算力的三核 NPU,能够在单芯片上实现人脸检测、人脸特征提取、人脸比对和人脸活体检测的完整流程,满足多路并发的实时人脸识别需求。

本文档介绍如何在 RK3576 上部署人脸检测与识别系统,涵盖以下核心模块:

  • 人脸检测:基于 SCRFD 或 RetinaFace 模型,从图像中定位人脸区域
  • 人脸对齐:通过关键点检测实现人脸仿射变换,标准化人脸姿态
  • 人脸识别:基于 ArcFace 模型提取人脸特征向量,进行 1:N 比对搜索
  • 活体检测:基于 RGB/IR 双模态的活体判断,防止照片/视频攻击

核心特性:

特性说明
人脸检测模型SCRFD / RetinaFace-MobileNet
人脸识别模型ArcFace-MobileFaceNet / ArcFace-IResNet
活体检测RGB 单目 / RGB+IR 双目
NPU 加速三核 NPU 并行(NPU0+NPU1+NPU2)
特征维度128 / 256 / 512 维向量
人脸库规模支持万级人脸库 1:N 搜索
推理框架RKNN Toolkit2 + RKNNLite2

1.2 应用场景

场景说明核心模块
门禁考勤人脸刷卡、无感通行检测 + 识别
安防监控陌生人告警、重点人员布控检测 + 识别 + 人脸库搜索
智慧零售VIP 识别、会员服务检测 + 识别
考试/会议签到快速人脸签到、防代考检测 + 活体 + 识别
公共安全机场/车站身份核验检测 + 活体 + 识别
金融支付人脸支付身份验证检测 + 活体 + 识别

1.3 工作原理

人脸识别系统的工作流程分为检测、对齐、特征提取和比对四个阶段:

视频流输入
    |
    v
[人脸检测] ---- SCRFD/RetinaFace 模型 -----> 人脸边界框 + 关键点
    |
    v
[人脸对齐] ---- 仿射变换(5点/6点关键点)-----> 标准化人脸图像(112x112)
    |
    v
[特征提取] ---- ArcFace 模型 ----------------> 128/256/512 维特征向量
    |
    v
[比对/搜索] --- 余弦相似度 / L2 距离 --------> 身份匹配结果
    |
    v
[活体检测] --- RGB/IR 模态特征 -------------> 活体/攻击判断

各阶段说明:

阶段输入输出模型说明
人脸检测原始图像(640x640)人脸边界框列表SCRFD定位图像中所有人脸位置
人脸对齐原始图像 + 关键点112x112 标准化人脸仿射变换通过关键点做仿射变换,统一人脸姿态
特征提取112x112 人脸图像特征向量ArcFace提取具有区分度的人脸嵌入向量
活体检测RGB + IR 人脸图像活体得分LivenessNet判断是否为真实活体(防止照片/视频攻击)
特征比对待识别特征 + 人脸库身份 ID余弦相似度在人脸库中搜索最近邻匹配

多核 NPU 并行处理架构:

RK3576 的三个 NPU 核心可以分别承载不同的模型推理任务,实现人脸处理流水线的并行加速:

┌─────────────────────────────────────────────────┐
│                 RK3576 三核 NPU                   │
│                                                   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐       │
│  │  NPU0    │  │  NPU1    │  │  NPU2    │       │
│  │ 人脸检测  │  │ 特征提取  │  │ 活体检测  │       │
│  │ SCRFD    │  │ ArcFace  │  │ Liveness │       │
│  └──────────┘  └──────────┘  └──────────┘       │
│                                                   │
│  流水线: 检测 --> 对齐 --> 特征提取 --> 比对        │
│          |           |          |                  │
│          └─ NPU0     └─ NPU1   └─ NPU2           │
└─────────────────────────────────────────────────┘

2. 硬件准备

2.1 硬件清单

序号物料名称型号/规格数量用途
1核心板 + 底板C-3576BQ 核心板 + M4-R2 底板1主开发板,6 TOPS NPU
2USB 摄像头UVC 兼容(720p/1080p)1RGB 图像采集,人脸检测与识别
3IR 摄像头(可选)UVC 兼容红外摄像头1红外活体检测,需与 RGB 摄像头同步
4调试串口USB to TTL 3.3V 转换器1串口调试,波特率 1500000
5电源适配器5V/2A 电源(Type-C 或 6pin 供电)1主板供电(空载最小 1000mA)
6M.2 SSD(可选)M.2 NVMe 固态硬盘1人脸库数据大容量存储
7显示器 + HDMI 线支持 4K 的显示器1人脸识别结果可视化(可选)

2.2 硬件确认

接入调试串口后,启动开发板,通过串口终端确认硬件信息:

# 查看 SoC 型号
cat /proc/device-tree/compatible
# 预期输出包含 rk3576 关键字

# 查看 NPU 设备节点
cat /proc/device-tree/npu/compatible
# 预期输出: rockchip,rk3576-npu

# 查看内存信息
cat /proc/meminfo | grep MemTotal
# 建议 4GB 及以上内存用于人脸识别应用

# 查看 USB 摄像头设备
ls /dev/video*
# 预期输出: /dev/video0 /dev/video1 ...

# 确认摄像头工作正常
v4l2-ctl --list-devices

摄像头同步说明(RGB+IR 双目方案):

若使用 RGB+IR 双目活体检测方案,需确保两个摄像头能够同步采集:

# 查看已连接的视频设备
v4l2-ctl --list-devices

# 测试摄像头
ffmpeg -f v4l2 -i /dev/video0 -frames 1 test_rgb.jpg
ffmpeg -f v4l2 -i /dev/video2 -frames 1 test_ir.jpg

3. 软件准备

3.1 内核配置

人脸检测与识别应用需要 NPU 驱动和 V4L2 摄像头驱动支持:

# 路径: Device Drivers → Accelerators → Rockchip NPU
CONFIG_ROCKCHIP_RKNPU=y
CONFIG_RKNPU=y

# 路径: Device Drivers → Multimedia support → V4L2
CONFIG_V4L2=y
CONFIG_USB_VIDEO_CLASS=y

确认内核版本及驱动加载情况:

# 查看内核版本(应为 Linux 6.1)
uname -a

# 查看 NPU 驱动
grep -i rknpu /boot/config-$(uname -r)
# 预期输出: CONFIG_ROCKCHIP_RKNPU=y

# 查看 V4L2 驱动
ls /sys/class/video4linux/

3.2 设备树

NPU 设备树节点定义了 NPU 硬件的寄存器地址、中断号、时钟和复位等信息:

npu: npu@<base_addr> {
    compatible = "rockchip,rk3576-npu";
    reg = <0x0 <base_addr> 0x0 0x20000>;
    interrupts = <GIC_SPI <irq_num> IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cru CLK_NPU>, <&cru PCLK_NPU>;
    clock-names = "clk_npu", "pclk_npu";
    resets = <&cru SRST_NPU>;
    reset-names = "npu";
    status = "disabled";
    #cooling-cells = <2>;
};

以上寄存器基地址、中断号与时钟标识为 RK 平台通用结构示例,具体数值以实际发布的 RK3576 SDK 设备树为准(待板上确认)。

在板级设备树中启用 NPU:

&npu {
    status = "okay";
};

3.3 开发环境依赖

PC 端(模型转换):

# 创建 Python 虚拟环境
python3 -m venv rknn_env
source rknn_env/bin/activate

# 安装 rknn-toolkit2
pip install rknn-toolkit2

# 安装模型导出依赖
pip install torch torchvision onnx onnxsim

# 验证安装
python3 -c "from rknn.api import RKNN; print('RKNN Toolkit2 OK')"

板端(推理运行):

# 安装 rknn-lite2 运行时
pip3 install rknn-lite2

# 安装 Python 依赖
pip3 install numpy opencv-python-headless

# 验证 NPU 驱动
lsmod | grep rknpu
cat /sys/kernel/debug/rknpu/version

3.4 模型文件准备

# 创建模型目录
mkdir -p /data/models
cd /data/models

# 人脸检测模型(SCRFD)-- 已转换的 RKNN 模型
# 需要从 SCRFD 官方仓库导出 ONNX 后转 RKNN,详见 4.1 节

# 人脸识别模型(ArcFace)
# 需要从 insightface 官方仓库导出 ONNX 后转 RKNN,详见 4.2 节

# 校准数据集(用于 INT8 量化)
# 从实际场景中采集 100-200 张包含人脸的图像
mkdir -p calibration_data
# 将校准图像路径写入 dataset 文件
ls calibration_data/*.jpg > face_calibration.txt

4. 操作步骤

4.1 SCRFD 人脸检测模型转换

SCRFD 是百度提出的轻量级人脸检测模型,适合嵌入式部署。以下为转换为 RKNN 格式的流程:

from rknn.api import RKNN

# SCRFD 模型参数
MODEL_INPUT_SIZE = 640
DATASET_FILE = 'face_calibration.txt'

rknn = RKNN()

# 配置输入预处理(SCRFD 标准预处理:mean=[127.5,127.5,127.5], std=[128,128,128])
rknn.config(
    mean_values=[[127.5, 127.5, 127.5]],
    std_values=[[128, 128, 128]],
    target_platform='rk3576',
    quantized_dtype='asymmetric_quantized-8'
)

# 加载 ONNX 模型
ret = rknn.load_onnx(model='scrfd_2.5g.onnx')
if ret != 0:
    print('加载 SCRFD 模型失败')
    exit(ret)

# 量化校准
ret = rknn.build(do_quantization=True, dataset=DATASET_FILE)
if ret != 0:
    print('构建 SCRFD 模型失败')
    exit(ret)

# 导出 RKNN 模型
ret = rknn.export_rknn('scrfd_2.5g.rknn')
if ret != 0:
    print('导出 SCRFD 模型失败')
    exit(ret)

rknn.release()
print('SCRFD 模型转换完成: scrfd_2.5g.rknn')

SCRFD 模型选择指南:

模型输入尺寸参数量检测精度 (WIDER FACE Easy)推荐场景
scrfd_0.5g320x3200.5M93.5%低算力、小人脸场景
scrfd_2.5g640x6402.5M95.8%通用场景,精度与速度均衡
scrfd_5g640x6405M96.5%高精度场景

说明: 检测精度为各模型公开基准的典型值,实际值随数据集与量化配置变化。

4.2 ArcFace 人脸识别模型转换

ArcFace 是业界广泛使用的人脸识别模型,通过加性角度间隔损失函数提升特征区分度:

from rknn.api import RKNN

rknn = RKNN()

# ArcFace 标准预处理:输入 112x112 RGB,归一化到 [-1, 1]
rknn.config(
    mean_values=[[127.5, 127.5, 127.5]],
    std_values=[[128, 128, 128]],
    target_platform='rk3576',
    quantized_dtype='asymmetric_quantized-8'
)

# 加载 ONNX 模型
ret = rknn.load_onnx(model='arcface_mobileface.onnx')
if ret != 0:
    print('加载 ArcFace 模型失败')
    exit(ret)

# 量化校准
ret = rknn.build(do_quantization=True, dataset='face_calibration.txt')
if ret != 0:
    print('构建 ArcFace 模型失败')
    exit(ret)

# 导出 RKNN 模型
ret = rknn.export_rknn('arcface_mobileface.rknn')
if ret != 0:
    print('导出 ArcFace 模型失败')
    exit(ret)

rknn.release()
print('ArcFace 模型转换完成: arcface_mobileface.rknn')

ArcFace 模型选择指南:

模型输入尺寸特征维度LFW 准确率推荐场景
MobileFaceNet112x11212899.28%嵌入式端侧,低功耗
IResNet-50112x11251299.78%高精度场景
IResNet-100112x11251299.83%最高精度,算力充足

说明: LFW 准确率为各模型公开基准的典型值,实际值随数据集与量化配置变化。

4.3 人脸检测与识别完整流程

以下为板端完整的 Python 推理流程,包含人脸检测、对齐、特征提取和人脸库搜索:

from rknnlite.api import RKNNLite
import cv2
import numpy as np
import time
import os


class FaceRecognizer:
    """RK3576 人脸识别完整流程"""

    def __init__(self, det_model_path, rec_model_path,
                 face_db_path=None, det_threshold=0.5,
                 rec_threshold=0.4):
        """
        初始化人脸识别器

        Args:
            det_model_path: 人脸检测 RKNN 模型路径
            rec_model_path: 人脸识别 RKNN 模型路径
            face_db_path: 人脸特征库路径(.npy 格式)
            det_threshold: 检测置信度阈值
            rec_threshold: 识别相似度阈值
        """
        self.det_threshold = det_threshold
        self.rec_threshold = rec_threshold

        # 初始化检测模型
        self.det_rknn = RKNNLite()
        ret = self.det_rknn.load_rknn(det_model_path)
        if ret != 0:
            raise RuntimeError(f'加载检测模型失败: {det_model_path}')
        ret = self.det_rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_0)
        if ret != 0:
            raise RuntimeError('初始化检测运行时失败')

        # 初始化识别模型
        self.rec_rknn = RKNNLite()
        ret = self.rec_rknn.load_rknn(rec_model_path)
        if ret != 0:
            raise RuntimeError(f'加载识别模型失败: {rec_model_path}')
        ret = self.rec_rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_1)
        if ret != 0:
            raise RuntimeError('初始化识别运行时失败')

        # 加载人脸特征库
        self.face_db = {}
        self.face_embeddings = None
        if face_db_path and os.path.exists(face_db_path):
            self.load_face_db(face_db_path)

    def load_face_db(self, db_path):
        """加载人脸特征库"""
        data = np.load(db_path, allow_pickle=True).item()
        self.face_db = data.get('names', [])
        self.face_embeddings = data.get('embeddings', None)
        print(f'已加载人脸库: {len(self.face_db)} 人')

    def detect_faces(self, image):
        """
        人脸检测

        Args:
            image: BGR 格式原始图像

        Returns:
            boxes: 人脸边界框列表 [[x1,y1,x2,y2], ...]
            scores: 置信度列表
            landmarks: 关键点列表
        """
        img_h, img_w = image.shape[:2]

        # 预处理:resize 到模型输入尺寸
        input_size = 640
        img = cv2.resize(image, (input_size, input_size))
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

        # NPU 推理
        outputs = self.det_rknn.inference(inputs=[img_rgb])

        # 后处理:解析检测结果
        boxes, scores, landmarks = self._parse_det_output(
            outputs, img_w, img_h, input_size
        )

        # NMS
        keep = self._nms(boxes, scores, iou_threshold=0.4)
        boxes = [boxes[i] for i in keep]
        scores = [scores[i] for i in keep]
        if landmarks:
            landmarks = [landmarks[i] for i in keep]

        return boxes, scores, landmarks

    def _parse_det_output(self, outputs, img_w, img_h, input_size):
        """解析 SCRFD 检测输出"""
        boxes, scores, landmarks = [], [], []
        # SCRFD 输出格式:每个 stride 的得分和偏移量
        for output in outputs:
            if output is None:
                continue
            # 简化解析:实际需根据模型具体输出格式调整
            if len(output.shape) == 3:
                for det in output[0]:
                    score = det[0]
                    if score > self.det_threshold:
                        x1 = int(det[1] * img_w)
                        y1 = int(det[2] * img_h)
                        x2 = int(det[3] * img_w)
                        y2 = int(det[4] * img_h)
                        boxes.append([x1, y1, x2, y2])
                        scores.append(float(score))
                        if len(det) > 9:
                            lm = det[5:15].reshape(5, 2)
                            lm[:, 0] *= img_w
                            lm[:, 1] *= img_h
                            landmarks.append(lm.tolist())

        return boxes, scores, landmarks

    def _nms(self, boxes, scores, iou_threshold=0.4):
        """非极大值抑制"""
        if not boxes:
            return []
        boxes_arr = np.array(boxes, dtype=float)
        scores_arr = np.array(scores, dtype=float)
        x1 = boxes_arr[:, 0]
        y1 = boxes_arr[:, 1]
        x2 = boxes_arr[:, 2]
        y2 = boxes_arr[:, 3]
        areas = (x2 - x1) * (y2 - y1)
        order = scores_arr.argsort()[::-1]

        keep = []
        while len(order) > 0:
            i = order[0]
            keep.append(i)
            if len(order) == 1:
                break
            xx1 = np.maximum(x1[i], x1[order[1:]])
            yy1 = np.maximum(y1[i], y1[order[1:]])
            xx2 = np.minimum(x2[i], x2[order[1:]])
            yy2 = np.minimum(y2[i], y2[order[1:]])
            inter = np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1)
            iou = inter / (areas[i] + areas[order[1:]] - inter)
            order = order[np.where(iou <= iou_threshold)[0] + 1]

        return keep

    def align_face(self, image, landmarks, target_size=112):
        """
        人脸对齐:通过 5 点关键点做仿射变换

        Args:
            image: 原始图像
            landmarks: 5 点关键点 [[x,y], ...]
            target_size: 输出尺寸

        Returns:
            aligned: 对齐后的人脸图像
        """
        if landmarks is None or len(landmarks) < 5:
            # 无关键点时使用边界框中心裁剪
            return None

        lm = np.array(landmarks[:5], dtype=float)

        # 标准模板坐标(ArcFace 训练时使用的 5 点坐标)
        template = np.array([
            [30.2946, 51.6963],
            [65.5318, 51.5014],
            [48.0252, 71.7366],
            [33.5493, 92.3655],
            [62.7299, 92.2041]
        ], dtype=float)

        # 缩放模板到目标尺寸
        if target_size == 112:
            template = template * (112.0 / 96.0)
            template += 8.0
        else:
            template *= (target_size / 96.0)
            template += (target_size - 96.0) / 2.0

        # 计算仿射变换矩阵
        M = cv2.estimateAffinePartial2D(lm, template, method=cv2.LMEDS)[0]

        # 执行仿射变换
        aligned = cv2.warpAffine(
            image, M, (target_size, target_size),
            flags=cv2.INTER_LINEAR
        )
        return aligned

    def extract_embedding(self, face_image):
        """
        提取人脸特征向量

        Args:
            face_image: 112x112 RGB 人脸图像

        Returns:
            embedding: 归一化后的特征向量
        """
        # 预处理
        img = cv2.resize(face_image, (112, 112))
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) if len(img.shape) == 3 else img

        # NPU 推理
        outputs = self.rec_rknn.inference(inputs=[img_rgb])

        # L2 归一化
        embedding = outputs[0].flatten().astype(np.float32)
        norm = np.linalg.norm(embedding)
        if norm > 0:
            embedding = embedding / norm

        return embedding

    def search_face(self, embedding, top_k=5):
        """
        在人脸库中搜索最相似的人脸

        Args:
            embedding: 待识别特征向量
            top_k: 返回前 K 个匹配结果

        Returns:
            results: [(name, similarity), ...]
        """
        if self.face_embeddings is None or len(self.face_db) == 0:
            return []

        # 余弦相似度(特征已归一化,直接点积)
        similarities = np.dot(self.face_embeddings, embedding)
        top_indices = similarities.argsort()[::-1][:top_k]

        results = []
        for idx in top_indices:
            name = self.face_db[idx]
            sim = float(similarities[idx])
            results.append((name, sim))

        return results

    def recognize_frame(self, image):
        """
        完整识别流程:检测 -> 对齐 -> 特征提取 -> 搜索

        Args:
            image: BGR 格式原始图像

        Returns:
            results: 识别结果列表
        """
        results = []
        boxes, scores, landmarks = self.detect_faces(image)

        for i, (box, score) in enumerate(zip(boxes, scores)):
            face_result = {
                'box': box,
                'det_score': score,
                'name': 'Unknown',
                'rec_score': 0.0
            }

            # 人脸对齐
            lm = landmarks[i] if landmarks and i < len(landmarks) else None
            x1, y1, x2, y2 = box
            face_crop = image[max(0,y1):y2, max(0,x1):x2]

            if lm is not None:
                # 将关键点坐标从原图映射到裁剪区域
                lm_crop = [[p[0]-x1, p[1]-y1] for p in lm]
                aligned = self.align_face(face_crop, lm_crop)
            else:
                aligned = cv2.resize(face_crop, (112, 112))

            if aligned is not None:
                # 特征提取
                embedding = self.extract_embedding(aligned)

                # 人脸库搜索
                matches = self.search_face(embedding, top_k=1)
                if matches and matches[0][1] > self.rec_threshold:
                    face_result['name'] = matches[0][0]
                    face_result['rec_score'] = matches[0][1]

            results.append(face_result)

        return results

    def release(self):
        """释放资源"""
        self.det_rknn.release()
        self.rec_rknn.release()


def main():
    """主函数:实时人脸识别"""
    recognizer = FaceRecognizer(
        det_model_path='scrfd_2.5g.rknn',
        rec_model_path='arcface_mobileface.rknn',
        face_db_path='face_database.npy',
        det_threshold=0.5,
        rec_threshold=0.4
    )

    cap = cv2.VideoCapture(0)
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

    print('人脸识别已启动,按 q 退出...')
    fps_count = 0
    fps_start = time.time()

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        results = recognizer.recognize_frame(frame)

        for r in results:
            x1, y1, x2, y2 = r['box']
            color = (0, 255, 0) if r['name'] != 'Unknown' else (0, 0, 255)
            cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
            label = f"{r['name']} ({r['rec_score']:.2f})"
            cv2.putText(frame, label, (x1, y1 - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)

        # FPS 计算
        fps_count += 1
        elapsed = time.time() - fps_start
        if elapsed >= 1.0:
            fps = fps_count / elapsed
            fps_count = 0
            fps_start = time.time()
            cv2.putText(frame, f'FPS: {fps:.1f}', (10, 30),
                        cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255), 2)

        cv2.imshow('Face Recognition', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()
    recognizer.release()


if __name__ == '__main__':
    main()

4.4 人脸库管理

人脸特征库的构建和管理是人脸识别系统的关键环节:

import numpy as np
import cv2
import os
from rknnlite.api import RKNNLite


class FaceDatabase:
    """人脸数据库管理"""

    def __init__(self, rec_model_path):
        self.rknn = RKNNLite()
        ret = self.rknn.load_rknn(rec_model_path)
        if ret != 0:
            raise RuntimeError('加载识别模型失败')
        ret = self.rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_0)
        if ret != 0:
            raise RuntimeError('初始化运行时失败')

        self.names = []
        self.embeddings = None

    def register_face(self, name, face_images):
        """
        注册人脸:从多张图像中提取特征向量并取平均

        Args:
            name: 人名标识
            face_images: 人脸图像列表(112x112 RGB)
        """
        embeddings = []
        for img in face_images:
            img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) \
                if len(img.shape) == 3 else img
            outputs = self.rknn.inference(inputs=[img_rgb])
            emb = outputs[0].flatten().astype(np.float32)
            norm = np.linalg.norm(emb)
            if norm > 0:
                emb = emb / norm
            embeddings.append(emb)

        # 多张图像取均值作为注册特征
        mean_emb = np.mean(embeddings, axis=0)
        norm = np.linalg.norm(mean_emb)
        if norm > 0:
            mean_emb = mean_emb / norm

        self.names.append(name)
        if self.embeddings is None:
            self.embeddings = mean_emb.reshape(1, -1)
        else:
            self.embeddings = np.vstack([self.embeddings, mean_emb.reshape(1, -1)])

        print(f'注册成功: {name},当前人脸库: {len(self.names)} 人')

    def search(self, embedding, top_k=5):
        """搜索最相似的人脸"""
        if self.embeddings is None or len(self.names) == 0:
            return []
        similarities = np.dot(self.embeddings, embedding)
        top_idx = similarities.argsort()[::-1][:top_k]
        return [(self.names[i], float(similarities[i])) for i in top_idx]

    def save(self, db_path):
        """保存人脸库到文件"""
        data = {'names': self.names, 'embeddings': self.embeddings}
        np.save(db_path, data)
        print(f'人脸库已保存: {db_path} ({len(self.names)} 人)')

    def load(self, db_path):
        """从文件加载人脸库"""
        data = np.load(db_path, allow_pickle=True).item()
        self.names = data['names']
        self.embeddings = data['embeddings']
        print(f'人脸库已加载: {len(self.names)} 人')

    def delete(self, name):
        """删除指定人员"""
        if name in self.names:
            idx = self.names.index(name)
            self.names.pop(idx)
            self.embeddings = np.delete(self.embeddings, idx, axis=0)
            print(f'已删除: {name}')
        else:
            print(f'未找到: {name}')

    def release(self):
        self.rknn.release()

人脸库数据格式:

# 人脸库文件格式 (.npy)
{
    'names': ['张三', '李四', '王五', ...],    # 人员名称列表
    'embeddings': np.array([                    # 特征向量矩阵
        [0.012, -0.034, 0.056, ...],  # 张三的特征
        [0.023, -0.045, 0.067, ...],  # 李四的特征
        ...
    ])  # shape: (N, feature_dim)
}

4.5 活体检测(RGB/IR 双模态)

活体检测用于防止照片、视频回放等攻击手段。RGB+IR 双模态方案通过红外图像辅助判断真实活体:

from rknnlite.api import RKNNLite
import cv2
import numpy as np


class LivenessDetector:
    """RGB/IR 双模态活体检测"""

    def __init__(self, liveness_model_path):
        self.rknn = RKNNLite()
        ret = self.rknn.load_rknn(liveness_model_path)
        if ret != 0:
            raise RuntimeError('加载活体检测模型失败')
        ret = self.rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_2)
        if ret != 0:
            raise RuntimeError('初始化活体运行时失败')

    def check_liveness(self, rgb_face, ir_face):
        """
        RGB+IR 双模态活体检测

        Args:
            rgb_face: RGB 模态人脸图像(112x112)
            ir_face: IR 模态人脸图像(112x112,与 RGB 对齐)

        Returns:
            is_live: 是否为活体
            confidence: 活体置信度
        """
        # 预处理
        rgb_input = cv2.resize(rgb_face, (112, 112))
        rgb_input = cv2.cvtColor(rgb_input, cv2.COLOR_BGR2RGB)

        ir_input = cv2.resize(ir_face, (112, 112))
        if len(ir_input.shape) == 2:
            ir_input = cv2.cvtColor(ir_input, cv2.COLOR_GRAY2RGB)

        # 拼接 RGB+IR 作为输入(根据模型定义调整)
        combined = np.concatenate([rgb_input, ir_input], axis=-1)

        # NPU 推理
        outputs = self.rknn.inference(inputs=[combined])

        # 解析输出
        score = float(outputs[0].flatten()[0])
        is_live = score > 0.5

        return is_live, score

    def check_liveness_rgb_only(self, rgb_face):
        """
        RGB 单目活体检测(无 IR 摄像头时使用)

        Args:
            rgb_face: RGB 人脸图像

        Returns:
            is_live: 是否为活体
            confidence: 活体置信度
        """
        img = cv2.resize(rgb_face, (112, 112))
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

        outputs = self.rknn.inference(inputs=[img_rgb])

        score = float(outputs[0].flatten()[0])
        is_live = score > 0.5

        return is_live, score

    def release(self):
        self.rknn.release()

活体检测方案对比:

方案模态安全等级硬件要求适用场景
RGB 单目仅 RGB中单 RGB 摄像头普通门禁、考勤
RGB+IR 双目RGB + IR高RGB + IR 摄像头金融支付、高安全门禁
RGB+深度RGB + Depth极高RGB + 结构光/ToF银行柜台、高端安防

4.6 多线程流水线处理

利用 RK3576 三核 NPU 实现人脸处理流水线,最大化吞吐量:

from rknnlite.api import RKNNLite
import cv2
import numpy as np
import threading
import queue
import time


class FacePipeline:
    """三核 NPU 人脸处理流水线"""

    def __init__(self, det_model, rec_model, face_db_path):
        self.det_queue = queue.Queue(maxsize=4)
        self.rec_queue = queue.Queue(maxsize=4)
        self.result_queue = queue.Queue(maxsize=8)

        # 检测模型(NPU0)
        self.det_rknn = RKNNLite()
        self.det_rknn.load_rknn(det_model)
        self.det_rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_0)

        # 识别模型(NPU1)
        self.rec_rknn = RKNNLite()
        self.rec_rknn.load_rknn(rec_model)
        self.rec_rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_1)

        # 加载人脸库
        self.face_db = np.load(face_db_path, allow_pickle=True).item()

        self.running = False

    def start(self):
        """启动流水线"""
        self.running = True

        self.det_thread = threading.Thread(target=self._detect_loop, daemon=True)
        self.rec_thread = threading.Thread(target=self._recognize_loop, daemon=True)

        self.det_thread.start()
        self.rec_thread.start()

    def _detect_loop(self):
        """检测线程:运行在 NPU0"""
        while self.running:
            try:
                frame = self.det_queue.get(timeout=1.0)
            except queue.Empty:
                continue

            # 预处理
            img = cv2.resize(frame, (640, 640))
            img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

            # NPU0 推理
            outputs = self.det_rknn.inference(inputs=[img_rgb])

            # 简化解析:提取检测到的人脸区域
            # 实际项目中需根据具体模型输出格式解析
            h, w = frame.shape[:2]
            face_regions = self._parse_faces(outputs, w, h)

            if face_regions:
                self.rec_queue.put((frame, face_regions))

    def _recognize_loop(self):
        """识别线程:运行在 NPU1"""
        while self.running:
            try:
                frame, face_regions = self.rec_queue.get(timeout=1.0)
            except queue.Empty:
                continue

            results = []
            for (x1, y1, x2, y2) in face_regions:
                face_crop = frame[y1:y2, x1:x2]
                if face_crop.size == 0:
                    continue

                # 对齐
                face_aligned = cv2.resize(face_crop, (112, 112))
                face_rgb = cv2.cvtColor(face_aligned, cv2.COLOR_BGR2RGB)

                # NPU1 推理
                outputs = self.rec_rknn.inference(inputs=[face_rgb])
                emb = outputs[0].flatten().astype(np.float32)
                norm = np.linalg.norm(emb)
                if norm > 0:
                    emb = emb / norm

                # 搜索人脸库
                name = 'Unknown'
                score = 0.0
                if self.face_db['embeddings'] is not None:
                    sims = np.dot(self.face_db['embeddings'], emb)
                    best_idx = sims.argmax()
                    if sims[best_idx] > 0.4:
                        name = self.face_db['names'][best_idx]
                        score = float(sims[best_idx])

                results.append({
                    'box': (x1, y1, x2, y2),
                    'name': name,
                    'score': score
                })

            self.result_queue.put(results)

    def _parse_faces(self, outputs, img_w, img_h):
        """解析检测输出"""
        faces = []
        scale_x = img_w / 640.0
        scale_y = img_h / 640.0
        for output in outputs:
            if output is None:
                continue
            if len(output.shape) == 3:
                for det in output[0]:
                    if det[0] > 0.5:
                        x1 = int(det[1] * scale_x)
                        y1 = int(det[2] * scale_y)
                        x2 = int(det[3] * scale_x)
                        y2 = int(det[4] * scale_y)
                        faces.append((x1, y1, x2, y2))
        return faces

    def stop(self):
        self.running = False
        self.det_rknn.release()
        self.rec_rknn.release()

5. 代码详解

5.1 SCRFD 人脸检测原理

SCRFD(Sample and Computation Redistribution for Face Detection)是基于 anchor-free 的人脸检测器:

SCRFD 核心流程:
1. Backbone: MobileNetV2 提取多尺度特征
2. FPN: 特征金字塔网络融合不同尺度特征
3. 检测头: 对每个特征图位置预测:
   - 分类分支: 该位置是否为人脸
   - 回归分支: 人脸边界框偏移量
   - 关键点分支: 5 个人脸关键点位置
4. 解码: 将网络输出解码为实际坐标
5. NMS: 去除重叠的检测框

SCRFD vs RetinaFace 对比:

对比项SCRFDRetinaFace
架构anchor-freeanchor-based
检测速度更快较慢
小人脸检测优秀良好
NPU 兼容性更优良好
推荐模型scrfd_2.5gretinanet-mnet

5.2 ArcFace 特征提取

ArcFace(Additive Angular Margin Loss)通过在角度空间添加间隔来增强特征区分度:

ArcFace 特征提取流程:
1. 输入: 112x112 RGB 人脸图像
2. Backbone: MobileNetV2 / IResNet 提取特征
3. 特征归一化: L2 归一化到单位超球面
4. 输出: 128/256/512 维特征向量

损失函数:
  L = -log(e^(s*cos(θ_yi+m)) / (e^(s*cos(θ_yi+m)) + Σ_j≠yi e^(s*cos(θ_j))))

其中:
  s = scale (通常 64)
  m = margin (通常 0.5 弧度)
  θ = 特征向量与权重向量的角度

特征向量维度选择:

维度存储开销 (1万人)搜索速度适用场景
1285 MB极快嵌入式端侧,小规模人脸库
25610 MB快通用场景,万级人脸库
51220 MB中等高精度场景,百万级人脸库

5.3 人脸对齐原理

人脸对齐通过仿射变换将不同姿态的人脸标准化:

仿射变换矩阵计算:
1. 提取 5 个关键点: 左眼、右眼、鼻尖、左嘴角、右嘴角
2. 定义标准模板坐标(ArcFace 训练时使用的固定坐标)
3. 通过 least-squares 求解 2x3 仿射变换矩阵 M
4. 使用 cv2.warpAffine() 对原图进行变换

变换公式:
  [x']   [m00 m01 m02] [x]
  [y'] = [m10 m11 m12] [y]
  [1 ]   [0   0   1  ] [1]

5.4 相似度度量方法

人脸比对常用的相似度度量方法:

| 方法 | 公式 | 特点 | | ---------- | --------------------------- | ------------------------------ | --- | --- | --- | ------------------------ | | 余弦相似度 | cos(A,B) = A.B / ( | A | * | B | ) | 对向量长度不敏感,最常用 | | L2 距离 | d(A,B) = sqrt(sum((A-B)^2)) | 直观的距离度量 | | 内积 | dot(A,B) = sum(A*B) | 特征已归一化时等价于余弦相似度 |

相似度阈值参考:

阈值范围误识率 (FAR)拒识率 (FRR)推荐场景
0.3 ~ 0.4极低较高高安全门禁
0.4 ~ 0.5低中等通用人脸识别
0.5 ~ 0.6中等较低宽松匹配场景

5.5 NPU 三核分工策略

RK3576 的三核 NPU 在人脸识别系统中的最优分工:

NPU 核心任务模型说明
NPU0人脸检测SCRFD检测为计算密集型,独立核心避免竞争
NPU1特征提取ArcFace识别需要等待检测结果,独立核心并行
NPU2活体检测LivenessNet活体检测可与识别并行执行

说明: 各阶段端到端延迟与流水线帧率需在 C-3576BQ + M4-R2 V10 板卡上实际测量(待板上验证)。上表核心分工为 RK3576 三核 NPU 通用调度结构描述。


6. 常见问题

6.1 检测不到人脸

现象: 图像中有人脸但检测框为空。

解决方案:

# 1. 降低检测阈值
recognizer = FaceRecognizer(
    det_model_path='scrfd_2.5g.rknn',
    rec_model_path='arcface_mobileface.rknn',
    det_threshold=0.3  # 从 0.5 降低到 0.3
)

# 2. 检查预处理参数是否与训练一致
rknn.config(
    mean_values=[[127.5, 127.5, 127.5]],  # SCRFD 标准预处理
    std_values=[[128, 128, 128]],
    target_platform='rk3576'
)

# 3. 检查输入图像质量
# 确保图像亮度充足,人脸区域不小于 20x20 像素

# 4. 使用更敏感的模型
# 从 scrfd_2.5g 切换到 scrfd_0.5g(更敏感但精度略低)

6.2 识别准确率低

现象: 人脸识别错误率高,匹配结果不准确。

解决方案:

# 1. 提高识别相似度阈值
recognizer = FaceRecognizer(
    ...,
    rec_threshold=0.5  # 从 0.4 提高到 0.5
)

# 2. 增加注册图像数量(每人 5-10 张,覆盖不同角度和光照)
for img in multiple_images:
    db.register_face(name, [img])  # 多次注册取均值

# 3. 检查人脸对齐质量
# 确保关键点检测准确,对齐后的人脸眼睛位置大致在 (38,38) 和 (74,38)

# 4. 使用更大模型
# 从 MobileFaceNet 切换到 IResNet-50(精度更高)

6.3 活体检测误判

现象: 真人被误判为攻击,或照片攻击通过检测。

解决方案:

# 1. RGB 单目方案:调整纹理分析参数
# - 增加多帧检测(连续 3 帧一致才判定)
# - 结合眨眼检测、头部转动等行为分析

# 2. RGB+IR 方案:确保 IR 摄像头工作正常
ffmpeg -f v4l2 -i /dev/video2 -frames 1 test_ir.jpg
# 检查 IR 图像是否包含有效信息

# 3. 调整活体阈值
is_live, score = detector.check_liveness(rgb_face, ir_face)
# score > 0.5 判定为活体,可调整阈值

6.4 推理帧率低

现象: 人脸检测与识别帧率低于预期。

解决方案:

# 1. 确认使用三核 NPU 流水线
#    检测(NPU0) + 识别(NPU1) + 活体(NPU2)

# 2. 确认 NPU 使能与频率状态
cat /sys/kernel/debug/clk/clk_npu/clk_rate

# 3. 降低检测输入分辨率
#    640x640 -> 320x320 可明显提速

# 4. 优化人脸库搜索
#    使用 FAISS 等库加速大规模向量搜索
pip3 install faiss-cpu

# 5. 检查 CPU 负载
top -d 1
# 将 Python 进程绑定到大核
taskset -c 4-7 python3 face_recognition.py

6.5 模型转换失败

现象: rknn.load_onnx() 或 rknn.build() 返回错误。

解决方案:

# 1. 升级 rknn-toolkit2
pip3 install --upgrade rknn-toolkit2

# 2. 简化 ONNX 模型
pip install onnx-simplifier
python3 -m onnxsim scrfd.onnx scrfd_sim.onnx

# 3. 检查不支持的算子
# 常见问题算子及替代方案:
# - GatherND -> Reshape + Gather
# - InstanceNorm -> LayerNorm 替代
# - SiLU -> 在导出时替换为 ReLU6 组合

# 4. 固定输入维度(避免动态 shape)
# 在模型导出时指定固定 batch size 和空间维度

6.6 人脸库加载失败

现象: 加载 .npy 格式人脸库时出错。

解决方案:

# 1. 检查文件格式
import numpy as np
data = np.load('face_database.npy', allow_pickle=True).item()
print(type(data))  # 应为 dict
print(data.keys())  # 应包含 'names' 和 'embeddings'

# 2. 检查数据一致性
assert len(data['names']) == data['embeddings'].shape[0], \
    f"名称数量({len(data['names'])})与特征数量({data['embeddings'].shape[0]})不匹配"

# 3. 检查特征维度
# MobileFaceNet: 128 维
# IResNet-50/100: 512 维
assert data['embeddings'].shape[1] in [128, 256, 512], \
    f"特征维度异常: {data['embeddings'].shape[1]}"

# 4. 检查文件权限
ls -la face_database.npy
chmod 644 face_database.npy

相关文档

文档名称路径说明
NPU 架构与性能概览NPU架构与性能概览RK3576 NPU 架构介绍
RKNN Toolkit2 安装与使用RKNN Toolkit2安装与使用工具链安装与基本使用
模型转换与量化模型转换与量化模型转换流程与量化
分类模型部署(LeNet/ResNet)分类模型部署(LeNet-ResNet)分类模型部署
目标检测部署(YOLOv5/v7/v8)目标检测部署(YOLOv5-v7-v8)YOLO 系列检测部署
语义分割部署语义分割部署分割模型部署
OCR 文字识别OCR文字识别OCR 模型部署
NPU 性能调优与调试NPU性能调优与调试NPU 推理性能调优

在 GitHub 上编辑此页