目录

1、前言

2、网络处理模块

2.1 消息处理流程

2.2 消息数据格式

3、人脸图像处理模块

3.1 人脸检测

3.1.1 MTCNN原理简介

3.1.2 算法集成

3.2 人脸对齐

3.3 人脸识别

3.3.1 FaceNet

3.3.2 InsightFace原理

3.4 算法集成设计与实现

3.4.1 类接口设计

3.4.2 算法集成实现

4、特征数据库管理模块

4.1 业务交互流程

4.2 数据库表设计

4.3 人脸特征存储格式


1、前言

本文是《人脸识别实战》系列文章的第二篇,主要描述服务器端各模块的详细设计,包括网络处理模块的处理流程,图像处理模块中的人脸检测与人脸识别算法的集成,以及数据库管理模块的业务逻辑与数据表的设计与实现。

关注公众号 AIPlayer获取项目源码地址

2、网络处理模块

2.1 消息处理流程

使用Reactor模式实现高并发处理,负责处理客户端网络连接与数据接收及发送。Reactor采用多线程+epoll的处理方式实现,同时使用单例模式定义Req_Mgt管理类,将Reactor分发来的消息请求入队,再定义Req_Processor线程取出队列中的请求作相关的业务处理,最终通过消息接口类Msg_Oper将结果发送给客户端。流程设计如下:

2.2 消息数据格式

消息格式使用Json数据,通过opencv读取的图像数据经过cv::imencode()编码为二进制数据后,再使用base64编码嵌入到Json的数据段中。封装好的Json数据使用 数据长度+数据负载 的格式进行发送和接收。具体的Json协议字段如下:

Request & Response Data
Payload length(4字节) payload
JSON长度 JSON数据

JSON 数据定义如下:

注册人脸JSON数据

注册人脸请求

{

"id": "gh_2c0f9xxx",  //用户id

"name": "AIPlayer", //用户名字

"type": 1,  //操作类型:0-识别,1-注册,2-删除

"detect_in_client": True, //根据输入的图像来选择,如果是已检测的人脸图则为True,如果是未经人脸检测处理的选择False

"mode": 1,  //模式选择:0-release,1-模型性能测试

"img_data": "adfadfadfadfadfah"  //base64编码图像数据

}

注册成功返回

{

"err_code": 0,

"msg": "Face regist OK."

}

注册失败返回

{

"err_code": -1,

"msg": "face regist error."

}

删除人脸JSON数据

删除人脸请求

{

"id": "gh_2c0f9xxx",  //用户id

"name": "AIPlayer", //用户名字

"type": 2,  //操作类型:0-识别,1-注册,2-删除

"detect_in_client": True, //根据输入的图像来选择,如果是已检测的人脸图则为True,如果是未经人脸检测处理的选择False

"mode": 1,  //模式选择:0-release,1-模型性能测试

"img_data": "adfadfadfadfadfah"  //base64编码图像数据

}

删除成功返回

{

"err_code": 0,

"msg": "Face delete OK."

}

删除失败返回

{

"err_code": -1,

"msg": "face delete error."

}

识别人脸JSON数据

识别人脸请求

{

"id": "gh_2c0f9xxx",  //用户id

"name": "AIPlayer", //用户名字

"type": 0,  //操作类型:0-识别,1-注册,2-删除

"detect_in_client": True, //根据输入的图像来选择,如果是已检测的人脸图则为True,如果是未经人脸检测处理的选择False

"mode": 1,  //模式选择:0-release,1-模型性能测试

"threshhold":0.8, //人脸识别相似度阈值

"img_data": "adfadfadfadfadfah"  //base64编码图像数据

}

识别成功返回

{

"err_code": 0,

"user_name": "AIPlayer", //识别到的用户名

"box": [0.3, 0.3, 0.8, 0.8], //人脸框左上与右下坐标与宽高比例

"img_data": " adfadfadfadfadfah " //base64编码的人脸框图像

}

识别失败返回

{

"err_code": -1,

"msg": "face recognize error."

}

3、人脸图像处理模块

3.1 人脸检测

3.1.1 MTCNN原理简介

