در سیستمهای بینایی ماشین، تشخیص شیء در یک فریم تنها نیمی از مسیر است. تا زمانی که نتوانید موقعیت همان شیء را در فریمهای متوالی دنبال کنید، ساخت قابلیتهایی مانند شمارش افراد در تردد، تحلیل الگوهای حرکتی در ورزش یا هدایت خودروهای خودران غیرممکن خواهد بود. ردیابی چند شیء (Multi-Object Tracking یا MOT) حلقهی گمشدهی میان تحلیل تکفریم و درک ویدیویی پیوسته است.
در این درس ساختار ردیابی کلاسیک مبتنی بر تشخیص (Tracking-by-detection) را از پایهایترین مفاهیم مانند فیلتر کالمن و الگوریتم مجارستانی تا راهکارهای مدرنتری مانند ByteTrack بررسی میکنیم. علاوه بر آن، با رویکردهای نوینی مثل ردیابی مبتنی بر بانک حافظه در مدلهای SAM 2 و SAM 3 آشنا میشوید تا بدانید در شرایط پوشیدگی شدید و ازدحام سوژهها، کدام معماری انتخاب مهندسی بهتری است.
کدهای شبیهسازی و پیادهسازی گامبهگام این درس روی پردازندههای معمولی (CPU) اجرا میشوند. البته اگر بخواهید بستههای پایتونی مرتبط با ردیابی و پردازش تصویر را نصب کنید یا مدلهای پیشآموزشدیده را از PyPI یا Hugging Face فراخوانی کنید، ممکن است به دلیل اختلالات و کندی شبکه نیاز به استفاده از ابزارهای کمکی یا آینههای داخلی داشته باشید.
ردیابی یعنی تشخیص بهاضافهی انتساب (association). در هر فریم اشیاء را تشخیص دهید و سپس تشخیصهای فریم فعلی را بر اساس شناسه (ID) به ردگیریهای (tracks) فریم قبلی متصل کنید.
اهداف یادگیری
- تمایز بین «ردیابی مبتنی بر تشخیص» (tracking-by-detection) و «ردیابی مبتنی بر پرسمان» (query-based tracking)، به همراه نام بردن از خانوادههای الگوریتمی مختلف (SORT، DeepSORT، ByteTrack، BoT-SORT، ردیاب مبتنی بر حافظهی SAM 2 و SAM 3.1 Object Multiplex)
- پیادهسازی گامبهگام تخصیص مجارستانی مبتنی بر IoU از صفر برای ردیابی کلاسیک مبتنی بر تشخیص
- توضیح بانک حافظهی SAM 2 و چرایی عملکرد بهتر آن در مواجهه با پوشیدگی (occlusion) نسبت به انتسابهای مبتنی بر IoU
- خواندن سه معیار ارزیابی ردیابی (MOTA، IDF1 و HOTA) و انتخاب معیار مناسب برای هر سناریو
صورت مسئله
یک آشکارساز (detector) فقط مشخص میکند اشیاء در یک فریم منفرد کجا قرار دارند. اما ردیاب تعیین میکند کدام تشخیص در فریم t، همان شیء فریم t-1 است. بدون این قابلیت، نمیتوانید اشیائی را که از یک خط فرضی رد میشوند بشمارید، توپی را پشت یک مانع دنبال کنید یا بفهمید که «خودروی شمارهی 4 به مدت 8 ثانیه در لاین مانده است».
ردیابی هستهی اصلی هر محصول ویدیویی است: تحلیل دادههای ورزشی، نظارت تصویری، رانندگی خودران، تحلیل ویدیوهای پزشکی، پایش حیات وحش و شمارش علائم تجاری (wordmarks). همهی این کاربردها اجزای بنیادین مشترکی دارند: یک مدل تشخیص در هر فریم، یک مدل حرکتی (فیلتر کالمن یا مدلی پیشرفتهتر)، گام انتساب (الگوریتم مجارستانی بر پایهی IoU، شباهت کسینوسی یا ویژگیهای یادگرفتهشده) و چرخهی حیات ردگیری (ایجاد، بهروزرسانی و حذف).
در سال 2026 دو الگوی تازه وارد این حوزه شدند: ردیابی مبتنی بر حافظهی SAM 2 (استفاده از حافظهی ویژگیها بهجای انتساب با مدل حرکتی) و SAM 3.1 Object Multiplex (حافظهی اشتراکی برای نمونههای متعدد از یک مفهوم). در این درس ابتدا پشتهی سنتی و کلاسیک را پیادهسازی میکنیم و سپس سراغ رویکرد مبتنی بر حافظه میرویم.
مفاهیم پایه
ردیابی مبتنی بر تشخیص (Tracking-by-detection)
هر ردیابی که در سال 2026 با آن کار کنید، روایتی از همین چرخه است. تفاوتهای اصلی آنها عبارت است از:
- SORT (سال 2016): فیلتر کالمن + انتساب مجارستانی با IoU. ساده، سریع و بدون مدل ظاهری.
- DeepSORT (سال 2017): الگوریتم SORT به همراه ویژگی ظاهری مبتنی بر CNN برای هر ردگیری (امبدینگ ReID). عبور اشیاء از روی یکدیگر را بهتر مدیریت میکند.
- ByteTrack (سال 2021): تشخیصهای با اطمینان پایین را در گام دوم منتسب میکند؛ نیازی به ویژگیهای ظاهری ندارد، اما بهترین عملکرد را روی MOT17 ثبت کرده است.
- BoT-SORT (سال 2022): الگوریتم Byte + جبران حرکت دوربین + ReID.
- StrongSORT / OC-SORT — شاخههای توسعهیافته از ByteTrack با مدلهای حرکتی و ظاهری بهتر.
فیلتر کالمن در یک پاراگراف
فیلتر کالمن وضعیت (x, y, w, h, dx, dy, dw, dh) را همراه با یک کوواریانس برای هر ردگیری نگه میدارد. در هر فریم، وضعیت شیء را با یک مدل سرعتثابت پیشبینی (predict) کنید و سپس با استفاده از تشخیص منتسبشده آن را بهروزرسانی (update) نمایید. اگر عدمقطعیت مرحلهی پیشبینی بالا باشد، بهروزرسانی اعتماد بیشتری به تشخیص نشان میدهد. این کار خروجی مسیرها را نرم میکند و امکان ادامهی ردگیری در پوشیدگیهای کوتاهمدت (1 تا 5 فریم) را فراهم میسازد.
همهی ردیابهای کلاسیک در گام پیشبینی حرکت از فیلتر کالمن استفاده میکنند.
الگوریتم مجارستانی (Hungarian algorithm)
اگر یک ماتریس هزینهی M x N (ردگیریها × تشخیصها) داشته باشید، این الگوریتم تخصیصی یکبهیک پیدا میکند که مجموع هزینهها را کمینه کند. هزینه معمولاً بهصورت 1 - IoU(track_bbox, detection_bbox) یا منفی شباهت کسینوسیِ ویژگیهای ظاهری تعریف میشود. زمان اجرای این الگوریتم است؛ اما برای تا حدود 1000 شیء، با تابع scipy.optimize.linear_sum_assignment در پایتون با سرعت کافی اجرا میشود.
ایدهی کلیدی ByteTrack
ردیابهای معمولی تشخیصهای با اطمینان پایین (کمتر از 0.5) را دور میاندازند. ByteTrack این موارد را بهعنوان کاندیداهای مرحلهی دوم نگه میدارد: پس از تطبیق ردگیریها با تشخیصهای مطمئن، ردگیریهای بدون تطابق تلاش میکنند با یک آستانهی IoU کمی آزادتر، به تشخیصهای ضعیفتر متصل شوند. این سازوکار پوشیدگیهای کوتاه و پرشهای شناسه (ID switches) در محیطهای شلوغ را بازیابی میکند.
ردیابی مبتنی بر حافظه در SAM 2
مدل SAM 2 با نگه داشتن یک بانک حافظه (memory bank) از ویژگیهای مکانی-زمانی هر نمونه (instance)، ویدیو را پردازش میکند. وقتی با یک پرامپت (کلیک، کادر یا ماسک) در یک فریم شیء را مشخص کنید، آن نمونه کدگذاری شده و وارد حافظه میشود. در فریمهای بعدی، حافظه با ویژگیهای فریم جدید اتنشن متقاطع (cross-attention) میزند و بخش رمزگشا ماسک همان نمونه را برای فریم تازه تولید میکند.
اینجا نه نیازی به فیلتر کالمن هست و نه الگوریتم مجارستانی. فرایند انتساب بهطور ضمنی درون عملیات اتنشنِ حافظه انجام میشود.
مزایا:
- مقاوم در برابر پوشیدگیهای طولانی (حافظه، هویت نمونه را در فریمهای پرشمار حفظ میکند).
- باز بودن دامنهی واژگان (Open-vocabulary) در صورت ترکیب با پرامپتهای متنی SAM 3.
- بدون نیاز به یک مدل حرکتی مجزا.
معایب:
- کندتر از ByteTrack برای ردیابی تعداد زیادی شیء.
- رشد مداوم بانک حافظه که پنجرهی زمینه (context window) را محدود میکند.
مدل SAM 3.1 Object Multiplex
در روشهای پیشین SAM 2 / SAM 3، برای هر نمونه یک بانک حافظهی مجزا ایجاد میشد؛ بنابراین برای 50 شیء، 50 بانک حافظه نیاز بود. ساختار Object Multiplex (عرضهشده در مارس 2026) همهی آنها را درون یک حافظهی اشتراکی با توکنهای پرسمان مجزا به ازای هر نمونه تجمیع میکند. با این کار، هزینه با افزایش تعداد نمونهها رفتاری زیرخطی (sub-linear) خواهد داشت.
امروزه Multiplex به استاندارد پیشفرض ردیابی جمعیت در سال 2026 تبدیل شده است: از تماشاگران کنسرت و کارگران انبار گرفته تا تقاطعهای ترافیکی.
سه معیار اصلی که باید بشناسید
- MOTA (Multi-Object Tracking Accuracy) — فرمول:
1 - (FN + FP + ID switches) / GT. خطاها در این سنجه وزندهی میشوند؛ تکمعیاری است که شکست در تشخیص و انتساب را در هم میآمیزد. - IDF1 (ID F1) — میانگین همساز دقت و بازخوانیِ شناسه. تمرکز اصلی آن مشخصاً روی این است که هر ردگیری واقعیت زمینی (Ground-truth) در طول زمان چقدر شناسهی خود را حفظ میکند. برای کاربردهای حساس به تعویض شناسه، بسیار بهتر از MOTA است.
- HOTA (Higher Order Tracking Accuracy) — به دو مؤلفهی دقت تشخیص (DetA) و دقت انتساب (AssA) تفکیک میشود. از سال 2020 به استاندارد جامعهی پژوهشی تبدیل شده و جامعترین سنجه به شمار میرود.
برای سامانههای نظارتی (اینکه چه کسی چه کسی است): باید IDF1 را گزارش کنید. برای تحلیلهای ورزشی (مثل شمارش پاسها): HOTA. برای مقایسههای عمومی دانشگاهی و مقالاتی: باز هم HOTA.
پیادهسازی از صفر
گام 1: ماتریس هزینه بر پایهی IoU
import numpy as np
def bbox_iou(a, b):
"""
a, b: (N, 4) arrays of [x1, y1, x2, y2].
Returns (N_a, N_b) IoU matrix.
"""
ax1, ay1, ax2, ay2 = a[:, 0], a[:, 1], a[:, 2], a[:, 3]
bx1, by1, bx2, by2 = b[:, 0], b[:, 1], b[:, 2], b[:, 3]
inter_x1 = np.maximum(ax1[:, None], bx1[None, :])
inter_y1 = np.maximum(ay1[:, None], by1[None, :])
inter_x2 = np.minimum(ax2[:, None], bx2[None, :])
inter_y2 = np.minimum(ay2[:, None], by2[None, :])
inter = np.clip(inter_x2 - inter_x1, 0, None) * np.clip(inter_y2 - inter_y1, 0, None)
area_a = (ax2 - ax1) * (ay2 - ay1)
area_b = (bx2 - bx1) * (by2 - by1)
union = area_a[:, None] + area_b[None, :] - inter
return inter / np.clip(union, 1e-8, None)
گام 2: ردیاب ساده به سبک SORT
برای خلاصهتر شدن کد، پیشبینی سرعتثابت کالمن را حذف کردهایم — در اینجا تنها از انتساب سادهی IoU استفاده میکنیم؛ اما در محیطهای عملیاتی، گام پیشبینی کالمن ضروری است. پکیج پایتونی sort نسخهی کامل آن را ارائه میدهد.
from scipy.optimize import linear_sum_assignment
class Track:
def __init__(self, tid, bbox, frame):
self.id = tid
self.bbox = bbox
self.last_frame = frame
self.hits = 1
def update(self, bbox, frame):
self.bbox = bbox
self.last_frame = frame
self.hits += 1
class SimpleTracker:
def __init__(self, iou_threshold=0.3, max_age=5):
self.tracks = []
self.next_id = 1
self.iou_threshold = iou_threshold
self.max_age = max_age
def step(self, detections, frame):
if not self.tracks:
for d in detections:
self.tracks.append(Track(self.next_id, d, frame))
self.next_id += 1
return [(t.id, t.bbox) for t in self.tracks]
track_boxes = np.array([t.bbox for t in self.tracks])
det_boxes = np.array(detections) if len(detections) else np.empty((0, 4))
iou = bbox_iou(track_boxes, det_boxes) if len(det_boxes) else np.zeros((len(track_boxes), 0))
cost = 1 - iou
cost[iou < self.iou_threshold] = 1e6
matched_track = set()
matched_det = set()
if cost.size > 0:
row, col = linear_sum_assignment(cost)
for r, c in zip(row, col):
if cost[r, c] < 1.0:
self.tracks[r].update(det_boxes[c], frame)
matched_track.add(r); matched_det.add(c)
for i, d in enumerate(det_boxes):
if i not in matched_det:
self.tracks.append(Track(self.next_id, d, frame))
self.next_id += 1
self.tracks = [t for t in self.tracks if frame - t.last_frame <= self.max_age]
return [(t.id, t.bbox) for t in self.tracks]
در 60 خط کد: تشخیصهای هر فریم را میگیرد و شناسههای ردگیری هر فریم را برمیگرداند. سیستمهای عملیاتی به این ساختار، پیشبینی کالمن، تطابق مجدد مرحلهی دوم ByteTrack و ویژگیهای ظاهری را اضافه میکنند.
گام 3: آزمون با مسیرهای مصنوعی
def synthetic_frames(num_frames=20, num_objects=3, H=240, W=320, seed=0):
rng = np.random.default_rng(seed)
starts = rng.uniform(20, 200, size=(num_objects, 2))
velocities = rng.uniform(-5, 5, size=(num_objects, 2))
frames = []
for f in range(num_frames):
dets = []
for i in range(num_objects):
cx, cy = starts[i] + f * velocities[i]
dets.append([cx - 10, cy - 10, cx + 10, cy + 10])
frames.append(dets)
return frames
tracker = SimpleTracker()
for f, dets in enumerate(synthetic_frames()):
tracks = tracker.step(dets, f)
سه شیء که در خط مستقیم حرکت میکنند باید شناسههای خود را در تمام 20 فریم حفظ کنند.
گام 4: سنجهی تعویض شناسه (ID-switch)
def count_id_switches(tracks_per_frame, gt_per_frame):
"""
tracks_per_frame: list of list of (track_id, bbox)
gt_per_frame: list of list of (gt_id, bbox)
Returns number of ID switches.
"""
prev_assignment = {}
switches = 0
for tracks, gts in zip(tracks_per_frame, gt_per_frame):
if not tracks or not gts:
continue
t_boxes = np.array([b for _, b in tracks])
g_boxes = np.array([b for _, b in gts])
iou = bbox_iou(g_boxes, t_boxes)
for g_idx, (gt_id, _) in enumerate(gts):
j = iou[g_idx].argmax()
if iou[g_idx, j] > 0.5:
t_id = tracks[j][0]
if gt_id in prev_assignment and prev_assignment[gt_id] != t_id:
switches += 1
prev_assignment[gt_id] = t_id
return switches
این یک سنجهی سادهشده و مشابه با IDF1 است: شمارش اینکه یک شیء واقعیت زمینی چند بار شناسهی ردگیری پیشبینیشدهاش تغییر میکند. ابزارهای کامل محاسبهی MOTA ،IDF1 و HOTA در کتابخانههای py-motmetrics و TrackEval قرار دارند.
استفاده از ابزارهای واقعی
ردیابهای آمادهی استفاده در محیطهای عملیاتی سال 2026:
- کتابخانهی
ultralytics— ترکیب توکار YOLOv8 بههمراه ByteTrack و BoT-SORT:results = model.track(source, tracker="bytetrack.yaml"). گزینهی پیشفرض. - کتابخانهی
supervision(متعلق به Roboflow) — پوستههای ByteTrack بههمراه ابزارهای بصریسازی و حاشیهنویسی. - مدلهای SAM 2 و SAM 3.1 — ردیابی مبتنی بر حافظه از طریق
processor.track(). - پشتهی اختصاصی: ترکیب یک مدل تشخیص (YOLOv8 یا RT-DETR) با ردیابهایی مثل
sort-trackerیاOC-SORTوStrongSORT.
راهنمای انتخاب:
- عابران پیاده، خودروها یا جعبهها با نرخ 30 فریم بر ثانیه به بالا: ByteTrack با ultralytics.
- تعداد زیاد نمونههای یک کلاس درون جمعیت: SAM 3.1 Object Multiplex.
- پوشیدگیهای شدید در سوژههایی با ظاهر متمایز: DeepSORT / StrongSORT (بهرهگیری از ویژگیهای ReID).
- تحلیلهای ورزشی و تعاملات فیزیکی پیچیده: BoT-SORT یا ردیابهای یادگیرنده (مثل MOTRv3).
خروجی این درس
این درس فایلهای زیر را تولید میکند:
outputs/prompt-tracker-picker.md— راهنمای انتخاب بین SORT ،ByteTrack ،BoT-SORT ،SAM 2 یا SAM 3.1 با توجه به نوع صحنه، الگوهای پوشیدگی و بودجهی تأخیر زمانی.outputs/skill-mot-evaluator.md— ابزار سنجش کامل معیارهای MOTA ،IDF1 و HOTA در برابر ردگیریهای واقعیت زمینی.
تمرینها
- (ساده) ردیاب مصنوعی بالا را با 3، 10 و 30 شیء اجرا کنید. در هر حالت تعداد جابهجاییهای شناسه (ID-switch) را گزارش دهید. بررسی کنید انتساب مبتنی بر IoU از چه نقطهای به بعد شکست میخورد.
- (متوسط) قبل از مرحلهی انتساب، یک گام پیشبینی سرعتثابت با فیلتر کالمن اضافه کنید. نشان دهید که پوشیدگیهای کوتاه (2 تا 3 فریم) دیگر باعث تغییر شناسه نمیشوند.
- (سخت) ردیاب مبتنی بر حافظهی SAM 2 را (از طریق کتابخانهی
transformers) بهعنوان موتور ردیابی پیاده کنید. هر دو ردیاب SimpleTracker و SAM 2 را روی یک ویدیوی 30 ثانیهای از یک جمعیت شلوغ اجرا کرده و تعداد تغییرات شناسه را با برچسبگذاری دستی برای 5 نفر از افراد شاخص مقایسه کنید.
اصطلاحات کلیدی
| اصطلاح | در گفتوگوها | معنای دقیق فنی |
|---|---|---|
| Tracking-by-detection | «اول تشخیص، بعد اتصال» | تشخیص اشیاء در هر فریم + تخصیص مجارستانی بر اساس IoU یا ویژگیهای ظاهری |
| Kalman filter | «پیشبینی حرکت» | دینامیک خطی + کوواریانس برای پیشبینی هموار مسیرها و مدیریت پوشیدگیها |
| Hungarian algorithm | «تخصیص بهینه» | حل مسئلهی تطابق دوپرتوی کمینههزینه؛ با scipy.optimize.linear_sum_assignment |
| ByteTrack | «پاس دوم با اطمینان پایین» | تطبیق مجدد ردگیریهای ناموفق با تشخیصهای دارای امتیاز پایین برای پوشش موانع گذرا |
| DeepSORT | «SORT بههمراه ظاهر» | افزودن ویژگیهای ReID برای تطابق بینفریمی؛ حفظ بهتر شناسهها |
| Memory bank | «ترفند SAM 2» | ذخیرهی ویژگیهای مکانی-زمانی هر نمونه در فریمها؛ جایگزینی انتساب صریح با اتنشن متقاطع |
| Object Multiplex | «حافظهی اشتراکی SAM 3.1» | حافظهی مشترک یکپارچه با پرسمانهای مجزا به ازای هر نمونه برای ردیابی سریع اشیاء پرشمار |
| HOTA | «معیار مدرن ردیابی» | تفکیک نتایج به دو دقت تشخیص و انتساب؛ استاندارد جامعهی علمی |
برای مطالعهی بیشتر
- مقاله SORT (نویسنده Bewley و همکاران، 2016) — مقالهی بنیادین ردیابی مینیمال مبتنی بر تشخیص
- مقاله DeepSORT (نویسنده Wojke و همکاران، 2017) — افزودن ویژگیهای ظاهری به ردیاب
- مقاله ByteTrack (نویسنده Zhang و همکاران، 2022) — پاس دوم برای تشخیصهای با اطمینان پایین
- مقاله BoT-SORT (نویسنده Aharon و همکاران، 2022) — جبران حرکت دوربین
- مقاله HOTA (نویسنده Luiten و همکاران، 2020) — معیار تفکیکپذیر برای ارزیابی ردیابی
- بخش تقطیع ویدیویی در SAM 2 (متا، 2024) — ردیاب مبتنی بر حافظه
- معرفی SAM 3.1 Object Multiplex (متا، مارس 2026)