这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 开源硬件 » 【树莓派5】智能门禁系统

共2条 1/1 1 跳转至

【树莓派5】智能门禁系统

工程师
2026-01-09 13:19:50     打赏

【树莓派5】智能门禁系统

本文介绍了树莓派 5 单板计算机结合 OpenCV 人脸识别和 PWM 舵机控制实现智能门禁系统的项目设计,包括硬件连接、舵机控制、人脸识别、网页前端设计、网页服务器设计、流程图、代码和效果演示等流程。

项目介绍

  • 准备工作:硬件连接、OpenCV 安装、人脸识别模型、训练图像等;

  • 舵机控制:PWM输出、转速和角度控制、代码、效果等;

  • 门禁系统:文件目录、流程图、代码、效果等。

准备工作

包括硬件连接、虚拟环境创建、OpenCV 安装、模型获取、图像训练等。

硬件连接

  • 连接 WiFi 实现无线网络通信;

  • 使用 Micro-USB 数据线实现设备供电;

hardware_connect.jpg


根据板载 40pin 引脚定义,驱动舵机使用支持 PWM 的物理引脚 12,对应 BCM 引脚编号 18;

40pinout.jpg

将舵机的信号线与 GPIO18 连接,还有供电和接地


Raspberry Pi 5SG90Description
GPIO18 (Pin12)S (Yellow)Signal
5V (Pin2)5V (Red)Power supply
GND (Pin6)GND (Brown)Ground

SG90_pinout.jpg

OpenCV 安装

  • 创建并激活虚拟环境

 mkdir ~/cv && cd ~/cv    # 创建 cv 文件夹,便于管理
 python3 -m venv venv     # 创建虚拟环境 venv
 source venv/bin/activate # 激活虚拟环境 venv
  • 安装 numpy 和 opencv

 pip install -U pip numpy                          # 安装 numpy
 pip install opencv-python opencv-contrib-python   # opencv 主模块及 contrib
  • 验证安装

 python3 -c "import cv2,sys,numpy;print('OpenCV:',cv2.__version__,'NumPy:',numpy.__version__)"

详见:OpenCV .

人脸识别

OpenCV 注册并训练目标人脸,使用 YuNet 模型检测人脸,之后结合 sface 模型识别人脸。

详见:opencv_zoo/models/face_recognition_sface · GitHub .

模型获取

下载所需模型文件;

 wget https://github.com/opencv/models/face_detection_yunet/face_detection_yunet_2023mar.onnx
 wget https://github.com/opencv/models/face_recognition_sface/face_recognition_sface_2021dec.onnx

将文件存放在 ./model 路径

参考:SFace Recognition | Github .

训练图片

  • 将目标人脸图片裁剪至合适大小;

  • 文件名为对应的人名;

  • 置于 ./face 文件夹。

fr_faces.jpg

舵机控制

使用树莓派板载 40pin 引脚接口的 PWM 功能,实现 SG90 舵机驱动,并控制旋转速度和角度。

SG90_structure.jpg

代码

终端执行指令 touch servo360.py 新建程序文件并添加如下代码

 import sys, time
 import RPi.GPIO as GPIO
 
 GPIO_PIN  = 18
 FREQ      = 50
 CENTER    = 7.5
 RANGE     = 2.5
 
 # --------- Parameters ---------
 SPEED_DPS = 0
 PWM_DEAD  = 0
 # ----------------------------
 
 def duty(speed):
     return CENTER + max(-1, min(1, speed)) * RANGE
 
 def rotate(target_deg, speed=1.0):
     if not target_deg:
         return
     direction = 1 if target_deg > 0 else -1
 
     pwm = GPIO.PWM(GPIO_PIN, FREQ)
     pwm.start(0)
     pwm.ChangeDutyCycle(duty(run_speed))
     time.sleep(run_time)
     pwm.ChangeDutyCycle(CENTER)
     time.sleep(PWM_DEAD)
     pwm.stop()
 
 if __name__ == '__main__':
 
     GPIO.setmode(GPIO.BCM)
     GPIO.setup(GPIO_PIN, GPIO.OUT)
     try:
         rotate(deg)
     finally:
         GPIO.cleanup()

保存代码。

效果

终端执行指令 python servo360.py 90 舵机逆时针转动 90 度。

servo_run.gif


门禁系统

在人脸识别和舵机控制的基础上,实现门禁系统的项目设计,包括文件目录、流程图、代码、效果演示等。

文件目录

 ~/AI/FaceRecognition $ tree
 .
 ├── access.names
 ├── app.py
 ├── face
 │   ├── Arnold.jpg
 │   ├── Clarke.jpg
 │   ├── Perry.jpg
 │   └── Robert.jpg
 ├── model
 │   ├── face_detection_yunet_2023mar.onnx
 │   ├── face_recognition_sface_2021dec.onnx
 │   └── face_registry.pkl
 ├── static
 │   └── result.jpg
 └── templates
     └── index.html

流程图

flowchart_dc-fr.png


代码

