Openface学习(一):使用dlib探测人脸并与模板人脸对齐
学习了开源人脸识别程序Openface的代码。Openface的思路是先将人脸从图像中提取出来,再通过FaceNet,即使用了triplet loss的神经网络将图像分类或者识别。
本篇文章的代码的作用是,使用dlib库将人脸探测、提取的方法集合成类,方便调用。
本篇文章的代码的思路是,在通用模板中的68个人脸标记点的基础上,使用dlib库以及预训练出的参数,确定输入图像的人脸标记点,再使用opencv的内置函数进行仿射变换,得到输出对齐的图像,以便下一步训练时使用。
# 使用dlib进行人脸切割,变换
import cv2
import dlib
import numpy as np
# 这是人脸的特征点,一共68个
TEMPLATE = np.float32([( , )... # 这里填数据 ])
# 下面将人脸的关键点标准化,即寻找人脸在最左侧的点和最上侧的点,作为图像的边缘,
# 其他点以这两个边缘为基准平移;最后除以(最右侧-最左侧)和(最下侧-最上侧)
# 使人脸的标准点均匀地分布在图形里,恰好不丢失特征,也无多余像素。
(TEM_MIN, TEM_MAX) = (np.min(TEMPLATE, axis = 0), np.max(TEMPLATE, axis = 0))
STANDARD_TEMPLATE = (TEMPLATE - TEM_MIN) / (TEM_MAX - TEM_MIN)
class AlignDlib():
INNER_EYES_AND_BOTTOM_LIP = [39, 42, 57] # 用于仿射变换的模板标记点(STANDARD_TEMPLATE)的索引
OUTER_EYES_AND_NOSE = [36, 45, 33]
def __init__(self, FacePredictor):
assert FacePredictor is not None
self.detector = dlib.get_frontal_face_detector() # 默dlib认的脸探测对象
self.predictor = dlib.shape_predictor(FacePredictor) # 根据FacePredictor参数构建预测人脸对象
def getAFBB(self, RgbImg):
# get all face bounding boxes
assert RgbImg is not None
try:
return self.detector(RgbImg, 1) # 探测图像中的人脸一次
except Exception as e:
print("Warning: {}".format(e))
return []
def getLFBB(self, RgbImg, SkipMulti = False):
# get largest face bounding box
# SkipMulti的意思是跳过多个人脸
# 这里有一个疑问:既然对齐脸只用了一次这个函数,而且是内部调用的,
# 跳不跳过多个脸,有什么用呢?
assert RgbImg is not None
faces = self.getAFBB(RgbImg) # 探测图像中所有的脸
if (not SkipMulti and len(faces) > 0) or len(faces) == 1:
return max(faces, key = lambda rect: rect.width() * rect.height())
else:
return None
def findL(self, RgbImg, bb): #寻找实际图像中人脸的标记点
assert RgbImg is not None
assert bb is not None
points = self.predictor(RgbImg, bb)
return list(map(lambda p: (p.x, p.y), points.parts()))
def align(self, ImgDim, RgbImg, bb = None,
landmarks = None, landmark_indices =
INNER_EYES_AND_BOTTOM_LIP,
SkipMulti = False):
assert RgbImg is not None
assert landmark_indices is not None
if ImgDim is None:
ImgDim = 96
if bb is None:
# bb是已经裁剪过的人脸,是一个矩形
bb = self.getLFBB(RgbImg, SkipMulti)
if bb is None:
return
if landmarks is None:
landmarks = self.findL(RgbImg, bb)
np_landmarks = np.float32(landmarks) # 转成numpy的类型
np_landmark_indices = np.array(landmark_indices)
H = cv2.getAffineTransform(np_landmarks[
np_landmark_indices], ImgDim *
STANDARD_TEMPLATE[
np_landmark_indices]) # 这是opencv自带的获得仿射变换矩阵的函数
thumb_nail = cv2.warpAffine(RgbImg, H, (ImgDim, ImgDim)) # 这是执行仿射变换,最后图像和模板标记点对齐
return thumb_nail # 得到对齐的图像