python实现人脸识别抓取人脸并做成熊猫头表情包(2)之优化

上次做完python实现人脸识别抓取人脸并做成熊猫头表情包之后就放了一下,因为还要好好学习Springboot毕竟这才是找工作的硬实力。但是优化这个代码心里面一直很想,借用《clean code》的话来说就是“Bad code tempts the mess to grow! ”所以优化是必要的。 
这里我优化了两个地方,第一个是掩膜的生成,第二个是表情位置的自动获取,同时也拆分一部分代码,和修改了一些注释,让代码看起来更简洁和已读。 
第一个是掩膜的生成。修改之前是这样的

#新建一个和原图一样大小的全白图片,用ImageDraw在上面勾出人脸轮廓,作为掩膜的模板
mask = np.ones(image.shape, dtype=np.uint8)*255
mask = Image.fromarray(mask)
q = ImageDraw.Draw(mask)
q.line(face_line[0], width=5, fill=(0, 0, 0))
mask.save(r"image/mask.jpg")#将图片写出是为了交给OpenCV处理
1
2
3
4
5
6
经过改动,包括让掩膜容纳更多脸以及将初始掩膜做成全黑

#新建一个和原图一样大小的全黑图片,用ImageDraw在上面勾出人脸轮廓,作为掩膜的模板
mask = np.zeros(image.shape, dtype=np.uint8)
mask = Image.fromarray(mask)
q = ImageDraw.Draw(mask)
for i in face_line:
    q.line(i, width=5, fill=(255, 255, 255))
mask.save(r"rbq/mask.jpg")#将图片写出是为了交给OpenCV处理
1
2
3
4
5
6
7
这里之所以将初始掩膜做成全黑是因为后面需要做一次水漫填充将非ROI区域变成全白,如果初始掩膜做成全白的话到提取表情的时候仍然需要再做一次水漫填充,这样子非常影响性能,本身python的运行速度就很慢。 
第二个是自动抓取表情的位置,这个相对之前的代码属于新增的功能,之前的代码需要自己手动调整截取位置以及熊猫头被替换的部分,正常来说是需要调整很多次才能得到。 
这里先定义几个函数

#获取脸部最高点
def the_top(x_list):
    return sorted(x_list, key=lambda x: x[1])

#获取脸部最低点
def the_bottom(x_list):
    return sorted(x_list, key=lambda x: x[1], reverse=True)

#获取脸部最左点
def the_left(y_list):
    return sorted(y_list, key=lambda y: y[0])

#获取脸部最右点
def the_right(y_list):
    return sorted(y_list, key=lambda y: y[0], reverse=True)

#计算正方形左上角和右下角的点
#表情位置用正方形把它截下来
def square(face_point):
    centre, top, bottom, left, right = face_point['centre'], face_point['top'], face_point['bottom'], face_point['left'], face_point['right']
    #用眉毛以及下巴作为选框参照
    # side = ((centre[1] - top[1]) if ((centre[1] - top[1]) > (bottom[1] - centre[1])) else (bottom[1] - centre[1]))
    #用左右轮廓作为选框参照
    side = ((centre[0] - left[0]) if ((centre[0] - left[0]) < (right[0] - centre[0])) else (right[0] - centre[0]))
    return (centre[0] - side, centre[1] - side), (centre[0] + side, centre[1] + side)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
这时候我在生成脸部轮廓的时候我把计算截取范围一并做了,这里我选择了鼻尖(鼻梁nose_bridge 的最后一个点)作为脸的中心


face_line = list()#用于记录脸部轮廓
face_point = list()#用于记录图片需要截取的范围
face = list()#用于记录脸

for face_landmarks in face_landmarks_list:

    #找出每张脸的轮廓用于生成掩膜
    chin = face_landmarks['chin']
    left_eyebrow = face_landmarks['left_eyebrow']
    right_eyebrow = face_landmarks['right_eyebrow']
    nose_bridge = face_landmarks['nose_bridge']
    chin.reverse()
    list_all = left_eyebrow + right_eyebrow + chin + [left_eyebrow[0]]
    face_line.append(list_all)

    #找到每张脸最左端点,最右端点,最高点,最低点以及中心,用于最大限度截取表情
    face_five_point = {'centre': nose_bridge[len(nose_bridge)-1],
                       'top': the_top(left_eyebrow + right_eyebrow)[0],
                       'bottom': the_bottom(chin)[0],
                       'left': the_left(chin)[0],
                       'right': the_right(chin)[0]
                       }
    start, end = square(face_five_point)
    face_point.append((start[0], start[1], end[0], end[1]))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
这时候你就会发现,如果我们将表情二值化之前把表情截取下来的话处理的python处理速度会提上去,这是因为需要处理的图片的范围小了。同时也不需要在做很多次膨胀腐蚀了,因为膨胀腐蚀的目的就是为了消除噪声,而提前截取了表情后,噪声的影响也就不太难以忍受了。 
这里为了保证表情包的效果,我添加了一个锐化图像的函数

#锐化函数
def custom_blur_demo(image):
    kernel1 = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) 
    dst = cv2.filter2D(image, -1, kernel=kernel1)
    return dst
1
2
3
4
5
这里放一下效果图。(掩膜和遮挡操作过后会有大片空白,可能会造成阅读不太方便,先道个歉) 
原图(用了基友的表情这次就不打码了,用这个图是因为这图里面有两个脸可以被识别,这样刚好用来做批量生产表情包) 

然后是掩膜和掩膜遮挡原图得到的图(这两张图做成GIF超级有趣) 


接着就是二值化,让表情变成黑白 

这里就是记录图片需要截取的范围的作用了,把脸直接粗暴地截下来 
第一张 
 
第二张 
 
最后就是把表情和熊猫头的合成 
 
 
至此,用人脸识别抓取人脸然后做成表情包的第一阶段的优化就做完了,基本上实现了自动化获取表情并生成表情包的功能。现在如果想拿很多丑照批量生产表情包应该是没问题的。但是感觉图片处理得还是不太够,锐化处理也帮不了太多忙,以后再说吧,虽然《clean code》说的是“ Later equals never.”
--------------------- 
作者:QuantumEntanglement 
来源:CSDN 
原文:https://blog.csdn.net/QuantumEntanglement/article/details/81639755 
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(机器学习,人脸检测)