目录

智能门铃项目实战:人脸识别 + 微信推送,家门口的小管家

快递到了不知道?陌生人按门铃不敢开?这个 DIY 智能门铃帮你盯着家门口!

上周我家门口被塞了好几张传单,等我下班回来才发现。当时就想:要是有个东西能自动识别门口的人,还能通知我就好了。于是这个周末,我动手做了个智能门铃——不仅能人脸识别,还能通过微信推送消息到手机。

整个项目成本不到 300 块,用树莓派 + 摄像头 + 微信推送服务就能搞定。今天把完整过程分享给大家。

需要准备什么?

物品 型号/规格 价格
树莓派 Raspberry Pi 4B 2GB ¥280
摄像头 USB 摄像头 1080P ¥35
麦克风 USB 麦克风(可选) ¥25
门铃按钮 常开自复位开关 ¥8
杜邦线 公对母 20cm ¥5
外壳 3D 打印/塑料盒 ¥20
**总计** **¥373**

如果你已经有树莓派,成本可以压到 100 块以内。摄像头我用的是普通的 USB webcam,淘宝随便买的,能看清人脸就行。

步骤 1:系统环境搭建

首先给树莓派装上系统。我推荐用 Raspberry Pi OS(64 位),下载地址:https://www.raspberrypi.com/software/operating-systems/

烧录好系统后,通过 SSH 登录树莓派,然后安装必要的依赖:

# 更新系统
sudo apt-get update
sudo apt-get upgrade -y

# 安装 Python 依赖
sudo apt-get install -y python3-pip python3-opencv python3-numpy
sudo apt-get install -y libatlas-base-dev libjasper-dev libqtgui4 libqt4-test

# 安装 face_recognition 库(基于 dlib)
pip3 install face_recognition
pip3 install requests
pip3 install gpiozero

注意事项: ⚠️ face_recognition 库编译比较慢,树莓派上可能需要 20-30 分钟。建议先喝杯咖啡,让它发热吧,别发光就好。

如果编译过程中报错,通常是缺少 C++ 编译器,执行下面命令:

sudo apt-get install -y build-essential cmake

步骤 2:录入家庭成员人脸

接下来要录入家里人的人脸数据。我写了一个简单的脚本,调用摄像头拍照并提取人脸特征:

# enroll_face.py
import cv2
import face_recognition
import pickle
import os

def enroll_face(name, num_photos=5):
    """录入人脸,拍摄多张照片取平均特征"""
    print(f"开始录入 {name} 的人脸,请保持表情自然...")

    encodings = []
    cap = cv2.VideoCapture(0)

    if not cap.isOpened():
        print("❌ 摄像头无法打开,请检查连接")
        return False

    for i in range(num_photos):
        ret, frame = cap.read()
        if not ret:
            continue

        # 转 RGB 格式
        rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        # 检测人脸
        face_locations = face_recognition.face_locations(rgb_frame)

        if len(face_locations) == 0:
            print(f"第{i+1}张:未检测到人脸,请正对摄像头")
            continue

        if len(face_locations) > 1:
            print(f"第{i+1}张:检测到多张人脸,请确保只有一人")
            continue

        # 提取人脸特征
        face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)
        if face_encodings:
            encodings.append(face_encodings[0])
            print(f"第{i+1}张:✅ 特征提取成功")

    cap.release()

    if not encodings:
        print("❌ 未能提取到任何人脸特征")
        return False

    # 保存特征(取平均)
    avg_encoding = [sum(e) / len(e) for e in zip(*encodings)]

    # 加载或创建数据库
    db_file = "face_database.pkl"
    if os.path.exists(db_file):
        with open(db_file, "rb") as f:
            database = pickle.load(f)
    else:
        database = {}

    database[name] = avg_encoding

    with open(db_file, "wb") as f:
        pickle.dump(database, f)

    print(f"✅ {name} 的人脸录入成功!共{len(encodings)}张有效照片")
    return True

if __name__ == "__main__":
    name = input("请输入姓名:")
    enroll_face(name)

运行脚本:

python3 enroll_face.py

按提示输入家人姓名,然后对着摄像头拍几张照片。建议每人录入 5 张以上,识别准确率会更高。