MTCNN,Multi-task convolutional neural network(多任务卷积神经网络),将人脸区域检测与人脸关键点检测放在了一起,可以认为它是一个级联的神经网络。和很多处理图像问题的卷积神经网络模型,该模型也用到了图像金字塔、边框回归、非最大值抑制等技术。MTCNN总体可分为P-Net、R-Net和O-Net三层网络结构。这三个级联的网络分别是:

  • P-Net,用于快速生成候选窗口。首先基于3层简单的CNN提取特征,然后通过一个人脸分类器判断该区域是否是人脸,同时使用边框回归和一个面部关键点的定位器来进行人脸区域的初步定位。该部分最终将输出多张可能存在人脸的区域,并作为R-Net的输入进行下一步的处理。P-Net本质上是一个单输入多输出结构的多任务卷积神经网络,包括了一个分类任务和两个回归任务。

  • R-Net,用于进行高精度候选窗口过滤选择。在结构上与P-Net类似,只是最后一层使用了全连接层,对特征的选择会更加的准确。该网络最后也是由一个人脸特征分类任务和边框回归及关键点回归任务组成,最后将输出较为可信的人脸区域,供O-Net使用。

  • O-Net,用于生成最终边界框与人脸关键点。在网络结构的最后同样是一个更大的256的全连接层,保留了更多的图像特征,同时再进行人脸判别、边框回归和人脸特征定位,最终输出人脸区域的左上角坐标和右下角坐标与人脸区域的五个特征点。

3.1.2 算法集成

系统通过Mtcnn_Detector()类集成了基于ncnn框架的实现的MTCNN,开源的项目地址为:

https://github.com/cpuimage/MTCNN,其中ncnn是Tencent开源的一个为手机端优化的高性能神经网络前向计算框架(https://github.com/Tencent/ncnn)。

3.2 人脸对齐

    在人脸特征提取之前,往往需要对检测到的人脸进行对齐。在实际场景中,检测器检测到的人脸常常会有一定的旋转角度,而对齐的作用就是将人脸调整到一个比较正面的角度。

本系统的人脸对齐方法比较简单,使用OpenCV的仿射变换来进行人脸的矫正。具体做法是根据MTCNN检测出的人脸区域及两个眼睛的坐标点,计算出旋转矩阵后,再调用仿射变换接口来获得对齐后的人脸图像。

3.3 人脸识别

3.3.1 FaceNet

FaceNet的网络架构与普通的卷积神经网络基本一致,但是FaceNet并没有使用传统的Softmax去进行分类学习,而是直接进行了端到端学习一个从图像到欧式空间的编码方法,然后基于这个编码再做人脸识别。如下图所示,Deep Architecture是卷积神经网络去掉softmax后的结构,经过L2的归一化之后得到特征表示Embedding,基于这个特征表示计算三元组的损失函数。

所谓的三元组就是三个样例:anchor,positive和negative。其中,anchor与positive是同一类,anchor与negative是异类,那么学习的过程就是学到一种表示,使得对于尽可能多的三元组中,anchor与positive的距离小于anchor与negative的距离,即类内距离小于类间距离。

因为很少的样本数据就可以产生大量的三元组,这对模型的收敛速度有着很大的影响。在FaceNet中使用了在线方法来选择三元组,即每训练一次mini-batch,根据当前的embedding,选择一次三元组,然后在这些三元组上计算triplet-loss,再对embedding进行更新,不断重复,直到收敛或训练到指定迭代次数。系统中使用了基于Tensorflow实现的版本,项目地址为https://github.com/davidsandberg/facenet/.

3.3.2 InsightFace原理

InsightFace算法基本流程如上图所示,它是在CosFace和SphereFace算法基础上对损失函数做了改进,在CNN网络得到特征向量后,利用余弦函数计算人脸特征和目标权重之间的夹角,然后在目标角度上增加一个附加的角余量,通过余弦函数再次得到目标logit。最后,用一个固定的特征范数重新缩放所有logits,并且后续步骤与softmax loss中的步骤完全相同。系统中使用了基于Tensorflow实现的版本,项目地址为https://github.com/luckycallor/InsightFace-tensorflow

3.4 算法集成设计与实现

3.4.1 类接口设计

为了方便对不同的人脸检测及识别算法进行扩展,采用模版模式的设计方法:编写接口类Face_Detector及Face_Recognizer,并以此为类型参数编写模板类Face_Handler。具体的类图如下所示:

3.4.2 算法集成实现

    这一小节主要描述如何集成Tensorflow实现的InsightFace算法。

(1)模型载入

首先通过ReadBinaryProto()读取模型的图结构定义,然后对GPU的内存使用情况进行设置,最后根据图定义及设置创建Session,后续的预测推理需要以此Session来进行处理。

int InsightFace_Recognizer::init_session(const string &graph_path)
{tensorflow::GraphDef graph_def;tensorflow::SessionOptions opts;TF_CHECK_OK(ReadBinaryProto(tensorflow::Env::Default(), graph_path, &graph_def));//graph::SetDefaultDevice("/gpu:0", &graph_def);opts.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(0.5);opts.config.mutable_gpu_options()->set_allow_growth(true);m_session.reset(tensorflow::NewSession(opts));TF_CHECK_OK(m_session->Create(graph_def));return 0;
}

