MÔ HÌNH NHẬN DIỆN VẬT THỂ YOLOv8 THỜI GIAN THỰC

Nếu như OpenCV truyền thống cần chúng ta tự chỉnh màu HSV, còn MediaPipe chuyên biệt cho bàn tay và khuôn mặt, thì YOLO (You Only Look Once) là đỉnh cao của thị giác máy tính hiện đại: nó có thể quét toàn bộ khung hình chỉ trong một lượt và nhận diện chính xác hàng chục loại vật thể khác nhau cùng lúc (con người, điện thoại, máy tính, cốc nước, xe cộ, chó, mèo...).

PHẦN 1: BẢN CHẤT CỦA YOLOv8

1. YOLO hoạt động như thế nào?

  • Trước khi có YOLO, các thuật toán cũ phải quét từng vùng nhỏ trên ảnh hàng trăm lần để tìm vật thể (rất chậm, chỉ đạt vài khung hình/giây).

  • YOLO đúng như tên gọi của nó (You Only Look Once): Đưa toàn bộ bức ảnh qua mạng nơ-ron tích chập (CNN) đúng 1 lần duy nhất.

  • Mạng nơ-ron chia bức ảnh thành một lưới (grid), đồng thời dự đoán:

    1. Bounding Box: Tọa độ khung chữ nhật $[x_1, y_1, x_2, y_2]$ ôm lấy vật thể.

    2. Class: Vật thể đó là gì (ví dụ: person, cup, cell phone).

    3. Confidence Score: Độ tin cậy/xác suất đoán đúng của AI (từ $0.0$ đến $1.0$).

2. Bộ dữ liệu COCO Dataset & Các phiên bản mô hình

Phiên bản tiền huấn luyện (Pre-trained) của YOLOv8 được học trên tập dữ liệu chuẩn COCO (Common Objects in Context) gồm 80 nhóm đồ vật phổ biến hằng ngày.

YOLOv8 có nhiều kích cỡ mô hình:

  • yolov8n.pt (Nano): Nhỏ nhất, nhẹ nhất (~6 MB), chạy cực kỳ mượt trên CPU của máy tính thông thường hoặc Raspberry Pi.

  • yolov8s.pt (Small), yolov8m.pt (Medium): Chính xác hơn nhưng nặng hơn, cần máy có card đồ họa (GPU).$\implies$ chúng ta sẽ chọn bản yolov8n.pt để đảm bảo tốc độ FPS cao nhất!

PHẦN 2: CÀI ĐẶT THƯ VIỆN ultralytics

Mở Terminal và cài đặt thư viện chính thức của hãng phát triển YOLO:

Bash
pip install ultralytics

(Lưu ý: Lần đầu tiên chạy code, thư viện sẽ tự động tải file trọng số nhẹ yolov8n.pt về máy tính trong vài giây).

PHẦN 3: LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG (OOP) VỚI YOLOv8

Chúng ta sẽ đóng gói thành lớp YOLODetector và xây dựng ứng dụng hiển thị tên đồ vật, độ tin cậy và FPS thời gian thực.

Tạo file buoi11_yolo_detection.py:

import cv2
import time
from ultralytics import YOLO

class YOLODetector:
    """Lớp quản lý mô hình YOLOv8"""
    def __init__(self, model_name="yolov8n.pt", conf_threshold=0.5):
        # 1. Nạp mô hình nhẹ Nano
        print(f"📦 Đang nạp mô hình {model_name}...")
        self.model = YOLO(model_name)
        self.conf_threshold = conf_threshold
        # Lấy danh sách tên 80 lớp từ mô hình
        self.classes = self.model.names

    def detect(self, frame):
        """Dự đoán và trích xuất các vật thể tìm thấy trong frame"""
        # verbose=False: Tắt in log dày đặc ra terminal của YOLO
        results = self.model(frame, conf=self.conf_threshold, verbose=False)
        detections = []

        # results[0].boxes chứa danh sách các bounding boxes tìm được
        for box in results[0].boxes:
            # Tọa độ hộp [x1, y1, x2, y2]
            x1, y1, x2, y2 = map(int, box.xyxy[0])
            # Độ tự tin (0.0 -> 1.0)
            conf = float(box.conf[0])
            # ID nhóm và tên đồ vật
            cls_id = int(box.cls[0])
            label = self.classes[cls_id]

            detections.append({
                "box": (x1, y1, x2, y2),
                "conf": conf,
                "label": label
            })

        return detections


