Theo dõi đối tượng bằng ByteTrack, BoT-SORT và TrackTrack
Gán cho mỗi đối tượng một ID ổn định xuyên suốt các khung hình, chọn tracker và tinh chỉnh các ngưỡng cho detector của bạn.
Mọi phép đếm, thời gian lưu lại và ước tính tốc độ đều phụ thuộc vào một câu hỏi: ID 17 trong khung hình này có phải là cùng đối tượng với ID 17 ở khung hình trước không? Trên cùng một đoạn video 62 khung hình có khoảng 30 người đi bộ và cùng một detector, ByteTrack tìm được 32 ID còn TrackTrack mặc định tìm được 9. Việc chọn và tinh chỉnh tracker là một phần của model; chọn sai sẽ âm thầm làm sai mọi số liệu ở các bước sau.
Thực hành
Tracker bổ sung điều gì#

Nhãn và đường theo vết trong khung hình này là kết quả do tracker tạo ra. Mỗi ID là một track, tức giả thuyết về một đối tượng thực; đường theo vết thể hiện lịch sử gần đây của đối tượng. Ở mỗi khung hình, tracker dự đoán vị trí của từng track bằng bộ lọc Kalman, rồi ghép các detection mới với những dự đoán đó dựa trên độ chồng lấp bbox (và tùy chọn, dựa trên ngoại hình):
Các track không được ghép trong track_buffer khung hình sẽ bị xóa. Đó là toàn bộ cơ chế, và các ngưỡng của nó quyết định mọi thứ tiếp theo.
Chọn tracker#
Chế độ tracking cung cấp sáu tracker: BoT-SORT, ByteTrack, OC-SORT, Deep OC-SORT, FastTracker và TrackTrack (mặc định khi bạn không truyền tracker). Ba tracker đáp ứng phần lớn nhu cầu:
| Bộ theo dõi | Tín hiệu dùng để ghép (cấu hình mặc định) | Nên chọn khi |
|---|---|---|
| ByteTrack | Chuyển động và độ chồng lấp bbox, cùng lượt ghép thứ hai để khôi phục các bbox có confidence thấp | Camera cố định, detector nhỏ hoặc thiếu chắc chắn, cần ưu tiên thông lượng |
| BoT-SORT | Ghép kiểu ByteTrack và bổ sung bù chuyển động camera (gmc_method: sparseOptFlow) | Camera di chuyển hoặc rung; đặt with_reid: True cho cảnh đông người và hiện tượng che khuất kéo dài |
| TrackTrack | Hàm chi phí đa tín hiệu (hình dạng bbox, confidence, góc), khởi tạo có xét đến track và bù chuyển động camera | Các detection có confidence cao từ một model mạnh, được huấn luyện tốt |
Ghép theo ngoại hình của BoT-SORT (tái định danh) mặc định bị tắt; khi dùng model: auto, phương thức này tái sử dụng chính các feature của detector nên bật lên chỉ làm tăng rất ít chi phí xử lý.
So sánh tracker trên cùng một đoạn video#
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
for tracker in ("bytetrack.yaml", "botsort.yaml", "tracktrack.yaml"):
ids, frames = set(), 0
for r in model.track(video, stream=True, tracker=tracker, classes=[0], verbose=False):
frames += 1
if r.boxes.is_track:
ids.update(r.boxes.id.int().tolist())
print(f"{tracker:16s} {frames} frames, {len(ids)} unique person IDs")bytetrack.yaml 62 frames, 32 unique person IDs
botsort.yaml 62 frames, 33 unique person IDs
tracktrack.yaml 62 frames, 9 unique person IDsĐoạn video ghi cảnh khoảng 30 người đi qua quảng trường nhìn từ trên cao, nên ByteTrack và BoT-SORT cho kết quả gần với thực tế. TrackTrack không bị lỗi: nó chỉ bắt đầu một track khi confidence vượt new_track_thresh: 0.7 và chỉ ghép trước tiên khi vượt track_high_thresh: 0.6, trong khi confidence trung vị của YOLO26n đối với người trong đoạn video này là 0.53 và chỉ 17% detection đạt 0.7. Phần lớn mọi người không được gán ID. Quy tắc ra quyết định: hãy so sánh các ngưỡng của tracker với phân bố confidence của detector trước khi tin vào bất kỳ số liệu đếm nào.
Dùng ID trong pipeline#
from collections import defaultdict
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
counts = defaultdict(set)
for r in model.track(video, stream=True, tracker="bytetrack.yaml", verbose=False):
if not r.boxes.is_track: # no confirmed tracks in this frame yet
continue
for cls, tid in zip(r.boxes.cls.int().tolist(), r.boxes.id.int().tolist()):
counts[r.names[cls]].add(tid)
for cls, ids in counts.items():
print(f"{cls}: {len(ids)} unique objects")person: 32 unique objectsMột set cho mỗi class sẽ đếm mỗi ID một lần, bất kể ID đó xuất hiện trong bao nhiêu khung hình, vì vậy kết quả là số đối tượng chứ không phải số detection. stream=True trả kết quả từng khung hình thay vì giữ toàn bộ video trong bộ nhớ. Đếm trong vùng, heatmap và tính khoảng cách là các lớp mỏng được xây dựng trên vòng lặp này.
Tracking các khung hình do bạn tự đọc#
Truyền đường dẫn hoặc URL sẽ tự xử lý trạng thái tracker. Khi khung hình đến từ decoder riêng, webcam hoặc camera RTSP, hãy truyền persist=True để mỗi lần gọi tiếp tục cùng một chuỗi (tài liệu Chế độ dự đoán liệt kê mọi loại nguồn):
import cv2
from ultralytics import YOLO
from ultralytics.utils.downloads import safe_download
model = YOLO("yolo26n.pt")
video = safe_download("https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4")
cap = cv2.VideoCapture(str(video)) # or 0 for a webcam, or an rtsp:// URL
seen = set()
while True:
ok, frame = cap.read()
if not ok:
break
r = model.track(frame, persist=True, tracker="bytetrack.yaml", classes=[0], verbose=False)[0]
if r.boxes.is_track:
seen.update(r.boxes.id.int().tolist()) # your logic: dwell time, trajectories, alerts
cap.release()
print(f"{len(seen)} unique IDs")32 unique IDsKết quả giống như khi truyền đường dẫn vì persist=True duy trì một tracker hoạt động qua cả 62 lần gọi.
Tinh chỉnh tracker cho detector của bạn#
Sao chép một cấu hình có sẵn, giảm các ngưỡng không phù hợp với detector của bạn rồi truyền tệp mới:
from pathlib import Path
from ultralytics import YOLO
from ultralytics.utils import ROOT
cfg = (ROOT / "cfg/trackers/tracktrack.yaml").read_text() # packaged defaults
for old, new in (
("track_high_thresh: 0.6", "track_high_thresh: 0.3"),
("track_low_thresh: 0.25", "track_low_thresh: 0.1"),
("new_track_thresh: 0.7", "new_track_thresh: 0.35"),
):
cfg = cfg.replace(old, new)
Path("tracktrack_tuned.yaml").write_text(cfg)
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
for tracker in ("tracktrack.yaml", "tracktrack_tuned.yaml"):
ids = set()
for r in model.track(video, stream=True, tracker=tracker, classes=[0], verbose=False):
if r.boxes.is_track:
ids.update(r.boxes.id.int().tolist())
print(f"{tracker:22s} {len(ids)} unique person IDs")tracktrack.yaml 9 unique person IDs
tracktrack_tuned.yaml 27 unique person IDsĐặt các ngưỡng thấp hơn một chút so với confidence trung vị của detector giúp TrackTrack tăng từ 9 lên 27 ID, gần với số đếm thủ công. Các tham số mà mọi tracker đều có:
| Tham số | Giá trị mặc định của ByteTrack | Tăng giá trị để | Giảm giá trị để |
|---|---|---|---|
track_high_thresh | 0.25 | Bỏ qua detection yếu ở lượt ghép đầu tiên | Theo dõi bằng detector có confidence thấp |
new_track_thresh | 0.25 | Loại bỏ các track giả tồn tại trong thời gian ngắn | Bắt đầu track cho các đối tượng mờ |
track_buffer | 30 khung hình | Duy trì track qua các lần che khuất lâu hơn | Giải phóng ID của các đối tượng đã rời đi sớm hơn |
match_thresh | 0.8 | Ghép linh hoạt hơn (chuyển động nhanh, bbox dao động) | Ghép chặt chẽ hơn (đám đông) |
Các lỗi thường gặp#
Triệu chứng: số ID ít hơn nhiều so với số đối tượng, đặc biệt với model nhỏ. Cách khắc phục: in confidence detection trung vị (xem lời giải) và đặt new_track_thresh cùng track_high_thresh thấp hơn một chút so với giá trị đó.
Triệu chứng: ID đặt lại ở mỗi frame khi bạn tự gọi model.track(frame), hoặc nhảy giữa các đối tượng khi hai camera cùng cấp dữ liệu vào một model. Cách khắc phục: truyền persist=True cho các frame liên tiếp của cùng một luồng và cấp cho mỗi camera một instance model riêng (hoặc dùng nguồn .streams, vốn duy trì một tracker cho mỗi luồng).
Triệu chứng: ID của một chiếc xe đang đỗ thay đổi sau mỗi vài frame. Cách khắc phục: tracker đang tạo track mới thay vì ghép với track cũ. Trước tiên, kiểm tra confidence của detector trên đối tượng đó, sau đó tăng match_thresh và track_buffer.
Hiển thị lời giải
Trước tiên hãy đo confidence của detector, sau đó đặt các ngưỡng thấp hơn một chút:
import torch
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
conf = torch.cat([r.boxes.conf for r in model.predict(video, stream=True, classes=[0], verbose=False)])
print(f"median {conf.median():.2f}, share >= 0.7: {(conf >= 0.7).float().mean():.0%}")median 0.53, share >= 0.7: 17%Với đoạn video quảng trường, bảng ghi: ByteTrack 32, BoT-SORT 33, TrackTrack 9, TrackTrack đã tinh chỉnh 27, số đếm thủ công khoảng 30. Chỉ 17% detection vượt ngưỡng new_track_thresh: 0.7 của TrackTrack, vì vậy giảm ngưỡng này xuống 0.35 (cùng với track_high_thresh: 0.3) là cách khắc phục phù hợp; với camera cố định nhìn từ trên cao này, ByteTrack thuần là lựa chọn đơn giản hơn.