(2)特征提取

  • 定义输入Tensor

因为输入图像使用OpenCV中的cv::Mat结构,而Tensorflow以tensorflow::Tensor作为模型的输入数据,所以需要将cv::Mat转为tensorflow::Tensor,转换的核心代码如下:

// copying the data into the corresponding tensor
for (int y = 0; y < height; ++y)
{const double* source_row = imgs[i].ptr<double>(y);for (int x = 0; x < width; ++x){const double* source_pixel = source_row + (x * depth);for (int c = 0; c < depth; ++c){const double* source_value = source_pixel + (2 - c); //BGR2RGBinput_tensor_mapped(i, y, x, c) = *source_value;}}
}
  • 推理获取特征

首先根据模型结构确定输入层与输出层的名称,然后定义相应的输入Tensor,接着根据之前创建好的session执行预测推理,最后获取输出的特征向量保存在vector中。基本的代码如下:

const string input_layer_1 = "input_images:0";
const string input_layer_2 = "train_phase_bn:0";
const string input_layer_3 = "train_phase_dropout:0";
const string output_layer = "embeddings:0";
Tensor train_phase(tensorflow::DT_BOOL, tensorflow::TensorShape());
train_phase.scalar<bool>()() = false;
Tensor train_phase_last(tensorflow::DT_BOOL, tensorflow::TensorShape());
train_phase_last.scalar<bool>()() = false;
std::vector<Tensor> outputs;tensorflow::Tensor face_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, height, width, depth}));
//推理
Status run_status = m_session->Run({{input_layer_1, face_tensor},{input_layer_2, train_phase},{input_layer_3, train_phase_last}},{output_layer},{},&outputs);
//获取特征向量
auto feature = outputs[0].tensor<float, 2>();
std::vector<float> feat_vec;
for (int i = 0; i < feature.size(); ++i)
{feat_vec.push_back(feature(i));
}

(3)相似度计算

在人脸特征比对中,使用欧式距离来进行特征比较,在某一设定阈值范围内取相似度最相近的作为识别的结果。

float cal_similarity(vector<float> &user_feat, vector<float> &face_feat)
{cv::Mat user_feat_mat = cv::Mat(user_feat);cv::Mat face_feat_mat = cv::Mat(face_feat);return cv::norm(user_feat_mat, face_feat_mat, cv::NORM_L2);
}
for (int i = 0; i < m_users->size(); ++i)
{float diff = cal_similarity(m_users->at(i).feat_vec, (*iter).feat_vec);if (diff < threshhold && diff < min_diff){min_diff = diff;idx = i;}
}

4、特征数据库管理模块

4.1 业务交互流程

  • 数据库初始化流程

  • 用户注册流程

4.2 数据库表设计

(1)用户表内容为:

id

name

feat_vec

created_at

updated_at

用户唯一标识

用户名字

人脸特征值

创建时间戳

更新时间戳

(2)初始化用户表脚本

#!/bin/bash
user=AIPlayer
password=123456
mysql_exec="/usr/bin/mysql -h127.0.0.1 -u$user -p$password"
##########################
#【用户人脸特征数据库】
##########################
db=face_db
$mysql_exec -e "drop database $db"
$mysql_exec -e "create database $db"
#-------------------------
# 用户表
#-------------------------
echo "begin create ${db}.tbl_user table";
$mysql_exec $db -e "CREATE TABLE ${db}.tbl_user(id varchar(18) COMMENT '唯一用户ID编号',name varchar(100) COMMENT '用户名称',feat_vec varchar(10000) COMMENT '人脸特征',    created_at bigint unsigned COMMENT '创建时间戳',updated_at bigint unsigned COMMENT '上次更新时间戳',    PRIMARY KEY(id)) ENGINE=InnoDB DEFAULT  CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";

4.3 人脸特征存储格式

提取的人脸特征是float类型的1xn维数据,在存储到数据库前需要将其转化为string类型,这里的处理方式是以逗号为连接符组合每个特征数据。