class ObjectDetectionApp:
    def __init__(self, camera_index=0):
        self.cap = cv2.VideoCapture(camera_index)
        # Giảm độ phân giải về 640x480 để CPU tính toán real-time
        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

        self.detector = YOLODetector(conf_threshold=0.55)
        self.prev_time = time.time()

    def run(self):
        if not self.cap.isOpened():
            print("❌ Không thể kết nối Camera.")
            return

        print("--- YOLOv8 OBJECT DETECTION ĐANG CHẠY ---")
        print(" -> Thử giơ điện thoại, cốc nước, chai lọ, sách vở trước camera!")
        print(" -> Nhấn [Q] để thoát")

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

            # Lật gương cho tự nhiên
            frame = cv2.flip(frame, 1)

            # 1. Nhận diện đồ vật qua YOLO
            detections = self.detector.detect(frame)

            # 2. Vẽ các hộp bao và nhãn tên lên khung hình
            for item in detections:
                x1, y1, x2, y2 = item["box"]
                conf = item["conf"]
                label = item["label"]

                # Đổi màu hộp: Người (person) màu xanh dương, đồ vật khác màu xanh lá
                box_color = (255, 100, 0) if label == "person" else (0, 255, 0)

                # Vẽ khung chữ nhật ôm vật thể
                cv2.rectangle(frame, (x1, y1), (x2, y2), box_color, 2)

                # Vẽ nền nhãn chữ cho dễ đọc
                text = f"{label} {int(conf * 100)}%"
                (w, h), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
                cv2.rectangle(frame, (x1, y1 - 25), (x1 + w + 5, y1), box_color, -1)
                cv2.putText(frame, text, (x1 + 2, y1 - 6),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)

            # 3. Tính và hiển thị FPS
            curr_time = time.time()
            fps = 1 / (curr_time - self.prev_time) if (curr_time - self.prev_time) > 0 else 0
            self.prev_time = curr_time

            cv2.putText(frame, f"FPS: {int(fps)}", (20, 35),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
            cv2.putText(frame, f"Detected: {len(detections)}", (20, 65),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 0), 2)

            cv2.imshow("Buoi 11: YOLOv8 Real-Time Detection", frame)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        self.cap.release()
        cv2.destroyAllWindows()
        print(" Đã tắt chương trình an toàn.")

if __name__ == "__main__":
    app = ObjectDetectionApp()
    app.run()

PHẦN 4: THỰC HÀNH CÙNG BÉ & THỬ THÁCH SUY LUẬN

  1. Thực hành trải nghiệm:

    • Cho bé lấy các vật dụng quen thuộc quanh phòng giơ trước webcam:

      • Cầm điện thoại di động $\rightarrow$ Máy sẽ hiện cell phone.

      • Cầm cốc/ly uống nước $\rightarrow$ Hiện cup hoặc bottle.

      • Cầm một cuốn sách $\rightarrow$ Hiện book.

      • Bé đứng lùi ra xa hoặc bố bước vào khung hình $\rightarrow$ Máy nhận diện cùng lúc 2 người (person).

  2. Thử thách tư duy cho bé:

    • Thử thách 1 (Bộ lọc đối tượng quan tâm - Class Filtering):

      • Làm thế nào để camera CHỈ báo động và vẽ khung khi nhìn thấy cell phone, còn mọi vật thể khác (người, bàn, ghế...) thì bỏ qua không vẽ? (Gợi ý: Thêm điều kiện if label == "cell phone":).

    • Thử thách 2 (Ứng dụng chống xao nhãng khi học bài):

      • Kết hợp logic: Nếu phát hiện cell phone xuất hiện liên tục trong khung hình quá 3 giây $\implies$ Bật cảnh báo: "Hãy cất điện thoại đi và tập trung học bài!".