跳转到内容

人脸 98 关键点识别

修订履历

NO版本修订内容修订日期
1Ver1.0新建2026/06/30

本文档中的信息可能会因文档改进而在不事先通知的情况下变更。最新版请参阅本公司网站。

未经株式会社日昇科技书面许可,严禁以任何形式复制本文档。

1. 人脸关键点概要

  人脸关键点定位也称为人脸关键点检测或人脸对齐。它是针对输入的人脸图像,估计眉毛、眼睛、鼻子、嘴巴、面部轮廓等面部重要区域位置的处理过程。与人脸检测类似,由于会受到姿态变化、遮挡等因素影响,人脸关键点检测也是一项难度较高的任务。

人脸关键点检测具有多种重要的应用场景。

・人脸姿态对齐:在人脸识别等算法中,为提高模型精度,需要进行人脸姿态对齐。

・人脸校正与编辑:基于关键点,可以准确分析脸型、眼部形状、鼻部形状等,并对人脸特定部位进行处理,从而实现人脸特效、美颜处理、贴纸叠加等娱乐功能。

・表情分析与唇部识别:基于关键点,可以分析面部表情,并用于互动娱乐、行为预测等场景。

本脸部 98 点关键点算法的关键点位置如下图所示:

图1-1 人脸 98 关键点索引定义

图1-1 人脸 98 关键点索引定义

算法在数据集上的性能:

人脸关键点算法NME(%)
300W2.78
COFW3.08
AFLW1.42

在 CSUN RV1126B 上的运行效率如下:

算法类型模型大小运行效率
face_detect44.23MB17ms
face_landmark9810.88MB23ms

2. 快速开始

2.1 开发环境准备

  如果您是首次阅读本文档,请参考《入门指南/开发编译环境的准备与更新》,并按照相关步骤部署编译环境。

在 PC 端 Ubuntu 系统中执行 run 脚本,进入 Docker 开发环境。步骤如下:

Terminal window
cd ~/linuxshare/work/rv1126b/jp/embedded/images/develop_environment
./run.sh 2204

图2-1 Docker 开发环境启动

图2-1 Docker 开发环境启动

2.2 源代码下载

在 Docker 开发环境中,创建用于保存源代码仓库的管理目录。

Terminal window
cd /opt/linuxshare/work/rv1126b/jp/AI/demo/ai-algorithm

使用 git 工具,在管理目录中克隆远程仓库。

Terminal window
git clone https://github.com/csunltd/rv1126b-ai-toolkit.git

※ 即使从 GitHub 网页下载,也请下载整个仓库。请不要只单独下载与本示例对应的目录。

※ 如果已经下载完成,可以跳过此步骤。

2.3 模型部署

要运行算法 Demo,首先需要下载人体关键点识别算法模型。

下载链接:

人脸检测模型:

https://dl.dragonwake.com/download/rv1126b/AI/demo/01_face-detect.zip

人脸关键点识别模型:

https://dl.dragonwake.com/download/rv1126b/AI/demo/11_face_landmark98.zip

之后,请将下载的人脸检测模型和人体关键点识别模型复制到 Release/ 目录。

图2-2 Release 目录内的文件配置

图2-2 Release 目录内的文件配置

2.4 示例构建

进入示例所在目录并执行构建。具体命令如下:

Terminal window
cd rv1126b-ai-toolkit/Demos/algorithm-face_landmark98/
Terminal window
./build.sh cpres

* 依赖库已配置在开发板上,因此交叉编译过程中需要保持 /mnt 挂载。

Terminal window
sudo mount -t nfs -o vers=3,proto=tcp,mountproto=tcp,nolock,retrans=5,timeo=5 192.168.10.85:/ /mnt

* 为 build.sh 脚本指定 cpres 参数后,Release/ 目录内的所有资源都会被复制到开发板。

图2-3 示例构建结果

图2-3 示例构建结果

2.5 示例运行及结果

将已编译的文件复制到基板。

Terminal window
cp Release/\* /mnt/userdata/Demo/algorithm-face_landmark98/

※ 如果使用 ./build.sh cpres 编译,会自动复制。

通过串口调试或 SSH 调试进入开发板后台,并按如下方式移动到示例部署目录。

Terminal window
cd /userdata/Demo/algorithm-face_landmark98/

执行示例的命令如下:

Terminal window
./test-face-landmark98 test.jpg

图2-4 示例运行结果

图2-4 示例运行结果

在 Docker 开发环境中,将测试结果图片从基板复制出来。

Terminal window
cp /mnt/userdata/Demo/algorithm-face_landmark98/result.jpg .

图2-5 结果图像复制命令

图2-5 结果图像复制命令

识别结果如下图所示。

图2-6 人脸 98 关键点识别结果图像

图2-6 人脸 98 关键点识别结果图像

关于 API 的详细说明以及 API 调用方式(本示例的源代码),请参见以下内容。

3. 人脸检测API 说明

3.1 引用方法

为了使用户能够从本地项目中直接调用 EASY EAI API 库,本列表列出了项目需要链接的库和头文件,便于用户直接添加。

项目说明
头文件目录easyeai-api/algorithm/face_detect
库文件目录easyeai-api/algorithm/face_detect
库链接参数-lface_detect

3.2 人脸检测初始化函数

人脸检测初始化函数原型如下。

int face_detect_init(rknn_context \*ctx, const char \*path)

详细说明如下。

函数名: face_detect_init()
头文件face_detect.h
输入参数ctx:rknn_context 句柄
输入参数path:算法模型路径
返回值成功时返回值:0
失败时返回值:-1
注意事项

3.3 人脸检测执行函数

人脸检测执行函数 face_detect_run 原型如下。

