news 2026/2/10 5:11:59

基于树莓派4b的安防门禁系统从零实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于树莓派4b的安防门禁系统从零实现

从零打造智能门禁:树莓派4B + 人脸识别实战全记录

最近在折腾一个让我既兴奋又头疼的小项目——用一块树莓派4B,搭一套能“认脸开门”的智能门禁系统。听起来像是科技公司的产品?其实成本不到500块,代码全是自己写的,硬件也是淘宝拼凑的。今天就来分享下这个DIY全过程,不讲空话套话,只聊真实踩过的坑、调过的参数、跑得动的代码


为什么是树莓派4B?

市面上做嵌入式开发的板子不少,Nano、ESP32也能跑基础逻辑,但要做实时人脸识别+网络服务+远程访问这一整套闭环,还得靠性能在线的平台。

我最终选了Raspberry Pi 4 Model B(8GB内存版),原因很实际:

关键指标树莓派4B表现实际意义
CPU四核Cortex-A72 @1.5GHz能跑轻量级深度学习模型
内存最高8GB LPDDR4多任务不卡顿,缓存视频流更稳
视频输入CSI-2接口 + 支持USB摄像头可接官方摄像头,低延迟采集
网络千兆以太网 + 双频Wi-Fi远程推流不断连
GPIO40针通用引脚控制继电器毫无压力

坦白说,如果你打算做个“按按钮开灯”级别的小玩具,树莓派有点杀鸡用牛刀。但一旦涉及图像处理+联网+本地决策,它几乎是目前性价比最高的选择。

更重要的是——社区资源太丰富了。OpenCV、PyTorch都能装,GitHub上随便一搜就是成堆的参考项目。省下的时间,够你多调试三轮算法。


核心技术拆解:人脸怎么“看懂”你是谁?

整个系统的灵魂当然是人脸识别。很多人一听就觉得高深莫测,其实现在开源工具链已经非常成熟,关键在于如何让它在树莓派这种边缘设备上跑得快、认得准

我的技术路线:MTCNN + FaceNet 组合拳

没有用什么商业SDK,全部基于facenet_pytorch库实现,两个核心组件:

  1. MTCNN:负责从画面中“找脸”
  2. InceptionResnetV1(FaceNet变体):把脸变成一串数字特征向量

这套组合的好处是:
- 模型小(<100MB),适合部署
- 准确率高,在LFW数据集上能达到99%+
- PyTorch支持良好,推理过程可控性强

实战代码优化版(亲测可用)

下面这段是我最终定稿的人脸识别函数,比原生示例更稳定,加了置信度过滤和异常处理:

import cv2 import torch import numpy as np from facenet_pytorch import MTCNN, InceptionResnetV1 # 自动检测是否可用CUDA(虽然Pi没有GPU,但保持结构统一) device = 'cpu' # Raspberry Pi无独立GPU mtcnn = MTCNN(keep_all=True, thresholds=[0.6, 0.7, 0.7], device=device) resnet = InceptionResnetV1(pretrained='vggface2').eval().to(device) # 加载已注册用户的特征库 registered_embeddings = { "张三": np.load("embeddings/zhangsan.npy"), "李四": np.load("embeddings/lisi.npy") } def recognize_face(frame): """ 输入BGR图像帧,返回是否匹配成功及姓名 """ boxes, probs = mtcnn.detect(frame) if boxes is None: return False, None for box, prob in zip(boxes, probs): if prob < 0.8: # 置信度太低直接跳过 continue x1, y1, x2, y2 = [int(b) for b in box] face_img = frame[y1:y2, x1:x2] try: face_tensor = mtcnn.preprocess(frame, box).unsqueeze(0).to(device) with torch.no_grad(): embedding = resnet(face_tensor).cpu().numpy() except Exception as e: print(f"特征提取失败: {e}") continue # 计算欧氏距离(越小越相似) min_distance = float('inf') matched_name = "未知" for name, saved_emb in registered_embeddings.items(): dist = np.linalg.norm(embedding - saved_emb) if dist < min_distance: min_distance = dist # 设定阈值(根据训练数据调整,一般0.8~1.0之间) if min_distance < 0.9: matched_name = list(registered_embeddings.keys())[ list(np.linalg.norm(embedding - v) for v in registered_embeddings.values()).index(min_distance) ] # 绘制框和标签 color = (0, 255, 0) if matched_name != "未知" else (0, 0, 255) cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2) cv2.putText(frame, f"{matched_name} ({min_distance:.2f})", (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2) if matched_name != "未知": return True, matched_name return False, None

💡经验贴士
- 阈值0.9是我通过测试几百张正脸/侧脸样本调出来的平衡点,太低会误识别,太高则熟人也进不来。
- 摄像头尽量固定位置,避免逆光或强阴影影响识别稳定性。
- 建议每人注册至少3张不同光照条件下的照片生成特征向量取平均。


如何让“识别结果”真正控制门锁?GPIO实战详解

识别出来了,接下来就得动手——怎么让软件判断变成物理世界的“咔哒”一声开门?

答案就是:GPIO + 继电器模块

硬件连接要点

我用的是常见的5V继电器模块(某宝十几块钱),接线如下:

树莓派GPIO接继电器端口说明
Pin 18 (BCM 18)IN控制信号输入
Pin 6 (GND)GND共地
继电器COM12V电源正极主回路接入点
继电器NO电磁锁正极常开触点,通电闭合
电磁锁负极接12V电源负极构成完整回路

⚠️重要提醒:电磁锁工作电压通常是12V,绝对不能直接接到树莓派!必须通过继电器隔离,否则轻则烧IO口,重则主板报废。

控制代码封装成可靠函数

别小看这一步,我第一次写完就忘了清理GPIO,重启后发现继电器一直吸合……差点把锁烧了。

改进后的安全版本:

import RPi.GPIO as GPIO import time RELAY_PIN = 18 GPIO.setmode(GPIO.BCM) GPIO.setup(RELAY_PIN, GPIO.OUT) GPIO.output(RELAY_PIN, GPIO.LOW) # 初始状态断开 def unlock_door(duration=3): """ 打开门锁 duration 秒后自动关闭 """ try: GPIO.output(RELAY_PIN, GPIO.HIGH) print(f"[{time.strftime('%H:%M:%S')}] 门已开启") time.sleep(duration) GPIO.output(RELAY_PIN, GPIO.LOW) print(f"[{time.strftime('%H:%M:%S')}] 门已关闭") except Exception as e: print(f"开门过程中出错: {e}") finally: pass # 不在此处 cleanup,防止其他线程受影响 # 使用示例 if __name__ == "__main__": try: unlock_door(5) finally: GPIO.cleanup() # 程序退出时释放资源

这个duration=3很关键——没人希望门一直开着。3秒足够进出,又能防尾随。


能不能不在现场也能开门?远程访问怎么搞?

设想一下:朋友来访你不在家,能不能手机一点,“滴”,门开了?

完全可以。我在树莓派上起了一个轻量级 Web 服务,前端用 HTML + JS 做了个简易面板,功能包括:

  • 查看实时画面(MJPG-Streamer 推流)
  • 点击按钮远程开门
  • 查询最近10条出入记录
  • 异常报警微信通知(后面讲)

Flask 服务最小可行实现

考虑到安全性,这里只暴露必要接口,并加入简单 token 验证:

from flask import Flask, jsonify, request import threading import logging app = Flask(__name__) SECRET_TOKEN = "your_very_secret_token_here" # 替换为你自己的密钥 is_locked = True @app.route('/status') def get_status(): return jsonify({ "locked": is_locked, "timestamp": time.time() }) @app.route('/unlock', methods=['POST']) def remote_unlock(): token = request.headers.get('X-Auth-Token') if token != SECRET_TOKEN: return jsonify({"success": False, "message": "认证失败"}), 403 global is_locked unlock_door(3) is_locked = False return jsonify({"success": True, "message": "门已开启"}) # 启动Web服务(单独线程) def start_web_server(): logging.basicConfig(level=logging.WARNING) app.run(host='0.0.0.0', port=8080, threaded=True) web_thread = threading.Thread(target=start_web_server) web_thread.daemon = True web_thread.start()

然后通过 Nginx 反向代理 + Let’s Encrypt 证书实现 HTTPS,再配合花生壳之类的动态DNS,外网就能安全访问了。

🔐安全建议
- 不要用默认端口80/443,容易被扫描
- 加IP白名单或登录页面更好
- Token定期更换


完整系统是如何运转的?

把所有模块串起来,整个流程就像一条流水线:

[摄像头] → [人脸检测] → [特征提取] → [比对数据库] → ↓(匹配成功) ↓(失败多次) [触发GPIO开锁] [记录日志 + 可选报警] ↓ [更新状态 → Web界面可见]

主循环伪代码大致如下:

cap = cv2.VideoCapture(0) # 或使用 picamera2 while True: ret, frame = cap.read() if not ret: continue success, name = recognize_face(frame) if success: log_access(name, success=True) unlock_door(3) send_welcome_message(name) # 如语音播放“欢迎回家” # 显示画面(调试用) cv2.imshow('Door Access System', frame) if cv2.waitKey(1) == ord('q'): break cap.release() cv2.destroyAllWindows()

实际部署中的那些“坑”

理论美好,落地才见真章。以下是几个血泪教训:

1. 电源问题最致命

一开始图省事,用同一个5V电源给树莓派和继电器供电,结果一启动继电器,树莓派直接重启——电压跌落严重