【人脸识别实战二】服务器端设计与实现相关推荐

  1. 【人脸识别实战一】系统架构设计

    1.前言 <人脸识别实战>系列文章将讲述一个人脸识别系统的设计与实现过程.本文是系列文章的开篇,主要描述系统的整体架构和各模块的功能职责,以及系统所需要的环境依赖部署.详细的设计细节及项目 ...

  2. 【项目实战课】基于Pytorch的MTCNN与Centerloss人脸识别实战

    欢迎大家来到我们的项目实战课,本期内容是<基于Pytorch的MTCNN与Centerloss人脸识别实战>. 所谓项目实战课,就是以简单的原理回顾+详细的项目实战的模式,针对具体的某一个 ...

  3. 二自由度云台扫描算法_基于HuskyLens人脸识别的二自由度自动跟踪云台

    "看什么看?" "就盯着你看!" --基于HuskyLens人脸识别的二自由度自动跟踪云台 试用群里的老师们先后放出了各色利用二哈人脸识别功能的案例,实验对象从 ...

  4. 实战:人脸识别实战项目(源码共享)

    首先我想问个问题:现在什么工程师最值钱? 毫无疑问,我想超 90% 的都会说:人工智能工程师.也难怪,随着近几年人工智能的发展,已经逐渐渗透到了各个领域,比如:医疗.教育.机械自动化.个性化推荐.信息 ...

  5. AI实战:人脸识别实战项目(源码共享)

    首先我想问个问题:现在什么工程师最值钱? 毫无疑问,我想超 90% 的都会说:人工智能工程师.也难怪,随着近几年人工智能的发展,已经逐渐渗透到了各个领域,比如:医疗.教育.机械自动化.个性化推荐.信息 ...

  6. 小白都能学会的Python基础 第七讲:综合实战3 - 文字识别、人脸识别实战

    1.华小智系列 - Python基础(案例版) <Python基础>目录 第七讲:综合实战3 - 文字识别.人脸识别实战 1.Python图片文字识别(OCR) 2.Python人脸识别( ...

  7. IOS人脸识别和二维码识别

    人脸识别应用于许多领域.二维码的识别更是疯狂.下面,我们一起去看看简单的人脸识别和二维码识别. 1.测试数据的展示(人脸). 原图: 1.人脸的大小 // 人脸大小 CGRect FaceRect  ...

  8. 人脸识别(二)----如何生成CSV文件

    人脸识别(二)----如何生成CSV文件 当我们写人脸模型训练的时候,我们需要读取人脸的路径path和人脸对应的标签label.人脸的路径就是人脸图片所在你的电脑的位置,标签就是一个人对应一个标签(注 ...

  9. 应用层下的人脸识别(二):人脸库

    本文作者根据多年人脸识别项目经验,总结了人脸识别技术在安防.商业领域应用及产品设计细节,汇总成应用层下的人脸识别系列文章. 本文为系列文章的第二篇,介绍人脸库的相关内容.人脸库是人脸识别的基础,建立人 ...

最新文章

  1. putty改oracle数据库密码,用putty远程访问虚拟机linux系统Oracle数据库。
  2. sql 把多列内容合并
  3. 【CTF】paradigm-CTF babysandbox
  4. 用 Arthas “庖丁解牛”
  5. Colored Sticks--POJ 2513
  6. 去除lcd图片的摩尔纹_宝妈时尚产后有妊娠纹怎么办?教你这三招,轻松修复肚皮!...
  7. OpenBSD 5.1 正式版发布
  8. 第三百三十六章 斗宗强者间的大战!
  9. 菜鸟请教高手web开发内存问题?
  10. firefox linux脚本启动,在Linux终端中使用后台运行模式启动程序的方法
  11. unity基础(1)——unity编辑器的基本介绍
  12. 计算机通讯端口怎么增加,plc通讯接口如何添加删除方法
  13. ubuntu下海信Hisense E920 usb连接不上的处理与adb的连接
  14. 2微信小程序的UI设计
  15. Maven子父工程依赖配置,小白也能看得懂
  16. 一份简单、直接、高效的中文求职信模板,一般是直接写在邮件正文中。
  17. Leetcode 781. 森林中的兔子 C++
  18. MAC常用命令及快捷键
  19. eLife:情绪学习对人脑记忆整合的回溯性促进机制
  20. Flink SQL Print Connector

热门文章

  1. 面向对象编程项目案例(栈与队列封装和乌龟吃鱼游戏)
  2. 深度优先搜索解决八数码难题
  3. 网络知识:IP地址的概念以及IPV4和IPV6的区别
  4. 量化CTA知识点笔记
  5. php 对象转数组 数组转对象
  6. 做自媒体文笔差,写作没方向?掌握这些方法也能月入1W+
  7. C++语言篇 第二章 顺序结构
  8. 15.线程信号(Signaling)
  9. D2 2018 7 27 作业
  10. 在一定范围内生成随机数