人脸关键点去背景实现
在人脸识别或者活体检测中,可以利用关键点信息对人脸进行去背景,然后再做检测和识别,会提高准确率。
关键点检测可以利用dlib或者自己的关键点检测模型来实现,这里不过多介绍。
实现过程分两个步骤:
(1)对图片进行68个关键点检测,找到轮廓的17个关键点,再结合左右眉毛最上端的两个关键点找到最左上、右上这两个点的坐标,一共19个,按顺序连起来,组成了一个新的区域D。代码如下:
# get outline landmarks
def get_outline_landmarks(landmarks, xy, zz):
# outline include 19 landmarks
shape_landmarks = np.zeros((19, 2))
for i in range(17):
shape_landmarks[i][0] = landmarks[i][0] - xy[0]
shape_landmarks[i][1] = landmarks[i][1] - xy[1]
shape_landmarks[17] = zz[0] - xy[0], xy[1] - xy[1]
shape_landmarks[18] = xy[0] - xy[0], xy[1] - xy[1]
return shape_landmarks
(2)然后遍历每一个像素点,判断该像素点是否在区域 D内,如果不在区域内就把像素点置0。怎么判断像素点是否在区域内呢,其实有一种算法叫射线法,大家可以去看一下。实现代码:
# 获取关键点轮廓坐标
# 参数:landmarks 为68个关键点的坐标 参数:xy 关键点的最小值坐标 参数zz:关键点的最大值坐标
outline = get_outline_landmarks(landmarks, xy, zz)
# 判断单个像素点是否在区域Region内,返回一个True或False
def inside(X, Y, Region):
j = len(Region) - 1
flag = False
for i in range(len(Region)):
if ((Region[i][1] < Y and Region[j][1] >= Y) or (Region[j][1] < Y and Region[i][1] >= Y)):
if (Region[i][0] + (Y - Region[i][1]) / (Region[j][1] - Region[i][1]) * (Region[j][0] - Region[i][0]) < X):
flag = not flag
j = i
return flag
# 遍历每个像素点
for i in range(region_y2-region_y1):
for j in range(region_x2-region_x1):
if not inside(j, i, outline):
# outside pixels value set to 0
landmark_region[i, j] = (0, 0, 0)
去背景前后的效果对照图:
改进:这种方法虽然实现了人脸去背景,但是特别耗时,时间复杂度为O(n^3),在pc上运行这个算法也要几百ms。几经研究发现可以使用opencv来实现去背景。前面人脸轮廓关键点的操作都一样,先连成一个区域,然后在使用opencv的cv2.polylines 函数来实现多边形抠图。
效果:原来的几百ms变为了0.2ms,算法速度有了极大的提高。