</>CoderDIY
← Quay lại danh sách
Bài viết

Camera an ninh AI phát hiện người lạ với Raspberry Pi

Tác giả: CoderDIY··Đọc bằng tiếng Anh
🕵️

Camera an ninh dùng cảm biến chuyển động PIR đơn thuần có một vấn đề kinh điển: báo động giả liên tục vì gió lay cành cây, bóng nắng di chuyển, hay chú mèo hàng xóm đi ngang. Bằng cách thêm một mô hình phát hiện đối tượng nhẹ chạy ngay trên Raspberry Pi, camera có thể phân biệt được “có chuyển động” và “có người thật” — chỉ gửi cảnh báo khi thực sự cần thiết, không cần gửi ảnh lên cloud để xử lý.

Nguyên lý hoạt động

  1. Camera liên tục chụp khung hình; một bước lọc chuyển động đơn giản (so sánh khung hình liên tiếp) chạy trước để tiết kiệm tài nguyên — chỉ khi có thay đổi đáng kể mới chuyển sang bước phát hiện đối tượng.
  2. Khung hình có chuyển động được đưa qua mô hình MobileNet SSD (Single Shot Detector) đã được huấn luyện sẵn, tối ưu để chạy đủ nhanh trên CPU của Raspberry Pi mà không cần GPU rời.
  3. Mô hình trả về danh sách các đối tượng phát hiện được kèm nhãn (person, car, dog…) và độ tin cậy; hệ thống chỉ coi là “cảnh báo thật” khi nhãn person xuất hiện với độ tin cậy trên một ngưỡng nhất định.
  4. Khi phát hiện người, hệ thống lưu ảnh/video ngắn kèm khung giờ, gửi cảnh báo qua Telegram kèm ảnh chụp để chủ nhà xem ngay được ai đang đứng trước cửa mà không cần mở app riêng.
<rect x="10" y="20" width="140" height="60" rx="10" class="box" />
<text x="80" y="45" text-anchor="middle" class="label">Đọc khung hình</text>
<text x="80" y="62" text-anchor="middle" class="label">liên tục</text>

<rect x="170" y="20" width="140" height="60" rx="10" class="box" />
<text x="240" y="45" text-anchor="middle" class="label">Lọc chuyển động</text>
<text x="240" y="62" text-anchor="middle" class="label">(so khung hình)</text>

<rect x="330" y="20" width="140" height="60" rx="10" class="box" />
<text x="400" y="45" text-anchor="middle" class="label">MobileNet SSD</text>
<text x="400" y="62" text-anchor="middle" class="label">phát hiện người</text>

<rect x="490" y="20" width="140" height="60" rx="10" class="box" />
<text x="560" y="45" text-anchor="middle" class="label">Lưu + gửi cảnh báo</text>
<text x="560" y="62" text-anchor="middle" class="label">(Telegram)</text>

<line x1="150" y1="50" x2="170" y2="50" class="arrow" />
<line x1="310" y1="50" x2="330" y2="50" class="arrow" />
<line x1="470" y1="50" x2="490" y2="50" class="arrow" />

<path d="M 560 80 L 560 190 L 80 190 L 80 80" class="arrow" fill="none" />
<text x="320" y="210" text-anchor="middle" class="sublabel">Không có chuyển động → bỏ qua bước AI, tiết kiệm CPU</text>
Lọc chuyển động trước giúp tiết kiệm tài nguyên, chỉ chạy mô hình AI nặng hơn khi thực sự cần kiểm tra.

Linh kiện

  • Raspberry Pi 4 (4GB trở lên, để chạy mô hình phát hiện đối tượng mượt hơn)
  • Raspberry Pi Camera Module hoặc webcam USB
  • Thẻ nhớ microSD dung lượng đủ lớn để lưu clip cảnh báo
  • Mô hình MobileNet SSD đã huấn luyện sẵn (file .caffemodel/.pb tải công khai, chạy qua OpenCV DNN module)
  • (Tùy chọn) Vỏ chống nước nếu lắp ngoài trời, và đèn hồng ngoại nếu cần quan sát ban đêm
<rect x="30" y="70" width="170" height="90" rx="10" class="box" />
<text x="115" y="120" text-anchor="middle" class="label">Camera Module</text>

<rect x="240" y="70" width="170" height="90" rx="10" class="box" />
<text x="325" y="120" text-anchor="middle" class="label">Raspberry Pi 4</text>