步骤 3:微信推送服务配置

这里用 Server 酱(https://sct.ftqq.com/)实现微信推送,免费且简单

  1. 访问 Server 酱官网,用微信扫码登录
  2. 绑定微信后,获取 SendKey(类似:SCT123456abcdef
  3. 在微信关注"方糖"公众号,就能收到推送

测试推送:

# 替换为你的 SendKey
curl -X POST "https://sctapi.ftqq.com/SCT123456abcdef.send" \
  -d "text=门铃测试" \
  -d "desp=有人在门口按门铃了!"

如果微信收到消息,说明配置成功。

步骤 4:主程序编写

重头戏来了!下面是完整的主程序,集成了人脸检测和微信推送:

# smart_doorbell.py
import cv2
import face_recognition
import pickle
import requests
import time
from gpiozero import Button
from datetime import datetime

# ============ 配置区 ============
SERVERCHAN_KEY = "SCT123456abcdef"  # 替换为你的 SendKey
FACE_DATABASE = "face_database.pkl"
BUTTON_PIN = 17  # GPIO 17 接门铃按钮
CAMERA_INDEX = 0
RECOGNITION_THRESHOLD = 0.6  # 人脸识别阈值
# ===============================

def load_face_database():
    """加载人脸数据库"""
    if not os.path.exists(FACE_DATABASE):
        print("❌ 人脸数据库不存在,请先运行 enroll_face.py")
        return {}, []

    with open(FACE_DATABASE, "rb") as f:
        database = pickle.load(f)

    names = list(database.keys())
    encodings = list(database.values())
    print(f"✅ 已加载 {len(names)} 个人脸:{', '.join(names)}")
    return names, encodings

def send_wechat_push(title, content, image_path=None):
    """发送微信推送"""
    url = f"https://sctapi.ftqq.com/{SERVERCHAN_KEY}.send"

    data = {
        "text": title,
        "desp": content
    }

    # 如果有图片,上传到图床后附加
    if image_path and os.path.exists(image_path):
        # Server 酱支持图片 URL,这里简化处理
        pass

    try:
        response = requests.post(url, data=data, timeout=10)
        if response.status_code == 200:
            print("✅ 微信推送成功")
            return True
        else:
            print(f"❌ 推送失败:{response.text}")
            return False
    except Exception as e:
        print(f"❌ 推送异常:{e}")
        return False

def recognize_face(frame, known_names, known_encodings):
    """识别人脸"""
    # 缩小图片加速处理
    small_frame = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5)
    rgb_frame = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB)

    # 检测人脸
    face_locations = face_recognition.face_locations(rgb_frame)

    if not face_locations:
        return None, "未检测到人脸"

    # 提取特征
    face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)

    if not face_encodings:
        return None, "无法提取人脸特征"

    # 匹配已知人脸
    face_encoding = face_encodings[0]
    matches = face_recognition.compare_faces(known_encodings, face_encoding, RECOGNITION_THRESHOLD)
    face_distances = face_recognition.face_distance(known_encodings, face_encoding)

    if len(face_distances) > 0:
        best_match_idx = np.argmin(face_distances)
        if matches[best_match_idx]:
            name = known_names[best_match_idx]
            confidence = 1 - face_distances[best_match_idx]
            return name, f"识别成功:{name} (置信度:{confidence:.2%})"

    return "陌生人", "⚠️ 检测到陌生人"

def capture_and_save():
    """抓拍并保存图片"""
    cap = cv2.VideoCapture(CAMERA_INDEX)
    ret, frame = cap.read()
    cap.release()

    if ret:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"captures/{timestamp}.jpg"
        os.makedirs("captures", exist_ok=True)
        cv2.imwrite(filename, frame)
        return filename
    return None

def main():
    print("🔔 智能门铃启动中...")

    # 加载人脸库
    known_names, known_encodings = load_face_database()
    if not known_names:
        return

    # 初始化门铃按钮
    doorbell_button = Button(BUTTON_PIN, pull_up=False)
    print("✅ 门铃系统就绪,等待按铃...")

    last_push_time = 0
    PUSH_COOLDOWN = 30  # 30 秒防抖

    while True:
        if doorbell_button.is_pressed:
            current_time = time.time()

            # 防抖处理
            if current_time - last_push_time < PUSH_COOLDOWN:
                time.sleep(0.5)
                continue

            last_push_time = current_time
            print("🔔 门铃被按下!")

            # 抓拍照片
            cap = cv2.VideoCapture(CAMERA_INDEX)
            ret, frame = cap.read()
            cap.release()

            if not ret:
                print("❌ 摄像头故障")
                continue

            # 人脸识别
            name, message = recognize_face(frame, known_names, known_encodings)

            # 生成推送内容
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            title = f"🔔 门铃提醒 - {name}"
            content = f"""
时间:{timestamp}
{message}

位置:家门口
设备:智能门铃 v1.0
            """.strip()

            # 保存图片
            img_path = capture_and_save()

            # 发送推送
            send_wechat_push(title, content, img_path)

            # 语音提示(可选)
            if name == "陌生人":
                print("⚠️ 陌生人在门口,请注意安全!")
            else:
                print(f"✅ {name} 回家啦!")

            time.sleep(1)

        time.sleep(0.1)

if __name__ == "__main__":
    import os
    import numpy as np
    main()

步骤 5:硬件连接

门铃按钮接线很简单:

树莓派 GPIO 17 ──┬── 按钮一端
                │
按钮另一端 ──────┬── GPIO GND

按钮用常开型,按下时 17 号引脚和 GND 导通。我用的是一种自复位开关,淘宝 8 块钱包邮。

如果想更精致,可以 3D 打印个外壳,把摄像头和按钮都装进去。

步骤 6:开机自启动

让门铃程序开机自动运行:

# 编辑 crontab
crontab -e

# 添加下面一行(替换实际路径)
@reboot cd /home/pi/smart-doorbell && /usr/bin/python3 smart_doorbell.py >> /var/log/doorbell.log 2>&1

重启测试:

sudo reboot

重启后检查日志:

tail -f /var/log/doorbell.log

常见问题排查

问题 1: 人脸识别很慢,要 3-4 秒才响应

  • 原因: 树莓派 CPU 性能有限,face_recognition 库计算量大
  • 解决:
    1. 缩小输入图片分辨率(代码中已处理)
    2. 改用 USB 加速棒(如 Intel Neural Compute Stick)
    3. 或者降低识别频率,改为定时检测

问题 2: 摄像头画面太暗,晚上看不清

  • 原因: 普通摄像头没有红外夜视
  • 解决:
    1. 加装红外补光灯(¥15 左右)
    2. 换带夜视功能的摄像头(¥60-80)
    3. 调整摄像头曝光参数

问题 3: 微信推送延迟高

  • 原因: Server 酱服务器响应慢
  • 解决:
    1. 检查网络连接
    2. 改用其他推送服务(如 Bark、PushPlus)
    3. 本地搭建 MQTT 服务,用 Home Assistant 推送

问题 4: 误识别率高,经常认错人

  • 原因: 录入照片太少或光线变化大
  • 解决:
    1. 每人录入 10 张以上照片(不同光线/角度)
    2. 调低识别阈值(代码中 RECOGNITION_THRESHOLD)
    3. 定期更新人脸库

扩展玩法

这个基础版本还能继续升级:

  1. 语音对讲:加装麦克风和喇叭,实现双向通话
  2. 远程开门:接继电器控制电锁,微信回复"开门"即可
  3. 视频录像:检测到陌生人自动录像保存
  4. 接入 Home Assistant:联动其他智能家居设备
  5. 多人识别:区分快递员、家人、访客,推送不同消息

总结

这个智能门铃项目用了不到一天就完成了,核心就是三点:

  1. face_recognition 库做人脸识别
  2. 用 Server 酱实现微信推送
  3. 用 GPIO 检测门铃按钮

成本可控,效果也不错。识别准确率大概 90% 左右,家里人基本都能认出来。陌生人会触发特别提醒,安全感满满。

如果你也想做一个,遇到问题欢迎在评论区留言。代码我已经放到 GitHub 上了,欢迎 Star:https://github.com/makeronsite/smart-doorbell

希望这篇博客文章对您有所帮助!


相关资源:

更多关于 的文章
关注创客出手公众号

关注创客出手