def siamese_track(state, im, mask_enable=False, refine_enable=False, device='cpu', debug=False): p = state['p'] net = state['net'] avg_chans = state['avg_chans'] window = state['window'] target_pos = state['target_pos'] target_sz = state['target_sz'] wc_x = target_sz[1] + p.context_amount * sum(target_sz) hc_x = target_sz[0] + p.context_amount * sum(target_sz) s_x = np.sqrt(wc_x * hc_x) scale_x = p.exemplar_size / s_x d_search = (p.instance_size - p.exemplar_size) / 2 pad = d_search / scale_x s_x = s_x + 2 * pad crop_box = [target_pos[0] - round(s_x) / 2, target_pos[1] - round(s_x) / 2, round(s_x), round(s_x)] if debug: im_debug = im.copy() crop_box_int = np.int0(crop_box) cv2.rectangle(im_debug, (crop_box_int[0], crop_box_int[1]), (crop_box_int[0] + crop_box_int[2], crop_box_int[1] + crop_box_int[3]), (255, 0, 0), 2) cv2.imshow('search area', im_debug) cv2.waitKey(0) # extract scaled crops for search region x at previous target position x_crop = Variable(get_subwindow_tracking(im, target_pos, p.instance_size, round(s_x), avg_chans).unsqueeze(0)) if mask_enable: score, delta, mask = net.track_mask(x_crop.to(device)) else: score, delta = net.track(x_crop.to(device)) delta = delta.permute(1, 2, 3, 0).contiguous().view(4, -1).data.cpu().numpy() score = F.softmax(score.permute(1, 2, 3, 0).contiguous().view(2, -1).permute(1, 0), dim=1).data[:, 1].cpu().numpy() delta[0, :] = delta[0, :] * p.anchor[:, 2] + p.anchor[:, 0] delta[1, :] = delta[1, :] * p.anchor[:, 3] + p.anchor[:, 1] delta[2, :] = np.exp(delta[2, :]) * p.anchor[:, 2] delta[3, :] = np.exp(delta[3, :]) * p.anchor[:, 3] def change(r): return np.maximum(r, 1. / r) def sz(w, h): pad = (w + h) * 0.5 sz2 = (w + pad) * (h + pad) return np.sqrt(sz2) def sz_wh(wh): pad = (wh[0] + wh[1]) * 0.5 sz2 = (wh[0] + pad) * (wh[1] + pad) return np.sqrt(sz2) # size penalty target_sz_in_crop = target_sz*scale_x s_c = change(sz(delta[2, :], delta[3, :]) / (sz_wh(target_sz_in_crop))) # scale penalty r_c = change((target_sz_in_crop[0] / target_sz_in_crop[1]) / (delta[2, :] / delta[3, :])) # ratio penalty penalty = np.exp(-(r_c * s_c - 1) * p.penalty_k) pscore = penalty * score # cos window (motion model) pscore = pscore * (1 - p.window_influence) + window * p.window_influence best_pscore_id = np.argmax(pscore) pred_in_crop = delta[:, best_pscore_id] / scale_x lr = penalty[best_pscore_id] * score[best_pscore_id] * p.lr # lr for OTB res_x = pred_in_crop[0] + target_pos[0] res_y = pred_in_crop[1] + target_pos[1] res_w = target_sz[0] * (1 - lr) + pred_in_crop[2] * lr res_h = target_sz[1] * (1 - lr) + pred_in_crop[3] * lr target_pos = np.array([res_x, res_y]) target_sz = np.array([res_w, res_h]) # for Mask Branch if mask_enable: best_pscore_id_mask = np.unravel_index(best_pscore_id, (5, p.score_size, p.score_size)) delta_x, delta_y = best_pscore_id_mask[2], best_pscore_id_mask[1] if refine_enable: mask = net.track_refine((delta_y, delta_x)).to(device).sigmoid().squeeze().view( p.out_size, p.out_size).cpu().data.numpy() else: mask = mask[0, :, delta_y, delta_x].sigmoid(). \ squeeze().view(p.out_size, p.out_size).cpu().data.numpy() def crop_back(image, bbox, out_sz, padding=-1): a = (out_sz[0] - 1) / bbox[2] b = (out_sz[1] - 1) / bbox[3] c = -a * bbox[0] d = -b * bbox[1] mapping = np.array([[a, 0, c], [0, b, d]]).astype(np.float) crop = cv2.warpAffine(image, mapping, (out_sz[0], out_sz[1]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=padding) return crop s = crop_box[2] / p.instance_size sub_box = [crop_box[0] + (delta_x - p.base_size / 2) * p.total_stride * s, crop_box[1] + (delta_y - p.base_size / 2) * p.total_stride * s, s * p.exemplar_size, s * p.exemplar_size] s = p.out_size / sub_box[2] back_box = [-sub_box[0] * s, -sub_box[1] * s, state['im_w'] * s, state['im_h'] * s] mask_in_img = crop_back(mask, back_box, (state['im_w'], state['im_h'])) target_mask = (mask_in_img > p.seg_thr).astype(np.uint8) if cv2.__version__[-5] == '4': contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) else: _, contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) cnt_area = [cv2.contourArea(cnt) for cnt in contours] if len(contours) != 0 and np.max(cnt_area) > 100: contour = contours[np.argmax(cnt_area)] # use max area polygon polygon = contour.reshape(-1, 2) # pbox = cv2.boundingRect(polygon) # Min Max Rectangle prbox = cv2.boxPoints(cv2.minAreaRect(polygon)) # Rotated Rectangle # box_in_img = pbox rbox_in_img = prbox else: # empty mask location = cxy_wh_2_rect(target_pos, target_sz) rbox_in_img = np.array([[location[0], location[1]], [location[0] + location[2], location[1]], [location[0] + location[2], location[1] + location[3]], [location[0], location[1] + location[3]]]) target_pos[0] = max(0, min(state['im_w'], target_pos[0])) target_pos[1] = max(0, min(state['im_h'], target_pos[1])) target_sz[0] = max(10, min(state['im_w'], target_sz[0])) target_sz[1] = max(10, min(state['im_h'], target_sz[1])) state['target_pos'] = target_pos state['target_sz'] = target_sz state['score'] = score[best_pscore_id] state['mask'] = mask_in_img if mask_enable else [] state['ploygon'] = rbox_in_img if mask_enable else [] return state
def track_vot(model, video, hp=None, mask_enable=False, refine_enable=False, device='cpu'): regions = [] # result and states[1 init / 2 lost / 0 skip] image_files, gt = video['image_files'], video['gt'] start_frame, end_frame, lost_times, toc = 0, len(image_files), 0, 0 for f, image_file in enumerate(image_files): im = cv2.imread(image_file) tic = cv2.getTickCount() if f == start_frame: # init cx, cy, w, h = get_axis_aligned_bbox(gt[f]) target_pos = np.array([cx, cy]) target_sz = np.array([w, h]) state = siamese_init(im, target_pos, target_sz, model, hp, device) # init tracker location = cxy_wh_2_rect(state['target_pos'], state['target_sz']) regions.append(1 if 'VOT' in args.dataset else gt[f]) elif f > start_frame: # tracking state = siamese_track(state, im, mask_enable, refine_enable, device, args.debug) # track if mask_enable: location = state['ploygon'].flatten() mask = state['mask'] else: location = cxy_wh_2_rect(state['target_pos'], state['target_sz']) mask = [] if 'VOT' in args.dataset: gt_polygon = ((gt[f][0], gt[f][1]), (gt[f][2], gt[f][3]), (gt[f][4], gt[f][5]), (gt[f][6], gt[f][7])) if mask_enable: pred_polygon = ((location[0], location[1]), (location[2], location[3]), (location[4], location[5]), (location[6], location[7])) else: pred_polygon = ((location[0], location[1]), (location[0] + location[2], location[1]), (location[0] + location[2], location[1] + location[3]), (location[0], location[1] + location[3])) b_overlap = vot_overlap(gt_polygon, pred_polygon, (im.shape[1], im.shape[0])) else: b_overlap = 1 if b_overlap: regions.append(location) else: # lost regions.append(2) lost_times += 1 start_frame = f + 5 # skip 5 frames else: # skip regions.append(0) toc += cv2.getTickCount() - tic if args.visualization and f >= start_frame: # visualization (skip lost frame) im_show = im.copy() if f == 0: cv2.destroyAllWindows() if gt.shape[0] > f: if len(gt[f]) == 8: cv2.polylines(im_show, [np.array(gt[f], np.int).reshape((-1, 1, 2))], True, (0, 255, 0), 3) else: cv2.rectangle(im_show, (gt[f, 0], gt[f, 1]), (gt[f, 0] + gt[f, 2], gt[f, 1] + gt[f, 3]), (0, 255, 0), 3) if len(location) == 8: if mask_enable: mask = mask > state['p'].seg_thr im_show[:, :, 2] = mask * 255 + (1 - mask) * im_show[:, :, 2] location_int = np.int0(location) cv2.polylines(im_show, [location_int.reshape((-1, 1, 2))], True, (0, 255, 255), 3) else: location = [int(l) for l in location] cv2.rectangle(im_show, (location[0], location[1]), (location[0] + location[2], location[1] + location[3]), (0, 255, 255), 3) cv2.putText(im_show, str(f), (40, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2) cv2.putText(im_show, str(lost_times), (40, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.putText(im_show, str(state['score']) if 'score' in state else '', (40, 120), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.imshow(video['name'], im_show) cv2.waitKey(1) toc /= cv2.getTickFrequency() # save result name = args.arch.split('.')[0] + '_' + ('mask_' if mask_enable else '') + ('refine_' if refine_enable else '') +\ args.resume.split('/')[-1].split('.')[0] if 'VOT' in args.dataset: video_path = join('test', args.dataset, name, 'baseline', video['name']) if not isdir(video_path): makedirs(video_path) result_path = join(video_path, '{:s}_001.txt'.format(video['name'])) with open(result_path, "w") as fin: for x in regions: fin.write("{:d}\n".format(x)) if isinstance(x, int) else \ fin.write(','.join([vot_float2str("%.4f", i) for i in x]) + '\n') else: # OTB video_path = join('test', args.dataset, name) if not isdir(video_path): makedirs(video_path) result_path = join(video_path, '{:s}.txt'.format(video['name'])) with open(result_path, "w") as fin: for x in regions: fin.write(','.join([str(i) for i in x])+'\n') logger.info('({:d}) Video: {:12s} Time: {:02.1f}s Speed: {:3.1f}fps Lost: {:d}'.format( v_id, video['name'], toc, f / toc, lost_times)) return lost_times, f / toc
def siamese_track(state, im): refine_enable=True mask_enable=True device= torch.device('cuda' if (torch.cuda.is_available()) else 'cpu') debug=True p = state['p'] net = state['net'] avg_chans = state['avg_chans'] window = state['window'] targets = state["targets"] zf_lists =[] BLUE = [255,255,255] for i,target in enumerate(targets): wc_x = target["target_sz"][1] + p.context_amount * sum(target["target_sz"]) hc_x = target["target_sz"][0] + p.context_amount * sum(target["target_sz"]) target["s_z"] = np.sqrt(wc_x*hc_x) target["scale_x"] = p.exemplar_size / target["s_z"] d_search = (p.instance_size - p.exemplar_size) / 2 pad = d_search / target["scale_x"] target["s_z"] = target["s_z"] + 2 * pad target["crop_box"]= [target["target_pos"][0] - round(target["s_z"])/ 2, target["target_pos"][1] - round(target["s_z"]) / 2, round(target["s_z"]), round(target["s_z"])] zf_lists.append(target["zf"]) crop_box = target["crop_box"] # extract scaled crops for search region x at previous target position targets = get_subwindow_tracking(im, p.instance_size, avg_chans,targets=targets) # x_crop = Variable(get_subwindow_tracking(im, target_pos, p.instance_size, round(s_x), avg_chans).unsqueeze(0)) tracking_data_list = [] tracking_data = dict() for target,zf in zip(targets,zf_lists): target["x_crop"] = Variable(target["im_to_torch"].unsqueeze(0)) target["x_crop"] = target["x_crop"].to(device) tracking_data_list.append({"x_crop":target["x_crop"],"zf":zf}) if mask_enable: results = net.track_mask(search=targets[0]["x_crop"],lists=tracking_data_list) else: score, delta = net.track(x_crop.to(device)) for result in results: delta = result["rpn_pred_loc"] score = result["rpn_pred_cls"] delta = delta.permute(1, 2, 3, 0).contiguous().view(4, -1).data.cpu().numpy() score = F.softmax(score.permute(1, 2, 3, 0).contiguous().view(2, -1).permute(1, 0), dim=1).data[:, 1].cpu().numpy() delta[0, :] = delta[0, :] * p.anchor[:, 2] + p.anchor[:, 0] delta[1, :] = delta[1, :] * p.anchor[:, 3] + p.anchor[:, 1] delta[2, :] = np.exp(delta[2, :]) * p.anchor[:, 2] delta[3, :] = np.exp(delta[3, :]) * p.anchor[:, 3] result["rpn_pred_loc"] = delta result["rpn_pred_cls"] = score def change(r): return np.maximum(r, 1. / r) def sz(w, h): pad = (w + h) * 0.5 sz2 = (w + pad) * (h + pad) return np.sqrt(sz2) def sz_wh(wh): pad = (wh[0] + wh[1]) * 0.5 sz2 = (wh[0] + pad) * (wh[1] + pad) return np.sqrt(sz2) # size penalty count =0 for target,result in zip(targets,results): delta = result["rpn_pred_loc"] score = result["rpn_pred_cls"] crop_box = target["crop_box"] target_sz_in_crop = target["target_sz"] * target["scale_x"] s_c = change(sz(delta[2, :], delta[3, :]) / (sz_wh(target_sz_in_crop))) # scale penalty r_c = change((target_sz_in_crop[0] / target_sz_in_crop[1]) / (delta[2, :] / delta[3, :])) # ratio penalty penalty = np.exp(-(r_c * s_c - 1) * p.penalty_k) pscore = penalty * score pscore = pscore * (1 - p.window_influence) + window * p.window_influence best_pscore_id = np.argmax(pscore) pred_in_crop = delta[:, best_pscore_id] / target["scale_x"] lr = penalty[best_pscore_id] * score[best_pscore_id] * p.lr # lr for OTB res_x = pred_in_crop[0] + target["target_pos"][0] res_y = pred_in_crop[1] + target["target_pos"][1] res_w = target["target_sz"][0] * (1 - lr) + pred_in_crop[2] * lr res_h = target["target_sz"][1] * (1 - lr) + pred_in_crop[3] * lr target["target_pos"] = np.array([res_x, res_y]) target["target_sz"] = np.array([res_w, res_h]) if mask_enable: best_pscore_id_mask = np.unravel_index(best_pscore_id, (5, p.score_size, p.score_size)) delta_x, delta_y = best_pscore_id_mask[2], best_pscore_id_mask[1] if refine_enable: mask = net.track_refine((delta_y, delta_x),index=count).to(device).sigmoid().squeeze().view( p.out_size, p.out_size).cpu().data.numpy() else: mask = mask[0, :, delta_y, delta_x].sigmoid(). \ squeeze().view(p.out_size, p.out_size).cpu().data.numpy() count+=1 def crop_back(image, bbox, out_sz, padding=-1): a = (out_sz[0] - 1) / bbox[2] b = (out_sz[1] - 1) / bbox[3] c = -a * bbox[0] d = -b * bbox[1] mapping = np.array([[a, 0, c], [0, b, d]]).astype(np.float) crop = cv2.warpAffine(image, mapping, (out_sz[0], out_sz[1]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=padding) return crop s = crop_box[2] / p.instance_size sub_box = [crop_box[0] + (delta_x - p.base_size / 2) * p.total_stride * s, crop_box[1] + (delta_y - p.base_size / 2) * p.total_stride * s, s * p.exemplar_size, s * p.exemplar_size] s = p.out_size / sub_box[2] back_box = [-sub_box[0] * s, -sub_box[1] * s, state['im_w'] * s, state['im_h'] * s] mask_in_img = crop_back(mask, back_box, (state['im_w'], state['im_h'])) target_mask = (mask_in_img > p.seg_thr).astype(np.uint8) if cv2.__version__[-5] == '4': contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) else: _, contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) cnt_area = [cv2.contourArea(cnt) for cnt in contours] if len(contours) != 0 and np.max(cnt_area) > 100: contour = contours[np.argmax(cnt_area)] # use max area polygon polygon = contour.reshape(-1, 2) # pbox = cv2.boundingRect(polygon) # Min Max Rectangle prbox = cv2.boxPoints(cv2.minAreaRect(polygon)) # Rotated Rectangle # box_in_img = pbox rbox_in_img = prbox else: # empty mask location = cxy_wh_2_rect(target["target_pos"], target["target_sz"]) rbox_in_img = np.array([[location[0], location[1]], [location[0] + location[2], location[1]], [location[0] + location[2], location[1] + location[3]], [location[0], location[1] + location[3]]]) target["target_pos"][0] = max(0, min(state['im_w'], target["target_pos"][0])) target["target_pos"][1] = max(0, min(state['im_h'], target["target_pos"][1])) target["target_sz"][0] = max(10, min(state['im_w'], target["target_sz"][0])) target["target_sz"][1] = max(10, min(state['im_h'], target["target_sz"][1])) # print("new targetPos {} and targetsize {} \n".format(target["target_pos"],target["target_sz"])) target["mask"] = mask_in_img if mask_enable else [] target['ploygon'] = rbox_in_img if mask_enable else [] target["score"] = score[best_pscore_id] state["targets"] = targets return state