基于mtcnn人脸检测+dlib人脸特征提取
前言本文主要是记录项目过程,主要的流程如下:1.传入视频流使用mtcnn人脸检测,将人脸区域裁剪出来并且保存。2.利用拉普拉斯算子去掉保存的图片中模糊的图片。3.利用dlib库中人脸特征提取的算法提取人脸特征,并且利用聚类去除重复人脸。准备工作Conda 是一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖关系,并在它们之间轻松切换。 Conda 是为 Pytho...
前言
本文主要是记录项目过程,主要的流程如下:
1.传入视频流使用mtcnn人脸检测,将人脸区域裁剪出来并且保存。
2.利用拉普拉斯算子去掉保存的图片中模糊的图片。
3.利用dlib库中人脸特征提取的算法提取人脸特征,并且利用聚类去除重复人脸。
准备工作
Conda 是一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖关系,并在它们之间轻松切换。 Conda 是为 Python 程序创建的,适用于 Linux,OS X 和Windows,也可以打包和分发其他软件。
1.利用conda安装相关库
pip install opencv-python
pip install facenet_recogonition#这里是pip社区中人脸识别库,里面自带dlib库
pip install tensorflow-gpu==1.15.0#我使用的版本
pip install numpy==1.16.2#这边我使用高版本的会报错所以使用这个
pip install pillow
#其他缺什么就下什么
2.在git上下载facenet
git clone https://github.com/davidsandberg/facenet
3.项目结构
align:这个文件夹是从facenet中拷贝的,https://github.com/davidsandberg/facenet/tree/master/src/align,主要是MTCNN人脸检测的相关文件
dataset:这个文件夹是用来存放图片,视频相关文件。
model:存放了dlib提取特征的模型。
1.第一阶段(mtcnn检测人脸)
人脸检测方法很多,如Dilb,OpenCV,OpenFace人脸检测等等,这里使用MTCNN进行人脸检测,一方面是因为其检测精度确实不错,另一方面facenet工程中,已经提供了用于人脸检测的mtcnn接口。 MTCNN是多任务级联CNN的人脸检测深度学习模型,该模型中综合考虑了人脸边框回归和面部关键点检测。它的参数模型也保存在align文件夹下,分别是det1.npy,det2.npy,det3.npy
1.1 捕捉视频流
首先,利用文件夹中Video_capture.py用来录制一段视频(包含人脸)保存至dataset/output文件夹中。
import cv2
cap = cv2.VideoCapture(0) # 打开相机
# 创建VideoWriter类对象
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('./dataset/video/output.avi', fourcc, 20 , (640, 480))
while (True):
ret, frame = cap.read() # 捕获一帧图像
out.write(frame) # 保存帧
cv2.imshow('frame', frame) # 显示帧
# 判断按键,如果按键为q,退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release() # 关闭相机
out.release()
cv2.destroyAllWindows() # 关闭窗口
1.2 将视频文件转换为图片格式
#Face_rect.py文件中
def Video_capture(video):
i=1
k=1
#打开摄像头||打开视频
cap = cv2.VideoCapture(video)
#视频帧计数间隔频率
timeF =20
while (True):
# 读取摄像头的每一帧图片
ret, frame = cap.read()
# 显示摄像头
#cv2.imshow('frame', frame)
if ret:
#保存成jpg格式
if(i%timeF==0):
cv2.imwrite("./dataset/images/" + str(k) + ".jpg", frame)
k=k+1
i = i+1
else:
break
# 当处理完成释放摄像头捕获
cap.release()
cv2.destroyAllWindows()
1.3 检测人脸并且裁剪出人脸区域
人脸检测使用mtcnn检测,也可以使用face_regoconition中的HOG或者CNN。
#Face_rect.py文件中
def detection_face(path):
# 这里引用facenet/src/align/align_dataset_mtcnn.py文件的代码对采集帧进行人脸检测和对齐
minsize = 20 # minimum size of face
threshold = [0.6, 0.7, 0.7] # three steps's threshold
factor = 0.709 # scale factor
with tf.Graph().as_default():
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.5)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))
#sess = tf.Session()
with sess.as_default():
pnet, rnet, onet = detect_face.create_mtcnn(sess, None)
image_path = gb.glob(path)
j=1
for path in image_path:
# 读取images文件夹中的图片
image = face_recognition.load_image_file(path)
# 使用默认的HOG模型找到所有包含脸的图片
#face_locations = face_recognition.face_locations(image)
# 使用cnn
#face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=0, model="cnn")
#使用align中mtcnn检测人脸
face_locations,_ = detect_face.detect_face(image,minsize,pnet,rnet,onet,threshold, factor)
print("I found {} face(s) in this photograph.".format(len(face_locations)))
for face_location in face_locations:
# 显示每一张脸在图片中的位置
top = int(face_location[1])
right = int(face_location[2])
bottom = int(face_location[3])
left = int(face_location[0])
#top, right, bottom, left = face_location
#print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
#更改人脸框的位置
h=(bottom-top)//4
w=(right-left)//4
try:
# 显示找到的人脸图片
face_image = image[(top-h):(bottom+h), (left-w):(right+w)]
pil_image = Image.fromarray(face_image)
except Exception as e:
print("could not save:",e)
# pil_image.show()
# 保存识别出来的人脸图片
pil_image.save("./dataset/images_result/" + "%f"%time.time() + ".jpg")
j=j+1
2. 第二阶段(去模糊图片)
有两种思路:
1.首先对输入的图片进行快速傅里叶变换操作;然后检测图片中高频分量和低频分量的分布情况;接着根据图片中包含的高频分量的多少进行合适的判断,如果图片中含有较少的高频分量,则表明该图片是模糊图片,否则是清晰图片。
2.即根据Laplacian变换的方差值进行判断。
这里选择第二种方式:
#image_process.py文件中
def variance_of_laplacian(image):
'''
计算图像的laplacian响应的方差值
'''
return cv2.Laplacian(image, cv2.CV_64F).var()
def compute_blurry(image_path,threshold):
i=0
path=gb.glob(image_path)
# 遍历每一张图片
for imagePath in path:
# 读取图片
image = cv2.imread(imagePath)
# 将图片转换为灰度图片
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 计算灰度图片的方差
fm = image_process.variance_of_laplacian(gray)
# 设置输出的文字
if fm < threshold:
os.remove(imagePath)
i=i+1
# 显示结果
print(" Deleted blurry images:",i,"s")
第三阶段人脸聚类
人脸聚类使用了dlib的人脸检测和特征点检测
import sys
import os
import dlib
import glob
import cv2
import time
# 指定路径
current_path = os.getcwd()
model_path = current_path + '/models/'
shape_predictor_model = model_path + '/shape_predictor_5_face_landmarks.dat'
face_rec_model = model_path + '/dlib_face_recognition_resnet_model_v1.dat'
face_folder = current_path + '/dataset/images_result/'
output_folder = current_path + '/dataset/output/'
# 导入模型
detector = dlib.get_frontal_face_detector()
shape_detector = dlib.shape_predictor(shape_predictor_model)
face_recognizer = dlib.face_recognition_model_v1(face_rec_model)
# 为后面操作方便,建了几个列表
descriptors = []
images = []
# 遍历faces文件夹中所有的图片
for f in glob.glob(os.path.join(face_folder, "*.jpg")):
print('Processing file:{}'.format(f))
# 读取图片
img = cv2.imread(f)
# 转换到rgb颜色空间
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 检测人脸
dets = detector(img2, 1)
print("Number of faces detected: {}".format(len(dets)))
# 遍历所有的人脸
for index, face in enumerate(dets):
# 检测人脸特征点
shape = shape_detector(img2, face)
# 投影到128D
face_descriptor = face_recognizer.compute_face_descriptor(img2, shape)
# 保存相关信息
descriptors.append(face_descriptor)
images.append((img2, shape))
# 聚类
labels = dlib.chinese_whispers_clustering(descriptors, 0.5)
print("labels: {}".format(labels))
num_classes = len(set(labels))
print("Number of clusters: {}".format(num_classes))
# 为了方便操作,用字典类型保存
face_dict = {}
for i in range(num_classes):
face_dict[i] = []
# print face_dict
for i in range(len(labels)):
face_dict[labels[i]].append(images[i])
#print (face_dict.keys())
# 遍历字典,保存结果
for key in face_dict.keys():
file_dir = os.path.join(output_folder)
if not os.path.isdir(file_dir):
os.makedirs(file_dir)
for index, (image, shape) in enumerate(face_dict[key]):
if index==0:
#file_path = os.path.join(file_dir, 'face_' + str(index))
#print (file_path)
dlib.save_face_chip(image, shape, file_dir+"%f"%time.time(), size=150, padding=0.25)
使用该方法发现效果不是特别理想,最终采用求取特征值然后计算每两张人脸之间的距离删除小于0.5的
#image_process.py文件中
def detect_faces_in_image(file_stream1, file_stream2):
try:
#提取图片中人脸的特征值
code1 = face_recognition.face_encodings(face_recognition.load_image_file(file_stream1))[0]
#print(code1)
code2 = face_recognition.face_encodings(face_recognition.load_image_file(file_stream2))[0]
#比较人脸特征值
if len(code1) > 0 and len(code2) > 0:
match_results = face_recognition.face_distance([code1], code2)
score=match_results[0]
return score
except Exception as d:
print("face detection error :",d)
def repeat_remove(image_path):
path=gb.glob(image_path)
imagepath=[]
l=0
for i in path:
imagepath.append(i)
try:
for j in range(0,len(imagepath)):
for k in range(j+1,len(imagepath)):
score=detect_faces_in_image(imagepath[j],imagepath[k])
try:
if score < 0.5:
os.remove(imagepath[k])
l=l+1
print(imagepath)
except Exception as c:
print("not a number :",c)
print("delete repetitive images:" ,l)
except Exception as e:
print("error :",e)
第四阶段测试
if __name__=="__main__":
videos = gb.glob("./dataset/video/*.*") # 得到文件夹下的所有文件名称
try:
for file in videos:
Video_capture(file)
detection_face("./dataset/images/*.jpg")
image_process.image_process.compute_blurry("./dataset/images_result/*.jpg",100)
#image_process.repeat_remove("./dataset/images_result/*.jpg")
#move_file("./dataset/images_result/", "./dataset/save/")
#os.remove(file)
except Exception as e:
print("No Videa file:",e)
更多推荐
所有评论(0)