打卡软件——人脸识别综合实现
目录
实现思路
1. 导入所需库
2. 加载人脸检测模型
3. 初始化存储结构
4. 特征提取函数
5. 打卡功能
6. 人脸录入功能
7. 开始人脸录入
8. 捕捉人脸
9. 显示摄像头画面
10. 数据保存
11. 主页面设置
12. 创建主窗口
整体代码
实现效果
结语
实现思路
这段代码实现了一个简单的人脸识别系统,主要分为人脸录入和打卡两大功能。以下是代码的详细实现思路:
1. 导入所需库
- cv2:用于图像处理,提供视频捕捉和图像操作功能。
- dlib:用于人脸检测和特征点提取。
- numpy:用于数组操作,方便进行数学计算。
- pickle:用于保存和加载人脸数据。
- tkinter:用于创建用户界面,包括窗口和按钮。
- scipy.spatial.distance:用于计算余弦相似度,帮助判断人脸是否匹配。
2. 加载人脸检测模型
- predictor_path:指定特征点检测模型的路径。
- detector:使用dlib的正面人脸检测器。
- predictor:加载68个特征点的人脸标记预测器。
3. 初始化存储结构
- face_data:使用字典存储录入的人脸信息,包括姓名、ID和提取的特征。
4. 特征提取函数
- extract_face_features:接收人脸区域和灰度图像,使用
predictor
提取68个特征点的坐标,并将其转换为一维数组返回。该特征用于后续的人脸匹配。
5. 打卡功能
- check_in:
- 使用
cv2.VideoCapture(0)
打开摄像头。 - 进入一个循环,不断读取视频帧。
- 将帧转换为灰度图像,并检测人脸。
- 对每个检测到的人脸,提取其特征并用矩形框标记。
- 遍历存储的人脸数据,计算每个人脸特征与存储特征的余弦相似度,判断是否匹配。
- 若匹配,显示姓名和ID;否则,显示“未识别”。
- 按下“q”键退出循环,释放摄像头并关闭窗口。
- 使用
6. 人脸录入功能
- enroll_face:
- 创建一个新窗口,要求用户输入密码。
- 确认密码正确后,调用
start_face_enrollment
函数开始录入人脸。
7. 开始人脸录入
- start_face_enrollment:
- 再次打开摄像头,并创建录入窗口,要求用户输入姓名和ID。
- 提供“捕捉人脸”按钮,点击后调用
capture_face
函数。
8. 捕捉人脸
- capture_face:
- 读取摄像头帧并进行人脸检测。
- 若检测到人脸,提取特征并存储至
face_data
字典中,使用姓名和ID作为键,特征作为值。 - 提示用户录入成功并保存数据。
- 释放摄像头,关闭窗口并返回主页面。
9. 显示摄像头画面
- show_camera:
- 持续读取摄像头帧,显示实时画面。
- 按下“q”键退出显示。
10. 数据保存
- save_data:
- 使用pickle将
face_data
字典保存到本地文件face_data.pkl
,方便下次加载。
- 使用pickle将
11. 主页面设置
- main_page:
- 清空当前窗口,设置主窗口的尺寸和标题。
- 提供“录入人脸”和“打卡”按钮,分别调用相应功能。
12. 创建主窗口
- 使用
Tk()
创建主窗口,并设置标题和初始大小。 - 通过调用
main_page()
初始化界面并进入主循环。
整体代码
import cv2
import dlib
import numpy as np
import pickle
from tkinter import *
from tkinter import messagebox
from scipy.spatial.distance import cosine# 加载人脸特征点检测模型
predictor_path = "./model/shape_predictor_68_face_landmarks.dat"
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)# 存储人脸信息的字典
face_data = {}# 提取特征函数
def extract_face_features(face, gray_image):landmarks = predictor(gray_image, face)features = np.array([landmarks.part(i).x for i in range(68)] + [landmarks.part(i).y for i in range(68)])return features# 打卡功能
def check_in():cap = cv2.VideoCapture(0)if not cap.isOpened():messagebox.showerror("Error", "Could not open camera.")returnwhile True:ret, frame = cap.read()if not ret:messagebox.showerror("Error", "Failed to read frame.")breakgray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)faces = detector(gray)for face in faces:x = face.left()y = face.top()cv2.rectangle(frame, (x, y), (face.right(), face.bottom()), (0, 255, 0), 2)face_features = extract_face_features(face, gray)recognized = Falsefor stored_face_id, data in face_data.items():stored_features = data['features']if cosine(stored_features, face_features) < 0.5: # 使用余弦相似度,阈值可调cv2.putText(frame, f"Name: {data['name']}, ID: {data['id']}", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)recognized = Truebreakif not recognized:cv2.putText(frame, "Not recognized", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)cv2.imshow("Check In", frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()# 录入人脸功能
def enroll_face():password_window = Toplevel(root)password_window.title("Enter Password")password_window.geometry("300x150")Label(password_window, text="Password").pack()password_entry = Entry(password_window, show='*')password_entry.pack()def confirm_password():if password_entry.get() != "2004":messagebox.showerror("Error", "Incorrect password")returnpassword_window.destroy()start_face_enrollment()Button(password_window, text="Confirm", command=confirm_password).pack()def start_face_enrollment():global capcap = cv2.VideoCapture(0)if not cap.isOpened():messagebox.showerror("Error", "Could not open camera.")returnframe_window = Toplevel(root)frame_window.title("Face Enrollment")frame_window.geometry("600x400")Label(frame_window, text="Name").pack()global name_entryname_entry = Entry(frame_window)name_entry.pack()Label(frame_window, text="ID").pack()global id_entryid_entry = Entry(frame_window)id_entry.pack()Button(frame_window, text="Capture Face", command=lambda: capture_face(frame_window)).pack()# 显示摄像头画面show_camera()def capture_face(frame_window):ret, frame = cap.read()if not ret:messagebox.showerror("Error", "Failed to read frame.")returngray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)faces = detector(gray)if len(faces) > 0:face = faces[0]x = face.left()y = face.top()# 提取特征并存储人脸信息features = extract_face_features(face, gray)name = name_entry.get()person_id = id_entry.get()# 确保不覆盖现有信息face_data[f"{name}_{person_id}"] = {'name': name, 'id': person_id, 'features': features}messagebox.showinfo("Success", "Face enrolled successfully!")save_data()cap.release()cv2.destroyAllWindows()main_page()else:messagebox.showerror("Error", "No face detected")def show_camera():while True:ret, frame = cap.read()if not ret:messagebox.showerror("Error", "Failed to read frame.")breakcv2.imshow("Face Capture", frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakdef save_data():with open('face_data.pkl', 'wb') as f:pickle.dump(face_data, f)def main_page():for widget in root.winfo_children():widget.destroy()root.geometry("300x200")Label(root, text="Face Recognition System").pack()Button(root, text="Enroll Face", command=enroll_face).pack()Button(root, text="Check In", command=check_in).pack()# 创建主窗口
root = Tk()
root.title("Face Recognition System")
root.geometry("300x200")main_page()
root.mainloop()
实现效果
结语
整段代码通过Tkinter提供的GUI实现了人脸的录入和识别功能,结合dlib的人脸检测和特征提取能力,构成了一个基本的人脸识别系统。用户可以通过简单的操作进行人脸的录入和打卡,系统将根据录入的信息进行识别。
但是说实话还是有很多的BUG和设计缺陷,我会继续的修改,所以在不久的时间内我会更新人脸识别打卡系统2.0.