SORT4 SORT项目代码解析

SORT系列

SORT-1 项目配置运行-WINDOWS
SORT-2 卡尔曼滤波推导和示例
SORT-3 匈牙利算法和SORT类
SORT-4 SORT项目代码解析
本项目地址

SORT项目逐层详解

main

if __name__ == '__main__'
	# 设置交互模式、参数、文件路径
		|
	# 创建 SORT 对象
    mot_tracker = Sort(max_age=, min_hits=,iou_threshold) 
    	|
    # "循环"读取每一个文件(每一帧)
    for frame in range(...):
        # 参数准备
        frame += 1 	# 帧数+1
        dets[] = .. # 存放 检测框
        total_frames += 1
        	|
        # 获取检测框
        dets[] = ...
        	|
        # 用检测框 dets 做一次更新; 返回满足条件可显示的trackers([x1,y1,x2,y2,ID])
        trackers = mot_tracker.update(dets)
        	|
       	# 作画
        for d in trakcers:
            fig.canvas.flush_events()...
           

1.SORT 类

class Sort(object):
    def __init__(self, max_age=1, min_hits=3, iou_threshold=0.3):
    # Sets key parameters for SORT
    self.max_age = max_age		# tracker 的最大寿命
    self.min_hits = min_hits	# 最小匹配次数
    self.iou_threshold = iou_threshold	# 匹配阈值
    self.trackers = []        	# 存放跟踪器类 KalmanBoxTracker 对象
    self.frame_count = 0
    
    
	def update(self, dets=np.empty((0, 5))):
    # 使用 检测框 做一次更新; dets:[x1,y1,x2,y2,ID]
    	# 0.参数准备
        trks = np.zeros(len(self,trackers),5)	# 
        to_del = []			# 待删除的 预测框
        ret = []			# 可显示的 tracker
        	|
        # 1.现有的跟踪器全部做一次更新预测,获得预测框
        for t,trk in enumerate(trks):
            pos = self.trackers[t].predict()[0]      	# 已有跟踪器上做一次预测
      		trk[:]=[pos[0], pos[1], pos[2], pos[3], 0]  # 获得 "预测框" 的坐标
        	|
        	# 去除非法的预测框
        trks = np.ma.compress_rows(np.ma.masked_invalid(trks))
        	|
        	# 删除 to_del 中待删除的 tracker
        for t in reversed(to_del):
      		self.trackers.pop(t)
            |
        # 2.预测框和 检测框 做一次匹配
        matched, unmatched_dets, unmatched_trks = \
        	associate_detections_to_trackers(dets,trks, self.iou_threshold)
    		|
            
        # 3.根据匹配结果 分别更新三类 trakcer
        	# 3.1 更新匹配成功的跟踪器
        for m in matched:
             self.trackers[m[1]].update(dets[m[0], :])
    		# 3.2 为未匹配到的检测框创建一个新的跟踪器
        for i in unmatched_dets:
            trk = KalmanBoxTracker(dets[i,:])
			self.trackers.append(trk)
            |
        	# 3.3 根据跟踪器的存在时间、匹配次数等决定是否加入显示列表

1.1卡尔曼跟踪器

卡尔曼滤波器系统如下图所示。

输入
状态量初始值 x k − 1 {x_{k-1}} xk1和状态量协方差初始值 P k − 1 {P_{k-1}} Pk1
卡尔曼滤波器中的参数设置: 状态转移矩阵 F F F,映射矩阵(或称测量矩阵) H H H
迭代输入每一步的 观测值 Z k Z_k Zk
输出
每一步的状态预测 x k x_k xk

在这里插入图片描述
在SORT项目中,观测量 来自 YOLO 的检测结果 b b o x ( [ x 1 , y 1 , x 2 , y 2 ] ) bbox([x1,y1,x2,y2]) bbox([x1,y1,x2,y2]) 的转化形式 Z ( [ u , v , s , r ] ) Z([u,v,s,r]) Z([u,v,s,r])。其中 [ u , v ] [u,v] [u,v] 是中心点的坐标, s s s 是面积, r r r 是面积宽高比。这样四个量将是独立的变量,减弱了 bbox 四个变量之间的相关性。

