写在前面
本文利用python中的face_recognition库进行人脸识别,该库需要调用dlib库,安装过程可参考其他博客。关于face_recognition库的介绍和案例,可参考该链接内容https://github.com/ageitgey/face_recognition.本文的代码也是根据其中的一个例子稍作改动而来。
注意:请使用python3.6版本运行此程序我开始使用python3.7在打包过程中遇到了无法解决的问题,换成python3.6便可成功打包运行。python3.6对于人脸识别比较友好。打包的相关注意事项在后面的文章中会提到。
本文基于上文的github中的examples文件夹中的facerec_from_webcam_faster.py文件改动而来。开始使用运用了多线程的facerec_from_webcam_multiprocessing.py,但是在打包后出现了内存一直增长但是摄像头窗口不出现的问题,一直没找到解决办法,在此希望有大佬可以解答一下。
程序
其中,face_dataset文件夹存放人脸图片并以人名命名(opencv显示摄像头窗口及名字,内置方法无法显示中文名字,人名须是英文或拼音),该程序先将图片的名字(i.e.人名)及face_recognition中face_encoding方法生成的128维向量存储为json文件格式(另外也写了一个sqlite3保存的),在摄像头识别时读取json文件中的向量与摄像头读取的向量进行比较。
pic2json.py
### pic2json.py
import face_recognition
import os
import json
import numpy as np
def read_files(path, file_types):
filenames = os.listdir(path)
filenames1 = []
for file_type in file_types:
for filename in filenames:
if os.path.splitext(filename)[1] == file_type:
filenames1.append(filename)
return filenames1
path = './face_dataset/' # 人脸图片数据库路径
def load_pic():
pic = read_files(path, ['.jpg', '.JPG', '.png'])
pic_name = [name.strip('.jpg') for name in pic]
pic_name = [name.strip('.JPG') for name in pic_name]
pic_name = [name.strip('.png') for name in pic_name] # 获取去掉后缀的图片名称
image_encoding = []
for i in range(len(pic)):
temp = face_recognition.load_image_file(path + pic[i])
face_encoding = face_recognition.face_encodings(temp)[0]
image_encoding.append(face_encoding)
return pic_name, image_encoding
# 将 人名 和 编码生成的128维向量 导入json文件
pic_name, image_encoding = load_pic()
face_dic = dict(map(lambda x, y: [x, y], pic_name, image_encoding))
class NpEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(NpEncoder, self).default(obj)
json_face = json.dumps(face_dic, cls=NpEncoder)
fileObject = open('./faceDataset.json', 'w')
fileObject.write(json_face)
print("json file has been successfully written")
read_json.py
### read_json.py
import json
import numpy as np
def load_json():
with open("./faceDataset.json", 'r') as f:
face_dict = json.load(f)
# print(face_dict)
pic_name = list(face_dict.keys())
image_encoding_temp = list(face_dict.values())
image_encoding = []
for i in range(len(image_encoding_temp)):
temp = np.array(image_encoding_temp[i])
image_encoding.append(temp)
return image_encoding, pic_name
facerec_from_webcam_faster.py
### facerec_from_webcam_faster.py
import face_recognition
import cv2
import numpy as np
from read_json import load_json
# Get a reference to webcam #0 (the default one)
video_capture = cv2.VideoCapture(0)
video_capture.set(3, 1080.0)
known_face_encodings, known_face_names = load_json()
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True
while True:
# Grab a single frame of video
ret, frame = video_capture.read()
# Resize frame of video to 1/4 size for faster face recognition processing
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
# Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)
rgb_small_frame = small_frame[:, :, ::-1]
# Only process every other frame of video to save time
if process_this_frame:
# Find all the faces and face encodings in the current frame of video
face_locations = face_recognition.face_locations(rgb_small_frame)
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
face_names = []
for face_encoding in face_encodings:
# See if the face is a match for the known face(s)
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Unknown"
# # If a match was found in known_face_encodings, just use the first one.
# if True in matches:
# first_match_index = matches.index(True)
# name = known_face_names[first_match_index]
# Or instead, use the known face with the smallest distance to the new face
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
name = known_face_names[best_match_index]
face_names.append(name)
process_this_frame = not process_this_frame
# Display the results
for (top, right, bottom, left), name in zip(face_locations, face_names):
# Scale back up face locations since the frame we detected in was scaled to 1/4 size
top *= 4
right *= 4
bottom *= 4
left *= 4
# Draw a box around the face
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
# Draw a label with a name below the face
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)
# Display the resulting image
cv2.imshow('Video', frame)
k = cv2.waitKey(1)
# 点击右上角叉叉关闭摄像头窗口
if cv2.getWindowProperty('Video', cv2.WND_PROP_AUTOSIZE) < 1:
break
if k == 27:
break
# Release handle to the webcam
video_capture.release()
cv2.destroyAllWindows()
打包
利用pyinstaller打包,pyinstaller 可以将程序打包成一个exe文件也可以打包成一个文件夹的形式。这里使用后者。由于face_recognition中有4个模块无法自动打包,需要修改spec文件手动加入,pyinstaller打包会先生成spec文件,在根据spec文件进行相关操作,可以在spec文件中手动加入打包的东西和图标等相关操作,具体可参考https://pyinstaller.readthedocs.io/en/stable/.
在主程序文件夹下终端输入
>pyinstaller facerec_from_webcam_faster.py
文件夹会生成一个dist文件夹、一个build文件夹、一个spec文件,只保留spec文件,其他删除,打开spec文件,改成如下形式,路径要改一下(或者写一个text文件改后缀也行)
# -*- mode: python ; coding: utf-8 -*-
import sys
sys.setrecursionlimit(1000000)
block_cipher = None
face_models = [
('.\\face_recognition_models\\models\\dlib_face_recognition_resnet_model_v1.dat', './face_recognition_models/models'),
('.\\face_recognition_models\\models\\mmod_human_face_detector.dat', './face_recognition_models/models'),
('.\\face_recognition_models\\models\\shape_predictor_5_face_landmarks.dat', './face_recognition_models/models'),
('.\\face_recognition_models\\models\\shape_predictor_68_face_landmarks.dat', './face_recognition_models/models'),
] # 手动打包的face_recognition模块,自己改路径,或者把face_recognition_models拖到当前文件夹下,这几行就不用改了
face_dataset=[
('./faceDataset.json','./')
] # 手动把json文件打包
a = Analysis(['facerec_from_webcam_faster.py'], # 打包文件
pathex=['F:\\PychamProject\\FaceRecognition_json'], # 打包文件路径
binaries=face_models, # 这里
datas=face_dataset, # 这里
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='facerec_from_webcam_faster',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
icon = 'icon.ico' # 图标 )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='facerec_from_webcam_faster')
然后在spec文件路径下的终端输入
> pyinstaller facerec_from_webcam_faster.spec
搞定!