一、安装opencv和dlib
我使用的anaconda,安装比较方便。
安装opencv,在指定环境下输入:
conda install opencv
安装dlib:
conda install -c conda-forge dlib
二、实现
1、项目结构介绍
其中face_detect文件夹保存检查到的人脸,face_repo里是待检测的人脸照片,face_test里是用来测试的照片。
2、人脸检测
定义检测器和识别模型:
detector = dlib.get_frontal_face_detector()
# detector = dlib.cnn_face_detection_model_v1('mmod_human_face_detector.dat')
sp = dlib.shape_predictor(FLAGS.shape_predictor)
facerec = dlib.face_recognition_model_v1(FLAGS.reco_model)
detector有两种选择,其中dlib.cnn_face_detection_model_v1使用的cnn进行检测。
对于单张图片的检测如下:
def return_face_features(path_img):
img = cv2.imread(path_img)
if img.shape[0] * img.shape[1] > 400000: # 对大图可以进行压缩,阈值可以自己设置
img = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)
dets = detector(img, 1) # 使用检测算子检测人脸,返回的是所有的检测到的人脸区域
print("检测的人脸图像:", path_img, "\n")
d = dets[0] # 默认处理第一个检测到的人脸区域
bb = np.zeros(4, dtype=np.int32)
bb[0] = np.maximum(d.left(), 0)
bb[1] = np.maximum(d.top(), 0)
bb[2] = np.minimum(d.right(), img.shape[1])
bb[3] = np.minimum(d.bottom(), img.shape[0])
rec = dlib.rectangle(bb[0], bb[1], bb[2], bb[3])
shape = sp(img, rec) # 获取landmark
face_descriptor = facerec.compute_face_descriptor(img, shape) # 使用resNet获取128维的人脸特征向量
face_array = np.array(face_descriptor).reshape((1, 128)) # 转换成numpy中的数据结构
# 显示人脸区域
cv2.rectangle(img, (bb[0], bb[1]), (bb[2], bb[3]), (0, 255, 0), 2)
cv2.waitKey(2)
cropped = img[bb[1]:bb[3], bb[0]:bb[2], :]
scaled = cv2.resize(cropped, (100, 100), interpolation=cv2.INTER_LINEAR)
cv2.imwrite(os.path.join(FLAGS.detected_faces, path_img.split('\\')[-1]), scaled)
cv2.imshow('image', img)
cv2.waitKey(1000)
return face_array
遍历face_repo文件夹下所有人的所有图片,调用上述方法进行检测:
def main():
data = np.zeros((1, 128)) # 定义一个128维的空向量data
label = [] # 定义空的list存放人脸的标签
for file in os.listdir(FLAGS.input_faces): # 遍历目录下的文件夹及文件
path = os.path.join(FLAGS.input_faces, file)
if os.path.isdir(path): # 如果是目录
feature_tmp = np.zeros((1, 128))
label_name = file
img_num = 0
for image in os.listdir(path):
if '.jpg' in image or '.png' in image:
img_num += 1
file_path = os.path.join(path, image)
print('current image: {}, current label: {}'.format(file_path, label_name))
feature_tmp += return_face_features(file_path)
if img_num > 0:
feature = feature_tmp / img_num
data = np.concatenate((data, feature)) # 保存每个人的人脸特征
label.append(label_name) # 保存标签
data = data[1:, :] # 因为data的第一行是128维0向量,所以实际存储的时候从第二行开始
np.savetxt(FLAGS.feature_dir, data, fmt='%f') # 保存人脸特征向量合成的矩阵到本地
label_file = open(FLAGS.label_dir, 'w')
json.dump(label, label_file) # 使用json保存list到本地
label_file.close()
cv2.destroyAllWindows() # 关闭所有的窗口
该过程主要是检测单张图片中的人脸,并保存其人脸特征数据和其label。此时输入的照片中应只有一个人脸,以便将不同人的人脸数据记录下来,作为后续识别对比之用。在这里将检测到的人脸截取并保存到face_detect文件夹中,如下:
选择了五个人,每人各有几张照片,检测区域还可以。
3、人脸识别
对于单张图片的识别过程如下:
def recognition(img):
dets = detector(img, 1)
bb = np.zeros(4, dtype=np.int32)
for k, d in enumerate(dets):
print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
k, d.left(), d.top(), d.right(), d.bottom()))
bb[0] = np.maximum(d.left(), 0)
bb[1] = np.maximum(d.top(), 0)
bb[2] = np.minimum(d.right(), img.shape[1])
bb[3] = np.minimum(d.bottom(), img.shape[0])
rec = dlib.rectangle(bb[0], bb[1], bb[2], bb[3])
shape = sp(img, rec)
face_descriptor = facerec.compute_face_descriptor(img, shape)
class_pre = find_most_likely_face(face_descriptor)
print(class_pre)
cv2.rectangle(img, (rec.left(), rec.top()), (rec.right(), rec.bottom()), (0, 255, 0), 2)
cv2.putText(img, class_pre, (rec.left(), rec.top()), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow('image', img)
cv2.waitKey()
检测图片中的人脸(可以有多个),针对每个人脸,将其和保存的人脸特征数据进行对比,选择距离最小的人脸特征,如果最小距离大于设定阈值,说明该人脸不属于已保存的任何一个人。
我随便找了几张包含刘诗诗和刘亦菲的照片,测试一下识别效果,其中几张结果如下:
测试结果发现效果很一般,尤其对于遮挡和侧脸。
4、可视化
可以使用tensorboard对数据进行可视化
2D效果如下:
图片数据太少,可视化效果不好
代码:https://github.com/buptlj/face
后续会介绍一下基于face_net的人脸识别,那个效果要好很多。