由此可以定义状态量 [ x , y , s , r , x ˙ , y ˙ , s ˙ ] T [x,y,s,r,\dot x,\dot y,\dot s]^T [x,y,s,r,x˙,y˙,s˙]T,其中 x ˙ , y ˙ , s ˙ \dot x,\dot y,\dot s x˙,y˙,s˙ 分别是 x , y , s x,y,s x,y,s 的一阶微分 d x , d y , d s dx,dy,ds dx,dy,ds
在线性模型中,可将其视为 距离-速度 模型,即 x k = x k − 1 + d x d t x_k=x_{k-1}+dxdt xk=xk1+dxdt,由此可得状态转移矩阵 F F F
F = [ 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 ] F=\begin{bmatrix}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 \end{bmatrix} F=1,0,0,0,1,0,00,1,0,0,0,1,00,0,1,0,0,0,10,0,0,1,0,0,00,0,0,0,1,0,00,0,0,0,0,1,00,0,0,0,0,0,1
x k = F ⋅ x k − 1 = [ 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 ] [ x y s r x ˙ y ˙ s ˙ ] x_k=F\cdot x_{k-1}=\begin{bmatrix}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 \end{bmatrix}\begin{bmatrix} x\\y\\s\\r\\\dot x\\\dot y\\\dot s\end{bmatrix} xk=Fxk1=1,0,0,0,1,0,00,1,0,0,0,1,00,0,1,0,0,0,10,0,0,1,0,0,00,0,0,0,1,0,00,0,0,0,0,1,00,0,0,0,0,0,1xysrx˙y˙s˙

即可得到 x k = x k − 1 + x ˙ x_k=x_{k-1}+\dot x xk=xk1+x˙ ( y , s y,s y,s同理), x ˙ = x ˙ \dot x=\dot x x˙=x˙ ( r , y ˙ r,\dot y r,y˙同理)。这就是卡尔曼滤波器是线性滤波器原因

class KalmanBoxTracker(object):
    
    count = 0		# 跟踪器的存在数量,static
    
    def __init__(self,bbox):
    # 卡尔曼滤波器的主要参数设置
    self.kf = KalmanFilter(dim_x=7, dim_z=4)  # 定义状态空间和观测空间维度,解释见下
    self.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]])
    self.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]])

    self.kf.R[2:,2:] *= 10.
    self.kf.P[4:,4:] *= 1000. 
    self.kf.P *= 10.
    self.kf.Q[-1,-1] *= 0.01
    self.kf.Q[4:,4:] *= 0.01

    self.kf.x[:4] = convert_bbox_to_z(bbox)     # [u,v,s,r,u',v',s']
    self.time_since_update = 0
    self.id = KalmanBoxTracker.count

    KalmanBoxTracker.count += 1

    self.history = []
    self.hits = 0
    self.hit_streak = 0
    self.age = 0

    def update(self,bbox):
    # 用检测框更新 tracker(kalman filter update)
    self.time_since_update = 0  # 自第一次 update(创建) 的匹配次数
    self.history = []			# 保存历次的
    self.hits += 1
    self.hit_streak += 1        # 与检测框成功匹配的次数
    self.kf.update(convert_bbox_to_z(bbox))	# 调用库函数的 update
    
    def predict(self):
     	if((self.kf.x[6]+self.kf.x[2])<=0):
      		self.kf.x[6] *= 0.0
        
    	self.kf.predict()
    
        self.age += 1
        if(self.time_since_update>0):
          self.hit_streak = 0
        self.time_since_update += 1
        self.history.append(convert_x_to_bbox(self.kf.x))
        return self.history[-1]     # 返回最后(新)一个 bbox

1.2检测框与预测框的关联

def associate_detections_to_trackers(detections,trackers,iou_threshold = 0.3):
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值