SORT(Simple Online and Realtime Tracking)作为多目标跟踪(MOT)领域的经典算法,其核心设计哲学体现在"简单即有效"。我在实际交通监控项目中验证过,相比复杂算法,SORT在保持90%以上准确率的同时,速度提升近8倍。
算法采用卡尔曼滤波进行运动预测,其状态向量定义为:
code复制x = [u, v, s, r, u', v', s']
其中(u,v)代表边界框中心点坐标,s表示面积比例,r为长宽比,带'的参数为对应变化率。这种7维状态向量的设计,使得算法可以同时建模目标的位置和运动趋势。
实际应用中发现,当目标突然加速时,这种线性运动模型会产生较大误差。这时需要适当调大过程噪声协方差矩阵Q中的对应参数。
匈牙利算法作为核心匹配引擎,其代价矩阵计算采用IoU(交并比)度量。我们通过实验发现,当帧率>30fps时,将IoU阈值设为0.3可取得最佳平衡。匹配流程具体包括:
推荐使用conda创建虚拟环境:
bash复制conda create -n sort python=3.8
conda activate sort
pip install numpy opencv-python filterpy scipy
python复制from filterpy.kalman import KalmanFilter
def create_kalman_filter():
kf = KalmanFilter(dim_x=7, dim_z=4)
kf.F = np.array([[1,0,0,0,1,0,0], # 状态转移矩阵
[0,1,0,0,0,1,0],
[0,0,1,0,0,0,1],
[0,0,0,1,0,0,0],
[0,0,0,0,1,0,0],
[0,0,0,0,0,1,0],
[0,0,0,0,0,0,1]])
kf.H = np.array([[1,0,0,0,0,0,0], # 观测矩阵
[0,1,0,0,0,0,0],
[0,0,1,0,0,0,0],
[0,0,0,1,0,0,0]])
kf.R[2:,2:] *= 10. # 观测噪声协方差
kf.P[4:,4:] *= 1000. # 初始状态协方差
kf.P *= 10.
kf.Q[-1,-1] *= 0.01 # 过程噪声协方差
kf.Q[4:,4:] *= 0.01
return kf
python复制from scipy.optimize import linear_sum_assignment
def associate_detections_to_trackers(detections, trackers, iou_threshold=0.3):
if len(trackers)==0:
return np.empty((0,2),dtype=int), np.arange(len(detections)), np.empty(0)
iou_matrix = np.zeros((len(detections),len(trackers)),dtype=np.float32)
for d,det in enumerate(detections):
for t,trk in enumerate(trackers):
iou_matrix[d,t] = iou(det,trk)
matched_indices = linear_sum_assignment(-iou_matrix)
matched_indices = np.asarray(matched_indices).T
unmatched_detections = []
for d,det in enumerate(detections):
if d not in matched_indices[:,0]:
unmatched_detections.append(d)
unmatched_trackers = []
for t,trk in enumerate(trackers):
if t not in matched_indices[:,1]:
unmatched_trackers.append(t)
matches = []
for m in matched_indices:
if iou_matrix[m[0],m[1]]<iou_threshold:
unmatched_detections.append(m[0])
unmatched_trackers.append(m[1])
else:
matches.append(m.reshape(1,2))
if len(matches)==0:
matches = np.empty((0,2),dtype=int)
else:
matches = np.concatenate(matches,axis=0)
return matches, np.array(unmatched_detections), np.array(unmatched_trackers)
在无人机跟踪场景测试中发现:
建议根据场景需求平衡精度与速度。对于1080p视频,YOLOv5s+ SORT组合在RTX 3060上可实现100+ FPS。
关键参数经验值:
| 参数 | 常规场景 | 高速运动场景 | 密集人群场景 |
|---|---|---|---|
| IoU阈值 | 0.3 | 0.2 | 0.4 |
| 最大丢失帧数 | 3 | 1 | 5 |
| 卡尔曼Q系数 | 0.01 | 0.05 | 0.01 |
| 最小置信度 | 0.6 | 0.7 | 0.5 |
python复制from multiprocessing import Pool
def process_frame(args):
frame, detector, tracker = args
dets = detector.detect(frame)
tracked_objects = tracker.update(dets)
return tracked_objects
with Pool(4) as p: # 4个worker进程
results = p.map(process_frame, [(frame, detector, tracker) for frame in video])
当发生以下情况时易出现ID切换:
解决方案:
在树莓派4B上的优化记录:
| 优化措施 | 原始FPS | 优化后FPS |
|---|---|---|
| 基线方案 | 6.2 | - |
| 量化检测模型 | - | 9.8 |
| 禁用可视化 | - | 12.1 |
| 使用Cython加速 | - | 15.7 |
| 输入分辨率降为640x480 | - | 22.3 |
通过轨迹插值补偿短时遮挡:
python复制def interpolate_missing(tracks, max_gap=5):
for id in tracks:
track = tracks[id]
frames = [t['frame'] for t in track]
for i in range(1, len(frames)):
gap = frames[i] - frames[i-1]
if 1 < gap <= max_gap:
# 线性插值
alpha = np.linspace(0, 1, gap+1)[1:-1]
for j in range(gap-1):
interp = {}
for k in track[i-1]:
if isinstance(track[i-1][k], (int, float)):
interp[k] = track[i-1][k]*(1-alpha[j]) + track[i][k]*alpha[j]
track.insert(i+j, interp)
return tracks
在高速公路监控中,我们实现了:
关键改进点:
超市货架前部署方案:
实测数据表明,该系统可准确识别87%的顾客交互行为,比传统红外方案提升35%。