SiamRPN代码分析:test


前言

  本文是SiamRPN代码分析的最后一篇test,代码从init和unpate(tracking)进行分析。


1、init

  init的主要任务是获得上分支的feature map与后续帧的feature map互相关,在获得127x127x3大小的目标模板图像后,要对其增加一个维度再输入网络,返回的分类卷积核和回归卷积核的shape分别为[10,256,4,4]、[20,256,4,4],这里名没有直接return返回这两个核,而是将它们存放在self里(SiamRPNTracker类),可以翻看第一篇architecture的分析;其次,init还要获取当前目标的位置,高宽等,后续update要对其进行更新,也就是预测新的目标位置和目标大小。

#初始帧
    def init(self, frame, bbox):
        #[l,t,w,h]->[center_x,center_y,w,h]
        self.bbox = np.array([bbox[0]-1 + (bbox[2]-1) / 2 , bbox[1]-1 + (bbox[3]-1) / 2 , bbox[2], bbox[3]])
        #获取目标中心点[c_x,c_y]以便后续使用
        self.pos = np.array([bbox[0]-1 + (bbox[2]-1) / 2 , bbox[1]-1 + (bbox[3]-1) / 2])
        #获取目标宽高[w,h]以便后续使用
        self.target_sz = np.array([bbox[2], bbox[3]])
        #获取目标宽高[w,h]以便后续使用
        self.origin_target_sz = np.array([bbox[2], bbox[3]])
        #获取需要图像R/G/B均值   img_mean.shape=(1,1,3)
        self.img_mean = np.mean(frame, axis=(0, 1))
        #获取模板图像
        #返回127x127x3大小的图像
        exemplar_img = get_exemplar_image(frame, self.bbox,config.exemplar_size, config.context_amount, self.img_mean)
        #增加一个batch维度再输入网络
        exemplar_img = self.transforms(exemplar_img)[None, :, :, :]
        self.model.track_init(exemplar_img.cuda())

2、update(tracking)

  update过程还是follow代码流程来分析

    def update(self, frame):
        #传入上一帧的bbox,以及保持初始帧的img_mean不变来填充后续所有帧
        #返回271x271x3大小的图片、缩放因子是271/(上下文信息x271/127)
        instance_img_np, _, _, scale_x = get_instance_image(frame, self.bbox, config.exemplar_size,config.instance_size, config.context_amount, self.img_mean)
        """————————————————得到分类分数和回归参数————————————"""
        #增加一个batch维度再送入网络
        instance_img = self.transforms(instance_img_np)[None, :, :, :]
        #返回score.shape=[1,10,19,19],regression.shape=[1,20,19,19]
        pred_score, pred_regression = self.model.track_update(instance_img.cuda())
        #[1,10,19,19]->[1,2,5*19*19]->[1,1805,2] conf即置信度
        pred_conf = pred_score.reshape(-1, 2, config.anchor_num * config.score_size * config.score_size).permute(0,2,1)
        #[1,20,19,19]->[1,4,5*19*19]->[1,1805,4] offset即位移,对anchor微调
        pred_offset = pred_regression.reshape(-1, 4,config.anchor_num * config.score_size * config.score_size).permute(0,2,1)

先获得271x271x3大小的检测图像,扩维后将其输入网络,得到互相关的输入,再调用track_update方法得到分类分数和回归参数,之后就是这两者shape变换,以便后续使用。

	    #传入的anchor(1805,4) delta(1805,4),delta是回归参数,对anchor进行调整,返回调整后的anchor,即pre_box(1805,4)
        box_pred = box_transform_inv(self.anchors, delta)
        #pred_conf=[1,1805,2]
        #score_pred.shape=torch.Size([1805]) 取1,表示取正样本
        score_pred = F.softmax(pred_conf, dim=2)[0, :, 1].cpu().detach().numpy()#计算预测分类得分

将1805组回归参数应用于1805个anchor,使其位置信息更加准确,并对分类分数的前景值进行softmax处理,得到1805个和为1的数,之后找到最大的数,该最大值对应的anchor就是预测框。

		#尺度惩罚 一个>1的数
        s_c = change(sz(box_pred[:, 2], box_pred[:, 3]) / (sz_wh(self.target_sz * scale_x)))
        #比例惩罚 一个>1的数
        r_c = change((self.target_sz[0] / self.target_sz[1]) / (box_pred[:, 2] / box_pred[:, 3]))
        # 尺度惩罚和比例惩罚 penalty_k=0.22,penalty最大为1,即不惩罚
        penalty = np.exp(-(r_c * s_c - 1.) * config.penalty_k)
        pscore = penalty * score_pred#对每一个anchors的正样本分类预测分数×惩罚因子
        pscore = pscore * (1 - config.window_influence) + self.window * config.window_influence #再乘以余弦窗
        max_pscore_id= np.argmax(pscore) #返回最大得分的索引id

惩罚的前提是假设目标在相邻帧的大小(尺度以及高宽比例)变化,所以增加了尺度和比例两个惩罚项,又假设目标在相邻帧的位置变化也不会太大,所以使用余弦窗来抑制大位移,正如论文所言,使用 p e n a l t y penalty penalty来抑制尺度和比例的大变化,余弦窗口抑制大位移。在代码 p e n a l t y penalty penalty公式中,倘若anchor的大小和比例与上一帧接近,s_c和r_c这两个值就都为1, p e n a l t y penalty penalty=e^0=1,即不惩罚。通过 p e n a l t y penalty penalty和余弦窗之后,得到最大的的前景分值索引,记为max_pscore_id。
在这里插入图片描述
  得到max_pscore_id后意味着找到了前景分数最大的anchor作为预测框,上面,已经对其进行了微调,所以现在得到的anchor就是最终的预测框了。接下来就是拿取新的预测框的中心位置和大小去更新目标状态,就不分析了。
  还有一点忘了说,nms操作在测试过程并没有使用,而论文却提到要使用nms来获取最终的包围框,但我个人理解貌似并没太大意义,跟踪过程只要找到最大的前景分值即可,并不需要nms,nms是用来剔出重叠anchor的,而获取最大前景分值不涉及anchor的重叠关系,在检测任务当中nms是很重要的一步。
在这里插入图片描述
谢谢观看!

猜你喜欢

转载自blog.csdn.net/qq_41831753/article/details/113930169
今日推荐