0. 引言
利用 Python 开发,借助 Dlib 库进行人脸检测 / face detection 和剪切;
将检测到的人脸剪切下来,依次排序平铺显示在新的图像上;
实现的效果如 图1 所示,将 图1 原图中的 6 张人脸检测出来,然后剪切下来,在图像窗口中依次输出显示人脸;
将检测到的人脸存储为单个人脸图像;
图 1 原图 和crop_faces_show.py处理后得到的平铺人脸图像窗口
图 2 crop_faces_save.py处理后得到的多个单张人脸图像文件
源码上传到了我的 Github;
1.开发环境
Python:3.6.3
Dlib: 19.7
OpenCv, NumPy
import dlib #人脸检测的库 Dlib
import numpy as np #数据处理的库 numpy
import cv2 #图像处理的库 OpenCv
2. 实现过程
工作内容主要以下两大块:Dlib 人脸检测和处理检测到的人脸图像
2.1 Dlib 人脸检测
利用已经训练好的 Dlib 正向人脸检测器detector = dlib.get_frontal_face_detector()进行人脸检测;
可以得到人脸外接矩形的坐标,用来之后进行裁剪;
具体 Dlib 的使用,请参考我另一篇博客;
1 #Dlib 检测器
2 detector =dlib.get_frontal_face_detector()3
4 #读取图像
5 path = "/***/image_path/"
6 img = cv2.imread(path+"test_faces.jpg")7 #print("img/shape:", img.shape)
8
9 #Dlib 检测
10 faces = detector(img, 1)11
12 print("人脸数:", len(faces))
2.2绘制新图像
如果你想让检测出来的人脸并排显示的话,需要遍历两次( for k, d in enumerate (faces) ):
第一次遍历:记录下我们需要生成的图像窗口的大小,因为需要将多张照片显示在一张图像上,所以需要知道每张人脸照片的大小;
第二次遍历:根据之前得到的图像尺寸新建空白图像,然后开始用人脸矩形填充图像;
2.2.1 确定空白图像尺寸
( 这部分首先要根据检测到的人脸数和人脸大小,来确定绘制图像所需要的尺寸)
第一次遍历:多张人脸要输出到一行,所以先进行一次人脸的遍历j记下每张人脸的大小,记每张人脸的尺寸为 [高度 height * 宽度 width ](高度和宽度说明见 图 3 ):
图 3 图像尺寸说明
我取的生成空白图像的尺寸:height_max(最大高度)和 width_sum(宽度之和),然后根据尺寸大小来新建空白图像:
img_blank = np.zeros((height_max, width_sum, 3), np.uint8)
图 4 图像尺寸 height_max 和 width_sum
2.2.2 图像填充
第二次遍历:多根据之前得到的图像尺寸新建空白图像,然后开始用人脸矩形填充图像,每次 width 方向从 blank_start 位置开始,每次填完一张之后记得更新起始位置:( blank_start += width ):
for i inrange(height): for j inrange(width): img_blank[i][blank_start + j] = img[d.top() + i][d.left() + j]
如果想访问图像的某点像素,可以利用 img [height] [width]:
存储像素其实是一个三维数组,先高度 height,然后宽度 width;
返回的是一个颜色数组(0-255,0-255,0-255),按照(B, G, R)的顺序;
比如蓝色就是(255,0,0),红色是(0,0,255);
3. 源码
3.1crop_faces_show.py
#created at -01-22#updated at -09-29
#Author: coneypo#Blog: /AdaminXie#GitHub: /coneypo/Dlib_face_cut
import dlib #人脸识别的库dlib
import numpy as np #数据处理的库numpy
import cv2 #图像处理的库OpenCv
#Dlib 检测器
detector =dlib.get_frontal_face_detector()
predictor= dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')#读取图像
path = "faces_for_test/"img= cv2.imread(path+"test_faces_1.jpg")#Dlib 检测
dets = detector(img, 1)print("人脸数:", len(dets), "\n")#记录人脸矩阵大小
height_max =0
width_sum=0#计算要生成的图像 img_blank 大小
for k, d inenumerate(dets):#计算矩形大小
#(x,y), (宽度width, 高度height)
pos_start =tuple([d.left(), d.top()])
pos_end=tuple([d.right(), d.bottom()])#计算矩形框大小
height = d.bottom()-d.top()
width= d.right()-d.left()#处理宽度
width_sum +=width#处理高度
if height >height_max:
height_max=heightelse:
height_max=height_max#绘制用来显示人脸的图像的大小
print("窗口大小:",'\n', "高度 / height:", height_max
,'\n', "宽度 / width:", width_sum)#生成用来显示的图像
img_blank = np.zeros((height_max, width_sum, 3), np.uint8)#记录每次开始写入人脸像素的宽度位置
blank_start =0#将人脸填充到img_blank
for k, d inenumerate(dets):
height= d.bottom()-d.top()
width= d.right()-d.left()#填充
for i inrange(height):for j inrange(width):
img_blank[i][blank_start+j] = img[d.top()+i][d.left()+j]#调整图像
blank_start +=width
cv2.namedWindow("img_faces")#, 2)
cv2.imshow("img_faces", img_blank)
cv2.waitKey(0
实现效果:
图 5 原图和处理后得到的图像窗口
3.2 crop_faces_save.py
如果你想将识别出来的人脸保存成单个的图像,方便之后处理用,只需将上述代码进行略微修改;
只需一次遍历,根据每次检测到的人脸尺寸,新建空白图像后写入,然后利用 cv2.imwrite 写入到本地:
crop_faces_save.py:
1 #created at -01-22
2 #updated at -09-29
3
4 #Author: coneypo
5 #Blog: /AdaminXie
6 #GitHub: /coneypo/Dlib_face_cut
7
8 import dlib #人脸识别的库dlib
9 import numpy as np #数据处理的库numpy
10 import cv2 #图像处理的库OpenCv
11 importos12
13 #读取图像的路径
14 path_read = "faces_for_test/"
15 img = cv2.imread(path_read+"test_faces_3.jpg")16
17 #用来存储生成的单张人脸的路径
18 path_save = "faces_separated/"
19
20
21 #Delete old images
22 defclear_images():23 imgs =os.listdir(path_save)24
25 for img inimgs:26 os.remove(path_save +img)27
28 print("clean finish", '\n')29
30
31 clear_images()32
33
34 #Dlib 预测器
35 detector =dlib.get_frontal_face_detector()36 predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')37
38
39 #Dlib 检测
40 faces = detector(img, 1)41
42 print("人脸数:", len(faces), '\n')43
44 for k, d inenumerate(faces):45
46 #计算矩形大小
47 #(x,y), (宽度width, 高度height)
48 pos_start =tuple([d.left(), d.top()])49 pos_end =tuple([d.right(), d.bottom()])50
51 #计算矩形框大小
52 height = d.bottom()-d.top()53 width = d.right()-d.left()54
55 #根据人脸大小生成空的图像
56 img_blank = np.zeros((height, width, 3), np.uint8)57
58 for i inrange(height):59 for j inrange(width):60 img_blank[i][j] = img[d.top()+i][d.left()+j]61
62 #cv2.imshow("face_"+str(k+1), img_blank)
63
64 #存在本地
65 print("Save to:", path_save+"img_face_"+str(k+1)+".jpg")66 cv2.imwrite(path_save+"img_face_"+str(k+1)+".jpg", img_blank)
图 6 生成的单个人脸图像文件