简介
随着时代的进步,全民刷脸已经成为一种新型的生活方式,这也是全球科技进步的又一阶梯,人脸识别技术已经成为一种大趋势,无论在智慧出行、智能家居、智慧办公等场景均有较广泛的应用场景,本文介绍了基于SeetaFace2人脸识别引擎在OpenAtom OpenHarmony(以下简称"OpenHarmony")上实现人脸识别的AI能力。
什么是SeetaFace2
SeetaFace2是由中科视拓(北京)科技有限公司开发并使用BSD开源协议开源出来的一款人脸识别引擎库,其搭建了一套全自动人脸识别系统所需的三个核心模块,即:人脸检测模块FaceDetector、面部关键点定位模块 FaceLandmarker 以及人脸特征提取与比对模块FaceRecognizer。除了三个核心模块外,它还提供了两个辅助模块FaceTracker和QualityAssessor用于人脸跟踪和质量评估。下图是SeetaFace2人脸识别算法组件:
SeetaFace2能做什么
SeetaFace2采用标准C++开发,全部模块均不依赖任何第三方库,支持x86架构(Windows、Linux)和ARM架构,可以轻松地移植到OpenHarmony上。SeetaFace2支持的上层应用包括但不限于人脸门禁、无感考勤、人脸比对等。如下图展示了SeetaFace2支持的应用矩阵:
SeetaFace2人脸识别原理
SeetaFace2人脸识别引擎搭建了一套全自动人脸识别系统所需的三个核心模块:
- 人脸检测(FaceDetector)
在图像中首先定位出人脸的位置,然后裁剪(crop)出包含人脸位置的矩形框,一般还会进行填充、缩放到指定尺寸,还可能会对人脸图像进行标准化normalize;
- 面部关键点定位(FaceLandmarker)
提取人脸关键点坐标,然后使用放射变化或相似变换等进行人脸对齐变换。面部关键点定位的目标就是把所有的人脸图片统一到一个固定的正脸姿态大小,从而提高模型对人脸姿态变化的鲁棒性。
- 人脸特征提取与比对模块(FaceRecognizer)
主要使用深度学习等方法提取人脸的特征,然后通过特征对比,计算人脸的相似度。
SeetaFace2人脸识别的具体过程如下图所示:
两步带你实现人脸识别
关于SeetaFace2的如何移植到OpenHarmony移植请参照文档:SeetaFace2移植开发文档(请参考文章末尾相关文档链接),这里我们主要分析通过SeetaFace2如何实现人脸识别。
从上面人脸识别的流程图可以知道人脸识别主要包含2个大块:人脸注册和人脸识别。
- 人脸注册
人脸注册首先需要对传入的图片进行人脸检测,当检测到人脸后会提取对应的人脸信息,并将信息保存用于对比。
人脸信息检测实现:
std::vector<SeetaFaceInfo> DetectFace(const SeetaImageData &image)
{
auto faces = FD.detect(image);
return std::vector<SeetaFaceInfo>(faces.data, faces.data + faces.size);
}
其中FD是三大模块中的人脸检测模块(FaceDetector),其加载了人脸检测模型:
seeta::ModeStting FD_model("fd_2_00.dat", seeta::ModeStting::CPU, 0);
而返回SeetaFaceInfo数据则是检测到的人脸信息,其中包含了人脸个数,人脸区域坐标以及人脸置信度得分数据。然后通过人脸信息检测返回的数据进行面部关键点定位。
面部关键点定位实现:
std::vector<SeetaPointF> DetectPoints(const SeetaImageData &image, const SeetaRect &face)
{
std::vector<SeetaPointF> points(PD.number());
PD.mark(image, face, points.data());
return std::move(points);
}
其中的PD是三大模块中的关键点定位模块(FaceLandmarker),关键点定位需要根据面部特征模型进行对比分析的,SeetaFace2提供2种面部特征模型。分别是通过5点定位和通过81点定位,此实例中我们使用的是81点定位模型:
seeta::ModeStting PD_model("pd_2_00_pts81.dat", seeta::ModeStting::CPU, 0);
获取完面部特征数据后,SeetaFace2提供了一个人脸数据库进行保存对应的人脸信息数据,以此来完成人脸信息的注册:
int64_t Register(const SeetaImageData &image)
{
auto faces = DetectFace(image);
auto points = DetectPoints(image, faces.pos);
return FDB.Register(image, points.data());
}
其中FDB是SeetaFace2实现的FaceDatabase数据库管理。该数据库也为人脸识别提供面部特征数据的对比结果,面部特征对比也需要一个人脸数据模型:
seeta::ModeStting FDB_model("fr_2_00.dat", seeta::ModeStting::CPU, 0);
通过以上步骤,我们就已经完成了人脸的注册。
- 人脸识别
人脸识别和人脸注册步骤类似,都需要先检测人脸信息及提取面部特征数据。唯一的区别在于提取面部特征时需要进行人脸质量评估,最后根据质量评估结果进行识别,具体实现如下:
int64_t RecogizePoint(const SeetaImageData &image)
{
int64_t result = 0;
seeta::ModeStting FD_model("fd_2_00.dat", seeta::ModeStting::CPU, 0); // 此3步创建3个模型
seeta::ModeStting PD_model("pd_2_00_pts81.dat", seeta::ModeStting::CPU, 0);
seeta::ModeStting FDB_model("fr_2_00.dat", seeta::ModeStting::CPU, 0);
seeta::FaceDetector FD(FD_model); // 创建人脸检测模块
seeta::FaceLandmarker PD(PD_model); // 创建面部关键点定位模块
seeta::FaceDatabase FDB(FDB_model); // 创建人脸特征信息数据库模块
auto faces = FD.detect(image); // 获取人脸特征信息
for (SeetaFaceInfo &face : faces) { // 对比每个人脸信息
int64_t index = -1;
float similarity = 0;
std::vector<SeetaPointF> points(PD.number());
PD.mark(image, face, points.data()); // 获取人脸框信息
auto score = QA.evaluate(image, face.pos, points.data()); // 获取人脸质量评分
if (score == 0) {
HILOGI("no ignored\r\n");
} else {
auto queried = FDB.QueryTop(image, points.data(), 1, &index, &similarity); // 从注册的人脸数据库中对比相似度
if (queried < 1) {
continue;
}
if (similarity > threshold) {
HILOGI("get recognized face!! \r\n");
result++;
}
}
}
return result;
}
为了帮助到大家能够更有效的学习OpenHarmony 开发的内容,下面特别准备了一些相关的参考学习资料:
OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy
《OpenHarmony源码解析》:https://qr18.cn/CgxrRy
- 搭建开发环境
- Windows 开发环境的搭建
- Ubuntu 开发环境搭建
- Linux 与 Windows 之间的文件共享
- ......
系统架构分析:https://qr18.cn/CgxrRy
- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ......