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

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

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

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

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


相关资源:
face_recognition 官方文档
Server 酱官网
树莓派 GPIO 引脚图
项目 GitHub 仓库