树莓派的OpenCV的人脸识别开锁
树莓派的OpenCV的人脸识别开锁
文档结尾有代码下载链接
🎯 实现效果
- 场景 1:“主人” 面对摄像头→ 屏幕显示 “已识别:主人”,绿色框框选人脸,继电器通电,门锁打开;



- 场景 2:陌生人面对摄像头→ 屏幕显示 “陌生人”,红色框框选人脸,继电器保持关闭,门锁不动;



- 场景 3:无一人→ 屏幕显示 “未检测到人脸”,继电器关闭。


- 退出程序:按键盘 “q” 键,程序自动释放摄像头、关闭继电器,安全退出。

🌟 系统组成
- 树莓派主板:树莓派4或树莓派5都可以;
- 摄像头模块:选择USB摄像头;
- 显示屏:小尺寸HDMI显示屏可实时显示识别信息;
- 网络模块:树莓派4和5自带WiFi/以太网,确保设备能连接互联网,用于数据上传;
- 电源:5V/3Amicro-USB电源,保证树莓派稳定运行,避免因供电不足导致识别中断。
- 继电器模块:5V 单路继电器控制门锁(电磁锁 / 舵机门锁)。
🌟 驱动思路
1.初始化配置
- 继电器配置:选用LGPIO驱动 GPIO,固定RELAY_BCM_PIN=17,设置初始值为False,用OutputDevice封装继电器操作,简化 “开 / 关 / 释放” 逻辑。
- 人脸识别配置:TARGET_FACE_ID=1:与前期 “样本采集程序” 的目标 ID 严格一致;CONFIDENCE_THRESHOLD=90:LBPH 模型的置信度阈值(注:LBPH 置信度越小表示匹配度越高,90 是平衡 “严格性与容错性” 的常用值 —— 既避免陌生人误触发,也允许目标人脸因光照、角度轻微变化导致的置信度波动);MODEL_PATH:指向前期训练好的模型文件(若模型缺失则直接退出,避免无意义运行)。
- 中文显示配置:通过PIL将 OpenCV 帧转为 RGB 格式,用ImageDraw绘制中文,再转回 BGR 格式;
2.摄像头捕获
(1). 多线程分工
- 后台线程_reader:持续调用摄像头cap.read()采集帧,若队列满则丢弃旧帧(只保留最新 3 帧,maxsize=3),避免帧堆积导致延迟;
- 主线程read():从队列中获取最新帧,无需等待摄像头采集,确保后续人脸检测、识别流程流畅。
(2). 资源控制
- 设线程为daemon=True:主程序退出时后台线程自动终止,避免资源泄漏;
- 提供terminate()方法:统一释放摄像头资源,配合后续 “程序退出时的资源清理”。
🌟 5.树莓派上部署运行
a. 搭建环境(树莓派端)
- 先安装所有依赖库,打开终端输命令安装。
b. 采集人脸样本,训练识别模型
- 创建样本文件夹:在树莓派上新建faceImage文件夹,放入 20 张以上 “主人” 的人脸照片(建议不同角度、光照,保证样本多样性)。
- 运行样本训练脚本:执行之前的LBPH.py,脚本会自动从照片中提取人脸、标准化处理,最终生成target_face_model.yml模型文件(若样本不足 20 个,建议补充后再训练,提高识别准确率)。
- 验证模型:脚本运行成功后,项目文件夹中会出现模型文件,说明 “主人” 的人脸特征已被记录。
c. 核心代码部署
- 注意修改 3 个关键参数:
- RELAY_BCM_PIN:继电器连接的树莓派 BCM 引脚(如 17,需与硬件接线一致);
- TARGET_FACE_ID:与样本训练时的 ID 保持一致(默认 1);
- MODEL_PATH:指向训练好的target_face_model.yml路径。
d. 硬件接线
- 继电器 “VCC”→ 树莓派 5V 引脚;
- 继电器 “GND”→ 树莓派 GND 引脚;
- 继电器 “IN”→ 树莓派 BCM 引脚
- 摄像头连接:USB 摄像头直接插树莓派 USB 口
E. 启动程序
- 在终端执行命令,启动人脸识别开锁系统:若是使用虚拟python,则需先进入虚拟环境再运行。
python3 OpenCVFace.py