包含三个代码文件,./access.names 为白名单,./app.py 为 flask 服务器后端,`./templates/index.html 为网页前端。

Flask 后端

终端执行 touch app.py 新建网页服务器后端程序文件,并添加如下代码

 #!/usr/bin/env python3
 import os, cv2, numpy as np, pickle, time
 from pathlib import Path
 from flask import Flask, request, jsonify, render_template, url_for
 import RPi.GPIO as GPIO
 import threading
 
 PIN_SERVO = 18
 FREQ      = 50
 GPIO.setmode(GPIO.BCM)
 GPIO.setup(PIN_SERVO, GPIO.OUT)
 pwm = GPIO.PWM(PIN_SERVO, FREQ)
 pwm.start(0)
 
 ACCESS_LIST = set(line.strip() for line in open('access.names') if line.strip())
 
 # ---------- 人脸模型 ----------
 detector   = cv2.FaceDetectorYN_create("model/face_yunet.onnx", "", (320, 320))
 recognizer = cv2.FaceRecognizerSF_create("model/face_sface.onnx", "")
 registry   = pickle.loads(Path("model/face_registry.pkl").read_bytes()) if Path("model/face").exists() else {}
 
 def rotate(angle, speed=480):
     duty = 2.5 if angle > 0 else 12.5
     pwm.ChangeDutyCycle(duty)
     time.sleep(abs(angle) / speed)
     pwm.ChangeDutyCycle(0)
 
 def door_cycle():
     rotate(90); time.sleep(3); rotate(-90)   # 门禁控制
 
 # ---------- Flask ----------
 app = Flask(__name__)
 
 @app.route('/')
 def index():
     return render_template('index.html')
 
 @app.route('/upload', methods=['POST'])
 def upload():
     file = request.files['image']
     img  = cv2.imdecode(np.frombuffer(file.read(), np.uint8), cv2.IMREAD_COLOR)
     h, w = img.shape[:2]
     detector.setInputSize((w, h))
     faces = detector.detect(img)[1]
     name, score = "Unknown", 0.0
     if faces is not None:
         face = faces[0]
         for reg_name, reg_feat in registry.items():
             s = recognizer.match(feat, reg_feat, cv2.FaceRecognizerSF_FR_COSINE)
             if s > score:
                 score, name = s, reg_name
         if score < 0.3:          # 识别阈值
             name = "Unknown"
 
     # 门禁动作
     if name != "Unknown" and name in ACCESS_LIST:
         threading.Thread(target=door_cycle, daemon=True).start()
         tip = f"{name} 请通行"
     else:
         tip = f"{name} 无权限,拒绝通行"
 
     if faces is not None:
         x, y, w_box, h_box = map(int, face[:4])
         cv2.rectangle(img, (x, y), (x + w_box, y + h_box), (0, 255, 0), 2)
 
     return jsonify(name=name, score=round(score, 3), tip=tip,
                    result_url=url_for('static', filename='result.jpg'))
 
 # ---------- 退出 ----------
 import atexit
 atexit.register(lambda: (pwm.stop(), GPIO.cleanup()))
 
 if __name__ == '__main__':
     app.run(host='0.0.0.0', port=5000, debug=False)

Web 前端

终端执行 touch ./templates/index.html 新建 HTML 前端网页程序,并添加如下代码

 <!doctype html>
 <html>
 <head>
   <meta charset="utf-8">
   <title>树莓派门禁</title>
   <style>
     body{font-family:Arial;background:#f2f2f2;margin:0;padding:30px;text-align:center}
     #box{background:#fff;max-width:400px;margin:auto;padding:30px;border-radius:8px;box-shadow:0 0 10px rgba(0,0,0,.1)}
     img{max-width:100%;margin-top:15px}
     .opened{color:green}
     .denied{color:red}
   </style>
 </head>
 <body>
   <div id="box">
     <h2>人脸识别门禁</h2>
     <input type="file" id="fileInput" accept="image/*"><br>
     <button onclick="upload()">上传识别</button>
     <img id="resultImg" style="display:none;">
   </div>
 
 <script>
 async function upload(){
   const file = document.getElementById('fileInput').files[0];
   if (!file) return alert('请选择图片');
   document.getElementById('status').innerText = '识别中...';
 
   const form = new FormData();
   form.append('image', file);
   const res = await fetch('/upload', {method:'POST', body:form}).then(r=>r.json());
 
   img.src = res.result_url + '?t=' + Date.now();
   img.style.display = 'block';
 
   setTimeout(() => {
      document.getElementById('status').innerText = '已关门,等待识别';
      img.style.display = 'none';
   }, 3000);
 }
 </script>
 </body>
 </html>

白名单

终端执行 touch access.names 新建白名单文件,并添加人名列表

 Linda
 Edward
 Clarke

保存代码。

效果

终端执行指令 python app_DC.py 运行程序;

终端打印 Web 服务器网址,如http://192.168.31.117:5000/ ;

dc_print.jpg

浏览器打开服务器前端网页;

  • 点击 选择文件 按钮,加载目标识别人脸;

  • 点击 上传识别 按钮,立即显示识别结果、是否允许通行;

dc_pass.jpg

dc_deny.jpg

  • 同时舵机逆时针转动,控制门禁档杆移动,表示允许通过;

  • 待三秒钟后,舵机顺时针旋转 90 度,表示门禁关闭;

  • 网页前端显示门禁已关闭,回到 等待识别 状态。

dc_wait.jpg

动态效果

dc_fr.gif


总结

本文介绍了树莓派 5 单板计算机结合 OpenCV 内置的 YuNet 算法和 SFace 模型实现人脸识别的项目设计,包括环境部署、预训练模型获取、关键代码、板端推理、效果演示等流程,为相关产品在边缘 AI 领域的快速开发和应用设计提供了参考。





关键词: 树莓派          门禁系统     舵机     人脸识别     OpenCV         

院士
2026-01-10 10:55:36     打赏
2楼

哇,好厉害的作品展示啊


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]