在上一篇的工作基础上,检测到人脸的关键点,并利用这些关键点组成一个区域,对区域外的背景置0;
话不多说,先上代码:
if __name__=='__main__':
path = 'res/00014206.jpg'
img = io.imread(path)
region = get_landmarks(img)
print img.shape
shape = list(img.shape) + [3] # 将图像转化为列表,便于访问
img1 = img.copy()
for i in xrange(shape[0]):
for j in xrange(shape[1]):
if not inside(j, i, region):
img1[i, j] = (0, 0, 0)
win.set_image(img1)
用imread读取图片后,调用get_landmarks(img)获取我们所要的人脸区域,代码如下:
def get_landmarks(img):
dets = detector(img, 1)
landmarks = np.zeros((19,2))
for k, d in enumerate(dets):
shape = predictor(img, d)
for i in range(17):
landmarks[i] = (shape.part(i).x, shape.part(i).y)
landmarks[17] = (shape.part(24).x, shape.part(24).y - 20)
landmarks[18] = (shape.part(19).x, shape.part(19).y - 20)
return landmarks
这里不需要之前dlib所有的68个关键点,重新构建了一个landmarks矩阵,存储脸颊17个点和眉毛2个中间点,总共19个关键点; 注意这里landmarks 要用 np.zeros((19,2))来创建;
为了后面访问landmarks的边,这里需要将19,24两个眉毛的位置调一下位置,放入landmarks中17,18两个位置。
获取完关键点后,复制图片img1 = img.copy(),img1用于获取我们所需的目标图片。遍历图片img1,用inside(j, i, region)判断不在关键点区域内的点(注意这里由于shape[0]和shape[1]的问题,调用inside()函数时需要将i,j顺序变换一下),将这些点的像素置0(img1[i, j] = (0, 0, 0));
inside(j, i, region)函数如下:
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
这个函数网上有很多解释,边的遍历顺序为(18->0->1->2->3->4->5->6->7->8->9->10->11->12->13->14->15->16->17->18)。
下面是背景区域去除后的效果: