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

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

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

**快递到了不知道?陌生人按门铃不敢开?这个 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 = 

    

    # 加载或创建数据库

    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 = 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:

            name = known_names

            confidence = 1 - face_distances

            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 > /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

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


相关资源:**