def prec_recall(self, that, th=0.5): none = torch.zeros((0,6)) bgt = torch.from_numpy(self.dets).float() bpd = torch.from_numpy(that.dets).float() overlaps = jaccard(bgt[:,2:], bpd[:,2:]) overlaps[overlaps<th] = 0 best_prior_overlap, best_prior_idx = overlaps.max(1) best_prior_idx = best_prior_idx.squeeze() tp_gt = torch.nonzero(best_prior_idx) if tp_gt.nelement() == 0: return 0, 0, (none, none, bgt, bpd) tp_gt_boxes = bgt.index_select(0,tp_gt.squeeze()) tp_pd = torch.index_select(best_prior_idx, 0, tp_gt.squeeze()) tp_pd_boxes = bpd.index_select(0,tp_pd.squeeze()) fn = torch.nonzero(best_prior_idx==0) if fn.nelement() == 0: fn_boxes = none else :fn_boxes = bgt.index_select(0,fn.squeeze()) fp = torch.ones((len(bpd))).cpu() fp = fp.index_fill_(0,tp_pd,0).nonzero() if fp.nelement() == 0: fp_boxes = none else: fp_boxes = bpd.index_select(0,fp.squeeze()) prec = len(tp_pd)/(len(tp_pd)+len(fp)) recall = len(tp_gt)/(len(tp_gt)+len(fn)) return prec, recall, (tp_gt_boxes, tp_pd_boxes, fn_boxes, fp_boxes)
def match_dis(othreshold, cthreshold, prevs_loc, prevs_conf, truths_loc, truths_cls, loc_match, cls_match, mask, idx): """ args othreshold: overlap threshold cthreshold: conf threshold prevs_loc: tensor [num_prevs, 4] prevs_conf: tensor [num_prevs] truths_loc: tensor [num_objs, 4] truths_cls: tensor [num_objs] loc_match: to be filled [batch, num_pres, 4] cls_match: to be filled [batch, num_pres] mask : to be filled [batch, num_pres] idx : current batch index count: num of good prevs return none """ overlaps = jaccard(truths_loc, prevs_loc) # [num_objs, num_prevs] # print('overlap',overlaps) best_truth_overlap, best_truth_idx = overlaps.max(0, keepdim=True) best_truth_idx.squeeze_(0) # [num_prevs] 每个prev最大overlap的obj序号 best_truth_overlap.squeeze_(0) # 每个prev的最大overlap # print('best',best_truth_idx) # print('xiaocl',cls_match[idx]) # for i in range(cls_match.size(1)): # cls_match[idx,i] = truths_cls[int(best_truth_idx[i])] # [num_prevs] 每个prev匹配obj的cls cls_match[idx] = truths_cls[best_truth_idx] # print('houcl',cls_match[idx]) loc_match[idx] = truths_loc[best_truth_idx, :] # [num_prevs, 4] 每个prev匹配obj的loc mask[idx][best_truth_overlap < othreshold] = 0 mask[idx][prevs_conf < cthreshold] = 0
def fast_nms(self, boxes, masks, scores, iou_threshold: float = 0.5, top_k: int = 200, second_threshold: bool = False): #sorted with the 1th dim scores, idx = scores.sort(1, descending=True) idx = idx[:, :top_k].contiguous() scores = scores[:, :top_k] #80 num_classes, num_dets = idx.size() boxes = boxes[idx.view(-1), :].view(num_classes, num_dets, 4) masks = masks[idx.view(-1), :].view(num_classes, num_dets, -1) iou = jaccard(boxes, boxes) #iou 80 x top_k x top_k iou.triu_(diagonal=1) #https://blog.csdn.net/Z_lbj/article/details/79766690 iou_max, _ = iou.max(dim=1) # Now just filter out the ones higher than the threshold keep = (iou_max <= iou_threshold) # We should also only keep detections over the confidence threshold, but at the cost of # maxing out your detection count for every image, you can just not do that. Because we # have such a minimal amount of computation per detection (matrix mulitplication only), # this increase doesn't affect us much (+0.2 mAP for 34 -> 33 fps), so we leave it out. # However, when you implement this in your method, you should do this second threshold. # TODO:: above if second_threshold: keep *= (scores > self.conf_thresh) # Assign each kept detection to its corresponding class #https://blog.csdn.net/m0_37586991/article/details/88830026 classes_t = torch.arange(num_classes, device=boxes.device)[:, None].expand_as(keep) #tensor([[ 0, 0, 0, ..., 0, 0, 0], # [ 1, 1, 1, ..., 1, 1, 1], # [ 2, 2, 2, ..., 2, 2, 2], classes = classes_t[keep] boxes = boxes[keep] masks = masks[keep] scores = scores[keep] # Only keep the top cfg.max_num_detections highest scores across all classes scores, idx = scores.sort(0, descending=True) idx = idx[:cfg.max_num_detections] scores = scores[:cfg.max_num_detections] classes = classes[idx] boxes = boxes[idx] masks = masks[idx] return boxes, masks, classes, scores
def prec_recall(gt_dets, pd_dets, th=0.5, filter_pups=False): if filter_pups: #print("gt_dets",gt_dets.shape) gt_dets = gt_dets[gt_dets[:, 0] != 4] #print("gt_dets",gt_dets.shape) pd_dets = pd_dets[pd_dets[:, 0] != 4] bgt = torch.from_numpy(gt_dets).float() bpd = torch.from_numpy(pd_dets).float() overlaps = jaccard(bgt[:, 2:], bpd[:, 2:]) overlaps[overlaps < th] = 0 best_prior_overlap, best_prior_idx = overlaps.max(1) best_prior_idx = best_prior_idx.squeeze() tp_gt = torch.nonzero(best_prior_idx) if tp_gt.nelement() == 0: return 0, 0, ([], [], bgt, bpd) tp_gt_boxes = bgt.index_select(0, tp_gt.squeeze()) tp_pd = torch.index_select(best_prior_idx, 0, tp_gt.squeeze()) tp_pd_boxes = bpd.index_select(0, tp_pd.squeeze()) fn = torch.nonzero(best_prior_idx == 0) if fn.nelement() == 0: fn_boxes = [] else: fn_boxes = bgt.index_select(0, fn.squeeze()) fp = torch.ones((len(bpd))).cpu() fp = fp.index_fill_(0, tp_pd, 0).nonzero() if fp.nelement() == 0: fp_boxes = [] else: fp_boxes = bpd.index_select(0, fp.squeeze()) prec = len(tp_pd) / (len(tp_pd) + len(fp)) recall = len(tp_gt) / (len(tp_gt) + len(fn)) #print("%.2f" % prec, "%.2f" % recall, len(tp_gt_boxes), len(fn_boxes), len(fp_boxes)) return prec, recall, (tp_gt_boxes, tp_pd_boxes, fn_boxes, fp_boxes)
def _bbox_iou(bbox1, bbox2, iscrowd=False): with timer.env('BBox IoU'): ret = jaccard(bbox1, bbox2, iscrowd) return ret
def evaluate_detections(dataset, config): # Load all the detections. with open(ALL_DETECTIONS_FILEPATH, 'rb') as file: all_detections = pickle.load(file) num_images = len(dataset) num_classes = config.model.num_classes # take the model num_classes, since we are omitting background classes_name = dataset.classes_name configs_dict = config.dict() # For each image, calculate # 1) the highest jaccard index for each ground truth. # 2) true positives and false positives/negatives for each class. true_pos = np.nan * np.zeros((num_images, num_classes)) false_pos = np.nan * np.zeros((num_images, num_classes)) false_neg = np.nan * np.zeros((num_images, num_classes)) truepos_jaccard_mean = np.nan * np.zeros((num_images, num_classes)) min_jaccard_overlap = 0.5 gts_exist = False for i in range(num_images): image_objects_gt = dataset.get_gt(i) if image_objects_gt.shape[0] == 0: continue gts_exist = True boxes_class_image = image_objects_gt[:, -1] for j in range(1, num_classes): boxes_limits_gt = image_objects_gt[boxes_class_image == (j - 1), :4] image_detections = all_detections[i][j] N_detections = len(image_detections) N_gts = boxes_limits_gt.shape[0] if N_detections == 0 or N_gts == 0: true_pos[i, j] = 0 false_neg[i, j] = N_gts false_pos[i, j] = N_detections truepos_jaccard_mean[i, j] = 0 continue # Get the box limits and confidence. boxes_limits_detections = image_detections[:, :4] detections_conf = image_detections[:, 4] # Calculate the jaccard overlap between detections and gt. boxes_limits_gt_tensor = torch.Tensor(boxes_limits_gt) boxes_limits_detections_tensor = torch.Tensor( boxes_limits_detections) # Permute columns to satisfy the input format of jaccard. boxes_limits_gt_tensor = boxes_limits_gt_tensor[:, (0, 2, 1, 3)] boxes_limits_detections_tensor = boxes_limits_detections_tensor[:, (0, 2, 1, 3 )] # intersect(boxes_limits_gt_tensor[0,:].unsqueeze(0),boxes_limits_detections_tensor[13,:].unsqueeze(0)) jaccard_mat = jaccard(boxes_limits_gt_tensor, boxes_limits_detections_tensor) # For each detection, find the best ground truth overlap. best_truth_jaccard, best_truth_index = jaccard_mat.max(0) # For each gt x, find the detection with highest confidence among all detections whose max overlap is x. best_detection_ind = np.zeros((N_gts, 1)) * np.nan best_detection_conf = np.zeros((N_gts, 1)) for k in range(N_detections): best_gt_ind = best_truth_index[k] if best_truth_jaccard[ k] > min_jaccard_overlap and detections_conf[ k] > best_detection_conf[best_gt_ind]: best_detection_ind[best_gt_ind] = k best_detection_conf[best_gt_ind] = detections_conf[k] # Remove nans, which correspond to unmatched gt boxes. best_detection_ind = best_detection_ind[ ~np.isnan(best_detection_ind)].astype(np.int16) # Calculate the true positives, false positives and false negatives. true_pos[i, j] = best_detection_ind.shape[0] false_neg[i, j] = N_gts - true_pos[i][j] false_pos[i, j] = len([ x for x in range(N_detections) if x not in best_detection_ind ]) truepos_jaccard_mean[i, j] = np.mean( best_truth_jaccard.cpu().numpy()[best_detection_ind]) if gts_exist: statistics_dict = {'dataset_name': config.dataset.name} statistics_dict.update( dict(zip(classes_name, [{}] * len(classes_name)))) for j in range(1, num_classes): class_dict = {} class_dict['N_groundtruths'] = int( np.sum(true_pos[:, j] + false_neg[:, j])) class_dict['N_detections'] = int( np.sum(true_pos[:, j] + false_pos[:, j])) class_dict['True Positives'] = int(np.sum(true_pos[:, j])) class_dict['False Positives'] = int(np.sum(false_pos[:, j])) class_dict['False Negatives'] = int(np.sum(false_neg[:, j])) class_dict['Precision'] = class_dict['True Positives'] / ( class_dict['True Positives'] + class_dict['False Positives']) class_dict['Recall'] = class_dict['True Positives'] / ( class_dict['True Positives'] + class_dict['False Negatives']) class_dict['Jaccard_TruePos_Average'] = np.mean( truepos_jaccard_mean[:, j]) total_false = false_pos[:, j] + false_neg[:, j] worst_image_id = np.argmax(total_false) class_dict['Highest False Pos + Neg Image'] = dataset.filenames[ worst_image_id] class_dict['Highest Error Image: False positives'] = int( false_pos[worst_image_id, j]) class_dict['Highest Error Image: False negatives'] = int( false_neg[worst_image_id, j]) statistics_dict[classes_name[j - 1]] = class_dict # Add useful info to statistics_dict. statistics_dict['model'] = configs_dict['model'] statistics_dict['eval'] = configs_dict['eval'] with open(DETECTION_STATISTICS_FILEPATH, 'w') as file: file.write( reformat_json( json.dumps(statistics_dict, sort_keys=False, indent=4))) else: print("No ground truths were found.")
def test_net(save_folder, net, cuda, testset, transform, thresh): # dump predictions and assoc. ground truth to text file for now filename = save_folder+'test1.txt' num_images = len(testset) mAP=0; for i in range(num_images): img = testset.pull_image(i) img_id, annotation = testset.pull_anno(i) x = torch.from_numpy(transform(img)[0]).permute(2, 0, 1) x = Variable(x.unsqueeze(0)) with open(filename, mode='a') as f: f.write('\nGROUND TRUTH FOR: '+img_id+'\n') if cuda: x = x.cuda() y = net(x) # forward pass detections = y.data # scale each detection back up to the image scale = torch.Tensor([img.shape[1], img.shape[0], img.shape[1], img.shape[0]]) pred_num = 0 detections2=detections[0,:,:,0].view(-1) detectionr, rind =detections2.sort(descending=True) ntop=40 jj=rind[:ntop]%200 ii=rind[:ntop]/200 gt_label=[box[-1] for box in annotation] possible=len(gt_label) if gt_label==0: continue gt_box=torch.tensor([box[:-1] for box in annotation]) dt_box=detections[0,ii,jj,1:]*scale iou=jaccard(dt_box,gt_box) k=0; correct=0; precisions=[]; while correct<possible and k<ntop: flag=False for j, gtl in enumerate(gt_label): if ii[k]-1==gtl and iou[k,j]>0.5: correct+=1 flag=True gt_label[j]=0 #turn the ground truth off break if flag: name = labelmap[ii[k]-1] conf = detectionr[k].item()*100 precision=correct/(k+1);recall=correct/possible precisions.append(precision) gtb=gt_box[j,:];dtb=dt_box[k,:]; iou1=iou[k,j].item() with open(filename, mode='a') as f: f.write('rank %d: %s(%d), score %1.2f%%, precision:%1.2f, recall:%1.2f\n'% (k,name,ii[k]-1,conf,precision,recall)) f.write('detection:'+' ||'.join('%d'%c.item() for c in dtb)+ ', ground truth: '+' ||'.join('%d'%c.item() for c in gtb)+', iou:%1.2f\n'%iou1) k+=1 AP=1; for j,p in enumerate(precisions): prec=np.max(np.array(precisions[j:])) AP+=prec*(np.floor(np.float(j+1)/possible/0.1)-np.floor(np.float(j)/possible/0.1)) AP=AP/11*100 mAP=(mAP*i+AP)/(i+1) with open(filename, mode='a') as f: f.write('---AP: %.1f%%, total AP: %.1f%%---'%(AP,mAP)) print('Image {:d}/{:d} AP: {:.1f}, total AP: {:.1f}'.format(i+1, num_images,AP,mAP))
def max_th(self): boxes = torch.from_numpy(self.dets[:,2:]).float() th = jaccard(boxes, boxes).numpy() for i in range(th.shape[0]): th[i][i] = 0 return np.max(th, axis=1)