Projects

Dự án: đếm người qua cửa với YOLO26 và tracking

Kết hợp phát hiện đối tượng và theo dõi để đếm lượt vào, ra theo hai chiều; đánh giá sai số và tăng tốc trên máy yếu.

Dự án: đếm người qua cửa với YOLO26 và tracking
Nội dung bài viết
  1. Vì sao cần tracking?
  2. Cài đặt
  3. Mã nguồn
  4. Đánh giá độ chính xác
  5. Chạy nhanh hơn trên máy yếu
  6. Quyền riêng tư

Đếm người ra vào cửa hàng, đếm xe qua cổng, đếm sản phẩm đa dạng trên băng tải: tất cả đều là một bài toán gồm hai phần, phát hiện (detection) và theo dõi (tracking). Dự án này dùng YOLO26 của Ultralytics với tracker tích hợp sẵn để đếm người đi qua một vạch theo hai chiều vào/ra.

Vì sao cần tracking?

Detection chỉ cho biết "khung hình này có 3 người ở đâu". Để đếm, ta cần biết người ở khung hình sau có phải là cùng một người ở khung hình trước không. Tracker gán cho mỗi đối tượng một ID ổn định qua các khung hình (Ultralytics mặc định dùng BoT-SORT, có thể đổi sang ByteTrack hoặc tracker khác qua file YAML).

Cài đặt

pip install ultralytics opencv-python

Mã nguồn

import cv2
from ultralytics import YOLO

model = YOLO("yolo26n.pt")             # mô hình COCO, lớp 0 = person
cap = cv2.VideoCapture("cua-ra-vao.mp4")
LINE_Y = 360                           # vạch đếm nằm ngang

last_y = {}                            # track_id -> tọa độ y của tâm ở khung trước
count_in, count_out = 0, 0

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

    results = model.track(frame, persist=True, classes=[0], conf=0.4, verbose=False)
    boxes = results[0].boxes

    if boxes.id is not None:
        ids = boxes.id.int().tolist()
        for tid, (cx, cy, w, h) in zip(ids, boxes.xywh.tolist()):
            prev = last_y.get(tid)
            if prev is not None:
                if prev < LINE_Y <= cy:
                    count_in += 1          # đi từ trên xuống: vào
                elif prev >= LINE_Y > cy:
                    count_out += 1         # đi từ dưới lên: ra
            last_y[tid] = cy
            cv2.rectangle(frame, (int(cx - w / 2), int(cy - h / 2)),
                          (int(cx + w / 2), int(cy + h / 2)), (0, 255, 0), 2)
            cv2.putText(frame, f"#{tid}", (int(cx - w / 2), int(cy - h / 2) - 6),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)

    cv2.line(frame, (0, LINE_Y), (frame.shape[1], LINE_Y), (0, 255, 255), 2)
    cv2.putText(frame, f"Vao: {count_in}  Ra: {count_out}", (10, 40),
                cv2.FONT_HERSHEY_SIMPLEX, 1.1, (0, 0, 255), 3)
    cv2.imshow("Dem nguoi", frame)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

Điểm mấu chốt là persist=True: nó giữ trạng thái tracker giữa các lần gọi, nếu thiếu thì ID bị đặt lại mỗi khung hình. Ultralytics cũng có sẵn lớp solutions.ObjectCounter làm việc tương tự chỉ với vài dòng; tự viết như trên giúp bạn hiểu cơ chế và tùy biến logic đếm.

Đánh giá độ chính xác

  1. Quay 10 phút video ở vị trí thật, tự đếm tay số người vào/ra.
  2. Chạy chương trình, so sánh. Sai số tính theo % của tổng số lượt.
  3. Xem lại các đoạn đếm sai để tìm nguyên nhân.
LỗiNguyên nhân thường gặpCách khắc phục
Đếm thiếu khi đông ngườiNgười che khuất nhauĐặt camera cao, nhìn chéo xuống hoặc nhìn thẳng từ trên
Đếm 2 lần một ngườiMất ID rồi gán ID mới khi đứng ngay vạchDùng "vùng đệm" hai vạch thay vì một vạch
Bỏ sót người ở xaNgười quá nhỏ trong ảnhTăng imgsz, dùng mô hình cỡ s/m

Chạy nhanh hơn trên máy yếu

  • Giảm độ phân giải đầu vào hoặc chỉ xử lý mỗi khung thứ 2.
  • Xuất sang OpenVINO (CPU Intel) hoặc TensorRT (GPU NVIDIA, Jetson): model.export(format="openvino").
  • Chỉ chạy detection trong vùng quanh cửa (cắt ROI).

Quyền riêng tư

Hệ thống đếm người xử lý hình ảnh con người. Chỉ lưu số đếm, không lưu video nếu không cần; thông báo rõ khu vực có camera và tuân thủ quy định về bảo vệ dữ liệu cá nhân hiện hành.

Muốn huấn luyện YOLO cho vật thể của riêng bạn? Xem bài Object Detection với YOLO26.

Ban biên tập HọcFree

Chúng tôi viết những bài hướng dẫn dễ hiểu, thực tế để ai cũng có thể tự học lập trình và ngoại ngữ, hoàn toàn miễn phí.