def update(self, im_blob, img0): self.frame_id += 1 activated_starcks = [] refind_stracks = [] lost_stracks = [] removed_stracks = [] width = img0.shape[1] height = img0.shape[0] inp_height = im_blob.shape[2] inp_width = im_blob.shape[3] c = np.array([width / 2., height / 2.], dtype=np.float32) s = max(float(inp_width) / float(inp_height) * height, width) * 1.0 meta = { 'c': c, 's': s, 'out_height': inp_height // self.opt.down_ratio, 'out_width': inp_width // self.opt.down_ratio } ''' Step 1: Network forward, get detections & embeddings''' with torch.no_grad(): output = self.model(im_blob)[-1] hm = output['hm'].sigmoid_() wh = output['wh'] id_feature = output['id'] id_feature = F.normalize(id_feature, dim=1) reg = output['reg'] if self.opt.reg_offset else None dets, inds = mot_decode(hm, wh, reg=reg, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) id_feature = _tranpose_and_gather_feat(id_feature, inds) id_feature = id_feature.squeeze(0) id_feature = id_feature.cpu().numpy() #torch.Size([1, 128, 6]) dets = self.post_process(dets, meta) # dets = self.merge_outputs([dets])[1] # remain_inds = dets[:, 4] > self.opt.conf_thres dets = dets[remain_inds] id_feature = id_feature[remain_inds] # vis ''' for i in range(0, dets.shape[0]): bbox = dets[i][0:4] cv2.rectangle(img0, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 2) cv2.imshow('dets', img0) cv2.waitKey(0) id0 = id0-1 ''' if len(dets) > 0: '''Detections''' occlution = np.zeros(shape=(len(dets), len(dets))) for i in range(len(dets)): for j in range(i + 1, len(dets)): occ1, occ2 = tlbr_occlution(dets[i, :4], dets[j, :4]) occlution[i, j] = occ1 occlution[j, i] = occ2 occlution = np.sum(occlution, axis=0) detections = [ STrack(STrack.tlbr_to_tlwh(tlbrs[:4]), tlbrs[4], f, self.opt.maxLen, occ) for (tlbrs, f, occ) in zip(dets[:, :5], id_feature, occlution) ] else: detections = [] ''' Add newly detected tracklets to tracked_stracks''' unconfirmed = [] tracked_stracks = [] # type: list[STrack] for track in self.tracked_stracks: if not track.is_activated: unconfirmed.append(track) else: tracked_stracks.append(track) ''' Step 2: First association, with embedding''' strack_pool = joint_stracks(tracked_stracks, self.lost_stracks) # Predict the current location with KF #for strack in strack_pool: #strack.predict() STrack.multi_predict(strack_pool) if self.opt.queue_dist: #we don't use occlution in detection for now dists = matching.queue_embedding_distance(strack_pool, detections, self.opt, metric="cosine", occlution=None) else: dists = matching.embedding_distance(strack_pool, detections) #dists = matching.gate_cost_matrix(self.kalman_filter, dists, strack_pool, detections) dists = matching.fuse_motion(self.kalman_filter, dists, strack_pool, detections, only_position=self.opt.only_position ,\ lambda_=self.opt.lambda_) matches, u_track, u_detection = matching.linear_assignment( dists, thresh=self.opt.matching_threshold) for itracked, idet in matches: track = strack_pool[itracked] det = detections[idet] if track.state == TrackState.Tracked: if self.opt.queue_dist: track.update(detections[idet], self.frame_id, occlution[idet]) else: track.update(detections[idet], self.frame_id) activated_starcks.append(track) else: track.re_activate(det, self.frame_id, new_id=False) refind_stracks.append(track) ''' Step 3: Second association, with IOU''' detections = [detections[i] for i in u_detection] r_tracked_stracks = [ strack_pool[i] for i in u_track if strack_pool[i].state == TrackState.Tracked ] dists = matching.iou_distance(r_tracked_stracks, detections) matches, u_track, u_detection = matching.linear_assignment(dists, thresh=0.5) for itracked, idet in matches: track = r_tracked_stracks[itracked] det = detections[idet] if track.state == TrackState.Tracked: if self.opt.queue_dist: track.update(det, self.frame_id, occlution[idet]) else: track.update(det, self.frame_id) activated_starcks.append(track) else: track.re_activate(det, self.frame_id, new_id=False) refind_stracks.append(track) for it in u_track: track = r_tracked_stracks[it] if not track.state == TrackState.Lost: track.mark_lost() lost_stracks.append(track) '''Deal with unconfirmed tracks, usually tracks with only one beginning frame''' detections = [detections[i] for i in u_detection] dists = matching.iou_distance(unconfirmed, detections) matches, u_unconfirmed, u_detection = matching.linear_assignment( dists, thresh=0.7) for itracked, idet in matches: if self.opt.queue_dist: unconfirmed[itracked].update(detections[idet], self.frame_id, occlution[idet]) else: unconfirmed[itracked].update(detections[idet], self.frame_id) activated_starcks.append(unconfirmed[itracked]) for it in u_unconfirmed: track = unconfirmed[it] track.mark_removed() removed_stracks.append(track) """ Step 4: Init new stracks""" for inew in u_detection: track = detections[inew] if track.score < self.det_thresh: continue track.activate(self.kalman_filter, self.frame_id) activated_starcks.append(track) """ Step 5: Update state""" for track in self.lost_stracks: if self.frame_id - track.end_frame > self.max_time_lost: track.mark_removed() removed_stracks.append(track) # print('Ramained match {} s'.format(t4-t3)) self.tracked_stracks = [ t for t in self.tracked_stracks if t.state == TrackState.Tracked ] self.tracked_stracks = joint_stracks(self.tracked_stracks, activated_starcks) self.tracked_stracks = joint_stracks(self.tracked_stracks, refind_stracks) self.lost_stracks = sub_stracks(self.lost_stracks, self.tracked_stracks) self.lost_stracks.extend(lost_stracks) self.lost_stracks = sub_stracks(self.lost_stracks, self.removed_stracks) self.removed_stracks.extend(removed_stracks) self.tracked_stracks, self.lost_stracks = remove_duplicate_stracks( self.tracked_stracks, self.lost_stracks) # get scores of lost tracks output_stracks = [ track for track in self.tracked_stracks if track.is_activated ] logger.debug('===========Frame {}=========='.format(self.frame_id)) logger.debug('Activated: {}'.format( [track.track_id for track in activated_starcks])) logger.debug('Refind: {}'.format( [track.track_id for track in refind_stracks])) logger.debug('Lost: {}'.format( [track.track_id for track in lost_stracks])) logger.debug('Removed: {}'.format( [track.track_id for track in removed_stracks])) return output_stracks
def update_tracking(self, im_blob, img_0): """ :param im_blob: :param img_0: :return: """ # update frame id self.frame_id += 1 # ----- reset the track ids for all object classes in the first frame if self.frame_id == 1: MCTrack.init_count(self.opt.num_classes) # ----- # record tracking results, key: class_id activated_tracks_dict = defaultdict(list) refined_tracks_dict = defaultdict(list) lost_tracks_dict = defaultdict(list) removed_tracks_dict = defaultdict(list) output_tracks_dict = defaultdict(list) height, width = img_0.shape[0], img_0.shape[1] # H, W of original input image net_height, net_width = im_blob.shape[2], im_blob.shape[3] # H, W of net input c = np.array([width * 0.5, height * 0.5], dtype=np.float32) s = max(float(net_width) / float(net_height) * height, width) * 1.0 h_out = net_height // self.opt.down_ratio w_out = net_width // self.opt.down_ratio ''' Step 1: Network forward, get detections & embeddings''' with torch.no_grad(): output = self.model.forward(im_blob)[-1] hm = output['hm'].sigmoid_() wh = output['wh'] reg = output['reg'] if self.opt.reg_offset else None id_feature = output['id'] # L2 normalize the reid feature vector id_feature = F.normalize(id_feature, dim=1) # detection decoding dets, inds, cls_inds_mask = mot_decode(heatmap=hm, wh=wh, reg=reg, num_classes=self.opt.num_classes, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) # ----- get ReID feature vector by object class cls_id_feats = [] # topK feature vectors of each object class for cls_id in range(self.opt.num_classes): # cls_id starts from 0 # get inds of each object class cls_inds = inds[:, cls_inds_mask[cls_id]] # gather feats for each object class cls_id_feature = _tranpose_and_gather_feat(id_feature, cls_inds) # inds: 1×128 cls_id_feature = cls_id_feature.squeeze(0) # n × FeatDim cls_id_feature = cls_id_feature.cpu().numpy() cls_id_feats.append(cls_id_feature) # translate and scale dets = map2orig(dets, h_out, w_out, height, width, self.opt.num_classes) # ----- parse each object class for cls_id in range(self.opt.num_classes): # cls_id从0开始 cls_dets = dets[cls_id] # filter out low confidence detections remain_inds = cls_dets[:, 4] > self.opt.conf_thres cls_dets = cls_dets[remain_inds] cls_id_feature = cls_id_feats[cls_id][remain_inds] if len(cls_dets) > 0: '''Detections, tlbrs: top left bottom right score''' cls_detects = [ MCTrack(MCTrack.tlbr_to_tlwh(tlbrs[:4]), tlbrs[4], feat, self.opt.num_classes, cls_id, 30) for (tlbrs, feat) in zip(cls_dets[:, :5], cls_id_feature) ] else: cls_detects = [] ''' Add newly detected tracks to tracked_tracks''' unconfirmed_dict = defaultdict(list) tracked_tracks_dict = defaultdict(list) for track in self.tracked_tracks_dict[cls_id]: if not track.is_activated: unconfirmed_dict[cls_id].append(track) else: tracked_tracks_dict[cls_id].append(track) ''' Step 2: First association, with embedding''' # building tracking pool for the current frame track_pool_dict = defaultdict(list) track_pool_dict[cls_id] = join_tracks(tracked_tracks_dict[cls_id], self.lost_tracks_dict[cls_id]) # Predict the current location with KF Track.multi_predict(track_pool_dict[cls_id]) dists = matching.embedding_distance(track_pool_dict[cls_id], cls_detects) dists = matching.fuse_motion(self.kalman_filter, dists, track_pool_dict[cls_id], cls_detects) matches, u_track, u_detection = matching.linear_assignment(dists, thresh=0.7) # thresh=0.7 for i_tracked, i_det in matches: track = track_pool_dict[cls_id][i_tracked] det = cls_detects[i_det] if track.state == TrackState.Tracked: track.update(cls_detects[i_det], self.frame_id) activated_tracks_dict[cls_id].append(track) # for multi-class else: track.re_activate(det, self.frame_id, new_id=False) refined_tracks_dict[cls_id].append(track) ''' Step 3: Second association, with IOU''' cls_detects = [cls_detects[i] for i in u_detection] r_tracked_tracks = [track_pool_dict[cls_id][i] for i in u_track if track_pool_dict[cls_id][i].state == TrackState.Tracked] dists = matching.iou_distance(r_tracked_tracks, cls_detects) matches, u_track, u_detection = matching.linear_assignment(dists, thresh=0.5) # thresh=0.5 for i_tracked, i_det in matches: track = r_tracked_tracks[i_tracked] det = cls_detects[i_det] if track.state == TrackState.Tracked: track.update(det, self.frame_id) activated_tracks_dict[cls_id].append(track) else: track.re_activate(det, self.frame_id, new_id=False) refined_tracks_dict[cls_id].append(track) for it in u_track: track = r_tracked_tracks[it] if not track.state == TrackState.Lost: track.mark_lost() lost_tracks_dict[cls_id].append(track) '''Deal with unconfirmed tracks, usually tracks with only one beginning frame''' cls_detects = [cls_detects[i] for i in u_detection] dists = matching.iou_distance(unconfirmed_dict[cls_id], cls_detects) matches, u_unconfirmed, u_detection = matching.linear_assignment(dists, thresh=0.7) for i_tracked, i_det in matches: unconfirmed_dict[cls_id][i_tracked].update(cls_detects[i_det], self.frame_id) activated_tracks_dict[cls_id].append(unconfirmed_dict[cls_id][i_tracked]) for it in u_unconfirmed: track = unconfirmed_dict[cls_id][it] track.mark_removed() removed_tracks_dict[cls_id].append(track) """ Step 4: Init new tracks""" for i_new in u_detection: track = cls_detects[i_new] if track.score < self.det_thresh: continue track.activate(self.kalman_filter, self.frame_id) activated_tracks_dict[cls_id].append(track) """ Step 5: Update state""" for track in self.lost_tracks_dict[cls_id]: if self.frame_id - track.end_frame > self.max_time_lost: track.mark_removed() removed_tracks_dict[cls_id].append(track) # print('Ramained match {} s'.format(t4-t3)) self.tracked_tracks_dict[cls_id] = [t for t in self.tracked_tracks_dict[cls_id] if t.state == TrackState.Tracked] self.tracked_tracks_dict[cls_id] = join_tracks(self.tracked_tracks_dict[cls_id], activated_tracks_dict[cls_id]) self.tracked_tracks_dict[cls_id] = join_tracks(self.tracked_tracks_dict[cls_id], refined_tracks_dict[cls_id]) self.lost_tracks_dict[cls_id] = sub_tracks(self.lost_tracks_dict[cls_id], self.tracked_tracks_dict[cls_id]) self.lost_tracks_dict[cls_id].extend(lost_tracks_dict[cls_id]) self.lost_tracks_dict[cls_id] = sub_tracks(self.lost_tracks_dict[cls_id], self.removed_tracks_dict[cls_id]) self.removed_tracks_dict[cls_id].extend(removed_tracks_dict[cls_id]) self.tracked_tracks_dict[cls_id], self.lost_tracks_dict[cls_id] = remove_duplicate_tracks( self.tracked_tracks_dict[cls_id], self.lost_tracks_dict[cls_id]) # get scores of lost tracks output_tracks_dict[cls_id] = [track for track in self.tracked_tracks_dict[cls_id] if track.is_activated] logger.debug('===========Frame {}=========='.format(self.frame_id)) logger.debug('Activated: {}'.format( [track.track_id for track in activated_tracks_dict[cls_id]])) logger.debug('Refind: {}'.format( [track.track_id for track in refined_tracks_dict[cls_id]])) logger.debug('Lost: {}'.format( [track.track_id for track in lost_tracks_dict[cls_id]])) logger.debug('Removed: {}'.format( [track.track_id for track in removed_tracks_dict[cls_id]])) return output_tracks_dict
def update_tracking(self, im_blob, img_0): """ :param im_blob: :param img_0: :return: """ # update frame id self.frame_id += 1 # 记录跟踪结果 # 记录跟踪结果: 默认只有一类, 修改为多类别, 用defaultdict(list)代替list # 以class id为key activated_starcks_dict = defaultdict(list) refind_stracks_dict = defaultdict(list) lost_stracks_dict = defaultdict(list) removed_stracks_dict = defaultdict(list) output_stracks_dict = defaultdict(list) height, width = img_0.shape[0], img_0.shape[ 1] # H, W of original input image net_height, net_width = im_blob.shape[2], im_blob.shape[ 3] # H, W of net input c = np.array([width * 0.5, height * 0.5], dtype=np.float32) s = max(float(net_width) / float(net_height) * height, width) * 1.0 h_out = net_height // self.opt.down_ratio w_out = net_width // self.opt.down_ratio ''' Step 1: Network forward, get detections & embeddings''' with torch.no_grad(): output = self.model.forward(im_blob)[-1] hm = output['hm'].sigmoid_() wh = output['wh'] reg = output['reg'] if self.opt.reg_offset else None id_feature = output['id'] id_feature = F.normalize(id_feature, dim=1) # L2 normalize # 检测和分类结果解析 dets, inds, cls_inds_mask = mot_decode( heatmap=hm, wh=wh, reg=reg, num_classes=self.opt.num_classes, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) # ----- get ReID feature vector by object class cls_id_feats = [] # topK feature vectors of each object class for cls_id in range(self.opt.num_classes): # cls_id starts from 0 # get inds of each object class cls_inds = inds[:, cls_inds_mask[cls_id]] # gather feats for each object class cls_id_feature = _tranpose_and_gather_feat( id_feature, cls_inds) # inds: 1×128 cls_id_feature = cls_id_feature.squeeze(0) # n × FeatDim cls_id_feature = cls_id_feature.cpu().numpy() cls_id_feats.append(cls_id_feature) # 检测结果后处理 # meta = {'c': c, # 's': s, # 'out_height': h_out, # 'out_width': w_out} # dets = self.post_process(dets, meta) # using affine matrix # dets = self.merge_outputs([dets]) dets = map2orig(dets, h_out, w_out, height, width, self.opt.num_classes) # translate and scale # ----- 解析每个检测类别 for cls_id in range(self.opt.num_classes): # cls_id从0开始 cls_dets = dets[cls_id] ''' # 可视化中间的检测结果(每一类) for i in range(0, cls_dets.shape[0]): bbox = cls_dets[i][0:4] cv2.rectangle(img0, (bbox[0], bbox[1]), # left-top point (bbox[2], bbox[3]), # right-down point [0, 255, 255], # yellow 2) cv2.putText(img0, id2cls[cls_id], (bbox[0], bbox[1]), cv2.FONT_HERSHEY_PLAIN, 1.3, [0, 0, 255], # red 2) cv2.imshow('{}'.format(id2cls[cls_id]), img0) cv2.waitKey(0) ''' # 过滤掉score得分太低的dets remain_inds = cls_dets[:, 4] > self.opt.conf_thres cls_dets = cls_dets[remain_inds] cls_id_feature = cls_id_feats[cls_id][remain_inds] if len(cls_dets) > 0: '''Detections, tlbrs: top left bottom right score''' cls_detections = [ STrack(STrack.tlbr_to_tlwh(tlbrs[:4]), tlbrs[4], feat, buff_size=30) for (tlbrs, feat) in zip(cls_dets[:, :5], cls_id_feature) ] else: cls_detections = [] # reset the track ids for a different object class for track in cls_detections: track.reset_track_id() ''' Add newly detected tracklets to tracked_stracks''' unconfirmed_dict = defaultdict(list) tracked_stracks_dict = defaultdict( list) # type: key(cls_id), value: list[STrack] for track in self.tracked_stracks_dict[cls_id]: if not track.is_activated: unconfirmed_dict[cls_id].append(track) else: tracked_stracks_dict[cls_id].append(track) ''' Step 2: First association, with embedding''' strack_pool_dict = defaultdict(list) strack_pool_dict[cls_id] = joint_stracks( tracked_stracks_dict[cls_id], self.lost_stracks_dict[cls_id]) # Predict the current location with KF # for strack in strack_pool: STrack.multi_predict(strack_pool_dict[cls_id]) dists = matching.embedding_distance(strack_pool_dict[cls_id], cls_detections) dists = matching.fuse_motion(self.kalman_filter, dists, strack_pool_dict[cls_id], cls_detections) matches, u_track, u_detection = matching.linear_assignment( dists, thresh=0.7) # thresh=0.7 for i_tracked, i_det in matches: track = strack_pool_dict[cls_id][i_tracked] det = cls_detections[i_det] if track.state == TrackState.Tracked: track.update(cls_detections[i_det], self.frame_id) activated_starcks_dict[cls_id].append( track) # for multi-class else: track.re_activate(det, self.frame_id, new_id=False) refind_stracks_dict[cls_id].append(track) ''' Step 3: Second association, with IOU''' cls_detections = [cls_detections[i] for i in u_detection] r_tracked_stracks = [ strack_pool_dict[cls_id][i] for i in u_track if strack_pool_dict[cls_id][i].state == TrackState.Tracked ] dists = matching.iou_distance(r_tracked_stracks, cls_detections) matches, u_track, u_detection = matching.linear_assignment( dists, thresh=0.5) # thresh=0.5 for i_tracked, i_det in matches: track = r_tracked_stracks[i_tracked] det = cls_detections[i_det] if track.state == TrackState.Tracked: track.update(det, self.frame_id) activated_starcks_dict[cls_id].append(track) else: track.re_activate(det, self.frame_id, new_id=False) refind_stracks_dict[cls_id].append(track) for it in u_track: track = r_tracked_stracks[it] if not track.state == TrackState.Lost: track.mark_lost() lost_stracks_dict[cls_id].append(track) '''Deal with unconfirmed tracks, usually tracks with only one beginning frame''' cls_detections = [cls_detections[i] for i in u_detection] dists = matching.iou_distance(unconfirmed_dict[cls_id], cls_detections) matches, u_unconfirmed, u_detection = matching.linear_assignment( dists, thresh=0.7) for i_tracked, i_det in matches: unconfirmed_dict[cls_id][i_tracked].update( cls_detections[i_det], self.frame_id) activated_starcks_dict[cls_id].append( unconfirmed_dict[cls_id][i_tracked]) for it in u_unconfirmed: track = unconfirmed_dict[cls_id][it] track.mark_removed() removed_stracks_dict[cls_id].append(track) """ Step 4: Init new stracks""" for i_new in u_detection: track = cls_detections[i_new] if track.score < self.det_thresh: continue track.activate(self.kalman_filter, self.frame_id) activated_starcks_dict[cls_id].append(track) """ Step 5: Update state""" for track in self.lost_stracks_dict[cls_id]: if self.frame_id - track.end_frame > self.max_time_lost: track.mark_removed() removed_stracks_dict[cls_id].append(track) # print('Ramained match {} s'.format(t4-t3)) self.tracked_stracks_dict[cls_id] = [ t for t in self.tracked_stracks_dict[cls_id] if t.state == TrackState.Tracked ] self.tracked_stracks_dict[cls_id] = joint_stracks( self.tracked_stracks_dict[cls_id], activated_starcks_dict[cls_id]) self.tracked_stracks_dict[cls_id] = joint_stracks( self.tracked_stracks_dict[cls_id], refind_stracks_dict[cls_id]) self.lost_stracks_dict[cls_id] = sub_stracks( self.lost_stracks_dict[cls_id], self.tracked_stracks_dict[cls_id]) self.lost_stracks_dict[cls_id].extend(lost_stracks_dict[cls_id]) self.lost_stracks_dict[cls_id] = sub_stracks( self.lost_stracks_dict[cls_id], self.removed_stracks_dict[cls_id]) self.removed_stracks_dict[cls_id].extend( removed_stracks_dict[cls_id]) self.tracked_stracks_dict[cls_id], self.lost_stracks_dict[ cls_id] = remove_duplicate_stracks( self.tracked_stracks_dict[cls_id], self.lost_stracks_dict[cls_id]) # get scores of lost tracks output_stracks_dict[cls_id] = [ track for track in self.tracked_stracks_dict[cls_id] if track.is_activated ] logger.debug('===========Frame {}=========='.format(self.frame_id)) logger.debug('Activated: {}'.format( [track.track_id for track in activated_starcks_dict[cls_id]])) logger.debug('Refind: {}'.format( [track.track_id for track in refind_stracks_dict[cls_id]])) logger.debug('Lost: {}'.format( [track.track_id for track in lost_stracks_dict[cls_id]])) logger.debug('Removed: {}'.format( [track.track_id for track in removed_stracks_dict[cls_id]])) return output_stracks_dict
def update(self, im_blob, img0): self.frame_id += 1 # 记录跟踪结果 activated_starcks = [] refind_stracks = [] lost_stracks = [] removed_stracks = [] width = img0.shape[1] height = img0.shape[0] inp_height = im_blob.shape[2] inp_width = im_blob.shape[3] c = np.array([width / 2., height / 2.], dtype=np.float32) s = max(float(inp_width) / float(inp_height) * height, width) * 1.0 meta = { 'c': c, 's': s, 'out_height': inp_height // self.opt.down_ratio, 'out_width': inp_width // self.opt.down_ratio } ''' Step 1: Network forward, get detections & embeddings''' with torch.no_grad(): # 前向推断过程不需要梯度反传 output = self.model.forward(im_blob)[-1] hm = output['hm'].sigmoid_() # print("hm shape ", hm.shape, "hm:\n", hm) wh = output['wh'] # print("wh shape ", wh.shape, "wh:\n", wh) id_feature = output['id'] id_feature = F.normalize(id_feature, dim=1) reg = output['reg'] if self.opt.reg_offset else None # print("reg shape ", reg.shape, "reg:\n", reg) # 检测和分类结果解析 dets, inds = mot_decode( heat=hm, # heatmap wh=wh, reg=reg, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) # 组织用于Re-IDd的特征向量 id_feature = _tranpose_and_gather_feat(id_feature, inds) id_feature = id_feature.squeeze(0) # K × FeatDim id_feature = id_feature.cpu().numpy() # 检测结果后处理 dets = self.post_process(dets, meta) dets = self.merge_outputs([dets])[1] # 过滤掉score得分太低的dets remain_inds = dets[:, 4] > self.opt.conf_thres dets = dets[remain_inds] id_feature = id_feature[remain_inds] # vis可视化bbox ''' for i in range(0, dets.shape[0]): bbox = dets[i][0:4] cv2.rectangle(img0, (bbox[0], bbox[1]), # left-top point (bbox[2], bbox[3]), # right-down point (0, 255, 0), 2) cv2.imshow('dets', img0) cv2.waitKey(0) id0 = id0-1 ''' if len(dets) > 0: '''Detections, tlbrs: top left bottom right score''' detections = [ STrack(STrack.tlbr_to_tlwh(tlbrs[:4]), tlbrs[4], feat, buff_size=30) for (tlbrs, feat) in zip(dets[:, :5], id_feature) ] else: detections = [] ''' Add newly detected tracklets to tracked_stracks''' unconfirmed = [] tracked_stracks = [] # type: list[STrack] for track in self.tracked_stracks: if not track.is_activated: unconfirmed.append(track) else: tracked_stracks.append(track) ''' Step 2: First association, with embedding''' strack_pool = joint_stracks(tracked_stracks, self.lost_stracks) # Predict the current location with KF # for strack in strack_pool: # strack.predict() STrack.multi_predict(strack_pool) dists = matching.embedding_distance(strack_pool, detections) # dists = matching.gate_cost_matrix(self.kalman_filter, dists, strack_pool, detections) dists = matching.fuse_motion(self.kalman_filter, dists, strack_pool, detections) matches, u_track, u_detection = matching.linear_assignment(dists, thresh=0.7) for i_tracked, i_det in matches: track = strack_pool[i_tracked] det = detections[i_det] if track.state == TrackState.Tracked: track.update(detections[i_det], self.frame_id) activated_starcks.append(track) else: track.re_activate(det, self.frame_id, new_id=False) refind_stracks.append(track) ''' Step 3: Second association, with IOU''' detections = [detections[i] for i in u_detection] r_tracked_stracks = [ strack_pool[i] for i in u_track if strack_pool[i].state == TrackState.Tracked ] dists = matching.iou_distance(r_tracked_stracks, detections) matches, u_track, u_detection = matching.linear_assignment(dists, thresh=0.5) for i_tracked, i_det in matches: track = r_tracked_stracks[i_tracked] det = detections[i_det] if track.state == TrackState.Tracked: track.update(det, self.frame_id) activated_starcks.append(track) else: track.re_activate(det, self.frame_id, new_id=False) refind_stracks.append(track) for it in u_track: track = r_tracked_stracks[it] if not track.state == TrackState.Lost: track.mark_lost() lost_stracks.append(track) '''Deal with unconfirmed tracks, usually tracks with only one beginning frame''' detections = [detections[i] for i in u_detection] dists = matching.iou_distance(unconfirmed, detections) matches, u_unconfirmed, u_detection = matching.linear_assignment( dists, thresh=0.7) for i_tracked, i_det in matches: unconfirmed[i_tracked].update(detections[i_det], self.frame_id) activated_starcks.append(unconfirmed[i_tracked]) for it in u_unconfirmed: track = unconfirmed[it] track.mark_removed() removed_stracks.append(track) """ Step 4: Init new stracks""" for i_new in u_detection: track = detections[i_new] if track.score < self.det_thresh: continue track.activate(self.kalman_filter, self.frame_id) activated_starcks.append(track) """ Step 5: Update state""" for track in self.lost_stracks: if self.frame_id - track.end_frame > self.max_time_lost: track.mark_removed() removed_stracks.append(track) # print('Ramained match {} s'.format(t4-t3)) self.tracked_stracks = [ t for t in self.tracked_stracks if t.state == TrackState.Tracked ] self.tracked_stracks = joint_stracks(self.tracked_stracks, activated_starcks) self.tracked_stracks = joint_stracks(self.tracked_stracks, refind_stracks) self.lost_stracks = sub_stracks(self.lost_stracks, self.tracked_stracks) self.lost_stracks.extend(lost_stracks) self.lost_stracks = sub_stracks(self.lost_stracks, self.removed_stracks) self.removed_stracks.extend(removed_stracks) self.tracked_stracks, self.lost_stracks = remove_duplicate_stracks( self.tracked_stracks, self.lost_stracks) # get scores of lost tracks output_stracks = [ track for track in self.tracked_stracks if track.is_activated ] logger.debug('===========Frame {}=========='.format(self.frame_id)) logger.debug('Activated: {}'.format( [track.track_id for track in activated_starcks])) logger.debug('Refind: {}'.format( [track.track_id for track in refind_stracks])) logger.debug('Lost: {}'.format( [track.track_id for track in lost_stracks])) logger.debug('Removed: {}'.format( [track.track_id for track in removed_stracks])) return output_stracks