<rect x="450" y="70" width="170" height="90" rx="10" class="box" />
<text x="535" y="105" text-anchor="middle" class="label">Telegram Bot</text>
<text x="535" y="123" text-anchor="middle" class="label">(điện thoại chủ nhà)</text>

<line x1="200" y1="115" x2="240" y2="115" class="wire" />
<text x="220" y="105" text-anchor="middle" class="sublabel">CSI/USB</text>

<line x1="410" y1="115" x2="450" y2="115" class="wire" />
<text x="430" y="105" text-anchor="middle" class="sublabel">WiFi</text>
Camera nối trực tiếp với Raspberry Pi để xử lý cục bộ, chỉ gửi dữ liệu ra ngoài khi phát hiện người thật qua Telegram.

Code mẫu

import cv2
import numpy as np
import time
import requests

PROTOTXT = "MobileNetSSD_deploy.prototxt"
MODEL = "MobileNetSSD_deploy.caffemodel"
CONFIDENCE_THRESHOLD = 0.5
BOT_TOKEN = "TELEGRAM_BOT_TOKEN"
CHAT_ID = "TELEGRAM_CHAT_ID"

CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle",
           "bus", "car", "cat", "chair", "cow", "diningtable", "dog",
           "horse", "motorbike", "person", "pottedplant", "sheep", "sofa",
           "train", "tvmonitor"]

net = cv2.dnn.readNetFromCaffe(PROTOTXT, MODEL)
cap = cv2.VideoCapture(0)
prev_gray = None
last_alert = 0
ALERT_COOLDOWN = 60  # giay, tranh gui lien tuc khi nguoi con dung truoc cua

def send_alert(frame_path):
    with open(frame_path, "rb") as photo:
        requests.post(
            f"https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto",
            data={"chat_id": CHAT_ID, "caption": "Phat hien nguoi la truoc cua!"},
            files={"photo": photo},
        )

def has_motion(frame):
    global prev_gray
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (21, 21), 0)
    if prev_gray is None:
        prev_gray = gray
        return False
    diff = cv2.absdiff(prev_gray, gray)
    prev_gray = gray
    return np.mean(diff) > 5  # nguong don gian, tuy chinh theo moi truong thuc te

def detect_person(frame):
    h, w = frame.shape[:2]
    blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 0.007843, (300, 300), 127.5)
    net.setInput(blob)
    detections = net.forward()

    for i in range(detections.shape[2]):
        confidence = detections[0, 0, i, 2]
        if confidence < CONFIDENCE_THRESHOLD:
            continue
        class_id = int(detections[0, 0, i, 1])
        if CLASSES[class_id] == "person":
            return True
    return False

while True:
    ret, frame = cap.read()
    if not ret:
        continue

    if has_motion(frame) and detect_person(frame):
        now = time.time()
        if now - last_alert > ALERT_COOLDOWN:
            frame_path = "alert_frame.jpg"
            cv2.imwrite(frame_path, frame)
            send_alert(frame_path)
            last_alert = now
            print("Da gui canh bao!")

    time.sleep(0.5)

Những lỗi thường gặp

  • Chạy mô hình AI trên mọi khung hình liên tục làm Raspberry Pi quá tải và nóng máy — luôn lọc chuyển động trước bằng phép so sánh khung hình đơn giản, chỉ chạy AI khi thực sự có thay đổi.
  • Không có cơ chế chống spam cảnh báo (ALERT_COOLDOWN) khiến điện thoại nhận hàng chục thông báo liên tục khi có người đứng lâu trước cửa — luôn đặt khoảng nghỉ tối thiểu giữa hai lần cảnh báo.
  • Độ tin cậy (CONFIDENCE_THRESHOLD) đặt quá thấp khiến hệ thống báo động giả với bóng người hoặc vật thể trông giống người — bắt đầu với 0.5 rồi tinh chỉnh theo môi trường lắp đặt thực tế.
  • Ánh sáng ban đêm kém làm mô hình phát hiện kém chính xác hẳn so với ban ngày — cân nhắc thêm đèn hồng ngoại hoặc camera có chế độ night vision nếu cần giám sát 24/7.

Mở rộng

Thêm nhận diện khuôn mặt để phân biệt người nhà và người lạ (chỉ cảnh báo với người lạ), lưu toàn bộ clip lên NAS hoặc cloud storage riêng thay vì chỉ ảnh tĩnh, hoặc kết hợp với dự án chuông cửa thông minh ESP32-CAM để vừa giám sát vừa cho phép giao tiếp hai chiều qua loa/micro khi có khách.

Thẻ:#raspberry-pi#opencv#security

Bình luận