Ultralytics YOLO27: انضم إلى قائمة الانتظار.
Get Started
Ultralytics YOLO في بيئة الإنتاج·التتبّع وبناء مسارات المعالجة·الدرس 5/9
الدرسمتوسط

تتبّع الكائنات باستخدام ByteTrack وBoT-SORT وTrackTrack

امنح كل كائن معرّفًا ثابتًا عبر الإطارات، واختر متتبّعًا، واضبط عتباته بما يتوافق مع كاشفك.

يعتمد كل إحصاء ومدة مكوث وتقدير للسرعة على سؤال واحد: هل المعرّف 17 في هذا الإطار يعود إلى الكائن نفسه الذي يحمل المعرّف 17 في الإطار السابق؟ على المقطع نفسه المكوّن من 62 إطارًا، والذي يضم نحو 30 من المشاة، وباستخدام الكاشف نفسه، حدّد ByteTrack عدد 32 معرّفًا، بينما حدّد TrackTrack بالإعدادات الافتراضية 9 معرّفات. اختيار المتتبّع وضبطه جزء من النموذج، واختيار متتبّع غير مناسب يعطّل بصمت كل الأرقام اللاحقة.

النتيجة

شغّل ثلاثة متتبّعات على مقطع فيديو واحد، واشرح عدد المعرّفات التي تنتجها استنادًا إلى درجات الثقة لدى الكاشف، واستخدم box.id في مسار معالجة، وأصلح عدم توافق المتتبّع باستخدام ملف YAML مضبوط.

المسار السريع
إذا كنت تعرف الأساسيات بالفعل، فإليك النسخة المختصرة.
  1. model.track(source, stream=True, tracker="bytetrack.yaml")؛ يحصل كل صندوق على id ثابت.

  2. هل تمرّر الإطارات بنفسك؟ مرّر persist=True لكي تستمر المعرّفات بين الاستدعاءات؛ واستخدم متتبّعًا واحدًا لكل كاميرا.

  3. الإعداد الافتراضي هو tracktrack.yaml؛ يتميز ByteTrack بالسرعة والتسامح؛ ويضيف BoT-SORT تعويض حركة الكاميرا، مع إمكانية تفعيل ReID اختياريًا.

  4. عدد المعرّفات أقل من المتوقع: قِس درجات ثقة الكاشف، وخفّض new_track_thresh وtrack_high_thresh في ملف YAML منسوخ.

عملي

ما الذي يضيفه المتتبّع#

