提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
环境配置:
win11
usb摄像头
Python 3.11.9
提示:以下是本篇文章正文内容,下面案例可供参考
一、pandas是什么?
python实现简单的人脸识别供功能。
1.功能实现
1, 普通状态对人脸进行校验,打印识别度
2,rec name命令注册人脸
代码目录如下

代码如下(示例):
python
# main.py
#from camera import Camera
#from face_detector import FaceDetector
#from face_recognition import FaceRecognizer
#from utils import draw_faces
#from config import WINDOW_NAME, EXIT_KEY, DEBUG
#import os
#import cv2
#
#def main():
# print("🚀 人脸识别签到系统启动...")
#
# # 初始化模块
# cam = Camera()
# detector = FaceDetector()
# recognizer = FaceRecognizer()
#
# try:
# cam.start()
#
# while True:
# ret, frame = cam.read_frame()
# if not ret:
# print("❌ 摄像头读取失败")
# break
#
# # 检测人脸
# faces, confidences = detector.detect(frame)
#
# # 绘制人脸框
# frame = draw_faces(frame, faces, confidences)
#
# # 显示检测数量
# cv2.putText(frame, f"Faces: {len(faces)}", (10, 30),
# cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
#
# # 显示结果
# cv2.imshow(WINDOW_NAME, frame)
#
# # 按 'q' 退出
# key = cv2.waitKey(1) & 0xFF
# if key == ord(EXIT_KEY):
# print("👋 退出程序")
# break
#
# # 调试:按 's' 保存第一张人脸
# if DEBUG and key == ord('s') and len(faces) > 0:
# from utils import save_face
# save_face(frame, faces[0], "debug_face.jpg")
#
# except KeyboardInterrupt:
# print("\n👋 程序被用户中断")
# except Exception as e:
# print(f"❌ 错误: {e}")
# finally:
# cam.release()
# cv2.destroyAllWindows()
#
#if __name__ == "__main__":
# main()
# main.py
from camera import Camera
from face_detector import FaceDetector
from face_recognition import FaceRecognizer
from utils import draw_faces, save_face
from config import WINDOW_NAME, EXIT_KEY, DEBUG
import cv2
import threading
import time
# 全局变量
stop_input = False
latest_frame = None # 用于命令线程获取最新帧
frame_lock = threading.Lock() # 线程安全访问帧
# 识别结果输出防抖:记录上次输出时间,避免刷屏
last_recognition_time = 0
RECOGNITION_OUTPUT_INTERVAL = 2.0 # 每2秒最多输出一次
def command_input_thread(recognizer, detector):
"""命令行输入线程:处理人脸录入"""
global stop_input, latest_frame, frame_lock
while not stop_input:
cmd = input("\n请输入命令 (rec <姓名>: 录入人脸, q: 退出): ").strip()
if cmd.lower() == 'q':
stop_input = True
break
elif cmd.startswith("rec "):
name = cmd[4:].strip()
if not name:
print("❌ 姓名不能为空")
continue
print(f"📸 请对准摄像头,3秒内将自动拍摄...")
# 等待 3 秒,让用户摆好姿势
time.sleep(3)
# 从共享变量获取最新一帧(线程安全)
with frame_lock:
frame_copy = latest_frame.copy() if latest_frame is not None else None
if frame_copy is None:
print("❌ 无法获取图像帧,请稍后再试")
continue
# 检测人脸
faces, _ = detector.detect(frame_copy)
if len(faces) == 0:
print("❌ 未检测到人脸,请面对摄像头后重试")
continue
x1, y1, x2, y2 = faces[0]
# 安全裁剪:防止坐标越界
h, w = frame_copy.shape[:2]
x1 = max(0, int(x1))
y1 = max(0, int(y1))
x2 = min(w, int(x2))
y2 = min(h, int(y2))
if x2 <= x1 or y2 <= y1:
print("❌ 人脸框无效:坐标异常")
continue
face_img = frame_copy[y1:y2, x1:x2]
# ✅ 关键检查:确保裁剪出的图像非空
if face_img.size == 0 or face_img.shape[0] <= 10 or face_img.shape[1] <= 10:
print("❌ 裁剪出的人脸图像无效或太小,无法录入")
print(f" 人脸区域尺寸: {face_img.shape if face_img.size > 0 else 'empty'}")
continue
# ✅ 安全调用 add_face,防止异常中断线程
try:
recognizer.add_face(face_img, name)
print(f"✅ 已录入人脸: {name}")
except Exception as e:
print(f"❌ 录入失败: {str(e)}")
else:
print("❌ 未知命令,支持: rec <姓名>, q")
def main():
global stop_input, latest_frame, last_recognition_time
print("🚀 人脸识别签到系统启动...")
# 初始化模块
cam = Camera()
detector = FaceDetector()
recognizer = FaceRecognizer()
# 启动命令输入线程
input_thread = threading.Thread(target=command_input_thread, args=(recognizer, detector))
input_thread.daemon = True
input_thread.start()
try:
cam.start()
while True:
if stop_input:
print("👋 正在退出...")
break
ret, frame = cam.read_frame()
if not ret:
print("❌ 摄像头读取失败或帧为空")
break
# ✅ 更新共享帧(线程安全)
with frame_lock:
latest_frame = frame.copy()
# 检测所有人脸
faces, confidences = detector.detect(frame)
# --- 终端输出识别信息(防抖)---
current_time = time.time()
if len(faces) > 0 and (current_time - last_recognition_time) > RECOGNITION_OUTPUT_INTERVAL:
x1, y1, x2, y2 = faces[0] # 只输出第一张人脸
face_img = frame[y1:y2, x1:x2]
name, confidence = recognizer.recognize(face_img)
if name != "Unknown":
print(f"✅ 识别到: {name} (置信度: {confidence:.2f})")
else:
print(f"❌ 未知人脸 (置信度: {confidence:.2f})")
last_recognition_time = current_time # 更新时间
# --- 画面显示部分 ---
# 识别每张人脸(用于画面显示)
for i, (x1, y1, x2, y2) in enumerate(faces):
face_img = frame[y1:y2, x1:x2]
name, confidence = recognizer.recognize(face_img)
label = f"{name} ({confidence:.2f})"
cv2.putText(frame, label, (x1, y1 - 15),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0), 2)
# 绘制人脸框
frame = draw_faces(frame, faces, confidences)
# 显示人数
cv2.putText(frame, f"Faces: {len(faces)}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
# 显示画面
cv2.imshow(WINDOW_NAME, frame)
# 按 'q' 退出
key = cv2.waitKey(1) & 0xFF
if key == ord(EXIT_KEY):
print("👋 用户按键退出")
break
# 调试:保存人脸
if DEBUG and key == ord('s') and len(faces) > 0:
save_face(frame, faces[0], "debug_face.jpg")
print("📸 调试人脸已保存: debug_face.jpg")
except KeyboardInterrupt:
print("\n👋 程序被用户中断 (Ctrl+C)")
except Exception as e:
print(f"❌ 程序异常: {e}")
finally:
stop_input = True
cam.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
python
# config.py
"""
项目配置文件
"""
# 摄像头设置
CAMERA_ID = 0
FRAME_WIDTH = 640
FRAME_HEIGHT = 480
# 模型路径
MODEL_DIR = "models"
FACE_DETECTOR_PB = "opencv_face_detector_uint8.pb"
FACE_DETECTOR_PBTXT = "opencv_face_detector.pbtxt"
# 检测参数
CONFIDENCE_THRESHOLD = 0.5
# 人脸保存路径
SAVE_DIR = "data/faces"
# 显示设置
WINDOW_NAME = "人脸识别签到系统"
SHOW_CONFIDENCE = True
EXIT_KEY = 'q' # 按 q 退出
DEBUG = True # 设为 True 才能使用 's' 键保存
python
# camera.py
import cv2
from config import CAMERA_ID, FRAME_WIDTH, FRAME_HEIGHT
class Camera:
def __init__(self):
self.cap = None
def start(self):
"""启动摄像头"""
self.cap = cv2.VideoCapture(CAMERA_ID)
if not self.cap.isOpened():
raise Exception(f"无法打开摄像头 {CAMERA_ID}")
# 设置分辨率
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, FRAME_WIDTH)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT)
# 再次获取实际分辨率(有些摄像头不支持精确设置)
actual_width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)
actual_height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
print(f"✅ 摄像头 {CAMERA_ID} 已启动,分辨率: {int(actual_width)}x{int(actual_height)}")
def read_frame(self):
"""读取一帧图像"""
ret, frame = self.cap.read()
if not ret:
print("⚠️ 摄像头读取失败,可能被占用或驱动问题")
return ret, frame
def release(self):
"""释放摄像头"""
if self.cap:
self.cap.release()
print("📷 摄像头已释放")
python
# utils.py
import cv2
from config import SHOW_CONFIDENCE
def draw_faces(frame, faces, confidences=None):
"""在图像上绘制人脸框"""
for i, (x1, y1, x2, y2) in enumerate(faces):
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
if SHOW_CONFIDENCE and confidences:
label = f"{confidences[i]:.2f}"
cv2.putText(frame, label, (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
return frame
def save_face(frame, face_box, save_path):
"""保存人脸图像"""
x1, y1, x2, y2 = face_box
face_img = frame[y1:y2, x1:x2]
cv2.imwrite(save_path, face_img)
print(f"📸 人脸已保存: {save_path}")
face_detector.py
python
# face_detector.py
import cv2
import os
from config import MODEL_DIR, CONFIDENCE_THRESHOLD
class FaceDetector:
def __init__(self):
pbtxt = os.path.join(MODEL_DIR, "opencv_face_detector.pbtxt")
pb = os.path.join(MODEL_DIR, "opencv_face_detector_uint8.pb")
if not os.path.exists(pbtxt) or not os.path.exists(pb):
raise FileNotFoundError(
f"❌ 模型文件未找到!\n"
f"请确保 '{MODEL_DIR}' 目录下有以下文件:\n"
f" - opencv_face_detector.pbtxt\n"
f" - opencv_face_detector_uint8.pb"
)
self.net = cv2.dnn.readNetFromTensorflow(pb, pbtxt)
self.confidence_threshold = CONFIDENCE_THRESHOLD
print("✅ DNN 人脸检测器已加载")
def detect(self, frame):
"""
检测人脸
返回: (faces: [(x1,y1,x2,y2)], confidences: [float])
"""
h, w = frame.shape[:2]
blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), [104, 117, 123], False, False)
self.net.setInput(blob)
detections = self.net.forward()
faces = []
confidences = []
for i in range(detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > self.confidence_threshold:
x1 = int(detections[0, 0, i, 3] * w)
y1 = int(detections[0, 0, i, 4] * h)
x2 = int(detections[0, 0, i, 5] * w)
y2 = int(detections[0, 0, i, 6] * h)
faces.append((x1, y1, x2, y2))
confidences.append(confidence)
return faces, confidences
face_recognition.py
python
# face_recognition.py
import os
import cv2
import numpy as np
import time
KNOWN_FACES_DIR = "known_faces"
os.makedirs(KNOWN_FACES_DIR, exist_ok=True)
class FaceRecognizer:
def __init__(self, db_path="known_faces"):
self.db_path = db_path
self.known_encodings = []
self.known_names = []
self.known_images = []
print("✅ 人脸比对模块已加载")
def add_face(self, face_img, name):
"""录入新的人脸"""
if face_img is None or face_img.size == 0 or len(face_img.shape) != 3:
raise ValueError("❌ 无效的人脸图像:为空或格式错误")
if face_img.shape[0] < 20 or face_img.shape[1] < 20:
raise ValueError("❌ 人脸图像太小,无法处理")
if not os.path.exists(self.db_path):
os.makedirs(self.db_path)
timestamp = int(time.time())
filename = f"{name}_{timestamp}.jpg"
path = os.path.join(self.db_path, filename)
success = cv2.imwrite(path, face_img)
if not success:
raise IOError(f"❌ 无法保存图像: {path}")
# 提取特征
resized = cv2.resize(face_img, (32, 32))
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
flattened = gray.flatten().astype(np.float32)
normalized = flattened / 255.0
self.known_encodings.append(normalized)
self.known_names.append(name)
self.known_images.append(face_img.copy())
print(f"✅ 已录入人脸: {name} (保存为 {path}),特征维度: {normalized.shape}")
def recognize(self, face_image):
"""识别人脸"""
if len(self.known_encodings) == 0:
return "未知", 0.0
if face_image is None or face_image.size == 0:
print("⚠️ 识别失败:输入图像为空")
return "未知", 0.0
h, w = face_image.shape[:2]
if h < 10 or w < 10:
print(f"⚠️ 图像太小: {w}x{h}")
return "未知", 0.0
try:
resized = cv2.resize(face_image, (32, 32))
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
test_vec = gray.flatten().astype(np.float32) / 255.0
except Exception as e:
print(f"❌ 图像预处理失败: {e}")
return "未知", 0.0
best_name = "未知"
best_similarity = 0.0
for name, enc in zip(self.known_names, self.known_encodings):
dot = np.dot(test_vec, enc)
norm_test = np.linalg.norm(test_vec)
norm_enc = np.linalg.norm(enc)
if norm_test == 0 or norm_enc == 0:
continue
similarity = dot / (norm_test * norm_enc)
confidence = (similarity + 1) / 2 # 转到 [0,1]
if confidence > best_similarity:
best_similarity = confidence
best_name = name
THRESHOLD = 0.85
if best_similarity < THRESHOLD:
return "未知", 0.0
return best_name, best_similarity
总结
以上介绍了python实现简单的人脸识别功能逻辑。