✅ 解决方案:树莓派用专用5V/3A适配器,继电器和电磁锁另接12V/2A稳压电源,共地但不共电。

2. 摄像头角度决定识别率

装太高,拍到头顶;装太低,下巴都看不见。反复调试后发现:

最佳安装高度:1.6米左右,俯角10°~15°,人脸基本正对镜头。

3. 特征库要多样化

只用一张正面照注册?那遇到戴帽子、眼镜、晚上光线差的情况,基本就歇菜了。

✅ 建议每人录入5张以上:白天/夜晚、戴镜/不戴镜、微笑/自然表情。

4. 日志一定要持久化

系统运行几天后想查谁什么时候进来过?没做日志等于瞎子。

✅ 用 SQLite 存每条识别事件:

CREATE TABLE access_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, success BOOLEAN, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP );

总结:这不是玩具,而是可用的解决方案

做完这套系统我才意识到,真正的智能不是炫技,而是解决问题

它帮我解决了几个实实在在的问题:

  • 不用带钥匙,刷脸进门,下雨天单手拎包也能进
  • 临时访客来了,手机一点就能放行
  • 有人半夜强行撬门?连续识别失败立刻发微信告警
  • 所有出入都有记录,再也不用猜“到底是谁忘关门”

未来我还计划升级的方向:

  • 接入 Home Assistant,实现“回家模式”自动开灯拉窗帘
  • 用 TensorFlow Lite + Coral USB Accelerator 加速推理
  • 添加语音提示:“您好,张三,门已为您打开”
  • 结合温湿度传感器,做一个多功能门口机

如果你也在考虑做个属于自己的智能门禁,不妨从这块小小的树莓派开始。
代码我已经整理好放在 GitHub,硬件清单也不超过500元。

技术不该只是大厂的专利,每个人都可以亲手构建自己想要的生活方式。

👉 想要完整项目代码或遇到具体问题?欢迎留言交流,一起完善这个“家门口的AI守卫”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/3 14:20:44

通过ESP32获取OBD实时车速:实战案例解析

用ESP32读取OBD车速&#xff1a;从协议到实战的完整链路拆解你有没有想过&#xff0c;只需一块十几块钱的开发板和一个OBD模块&#xff0c;就能实时拿到自己爱车的速度、转速甚至油耗&#xff1f;这并不是什么高端诊断设备才有的功能。今天我们就来干一件“接地气”的事——用E…

作者头像 李华
网站建设 2026/2/9 9:04:24

DiffSynth Studio:让入门显卡也能畅享AI绘图乐趣的显存优化工具

DiffSynth Studio&#xff1a;让入门显卡也能畅享AI绘图乐趣的显存优化工具 【免费下载链接】DiffSynth-Studio DiffSynth Studio 是一个扩散引擎。我们重组了包括 Text Encoder、UNet、VAE 等在内的架构&#xff0c;保持了与开源社区模型的兼容性&#xff0c;同时提高了计算性…

作者头像 李华
网站建设 2026/2/5 9:47:04

从零上手MobileNetV2-ONNX部署:概念解析到实战调优全指南

从零上手MobileNetV2-ONNX部署&#xff1a;概念解析到实战调优全指南 【免费下载链接】models A collection of pre-trained, state-of-the-art models in the ONNX format 项目地址: https://gitcode.com/gh_mirrors/model/models 你是否曾经面对深度学习模型部署时感…

作者头像 李华
网站建设 2026/2/10 5:09:26

FreeCAD参数化建模实战指南:解决设计困境的完整方案

FreeCAD参数化建模实战指南&#xff1a;解决设计困境的完整方案 【免费下载链接】FreeCAD This is the official source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler. 项目地址: https://gitcode.com/GitHub_Trending/fr/freecad 面对…

作者头像 李华
网站建设 2026/2/9 11:05:07

Broadcom蓝牙固件完整使用指南:如何快速解决Linux蓝牙设备问题

Broadcom蓝牙固件完整使用指南&#xff1a;如何快速解决Linux蓝牙设备问题 【免费下载链接】broadcom-bt-firmware Repository for various Broadcom Bluetooth firmware 项目地址: https://gitcode.com/gh_mirrors/br/broadcom-bt-firmware Broadcom蓝牙固件项目为Linu…

作者头像 李华
网站建设 2026/2/6 4:27:49

5分钟搞定PCSX2模拟器:新手零基础配置全攻略

还在为PS2模拟器复杂的安装步骤而头疼吗&#xff1f;想要重温《最终幻想X》、《战神》等经典游戏&#xff0c;却被各种技术术语劝退&#xff1f;别担心&#xff0c;这篇指南将用最简单的方式带你轻松配置PCSX2&#xff0c;让你快速开启怀旧游戏之旅&#xff01; 【免费下载链接…

作者头像 李华