基于Python_opencv人脸录入识别系统(应用dlib机器学习库)
Posted Svan.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Python_opencv人脸录入识别系统(应用dlib机器学习库)相关的知识,希望对你有一定的参考价值。
基于python_opencv人脸录入、识别系统(应用dlib机器学习库)
近几年应用opencv机器学习方法识别人脸的技术成为了热潮,本人根据当今的识别技术与方法,历时四个多月开发出一套基于dlib机器学习库的识别项目。希望大家能一起交流学习。
项目英文名:Face recognition from camera with Dlib
文章目录
1、项目功能介绍
- Tkinter 人脸录入界面, 支持录入时设置 (中文) 姓名;
- 调用摄像头进行人脸识别, 支持多张人脸同时识别;
- 定制显示名字, 可以写中文;
2、项目运行截图
下面直接上运行截图:
GUI界面运行结果: UI界面可以录入使用者的信息,并设置保存录入图片按钮
初次录入界面:
距离摄像头太近或太远会有提示:
中文识别界面运行结果: 识别信息包括开始录入时设置的名字,以及镜头下识别的人数
支持多人识别:
3、项目流程图
项目的流程图如下:
4、项目源码结构及模块化介绍(需要源码的朋友关注并私信我)
项目源码的结构如下:
- get_faces_from_camera_tkinter.py:进行人脸信息采集录入, Tkinter GUI
- get_face_from_camera.py:进行人脸信息采集录入, OpenCV GUI
- features_extraction_to_csv.py:提取所有录入人脸数据存入
features_all.csv
- face_reco_from_camera.py:调用摄像头进行实时人脸识别
- face_reco_from_camera_single_face.py:对于人脸数<=1, 调用摄像头进行实时人脸识别
- face_reco_from_camera_ot.py:利用 OT 算法, 调用摄像头进行实时人脸识别
Python详细源码模块化介绍:
人脸信息采集录入模块(get_face_from_camera.py):
- 请注意存储人脸图片时, 矩形框不要超出摄像头范围, 要不然无法保存到本地;
- 超出会有 “out of range” 的提醒;
class Face_Register:
def __init__(self):
self.path_photos_from_camera = "data/data_faces_from_camera/"
self.font = cv2.FONT_ITALIC
self.existing_faces_cnt = 0 # 已录入的人脸计数器 / cnt for counting saved faces
self.ss_cnt = 0 # 录入 personX 人脸时图片计数器 / cnt for screen shots
self.current_frame_faces_cnt = 0 # 录入人脸计数器 / cnt for counting faces in current frame
self.save_flag = 1 # 之后用来控制是否保存图像的 flag / The flag to control if save
self.press_n_flag = 0 # 之后用来检查是否先按 'n' 再按 's' / The flag to check if press 'n' before 's'
# FPS
self.frame_time = 0
self.frame_start_time = 0
self.fps = 0
self.fps_show = 0
self.start_time = time.time()
# 新建保存人脸图像文件和数据 CSV 文件夹 / Mkdir for saving photos and csv
def pre_work_mkdir(self):
# 新建文件夹 / Create folders to save face images and csv
if os.path.isdir(self.path_photos_from_camera):
pass
else:
os.mkdir(self.path_photos_from_camera)
# 删除之前存的人脸数据文件夹 / Delete old face folders
def pre_work_del_old_face_folders(self):
# 删除之前存的人脸数据文件夹, 删除 "/data_faces_from_camera/person_x/"...
folders_rd = os.listdir(self.path_photos_from_camera)
for i in range(len(folders_rd)):
shutil.rmtree(self.path_photos_from_camera+folders_rd[i])
if os.path.isfile("data/features_all.csv"):
os.remove("data/features_all.csv")
# 如果有之前录入的人脸, 在之前 person_x 的序号按照 person_x+1 开始录入 / Start from person_x+1
def check_existing_faces_cnt(self):
if os.listdir("data/data_faces_from_camera/"):
# 获取已录入的最后一个人脸序号 / Get the order of latest person
person_list = os.listdir("data/data_faces_from_camera/")
person_num_list = []
for person in person_list:
person_num_list.append(int(person.split('_')[-1]))
self.existing_faces_cnt = max(person_num_list)
# 如果第一次存储或者没有之前录入的人脸, 按照 person_1 开始录入 / Start from person_1
else:
self.existing_faces_cnt = 0
# 更新 FPS / Update FPS of Video stream
def update_fps(self):
now = time.time()
# 每秒刷新 fps / Refresh fps per second
if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
self.fps_show = self.fps
self.start_time = now
self.frame_time = now - self.frame_start_time
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
# 生成的 cv2 window 上面添加说明文字 / PutText on cv2 window
def draw_note(self, img_rd):
# 添加说明 / Add some notes
cv2.putText(img_rd, "Face Register", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 100), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(self.current_frame_faces_cnt), (20, 140), self.font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "N: Create face folder", (20, 350), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "S: Save current face", (20, 400), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
# 获取人脸 / Main process of face detection and saving
def process(self, stream):
# 1. 新建储存人脸图像文件目录 / Create folders to save photos
self.pre_work_mkdir()
# 2. 删除 "/data/data_faces_from_camera" 中已有人脸图像文件
# / Uncomment if want to delete the saved faces and start from person_1
# if os.path.isdir(self.path_photos_from_camera):
# self.pre_work_del_old_face_folders()
# 3. 检查 "/data/data_faces_from_camera" 中已有人脸文件
self.check_existing_faces_cnt()
while stream.isOpened():
flag, img_rd = stream.read() # Get camera video stream
kk = cv2.waitKey(1)
faces = detector(img_rd, 0) # Use Dlib face detector
# 4. 按下 'n' 新建存储人脸的文件夹 / Press 'n' to create the folders for saving faces
if kk == ord('n'):
self.existing_faces_cnt += 1
current_face_dir = self.path_photos_from_camera + "person_" + str(self.existing_faces_cnt)
os.makedirs(current_face_dir)
logging.info("\\n%-40s %s", "新建的人脸文件夹 / Create folders:", current_face_dir)
self.ss_cnt = 0 # 将人脸计数器清零 / Clear the cnt of screen shots
self.press_n_flag = 1 # 已经按下 'n' / Pressed 'n' already
# 5. 检测到人脸 / Face detected
if len(faces) != 0:
# 矩形框 / Show the ROI of faces
for k, d in enumerate(faces):
# 计算矩形框大小 / Compute the size of rectangle box
height = (d.bottom() - d.top())
width = (d.right() - d.left())
hh = int(height/2)
ww = int(width/2)
# 6. 判断人脸矩形框是否超出 480x640 / If the size of ROI > 480x640
if (d.right()+ww) > 640 or (d.bottom()+hh > 480) or (d.left()-ww < 0) or (d.top()-hh < 0):
cv2.putText(img_rd, "OUT OF RANGE", (20, 300), self.font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
color_rectangle = (0, 0, 255)
save_flag = 0
if kk == ord('s'):
logging.warning("请调整位置 / Please adjust your position")
else:
color_rectangle = (255, 255, 255)
save_flag = 1
cv2.rectangle(img_rd,
tuple([d.left() - ww, d.top() - hh]),
tuple([d.right() + ww, d.bottom() + hh]),
color_rectangle, 2)
# 7. 根据人脸大小生成空的图像 / Create blank image according to the size of face detected
img_blank = np.zeros((int(height*2), width*2, 3), np.uint8)
if save_flag:
# 8. 按下 's' 保存摄像头中的人脸到本地 / Press 's' to save faces into local images
if kk == ord('s'):
# 检查有没有先按'n'新建文件夹 / Check if you have pressed 'n'
if self.press_n_flag:
self.ss_cnt += 1
for ii in range(height*2):
for jj in range(width*2):
img_blank[ii][jj] = img_rd[d.top()-hh + ii][d.left()-ww + jj]
cv2.imwrite(current_face_dir + "/img_face_" + str(self.ss_cnt) + ".jpg", img_blank)
logging.info("%-40s %s/img_face_%s.jpg", "写入本地 / Save into:",
str(current_face_dir), str(self.ss_cnt))
else:
logging.warning("请先按 'N' 来建文件夹, 按 'S' / Please press 'N' and press 'S'")
self.current_frame_faces_cnt = len(faces)
# 9. 生成的窗口添加说明文字 / Add note on cv2 window
self.draw_note(img_rd)
# 10. 按下 'q' 键退出 / Press 'q' to exit
if kk == ord('q'):
break
# 11. Update FPS
self.update_fps()
cv2.namedWindow("camera", 1)
cv2.imshow("camera", img_rd)
def run(self):
# cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
cap = cv2.VideoCapture(0) # Get video stream from camera
self.process(cap)
cap.release()
cv2.destroyAllWindows()
def main():
logging.basicConfig(level=logging.INFO)
Face_Register_con = Face_Register()
Face_Register_con.run()
if __name__ == '__main__':
main()
进行人脸信息采集录入 Tkinter GUI(get_faces_from_camera_tkinter.py):
class Face_Register:
def __init__(self):
self.current_frame_faces_cnt = 0 # 当前帧中人脸计数器 / cnt for counting faces in current frame
self.existing_faces_cnt = 0 # 已录入的人脸计数器 / cnt for counting saved faces
self.ss_cnt = 0 # 录入 person_n 人脸时图片计数器 / cnt for screen shots
# Tkinter GUI
self.win = tk.Tk()
self.win.title("Face Register @coneypo")
# PLease modify window size here if needed
self.win.geometry("1300x550")
# GUI left part
self.frame_left_camera = tk.Frame(self.win)
self.label = tk.Label(self.win)
self.label.pack(side=tk.LEFT)
self.frame_left_camera.pack()
# GUI right part
self.frame_right_info = tk.Frame(self.win)
self.label_cnt_face_in_database = tk.Label(self.frame_right_info, text=str(self.existing_faces_cnt))
self.label_fps_info = tk.Label(self.frame_right_info, text="")
self.input_name = tk.Entry(self.frame_right_info)
self.input_name_char = ""
self.label_warning = tk.Label(self.frame_right_info)
self.label_face_cnt = tk.Label(self.frame_right_info, text="Faces in current frame: ")
self.log_all = tk.Label(self.frame_right_info)
self.font_title = tkFont.Font(family='Helvetica', size=20, weight='bold')
self.font_step_title = tkFont.Font(family='Helvetica', size=15, weight='bold')
self.font_warning = tkFont.Font(family='Helvetica', size=15, weight='bold')
self.path_photos_from_camera = "data/data_faces_from_camera/"
self.current_face_dir = ""
self.font = cv2.FONT_ITALIC
# Current frame and face ROI position
self.current_frame = np.ndarray
self.face_ROI_image = np.ndarray
self.face_ROI_width_start = 0
self.face_ROI_height_start = 0
self.face_ROI_width = 0
self.face_ROI_height = 0
self.ww = 0
self.hh = 0
self.out_of_range_flag = False
self.face_folder_created_flag = False
# FPS
self.frame_time = 0
self.frame_start_time = 0
self.fps = 0
self.fps_show = 0
self.start_time = time.time()
self.cap = cv2.VideoCapture(0) # Get video stream from camera
# self.cap = cv2.VideoCapture("test.mp4") # Input local video
# 删除之前存的人脸数据文件夹 / Delete old face folders
def GUI_clear_data(self):
# 删除之前存的人脸数据文件夹, 删除 "/data_faces_from_camera/person_x/"...
folders_rd = os.listdir(self.path_photos_from_camera)
for i in range(len(folders_rd)):
shutil.rmtree(self.path_photos_from_camera + folders_rd[i])
if os.path.isfile("data/features_all.csv"):
os.remove("data/features_all.csv")
self.label_cnt_face_in_database['text'] = "0"
self.existing_faces_cnt = 0
self.log_all["text"] = "Face images and `features_all.csv` removed!"
def GUI_get_input_name(self):
self.input_name_char = self.input_name.get()
self.create_face_folder()
self.label_cnt_face_in_database['text'] = str(self.existing_faces_cnt)
def GUI_info(self):
tk.Label(self.frame_right_info,
text="Face register",
font=self.font_title).grid(row=0, column=0, columnspan=3, sticky=tk.W, padx=2, pady=20)
tk.Label(self.frame_right_info,
text="FPS: ").grid(row=1, column=0, columnspan=2, sticky=tk.W, padx=5, pady=2)
self.label_fps_info.grid(row=1, column=2, sticky=tk.W, padx=5, pady=2)
tk.Label(self.frame_right_info,
text="Faces in database: ").grid(row=2, column=0, columnspan=2, sticky=tk.W, padx=5, pady=2)
self.label_cnt_face_in_database.grid(row=2, column=2, columnspan=3, sticky=tk.W, padx=以上是关于基于Python_opencv人脸录入识别系统(应用dlib机器学习库)的主要内容,如果未能解决你的问题,请参考以下文章