FaceDetection
算法架构
顶层:多个针对不同姿态的快速LAB特征分类器
LAB特征
LAB特征是那些结合8个局部邻接2-矩形的二分Haar特征,它们大小相同并且共享同一个中心矩形
LAB特征示例
级联强分类器
将若干个强分类器由简单到复杂排列,希望经过训练使每个强分类器都有较高检测率,而误识率可以放低,比如几乎99%的人脸可以通过,但50%的非人脸也可以通过,
是一种退化的决策树,决策树是二叉树,级联是对于前面不匹配的直接抛弃,不会继续分类
如何搜索人脸
在图像中做“穷尽搜索”,扫描所有的分类器,这些分类器会在图像上搜索所有可能的位置和大小
示例
搜索方法
窗口中心分类器
存在重复计算
图中矩形框内的特征,被每个特征分类器计算。
副产品是计算过程会得到特征图
滑动窗口以计算图中所有位置的所有特征
特征中心分类器
计算方法
特征值图像可以通过扫描图像中所有坐标的upper特征来计算
然后特征中心的分类器会运行在特征值图像中,并不再需要特征计算操作
注意
所有的特征都是相同大小,因为他们都是通过在图像平移了一个特殊特征来搜集的。
当然,任意大小窗口都可以用来构建特征中心分类器。但是最好是选择最有效率的一个
贪心算法
两种算法的计算差异
假若分类窗口尺寸为24x24,特征为3x3的LAB特征,因此一个窗口中会有256((24-9+1)x(24-9+1))个特征
窗口中心方法
所有的256个分类操作将导致这256个特征在每个候选窗口中被操作一次,所以,每个窗口的平均分类操作数是256
特征中心级联方法
随着过程的推进某些窗口会被抛弃,每个窗口的平均分类操作是小于256的
使用 RealBoost学习算法来学习线性(窗口中心或特征中心)分类函数
中层:若干基于SURF特征的多层感知机
LAB级联阶段之后,大部分非人脸窗口被抛弃,剩下的部分对于单个LAB 特征难以处理。因此,接下来,候选窗口将交给更复杂的分类器来处理,比如带 SURF的MLP
粗粒度MLP
输入是候选窗口的SURF特征
MLP级联可以连接多个LAB级联分类器
底层:一个统一的基于SURF特征的多层感知机,来处理所有姿态的候选窗口
多视角人脸外貌之间存在一些冲突,主要源于非对齐特征
基于坐标抽取的特征存在语义不一致问题
采取了一种基于形状索引的方法在语义相同的位置上抽取特征作为细粒度MLP级联分类器的输入
使用步骤
1. 载入头文件
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "face_detection.h"
2 加载人脸识别引擎
seeta::FaceDetection detector(‘seeta_fd_frontal_v1.0’);
3. 设置最小人脸大小
这个根据实际情况调整,图片中,人脸越大,这个值也越大,因为这个值越小,人脸识别速度越慢。
detector.SetMinFaceSize(40);
4. 识别图片中的人脸
std::vector<seeta::FaceInfo> faces = detector.Detect(img_data);
5. 输出人脸识别的结果
人脸左上角坐标
人脸长和宽
faces[i].bbox.x
faces[i].bbox.y
faces[i].bbox.width
faces[i].bbox.height
代码结构
face_detection.cpp
fust.cpp
LoadModel 从模型路径载入模型
Detect
CreateModelReader根据传入的分类类别创建不同的reader
LAB_Boosted_Classifier
LABBoostModelReader
SURF_MLP
SURFMLPModelReader
CreateClassifier 根据传入的分类类别创建不同的分类器
LAB_Boosted_Classifier
LABBoostedClassifier
SURF_MLP
SURFMLP
CreateFeatureMap 根据传入的分类类别创建不同FeatureMap
LAB_Boosted_Classifier
LABFeatureMap
SURF_MLP
SURFFeatureMap
GetWindowData 从输入的图像中获取指定矩形的窗口ROI数据
image_pyramid.cpp 将图像按照一定比例同时缩放宽和高
GetNextScaleImage 根据传入的缩放尺寸缩放图像
SetImage1x 重置图像的缓存空间大小
UpdateBufScaled()
lab_boost_model_reader.cpp
Read
ReadFeatureParam
ReadBaseClassifierParam
surf_mlp_model_reader.cpp
Read
lab_boosted_classifier.cpp
SetWeights
Classify
AddFeature
AddBaseClassifier
lab_feature_map.cpp
Compute
GetStdDev
Reshape
ComputeIntegralImages 计算积分图像
ComputeRectSum
ComputeFeatureMap 计算LAB特征
mlp.cpp
MLPLayer::Compute
MLP::Compute
MLP::AddLayer
nms.cpp
CompareBBox
NonMaximumSuppression
surf_feature_map.cpp
SURFFeaturePool
AddPatchFormat
Create()
AddAllFeaturesToPool
SURFFeatureMap
:Compute
GetFeatureVector
InitFeaturePool
Reshape
ComputeGradientImages
ComputeGradX
ComputeGradY
ComputeIntegralImages
MaskIntegralChannel
Integral
VectorCumAdd
ComputeFeatureVector
NormalizeFeatureVectorL2
surf_mlp.cpp
Classify
AddFeatureByID
AddLayer
FaceAlignment
核心
级联多个栈式自编码器来回归5个特征点(两个眼睛,鼻子,两个嘴角)
CFAN由4个级连的SAN网络构成, 每个都是四层网络,三个隐层, 用sigmoid激活,最后一层为线性激活
第一个全局SAN用于粗定位68个形状特征点
输入为 50x50 的低分辨率图像,即2500个输入单元
中间层分别为1600,900,400个单元
输出为68个形状特征点的位置,即 68x2=136个输出元素
三个局部SAN
输入为68个特征点在高分辨率图中从周围区域提取出来的形状索引特征(SIFT)。
原始输入应该是从每个形状特征点周围提取了128个SIFT特征,即共 68x128=8704个特征。
采用PCA的方法,分别降维到了1695、2418、2440输入元素
中间层分别为1296,784,400个单元
输出仍然为逐步校正后的136个特征位置
提出一种由粗到细的自编码网络(CFAN)来求解从人脸表现到人脸形状的复杂的非线性映射过程
算法步骤
1.直接从人脸的低分辨率中快速估计大致的人脸形状S0
2 提高输入人脸的分辨率,并抽取当前人脸形状S0(相应地提升分辨率)各特征点位置的局部特征
3 输入到下一级自编码网络进一步优化对齐结果
FaceIdentification
核心
采用一个9层CNN(VIPFaceNet)来提取人脸特征
VIPFaceNet由7层CNN+2层全连接组成,修改自AlexNet
优化
将5x5的卷积核拆分为2层3x3卷积核,增加了网络深度,而没有增加计算量
减少了每个卷积层的kernel数目,以及最后一层全连接层神经元数目
引入Fast Normalization Layer加速网络收敛速度,并提升模型泛化能力