Việc đếm số người trong một bức ảnh hoặc một khung hình video là một bài toán rất thực tế và có mặt trong nhiều lĩnh vực quan trọng. Trong giao thông đô thị, giám sát đám đông, quản lý sự kiện hoặc giám sát an ninh, việc biết chính xác có bao nhiêu người đang xuất hiện trong vùng quan sát là vô cùng quan trọng để đưa ra các quyết định điều phối, cảnh báo hoặc lưu trữ dữ liệu.
Truyền thống, các hệ thống camera chỉ phát hiện có người hay không, nhưng nhờ thị giác máy tính (computer vision), chúng ta có thể tự động đếm chính xác số lượng người đang có mặt trong ảnh tĩnh hoặc video, ngay cả khi họ đứng gần nhau, di chuyển, hoặc bị che khuất một phần. Trong số các kỹ thuật hiện đại, segmentation – đặc biệt là instance segmentation – đang trở thành giải pháp hiệu quả nhất để giải quyết bài toán này.
Vì sao dùng segmentation thay vì object detection?
Trong các hệ thống cổ điển như YOLO hoặc SSD, mô hình sẽ phát hiện người bằng các bounding box. Tuy nhiên, khi người đứng gần nhau hoặc bị che khuất, các bounding box có thể bị chồng lên nhau hoặc gộp nhầm thành một. Điều này khiến kết quả đếm không chính xác – một vấn đề rất phổ biến khi triển khai hệ thống trong môi trường đông người.
Khác với detection, kỹ thuật instance segmentation có khả năng vẽ vùng (mask) chính xác cho từng cá thể riêng biệt, kể cả khi họ đứng sát nhau. Mỗi người sẽ được phân đoạn độc lập, nhờ đó hệ thống có thể đếm từng người một cách chính xác, tránh hiện tượng đếm trùng hoặc bỏ sót.
Kỹ thuật segmentation phù hợp nhất với các môi trường như:
-
Bến tàu, sân bay, ga tàu điện ngầm
-
Trung tâm thương mại, sân vận động
-
Giao lộ hoặc điểm nút giao thông
-
Cảnh quay từ trên cao hoặc camera giám sát góc rộng
Các phương pháp segmentation dùng để đếm người
Có 3 phương pháp segmentation chính trong thị giác máy tính:
-
Semantic segmentation: phân biệt các vùng như “người”, “xe”, “cây”… nhưng không tách cá thể riêng.
-
Instance segmentation: phân biệt từng cá thể riêng biệt của cùng một lớp (nhiều người, nhiều xe).
-
Panoptic segmentation: kết hợp semantic và instance segmentation.
Trong bài toán đếm người, ta cần dùng instance segmentation. Một số mô hình phổ biến hỗ trợ tốt tác vụ này gồm:
-
Mask R-CNN: mô hình cổ điển mạnh mẽ, độ chính xác cao, nhưng chạy chậm hơn.
-
YOLOv8-seg: phiên bản mới của YOLO hỗ trợ segmentation, nhanh, nhẹ và dễ triển khai.
-
Detectron2: framework mạnh mẽ của Facebook AI, hỗ trợ segmentation cực kỳ chi tiết.
Cài đặt thư viện cần thiết để thực hiện segmentation
Trước khi bắt đầu viết code đếm người, bạn cần cài đặt các thư viện cần thiết. Trong bài này, mình sẽ dùng YOLOv8-seg từ thư viện ultralytics, vốn rất dễ dùng và hỗ trợ cả detection lẫn segmentation.
Đầu tiên, mở terminal và chạy lệnh sau để cài các thư viện:
pip install ultralytics opencv-python torch torchvision
Lệnh này sẽ cài:
-
ultralytics: chứa YOLOv8 và các phiên bản segmentation -
opencv-python: dùng để xử lý ảnh và hiển thị -
torch,torchvision: dùng cho inference mô hình deep learning
Tải mô hình YOLOv8 segmentation và chạy thử
Sau khi cài xong, bạn có thể tải mô hình segmentation đã huấn luyện sẵn từ Ultralytics. Các mô hình có hậu tố -seg.pt là bản segmentation. Ví dụ:
-
yolov8n-seg.pt: bản nhẹ nhất, chạy nhanh, ít chính xác hơn -
yolov8s-seg.pt: bản nhẹ nhưng tốt hơn -
yolov8m-seg.pt,l,x: bản lớn hơn, chính xác hơn
Trong ví dụ này, ta dùng bản n để dễ thử nghiệm:
from ultralytics import YOLO
model = YOLO('yolov8n-seg.pt') # segmentation model
Đếm số người trong ảnh bằng segmentation
Sau khi model đã sẵn sàng, ta sẽ viết code để đếm số lượng cá thể có lớp là “person” trong ảnh.
Trước khi viết code, bạn cần hiểu rằng mỗi kết quả từ mô hình YOLOv8-seg sẽ bao gồm:
-
boxes: thông tin toạ độ của các đối tượng
-
masks: thông tin phân đoạn
-
class_ids: chỉ số lớp, trong đó 0 là “person” (theo COCO dataset)
from ultralytics import YOLO
import cv2
# Load mô hình segmentation
model = YOLO('yolov8n-seg.pt')
# Load ảnh
image_path = 'people.jpg'
image = cv2.imread(image_path)
# Chạy model
results = model(image)[0]
# Đếm số người có class_id == 0 (tức là 'person' trong COCO)
person_count = sum(1 for cls in results.boxes.cls if int(cls) == 0)
print("Số người trong ảnh:", person_count)
# Hiển thị ảnh có mask
annotated_image = results.plot()
cv2.imshow("Segmentation Result", annotated_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Sau khi chạy, bạn sẽ thấy số người được đếm hiển thị trong terminal.
Một số lưu ý để tăng độ chính xác
Khi triển khai bài toán đếm người bằng segmentation, có vài yếu tố ảnh hưởng đến kết quả:
- Chất lượng ảnh: Ảnh mờ, nhỏ hoặc bị lóa sẽ gây khó khăn cho mô hình.
- Số người quá đông: Nếu quá nhiều người đứng gần nhau, kể cả segmentation vẫn có thể lỗi mask.
- Bị che khuất: Nếu người đứng sau bị khuất, model có thể bỏ sót.
Để cải thiện kết quả, bạn có thể:
-
Dùng model lớn hơn như
yolov8m-seg.pt -
Resize ảnh lớn hơn trước khi đưa vào model
-
Kết hợp thêm post-processing loại bỏ mask nhỏ, hoặc đếm theo độ tin cậy (confidence threshold)
Mở rộng: đếm người trong video hoặc camera realtime
Sau khi làm việc với ảnh tĩnh, bạn có thể mở rộng sang xử lý video hoặc camera realtime. Thay vì đọc cv2.imread(), bạn sẽ dùng:
from ultralytics import YOLO
import cv2
# Load model segmentation
model = YOLO('yolov8n-seg.pt')
# Khởi động webcam (0 là webcam mặc định)
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
# Chạy model
results = model(frame)[0]
# Đếm số người
count = sum(1 for cls in results.boxes.cls if int(cls) == 0)
print("Số người:", count)
# Hiển thị ảnh
annotated_frame = results.plot()
cv2.imshow("Live Count", annotated_frame)
# Bấm 'q' để thoát
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