int face_detect_run(rknn_context ctx, cv::Mat &input_image, std::vector\<det\> &result)

详细说明如下。

函数名:face_detect_run()
头文件face_detect.h
输入参数ctx:rknn_context 句柄
输入参数input_image:图像数据输入(cv::Mat 为 OpenCV 类型)
输出参数result:目标检测框输出
返回值成功时返回值:0
失败时返回值:-1
注意事项

3.4 人脸检测释放函数

人脸检测释放函数原型如下。

int face_detect_release(rknn_context ctx)

详细说明如下。

函数名:face_detect_release ()

头文件face_detect.h
输入参数ctx:rknn_context 句柄
返回值成功时返回值:0
失败时返回值:-1
注意事项

4. 人脸 98 点关键点API 说明

4.1 引用方法

为了使用户能够从本地项目中直接调用 EASY EAI API 库,本项目需要链接的库和头文件如下所示。用户可以直接添加。

项目说明
头文件目录easyeai-api/algorithm_api/face_landmark98
库文件目录easyeai-api/algorithm_api/face_landmark98
库链接参数-lface_landmark98

4.2 人脸 98 点关键点初始化函数

人脸 98 点关键点初始化函数原型如下。

int face_landmark98_init(rknn_face_landmark_context_t \*p_face_landmark, const char \*p_model_path)

详细说明如下。

函数名: face_landmark98_init()
头文件face_landmark98.h
输入参数p_face_landmark:rknn_face_landmark_context_t句柄
输入参数p_model_path:算法模型路径
返回值成功时返回值:0
失败时返回值:-1
注意事项

4.3 人脸 98 点关键点执行函数

face_landmark98_run 函数原型如下。

std::vector\<cv::Point\> face_landmark98_run(cv::Mat image, rknn_face_landmark_context_t \*p_face_landmark)

详细说明如下。

函数名:face_landmark98_run ()
头文件face_landmark98.h
输入参数p_face_landmark:rknn_face_landmark_context_t句柄
输入参数image:图像数据输入(cv::Mat 为 OpenCV 类型)
返回值std::vector<cv::Point>:算法输出的人脸关键点坐标
注意事项

4.4 人脸 98 点关键点释放函数

人脸 98 点关键点释放函数原型如下。

int face_landmark98_release(rknn_face_landmark_context_t\* p_face_landmark)

详细说明如下。

函数名:face_landmark98_release ()
头文件face_landmark98.h
输入参数p_face_landmark:rknn_face_landmark_context_t句柄
返回值成功时返回值:0
失败时返回值:-1
注意事项

5. 人体关键点识别示例

示例目录为 Demos/algorithm-face_landmark98/test-face-landmark98.cpp,操作流程如下。

图5-1 人脸 98 关键点识别算法处理流程

图5-1 人脸 98 关键点识别算法处理流程

参考示例如下。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <fstream>
#include <atomic>
#include <queue>
#include <thread>
#include <mutex>
#include <chrono>
#include <sys/time.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <opencv2/opencv.hpp>
#include <unistd.h>
#include <sys/syscall.h>
#include "face_detect.h"
#include "face_landmark98.h"
using namespace std;
using namespace cv;
int main(int argc, char **argv)
{
if( argc != 2) {
printf("./test-face-landmark98 xxx.jpg \n");
return -1;
}
struct timeval start;
struct timeval end;
float time_use=0;
rknn_context detect_ctx;
std::vector<det> result;
int ret;
cv::Mat src;
src = cv::imread(argv[1], 1);
face_detect_init(&detect_ctx, "./face_detect.model");
/* 顔ランドマーク位置推定を初期化します */
rknn_face_landmark_context_t face_landmark;
ret = face_landmark98_init(&face_landmark, "./face_landmark98.model");
if( ret < 0) {
printf("face_mask_judgement_init fail! ret=%d\n", ret);
return -1;
}
gettimeofday(&start,NULL);
face_detect_run(detect_ctx, src, result);
gettimeofday(&end,NULL);
time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);//マイクロ秒
printf("face_detect time_use is %f\n",time_use/1000);
printf("face num:%d\n", (int)result.size());
for (int i = 0; i < (int)result.size(); i++)
{
int x = (int)(result[i].box.x);
int y = (int)(result[i].box.y);
int w = (int)(result[i].box.width);
int h = (int)(result[i].box.height);
int max = (w > h)?w:h;
// 画像の切り出し範囲が境界を超えていないか確認します
if( (x < 0) || (y < 0) || ((x +max) > src.cols) || ((y +max) > src.rows) ) {
continue;
}
// 顔位置
cv::Rect rect(x, y, w, h);
cv::Mat face_roi =src(rect).clone();
gettimeofday(&start,NULL);
std::vector<cv::Point> keys = face_landmark98_run(&face_landmark, face_roi);
gettimeofday(&end,NULL);
time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);//マイクロ秒
printf("face_landmark time_use is %f\n",time_use/1000);
// 元画像上の位置
for (int i = 0; i < (int)keys.size(); i++) {
keys[i].x += rect.x;
keys[i].y += rect.y;
}
for (int i = 0; i < (int)keys.size(); i++)
{
printf("keyPoints %d :[%d, %d]\n", i, keys[i].x, keys[i].y);
cv::circle(src, keys[i], 2, CV_RGB(0, 255, 0), 2);
}
//cv::rectangle(src, rect, CV_RGB(0, 255, 0), 2);
}
cv::imwrite("result.jpg", src);
/* 顔検出を解放します */
face_detect_release(detect_ctx);
/* 顔ランドマーク位置推定を解放します */
face_landmark98_release(&face_landmark);
return 0;
}