🎯 程序代码
OpenCVFace.py
# -*- coding: utf-8 -*-
import cv2
import queue
import threading
import time
from gpiozero import OutputDevice
from gpiozero.pins.lgpio import LGPIOFactory
from PIL import Image, ImageDraw, ImageFont
import numpy as np #虚拟环境下安装 pip install lgpio
# -------------- 初始化配置 --------------
# 继电器配置
RELAY_BCM_PIN = 17
lgpio_factory = LGPIOFactory()
relay = OutputDevice(RELAY_BCM_PIN, active_high=True, initial_value=False,pin_factory=lgpio_factory
)# 人脸识别核心配置
TARGET_FACE_ID = 1 # 与样本采集时的ID一致
CONFIDENCE_THRESHOLD = 90 # 置信度阈值(越小越严格,建议70-90)
MODEL_PATH = "./target_face_model.yml" # 训练好的模型路径# 中文显示函数(复用原有逻辑)
def draw_chinese_text(img, text, position, color=(0, 255, 0), size=20):img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img_pil)font_paths = ["/usr/share/fonts/truetype/wqy/wqy-microhei.ttc","/usr/share/fonts/truetype/simhei/simhei.ttf",ImageFont.load_default()]font = Nonefor path in font_paths:try:font = ImageFont.truetype(path, size, encoding="utf-8")breakexcept:continuedraw.text(position, text, color, font=font)return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)# -------------- 摄像头捕获类(复用原有逻辑) --------------
class VideoCapture:def __init__(self, camera_id):self.cap = cv2.VideoCapture(camera_id)self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)self.q = queue.Queue(maxsize=3)self.stop_threads = False th = threading.Thread(target=self._reader)th.daemon = True th.start()def _reader(self):while not self.stop_threads:ret, frame = self.cap.read()if not ret:breakif not self.q.empty():try:self.q.get_nowait() except queue.Empty:passself.q.put(frame)def read(self):return self.q.get()def terminate(self):self.stop_threads = Trueself.cap.release()# -------------- 主程序 --------------
if __name__ == "__main__":print(f"OpenCV版本: {cv2.__version__}")# 1. 初始化摄像头cap = VideoCapture(0)if not cap.cap.isOpened():print("❌ 无法打开摄像头")cap.terminate()relay.off()relay.close()exit()# 2. 加载人脸检测器和识别模型# 人脸检测器(检测是否有人脸)face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')if face_cascade.empty():print("❌ 无法加载人脸分类器")cap.terminate()relay.off()relay.close()exit()# 人脸识别模型(判断是否为指定人脸)recognizer = cv2.face.LBPHFaceRecognizer_create()try:recognizer.read(MODEL_PATH)except:print(f"❌ 无法加载模型文件,请先运行样本采集程序生成 {MODEL_PATH}")cap.terminate()relay.off()relay.close()exit()print("✅ 模型加载成功,开始指定人脸检测(按'q'退出)")# 3. 创建显示窗口cv2.namedWindow("人脸开锁系统", cv2.WINDOW_NORMAL)cv2.resizeWindow("人脸开锁系统", 680, 500)try:while True:frame = cap.read()if frame is None:print("⚠️ 未获取到摄像头帧")time.sleep(0.1)continue# 4. 检测人脸(先找画面中的人脸位置)gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)faces = face_cascade.detectMultiScale(gray, 1.1, 5)# 5. 人脸识别与继电器控制relay_status = "关闭" # 继电器状态face_status = "未检测到人脸" # 人脸状态(显示用)if len(faces) > 0:# 对每个检测到的人脸进行识别(默认只处理单张人脸)x, y, w, h = faces[0]# 提取人脸区域(灰度图,与训练样本尺寸一致)face_roi = cv2.resize(gray[y:y+h, x:x+w], (100, 100))# 识别:返回(匹配的ID,置信度),置信度越小匹配度越高predicted_id, confidence = recognizer.predict(face_roi)# 判断是否为指定人脸if predicted_id == TARGET_FACE_ID and confidence < CONFIDENCE_THRESHOLD:relay.on()relay_status = "打开"#face_status = f"已识别:主人(置信度:{confidence:.1f})"face_status = f"已识别:主人"box_color = (0, 255, 0) # 匹配成功:绿色框else:relay.off()relay_status = "关闭"#face_status = f"陌生人(置信度:{confidence:.1f})"face_status = f"陌生人"box_color = (0, 0, 255) # 匹配失败:红色框# 绘制人脸框cv2.rectangle(frame, (x, y), (x+w, y+h), box_color, 2)# 6. 绘制状态文字frame = draw_chinese_text(frame, f"继电器状态:{relay_status}", (10, 30), (0, 255, 0), 25)frame = draw_chinese_text(frame, face_status, (10, 70), (0, 255, 255), 25)# 7. 显示画面cv2.imshow("人脸开锁系统", frame)# 按q退出if cv2.waitKey(1) & 0xFF == ord('q'):breakfinally:# 释放资源cap.terminate()cv2.destroyAllWindows()relay.off()relay.close()print("✅ 程序退出,资源已释放")
🎯 代码下载链接
https://download.csdn.net/download/qq_41954594/92211413
