# 人脸属性检测算法 ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- 本章介绍人脸属性检测 SDK 的算法能力、接口调用、部署准备、工程构建和运行排查。SDK 通过 ModelInfer/RKNN 在 RK3576 NPU 上执行图像推理。 SDK 采用 WiderFace 人脸检测与 FER 属性分类级联流程,输出人脸框、表情、年龄估计和性别分类结果。 ```{image} images/image_BZeRbk5zfo7GkNxy956cxowvn1g.webp :width: 1280px :height: 800px :align: center ``` ## 算法能力 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 的关键目录如下: ```bash 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 开发包。联网安装编译依赖时可执行: ```bash sudo apt update sudo apt install -y build-essential pkg-config qtbase5-dev ``` 检查工具链: ```bash g++ --version make --version pkg-config --exists Qt5Widgets && echo "Qt5 OK" v4l2-ctl --version ``` `v4l2-ctl` 用于枚举和排查摄像头设备。SDK 与 OpenCV 运行库应使用同一 RK3576 Linux SDK 交付版本。 ## 项目结构 ```bash 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 初始化的基本流程,应放在函数体内调用: ```cpp 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 连续内存、行数、列数和通道数: ```cpp std::vector 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```:`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 集成到程序时,可按以下顺序组织生命周期: 1. 由应用负责取得输入图像。静态图可使用 `cv::imread()`;摄像头场景由应用的视频采集模块取得帧。 2. 将图像转换为 SDK 要求的三通道 BGR 连续内存;非连续图像需先 `clone()`。 3. 创建 `FacialAttributesDetection` 实例并调用 `set_param()` 设置检测阈值。 4. 调用 `init()` 加载检测/FER 模型并传入设备授权文件路径、module `3` 和算法授权码。 5. 检查 `init()` 返回值及 `get_status(0)`;初始化成功后调用 `inference()`。 6. 遍历 `FaceContext` 结果,读取检测框、表情分数、年龄估计及性别分类结果。 7. 按应用需求使用 `save_result()` 导出 SDK 标注图/LabelMe JSON,或自行序列化结果;需要测量推理性能时调用 `get_benchmark_info()`。 8. 处理结束后调用 `uinit()` 释放 SDK 资源。 连续视频处理时,应由应用控制采集和推理调度,避免对同一 SDK 实例进行并发推理调用。若需要保持数据采集不阻塞业务主线程,可将采集和推理放入工作线程,并通过线程安全的数据结构传递帧与结果。 ## 部署与运行 ### SDK 目录要求 `setup_from_sdk.sh` 的参数应指向 RK3576 Linux SDK 根目录,目录内容见“部署前准备”。该脚本会把 SDK 公开头文件、运行库、模型和样例图复制到工程对应目录。 ### 传输工程与 SDK 在 Windows PowerShell 中将工程和 SDK 推送到设备临时目录: ```powershell adb devices adb push "" /tmp/facial_attributes_detection_RK3576 adb push "facial_attributes_project" /tmp/ ``` 在 Quectel Pi M2 终端中将文件复制到 `pi` 用户家目录。 ```bash 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`)编译: ```bash 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 头或二进制。 ### **运行示例程序** ```bash cd /home/pi/facial_attributes_project sh run.sh ``` `run.sh` 设置 `LD_LIBRARY_PATH`、默认 license 路径和 `FAD_AUTH_CODE`,然后启动 SDK 集成示例。建议以拥有工程文件和摄像头设备访问权限的普通用户运行。 ## 授权配置 算法 module 对 RK3576 固定为 `3`。项目中的 `run.sh` 含占位符: ```bash 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` 用户之间混用生成目录 |