Ultralytics YOLO27: Tham gia danh sách chờ.
Get Started
Ultralytics YOLO trong môi trường production·Tracking và xây dựng pipeline·Bài học 5/9
Bài họctrung cấp

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.

Kết quả

Chạy ba tracker trên một video, giải thích số lượng ID của chúng dựa trên confidence của detector, dùng box.id trong một pipeline và khắc phục tracker không phù hợp bằng một YAML đã tinh chỉnh.

Lộ trình cấp tốc
Nếu bạn đã nắm rõ cách thực hiện, đây là phiên bản tóm tắt.
  1. model.track(source, stream=True, tracker="bytetrack.yaml"); mỗi bbox được gán một id ổn định.

  2. Tự cung cấp các khung hình? Truyền persist=True để duy trì ID qua các lần gọi; mỗi camera dùng một tracker.

  3. Mặc định là tracktrack.yaml; ByteTrack nhanh và dễ thích ứng; BoT-SORT bổ sung bù chuyển động camera, còn ReID là tùy chọn bật thêm.

  4. Quá ít ID: đo confidence của detector rồi giảm new_track_thresh và track_high_thresh trong một bản YAML đã sao chép.

Thực hành

Tracker bổ sung điều gì#

YOLO Ultralytics tracking giao thông trên đường cao tốc: mỗi ô tô, xe buýt và xe tải giữ một ID được đánh số (ô tô #12, xe buýt #21, xe tải #16) và có một đường màu thể hiện quãng đường di chuyển gần đây

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õiTín hiệu dùng để ghép (cấu hình mặc định)Nên chọn khi
ByteTrackChuyể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ấpCamera cố định, detector nhỏ hoặc thiếu chắc chắn, cần ưu tiên thông lượng
BoT-SORTGhé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
TrackTrackHà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 cameraCá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 objects

Mộ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 IDs

Kế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 ByteTrackTăng giá trị đểGiảm giá trị để
track_high_thresh0.25Bỏ qua detection yếu ở lượt ghép đầu tiênTheo dõi bằng detector có confidence thấp
new_track_thresh0.25Loại bỏ các track giả tồn tại trong thời gian ngắnBắt đầu track cho các đối tượng mờ
track_buffer30 khung hìnhDuy trì track qua các lần che khuất lâu hơnGiải phóng ID của các đối tượng đã rời đi sớm hơn
match_thresh0.8Ghé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#

Ngưỡng cao hơn confidence của detector

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ị đó.

Quên persist hoặc dùng chung persist

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).

ID nhấp nháy ở các đối tượng di chuyển chậm

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.

Dùng thử

Lấy một video dài 30–60 giây từ lĩnh vực của bạn và tự đếm các đối tượng thuộc một class. Chạy compare_trackers.py trên video đó, đo confidence của detector bằng solution script, rồi tinh chỉnh một YAML của tracker để số lượng ID tiến gần hơn đến số đếm thủ công. Tạo một bảng gồm: tracker, số ID duy nhất, số đếm thủ công.

Điều kiện hoàn thành
Bạn đã hoàn thành bài học khi tất cả các điều kiện sau đều đúng.
  • Bạn có số lượng ID duy nhất của ByteTrack, BoT-SORT và TrackTrack trên cùng một video, kèm theo số đếm thủ công.

  • Bạn có thể giải thích số lượng thấp nhất dựa trên các ngưỡng của tracker và confidence trung vị của detector.

  • Một YAML tracker đã tinh chỉnh làm thay đổi số lượng theo đúng hướng bạn dự đoán trước khi chạy.

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.

Tiếp theo là gì

Khi đã có ID ổn định, bài học tiếp theo sẽ xây dựng các pipeline production phổ biến nhất dựa trên chúng: đếm, vùng, heatmap và tốc độ.

Đăng nhập để lưu tiến độ