本章介绍人脸属性检测 SDK 的算法能力、接口调用、部署准备、工程构建和运行排查。SDK 通过 ModelInfer/RKNN 在 RK3576 NPU 上执行图像推理。
SDK 采用 WiderFace 人脸检测与 FER 属性分类级联流程,输出人脸框、表情、年龄估计和性别分类结果。
算法能力
SDK 在一张 BGR 图像上执行级联推理:
BGR 图像 → WiderFace 检测 → 人脸裁剪 → FER 属性分类 → 输出检测框及表情、年龄、性别结果
| 能力 | 输出 | 说明 |
|---|---|---|
| 人脸检测 | 人脸框 x/y/width/height、检测分数 | 坐标对应输入原图像素 |
| 表情分类 | Neutral、Happy、Sad、Surprise、Fear、Disgust、Anger 七类及分数 | 输出模型分类结果及各类别分数 |
| 年龄估计 | 一个整数年龄 | 根据九个年龄段的分类分数和代表年龄加权计算并取整 |
| 性别分类 | Female、Male 标签及两个分数 | 模型二分类估计,不代表已核实的个人信息 |
| 多人脸 | 每张检测到的人脸各有一份属性结果 | 每个人脸分别返回检测框和属性分类结果 |
模型文件位于部署后的 models/:
| 文件 | 用途 |
|---|---|
| RK3576_Ubuntu_widerface_last.engine | WiderFace 人脸检测 |
| RK3576_Ubuntu_FER_best.engine | FER 分类:7 类表情、2 类性别、9 个年龄段 |
表情、年龄和性别均为模型估计。年龄结果是预测值,表情和性别分数表示模型输出,不代表经独立核验的个人信息。
部署前准备
资源获取
| 资源包 | 说明 |
|---|---|
facial_attributes_detection_RK3576 |
算法SDK,包含公开头文件、算法库、ModelInfer/RKNN/OpenCV 运行库、检测与 FER 模型、样例图 |
facial_attributes_project 示例工程 |
包含 SDK 调用示例、构建文件及依赖准备和运行脚本 |
SDK 应与 RK3576 Debian aarch64 平台匹配;应用通过 SDK 公开接口调用算法。
RK3576 Linux SDK 的关键目录如下:
facial_attributes_detection_RK3576/
├── include/
│ └── facial_attributes_detection.h
├── lib/
│ └── libfacial_attributes_detection.so
├── 3rd_party/
│ ├── modelinfer/
│ ├── rknn/
│ └── opencv/
├── models/
│ ├── RK3576_Ubuntu_widerface_last.engine
│ └── RK3576_Ubuntu_FER_best.engine
├── images/
│ └── input.jpg
└── example.cpp
具体以 SDK 随附的 README_SDK.md 为准。请使用 RK3576 Linux 版本,不要混用 RK3568、Android 或其他版本的动态库和模型。
硬件与系统要求
| 项目 | 要求 |
|---|---|
| 主控 | Quectel Pi M2 |
| 系统 | Debian aarch64 |
| USB摄像头 | 可选 USB V4L2 摄像头;使用摄像头输入时需要 |
| 设备访问 | PC 可通过 ADB 连接开发板;运行用户需要具备工程文件及摄像头设备访问权限 |
软件依赖
算法运行依赖 SDK 附带的 ModelInfer、RKNN 和 OpenCV world 库。编译本仓库示例工程需要 C++17 编译器、Make、pkg-config 和 Qt5 Widgets 开发包。联网安装编译依赖时可执行:
sudo apt update
sudo apt install -y build-essential pkg-config qtbase5-dev
检查工具链:
g++ --version
make --version
pkg-config --exists Qt5Widgets && echo "Qt5 OK"
v4l2-ctl --version
v4l2-ctl 用于枚举和排查摄像头设备。SDK 与 OpenCV 运行库应使用同一 RK3576 Linux SDK 交付版本。
项目结构
facial_attributes_project/
├── src/
│ └── facial_attributes_cam_demo.cpp SDK 接口调用和图像输入处理
├── Makefile C++17 编译和链接规则
├── build.sh 并行调用 make
├── setup_from_sdk.sh 从 SDK 复制头文件、动态库和模型
├── run.sh 配置运行库路径及授权码
├── include/ SDK 公开头和 OpenCV 头文件(准备依赖后生成)
├── lib/ SDK 及 ModelInfer/RKNN/OpenCV 动态库(准备依赖后生成)
├── models/ 检测和 FER 模型(准备依赖后生成)
├── images/ SDK 示例图 input.jpg(准备依赖后生成)
├── license/ SDK 生成的设备绑定授权文件
├── outputs/ 示例程序导出的结果文件
└── facial_attributes_cam_demo 编译生成的示例可执行文件
include/、lib/、models/ 和 images/ 由 setup_from_sdk.sh 从匹配的 RK3576 Linux SDK 交付包生成。部署前请取得对应 SDK 及所需授权许可。
算法 SDK 接口
SDK 公开头文件为 include/facial_attributes_detection.h,级联入口类为 FacialAttributesDetection。RK3576 的 module 参数为 3;算法 appid 147 由 SDK 内部管理。
初始化与生命周期
以下代码展示 SDK 初始化的基本流程,应放在函数体内调用:
FacialAttributesDetection sdk;
float confidence = 0.25f;
float nmsIou = 0.20f;
float detectionFilter = 0.0f;
float classificationFilter = 0.0f;
sdk.set_param(confidence, nmsIou, detectionFilter, classificationFilter);
std::string detector = "models/RK3576_Ubuntu_widerface_last.engine";
std::string classifier = "models/RK3576_Ubuntu_FER_best.engine";
std::string license = "license/fad_license.txt";
std::string authCode = std::getenv("FAD_AUTH_CODE") ? std::getenv("FAD_AUTH_CODE") : "";
const auto result = sdk.init(detector.data(), classifier.data(), license.data(), 3, authCode.data());
if (result != FACIAL_PROCESS_OK || sdk.get_status(0) != 0) {
return;
}
std::string::data() 在 C++17 中返回可写字符存储,符合 SDK 的 char* 参数签名。模型路径相对于应用的工作目录。应用结束时调用 sdk.uinit() 释放资源。
get_status(0) 是算法初始化状态;get_status(1) 是授权状态。调用方应在初始化成功后再调用推理接口。
set_param 的完整签名还有 scoreThresh_det 和 scoreThresh_cla 两项:前者是检测结果输出过滤阈值,后者为跨平台接口保留参数,RK3576 SDK 当前未使用。示例将两者设置为 0.0。
输入约定与推理
SDK inference 的输入是 BGR 连续内存、行数、列数和通道数:
std::vector<facial_info::FaceContext> faces;
if (!bgr.isContinuous()) bgr = bgr.clone();
const auto result = sdk.inference(bgr.data, bgr.rows, bgr.cols, bgr.channels(), faces);
cv::imread(..., cv::IMREAD_COLOR)和 V4L2/OpenCV 采集帧均按 BGR 处理;通道数应为 3。- 非连续 ROI 在送入 SDK 前复制为连续矩阵。
- SDK 内部负责 FER 所需的颜色转换和模型预处理,调用方不应重复归一化或转换为 RGB 后直接传入。
faces是输出参数;调用成功后包含每张检测人脸的facial_info::FaceContext。应用应检查检测框坐标和尺寸后再使用结果。FACIAL_PROCESS_OK只表示本次调用成功;合法成功结果也可能是零张人脸。
返回结果
| 字段 | 内容 | 输出说明 | |
|---|---|---|---|
box |
shared_ptr<Box>:x/y/width/height/score/class_id |
绘制人脸框、显示检测分数、写入 JSON | |
emotion |
scores[8] 和 emotion_type |
七类表情标签及模型分数 | |
age_gender.age |
SDK 计算的整数年龄估计 | 根据九类年龄段分数加权计算 | |
age_gender.gender_scores[2] |
[female, male] 分数 |
与 gender_type 类别结果对应 |
表情分数索引依次对应 0 Neutral、1 Happy、2 Sad、3 Surprise、4 Fear、5 Disgust、6 Anger。
年龄模型输出九类分布,SDK 按代表年龄 1/6/14/24/34/44/54/64/75 加权并取整。年龄、表情和性别结果均为模型估计。
SDK 返回码与授权状态
常见 FACIAL_ATTRIBUTES_DETECTION_RES_CODE:
| 返回码 | 名称 | 说明 |
|---|---|---|
| 0 | FACIAL_PROCESS_OK | 当前操作成功 |
| -1 | FACIAL_INIT_ERROR | 初始化失败,包括模型或授权失败 |
| -2 | FACIAL_UNINIT_ERROR | 尚未初始化 |
| -3 | FACIAL_ERR_INFERENCE_ERROR | 推理失败 |
| -4 | FACIAL_ERR_IMAGE_EMPTY | 图像为空或尺寸/通道不合法 |
| -5 | FACIAL_ERR_JSON_NULL | JSON 结果为空;兼容接口保留 |
| -6 | FACIAL_ERR_JSON_PARSE | JSON 解析失败;兼容接口保留 |
公开类还提供以下方法:
| 方法 | 用途 | |
|---|---|---|
save_result(img_src, results, output_path, image_path, save_img, save_labelme_json) |
按选项保存检测标注图和 LabelMe JSON | |
get_benchmark_info(img_src, repeat_times) |
对输入图像重复推理并输出耗时统计;repeat_times 默认值为 100 |
|
uinit() |
反初始化并释放 SDK 内部推理资源 |
算法授权分两层,由 SDK 实现并严格执行“引擎授权 → 算法授权 → 引擎初始化”的顺序。L1 引擎层使用引擎内部 appid 133 身份,由 SDK 在初始化流程中处理。应用传入 module 3 和算法授权码,供 L2 算法 appid 147 校验。授权流程和状态映射以 SDK 文档为准。
| get_status(1) | 常见含义 |
|---|---|
| 0 | 正式授权成功 |
| 100014 | 常见于未提供授权码或无有效本地授权件;在 LicenseSDK V2.2.9 的离线流程中也可能作为离线返回码,需结合 init()、初始化状态和 SDK 版本判断 |
| 100010 | 授权相关状态;是否进入试用由 SDK 的网络探测及授权流程决定 |
| 100002 | 算法试用到期 |
| 其他非零值 | SDK/LicenseSDK 返回的授权错误码 |
具体授权策略、服务器判定和状态映射以随包 SDK 的 README_SDK.md 为准。首次正式授权可能需要联网
SDK 集成流程
将 SDK 集成到程序时,可按以下顺序组织生命周期:
- 由应用负责取得输入图像。静态图可使用
cv::imread();摄像头场景由应用的视频采集模块取得帧。 - 将图像转换为 SDK 要求的三通道 BGR 连续内存;非连续图像需先
clone()。 - 创建
FacialAttributesDetection实例并调用set_param()设置检测阈值。 - 调用
init()加载检测/FER 模型并传入设备授权文件路径、module3和算法授权码。 - 检查
init()返回值及get_status(0);初始化成功后调用inference()。 - 遍历
FaceContext结果,读取检测框、表情分数、年龄估计及性别分类结果。 - 按应用需求使用
save_result()导出 SDK 标注图/LabelMe JSON,或自行序列化结果;需要测量推理性能时调用get_benchmark_info()。 - 处理结束后调用
uinit()释放 SDK 资源。
连续视频处理时,应由应用控制采集和推理调度,避免对同一 SDK 实例进行并发推理调用。若需要保持数据采集不阻塞业务主线程,可将采集和推理放入工作线程,并通过线程安全的数据结构传递帧与结果。
部署与运行
SDK 目录要求
setup_from_sdk.sh 的参数应指向 RK3576 Linux SDK 根目录,目录内容见“部署前准备”。该脚本会把 SDK 公开头文件、运行库、模型和样例图复制到工程对应目录。
传输工程与 SDK
在 Windows PowerShell 中将工程和 SDK 推送到设备临时目录:
adb devices
adb push "<SDK 主机路径>" /tmp/facial_attributes_detection_RK3576
adb push "facial_attributes_project" /tmp/
在 Quectel Pi M2 终端中将文件复制到 pi 用户家目录。
sudo mkdir -p "$HOME/facial_attributes_detection_RK3576" "$HOME/facial_attributes_project"
sudo cp -a /tmp/facial_attributes_detection_RK3576/. "$HOME/facial_attributes_detection_RK3576/"
sudo cp -a /tmp/facial_attributes_project/. "$HOME/facial_attributes_project/"
sudo chown -R "$USER:$(id -gn)" \
"$HOME/facial_attributes_detection_RK3576" \
"$HOME/facial_attributes_project"
编译
板端以普通桌面用户(示例为 pi)编译:
sudo apt update
sudo apt install -y build-essential pkg-config qtbase5-dev qtwayland5
cd /home/pi/facial_attributes_project
sh setup_from_sdk.sh /home/pi/facial_attributes_detection_RK3576
sh build.sh
不传 SDK 路径时,脚本默认使用 $HOME/facial_attributes_detection_RK3576。build.sh 按在线 CPU 数调用 make。Makefile 用 C++17 编译 src/facial_attributes_cam_demo.cpp,从工程 include/、lib/ 查找 SDK 头文件和库,链接 libfacial_attributes_detection.so、libopencv_world.so、Qt5 开发库及系统线程/动态加载库,生成 facial_attributes_cam_demo。
SDK 公开头的 Landmarks 构造函数对带自定义构造函数的 Point 数组调用 memset,某些 GCC 版本可能输出 -Wclass-memaccess 警告。这是 SDK 头文件产生的警告;本项目不修改供应商 SDK。不要为了消除它而提交修改过的 SDK 头或二进制。
运行示例程序
cd /home/pi/facial_attributes_project
sh run.sh
run.sh 设置 LD_LIBRARY_PATH、默认 license 路径和 FAD_AUTH_CODE,然后启动 SDK 集成示例。建议以拥有工程文件和摄像头设备访问权限的普通用户运行。
授权配置
算法 module 对 RK3576 固定为 3。项目中的 run.sh 含占位符:
export FAD_AUTH_CODE="${FAD_AUTH_CODE:-REPLACE_WITH_ALGORITHM_AUTH_CODE}"
将占位符替换为 授权码;也可通过环境变量 FAD_AUTH_CODE 覆盖。授权码缺失或校验失败时,SDK 根据网络探测和授权结果执行拒绝或其定义的离线试用策略。
应用演示
常见问题
| 现象 | 检查方向 |
|---|---|
init() 返回 FACIAL_INIT_ERROR,授权状态为 100014 |
检查 FAD_AUTH_CODE 是否仍为占位符或为空,并确认网络和授权配置。license 文件不是授权码 |
inference() 成功但结果向量为空 |
当前图像可能没有达到阈值的人脸;确认输入非空、为 BGR 三通道,并检查人脸尺寸、清晰度和检测阈值 |
| 出现多个重叠框 | 适当降低 NMS IoU 以加强重复框抑制;同时检查检测阈值 |
| 摄像头采集失败 | 用 v4l2-ctl --list-devices 查看采集设备;确认使用 USB V4L2 节点,并检查运行用户是否有 video 设备访问权限 |
Could not load ... .so |
检查 setup_from_sdk.sh 是否使用了 RK3576 Linux SDK,确认 lib/ 文件齐全并通过 run.sh 启动 |
-Wclass-memaccess 警告 |
警告来自 SDK 公开头文件的 memset(Point[]);不要改 SDK 文件,确认构建本身是否成功 |
| 保存失败 | 检查工程 outputs/ 是否可写、磁盘空间是否足够;不要在 root 和 pi 用户之间混用生成目录 |
技术支持与贡献
如在使用过程中遇到问题,欢迎在移远官方论坛提交技术咨询,移远技术支持团队将及时为您解答。
欢迎提交Issue反馈问题或Pull Request贡献代码改进!