树莓派的OpenCV的人脸识别开锁
【代码】树莓派的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 = None
for path in font_paths:
try:
font = ImageFont.truetype(path, size, encoding="utf-8")
break
except:
continue
draw.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:
break
if not self.q.empty():
try:
self.q.get_nowait()
except queue.Empty:
pass
self.q.put(frame)
def read(self):
return self.q.get()
def terminate(self):
self.stop_threads = True
self.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'):
break
finally:
# 释放资源
cap.terminate()
cv2.destroyAllWindows()
relay.off()
relay.close()
print("✅ 程序退出,资源已释放")
🎯 代码下载链接
https://download.csdn.net/download/qq_41954594/92211413
更多推荐

所有评论(0)