تتبّع حركة المرور على طريق سريع باستخدام Ultralytics YOLO: يحتفظ كل من السيارة والحافلة والشاحنة بمعرّف مرقّم (السيارة #12، الحافلة #21، الشاحنة #16)، ويتبع مساره الأخير خط ملوّن

التسميات والمسارات في هذا الإطار هي ما ينتجه المتتبّع. كل معرّف هو مسار، أي فرضية عن كائن حقيقي واحد، والمسار المرئي هو سجلّه الأخير. في كل إطار، يتنبأ المتتبّع بموضع كل مسار باستخدام مرشح كالمان، ثم يطابق الكشوف الجديدة مع تلك التنبؤات استنادًا إلى تداخل الصناديق (والمظهر اختياريًا):

تُحذف المسارات التي لا تُطابق أي كشف لمدة track_buffer من الإطارات. هذه هي الآلية بأكملها، وعتباتها هي التي تحدد كل ما يأتي بعدها.

اختر متتبّعًا#

توفّر وضع التتبّع ستة متتبّعات: BoT-SORT وByteTrack وOC-SORT وDeep OC-SORT وFastTracker وTrackTrack (وهو الافتراضي عند عدم تمرير tracker). وتلبي ثلاثة منها معظم الاحتياجات:

أداة التتبعإشارات المطابقة (الإعداد الافتراضي)استخدمه عندما
ByteTrackالحركة وتداخل الصناديق، بالإضافة إلى مرحلة مطابقة ثانية تستعيد الصناديق منخفضة الثقةالكاميرات الثابتة، أو الكواشف الصغيرة أو غير اليقينية، أو عندما تكون الإنتاجية مهمة
BoT-SORTمطابقة على نمط ByteTrack مع تعويض حركة الكاميرا (gmc_method: sparseOptFlow)الكاميرات المتحركة أو المهتزة؛ اضبط with_reid: True للتعامل مع الحشود وحالات الاحتجاب الطويلة
TrackTrackتكلفة متعددة الإشارات (شكل الصندوق، والثقة، والزاوية)، وتهيئة تراعي المسارات، وتعويض حركة الكاميراكشوف عالية الثقة من نموذج قوي ومدرّب جيدًا

مطابقة المظهر في BoT-SORT (إعادة التعرّف) معطّلة افتراضيًا؛ وعند استخدام model: auto، يعيد المتتبّع استخدام ميزات الكاشف نفسه، لذا فإن تفعيلها لا يضيف إلا عبئًا ضئيلًا.

قارن المتتبّعات على مقطع واحد#

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

يُظهر المقطع نحو 30 شخصًا يعبرون ساحة من منظور علوي، لذا تقترب نتائج ByteTrack وBoT-SORT من العدد الفعلي. أما TrackTrack فليس معطّلًا: فهو يبدأ مسارًا فقط عندما تتجاوز الثقة new_track_thresh: 0.7، ولا يجري المطابقة الأولية إلا عندما تتجاوز track_high_thresh: 0.6، في حين أن وسيط ثقة YOLO26n للأشخاص في هذا المقطع هو 0.53، ولا تبلغ سوى 17% من الكشوف قيمة 0.7. لذلك لا يحصل معظم الأشخاص على معرّف. قاعدة اتخاذ القرار: قارن عتبات المتتبّع بتوزيع درجات الثقة لدى كاشفك قبل الوثوق بأي إحصاء.

استخدم المعرّفات في مسار معالجة#

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

تحتفظ مجموعة لكل فئة بكل معرّف مرة واحدة، بصرف النظر عن عدد الإطارات التي يظهر فيها، ولذلك تكون النتيجة عدد الكائنات لا عدد الكشوف. يعيد stream=True النتائج إطارًا تلو الآخر بدلًا من الاحتفاظ بالفيديو كله في الذاكرة. إن عدّ المناطق والخرائط الحرارية وحساب المسافة طبقات بسيطة مبنية فوق هذه الحلقة.

تتبّع الإطارات التي تقرؤها بنفسك#

يتولى تمرير مسار أو عنوان URL إدارة حالة المتتبّع نيابةً عنك. أما إذا جاءت الإطارات من وحدة فك ترميز خاصة بك، أو كاميرا ويب، أو كاميرا RTSP، فمرّر persist=True لكي يواصل كل استدعاء التسلسل نفسه (تسرد وثائق وضع التنبؤ جميع أنواع المصادر):

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

النتيجة نفسها كما لو مرّرت المسار، لأن persist=True أبقى متتبّعًا واحدًا نشطًا خلال الاستدعاءات الـ62 جميعها.

اضبط المتتبّع ليتوافق مع كاشفك#

انسخ إعدادًا مضمّنًا، وخفّض العتبات التي لا تناسب كاشفك، ثم مرّر الملف الجديد:

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

أدى ضبط العتبات لتكون أدنى بقليل من وسيط ثقة الكاشف إلى رفع عدد المعرّفات في TrackTrack من 9 إلى 27، وهو قريب من العدّ اليدوي. وفيما يلي عناصر الضبط المشتركة بين جميع المتتبّعات:

الإعدادالإعداد الافتراضي لـ ByteTrackارفعه من أجلاخفضه من أجل
track_high_thresh0.25تجاهل الكشوف الضعيفة في المطابقة الأولىتتبّع كاشفًا منخفض الثقة
new_track_thresh0.25استبعاد المسارات الخاطئة قصيرة الأمدبدء مسارات للأجسام الخافتة
track_buffer30 إطارًاتحمّل حالات الاحتجاب الأطولتحرير معرّفات الأجسام التي غادرت في وقت أقرب
match_thresh0.8مطابقة أكثر تساهلًا (حركة سريعة، وصناديق متذبذبة)مطابقة أكثر صرامة (الحشود)

مواطن الخلل#

عتبات أعلى من ثقة الكاشف

العَرَض: عدد المعرّفات أقل بكثير من عدد الأجسام، خصوصًا مع نموذج صغير. الحل: اطبع وسيط ثقة الكشف (انظر الحل)، واضبط new_track_thresh وtrack_high_thresh على قيم أدنى منه بقليل.

نسيان persist أو مشاركته

العَرَض: تُعاد تهيئة المعرّفات كل إطار عند استدعاء model.track(frame) بنفسك، أو تنتقل بين الأجسام عندما تغذي كاميرتان نموذجًا واحدًا. الحل: مرّر persist=True للإطارات المتتالية من تدفق واحد، وخصص نسخة نموذج لكل كاميرا (أو استخدم مصدر .streams، الذي يحتفظ بمتعقّب لكل تدفق).

وميض المعرّفات مع الأجسام البطيئة

العَرَض: يتغير معرّف سيارة متوقفة كل بضعة إطارات. الحل: ينشئ المتعقّب مسارات جديدة بدلًا من مطابقة المسارات القديمة. تحقّق أولًا من ثقة الكاشف في ذلك الجسم، ثم ارفع match_thresh وtrack_buffer.

جرّبه

التقط مقطع فيديو مدته 30–60 ثانية من المجال الذي تعمل فيه، واحصِ يدويًا أجسام فئة واحدة. شغّل compare_trackers.py عليه، وقِس درجات ثقة الكاشف باستخدام سكربت الحل، واضبط ملف YAML لمتتبّع واحد بحيث يقترب عدد المعرّفات من العدّ اليدوي. قدّم جدولًا يتضمن: المتتبّع، والمعرّفات الفريدة، والعدّ اليدوي.

متى يُعدّ مكتملًا
تكون قد أتممت الدرس عند تحقق جميع الشروط التالية.
  • لديك أعداد المعرّفات الفريدة لكل من ByteTrack وBoT-SORT وTrackTrack على الفيديو نفسه، إلى جانب العدّ اليدوي.

  • يمكنك تفسير العدد الأقل باستخدام عتبات المتتبّع ووسيط ثقة الكاشف.

  • غيّر ملف YAML لمتتبّع مضبوط العدد في الاتجاه الذي توقعته قبل تشغيله.

عرض الحل

قِس درجات ثقة الكاشف أولًا، ثم اضبط العتبات لتكون أدنى منها بقليل:

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%

في جدول مقطع الساحة، تكون النتائج: ByteTrack: 32، وBoT-SORT: 33، وTrackTrack: 9، وTrackTrack المضبوط: 27، والعدّ اليدوي: نحو 30. لا تتجاوز عتبة TrackTrack new_track_thresh: 0.7 سوى 17% من الكشوف، لذا فإن خفضها إلى 0.35 (باستخدام track_high_thresh: 0.3) هو الحل المناسب؛ وفي هذه الكاميرا العلوية الثابتة، يكون ByteTrack العادي الخيار الأبسط.

ما الخطوة التالية

بعد الحصول على معرّفات ثابتة، يشرح الدرس التالي أكثر مسارات المعالجة شيوعًا في بيئات الإنتاج اعتمادًا عليها: الإحصاء، والمناطق، والخرائط الحرارية، والسرعات.

سجّل الدخول لحفظ التقدم