def polymask2poly(masks): polys = [] for mask in masks: all_mask_points = np.concatenate(mask, axis=0)[None, :] if all_mask_points.size != 8: all_mask_points = bt.bbox2type(all_mask_points, 'obb') all_mask_points = bt.bbox2type(all_mask_points, 'poly') polys.append(all_mask_points) if not polys: polys = np.zeros((0, 8), dtype=np.float32) else: polys = np.concatenate(polys, axis=0) return polys
def bbox2mask(bboxes, w, h, mask_type='polygon'): polys = bt.bbox2type(bboxes, 'poly') assert mask_type in ['polygon', 'bitmap'] if mask_type == 'bitmap': masks = [] for poly in polys: rles = maskUtils.frPyObjects([poly.tolist()], h, w) masks.append(maskUtils.decode(rles[0])) gt_masks = BitmapMasks(masks, h, w) else: gt_masks = PolygonMasks([[poly] for poly in polys], h, w) return gt_masks
def _load_bboxes(self, results): ann_info = results['ann_info'] gt_bboxes = ann_info['bboxes'].copy() results['gt_bboxes'] = bt.bbox2type(gt_bboxes, 'hbb') results['bbox_fields'].append('gt_bboxes') if self.obb_as_mask: MaskClass = PolygonMasks if self.bbox_mtype == 'polygon' \ else BitmapMasks h, w = results['img_info']['height'], results['img_info']['width'] results['gt_masks'] = bbox2mask(gt_bboxes, w, h, self.bbox_mtype) results['gt_masks_ignore'] = MaskClass([], h, w) results['mask_fields'].append('gt_masks') return results
def get_matrix_and_size(self, results): angle = results['angle'] height, width = results['img_shape'][:2] if self.keep_shape: center = ((width - 1) * 0.5, (height - 1) * 0.5) matrix = cv2.getRotationMatrix2D(center, angle, 1) else: matrix = cv2.getRotationMatrix2D((0, 0), angle, 1) img_bbox = np.array([[0, 0, width, 0, width, height, 0, width]]) img_bbox = bt.bbox2type(bt.warp(img_bbox, matrix), 'hbb') width = int(img_bbox[0, 2] - img_bbox[0, 0] + 1) height = int(img_bbox[0, 3] - img_bbox[0, 1] + 1) matrix[0, 2] = -img_bbox[0, 0] matrix[1, 2] = -img_bbox[0, 1] return matrix, width, height
def _merge_func(info, CLASSES, iou_thr, task): img_id, label_dets = info label_dets = np.concatenate(label_dets, axis=0) labels, dets = label_dets[:, 0], label_dets[:, 1:] nms_ops = bt.choice_by_type(nms, obb_nms, BT_nms, dets, with_score=True) big_img_results = [] for i in range(len(CLASSES)): cls_dets = dets[labels == i] nms_dets, _ = nms_ops(cls_dets, iou_thr) if task == 'Task2': bboxes = bt.bbox2type(nms_dets[:, :-1], 'hbb') nms_dets = np.concatenate([bboxes, nms_dets[:, -1:]], axis=1) big_img_results.append(nms_dets) return img_id, big_img_results
def _proposal2json(self, results): """Convert proposal results to COCO json style""" json_results = [] for idx in range(len(self)): img_id = self.img_ids[idx] bboxes = results[idx] bboxes, scores = bboxes[:, :-1], bboxes[:, [-1]] bboxes = bt.bbox2type(bboxes, 'hbb') bboxes = np.concatenate([bboxes, scores], axis=1) for i in range(bboxes.shape[0]): data = dict() data['image_id'] = img_id data['bbox'] = self.xyxy2xywh(bboxes[i]) data['score'] = float(bboxes[i][4]) data['category_id'] = 1 json_results.append(data) return json_results
def bitmapmask2poly(masks): if len(masks) == 0: return np.zeros((0, 8), dtype=np.float32) height, width = masks.height, masks.width x, y = np.arange(width), np.arange(height) xx, yy = np.meshgrid(x, y) coors = np.stack([xx, yy], axis=-1) coors = coors.astype(np.float32) obbs = [] for mask in masks: points = coors[mask == 1] (x, y), (w, h), angle = cv2.minAreaRect(points) angle = -angle theta = angle / 180 * pi obbs.append([x, y, w, h, theta]) obbs = np.array(obbs, dtype=np.float32) return bt.bbox2type(obbs, 'poly')
def _segm2json(self, results): """Convert instance segmentation results to COCO json style""" bbox_json_results = [] segm_json_results = [] for idx in range(len(self)): img_id = self.img_ids[idx] det, seg = results[idx] for label in range(len(det)): # bbox results bboxes = det[label] bboxes, scores = bboxes[:, :-1], bboxes[:, [-1]] bboxes = bt.bbox2type(bboxes, 'hbb') bboxes = np.concatenate([bboxes, scores], axis=1) for i in range(bboxes.shape[0]): data = dict() data['image_id'] = img_id data['bbox'] = self.xyxy2xywh(bboxes[i]) data['score'] = float(bboxes[i][4]) data['category_id'] = self.cat_ids[label] bbox_json_results.append(data) # segm results # some detectors use different scores for bbox and mask if isinstance(seg, tuple): segms = seg[0][label] mask_score = seg[1][label] else: segms = seg[label] mask_score = [bbox[4] for bbox in bboxes] for i in range(bboxes.shape[0]): data = dict() data['image_id'] = img_id data['score'] = float(mask_score[i]) data['category_id'] = self.cat_ids[label] if isinstance(segms[i]['counts'], bytes): segms[i]['counts'] = segms[i]['counts'].decode() data['segmentation'] = segms[i] segm_json_results.append(data) return bbox_json_results, segm_json_results
def single_vis(task, btype, class_names, colors, thickness, text_off, font_size, show_off, wait_time, lock, prog, total): imgpath, out_file, bboxes, labels, scores = task bboxes = bt.bbox2type(bboxes, btype) if btype else bboxes bt.imshow_bboxes(imgpath, bboxes, labels, scores, class_names=class_names, colors=colors, thickness=thickness, with_text=(not text_off), font_size=font_size, show=(not show_off), wait_time=wait_time, out_file=out_file) lock.acquire() prog.value += 1 msg = f'({prog.value/total:3.1%} {prog.value}:{total})' msg += ' - ' + f"Filename: {osp.split(imgpath)[-1]}" print(msg) lock.release()
def _list_mask_2_obb(dets, segments): new_dets = [] for cls_dets, cls_segments in zip(dets, segments): new_cls_dets = [] for ds, segs in zip(cls_dets, cls_segments): _, scores = ds[:, :-1], ds[:, -1] new_bboxes = [] for seg in segs: try: contours, _ = cv2.findContours(seg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) except ValueError: _, contours, _ = cv2.findContours(seg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) max_contour = max(contours, key=len).reshape(1, -1) new_bboxes.append(bt.bbox2type(max_contour, 'obb')) new_bboxes = np.zeros((0, 5)) if not new_bboxes else \ np.concatenate(new_bboxes, axis=0) new_cls_dets.append( np.concatenate([new_bboxes, scores[:, None]], axis=1)) new_dets.append(new_cls_dets) return new_dets
def evaluate(self, results, metric='mAP', logger=None, with_merge=True, ign_diff=True, ign_scale_ranges=None, save_dir=None, merge_iou_thr=0.1, use_07_metric=True, scale_ranges=None, eval_iou_thr=[0.5], proposal_nums=(2000, ), nproc=10): nproc = min(nproc, os.cpu_count()) if not isinstance(metric, str): assert len(metric) == 1 metric = metric[0] allowed_metrics = ['mAP', 'recall'] if metric not in allowed_metrics: raise KeyError(f'metric {metric} is not supported') task = self.task eval_results = {} if metric == 'mAP': merged_results = self.format_results( results, nproc=nproc, with_merge=with_merge, ign_scale_ranges=ign_scale_ranges, iou_thr=merge_iou_thr, save_dir=save_dir) infos = self.ori_infos if with_merge else self.data_infos id_mapper = {ann['id']: i for i, ann in enumerate(infos)} det_results, annotations = [], [] for k, v in merged_results: det_results.append(v) ann = infos[id_mapper[k]]['ann'] gt_bboxes = ann['bboxes'] gt_labels = ann['labels'] diffs = ann.get('diffs', np.zeros((gt_bboxes.shape[0], ), dtype=np.int)) if task == 'Task2': gt_bboxes = bt.bbox2type(gt_bboxes, 'hbb') gt_ann = {} if ign_diff: gt_ann['bboxes_ignore'] = gt_bboxes[diffs == 1] gt_ann['labels_ignore'] = gt_labels[diffs == 1] gt_bboxes = gt_bboxes[diffs == 0] gt_labels = gt_labels[diffs == 0] gt_ann['bboxes'] = gt_bboxes gt_ann['labels'] = gt_labels annotations.append(gt_ann) print('\nStart calculate mAP!!!') print('Result is Only for reference,', 'final result is subject to DOTA_devkit') mean_ap, _ = eval_arb_map(det_results, annotations, scale_ranges=scale_ranges, iou_thr=eval_iou_thr, use_07_metric=use_07_metric, dataset=self.CLASSES, logger=logger, nproc=nproc) eval_results['mAP'] = mean_ap elif metric == 'recall': assert mmcv.is_list_of(results, np.ndarray) gt_bboxes = [] for info in self.data_infos: bboxes = info['ann']['bboxes'] if ign_diff: diffs = info['ann'].get( 'diffs', np.zeros((bboxes.shape[0], ), dtype=np.int)) bboxes = bboxes[diffs == 0] gt_bboxes.append(bboxes) if isinstance(eval_iou_thr, float): eval_iou_thr = [eval_iou_thr] recalls = eval_arb_recalls(gt_bboxes, results, True, proposal_nums, eval_iou_thr, logger=logger) for i, num in enumerate(proposal_nums): for j, iou in enumerate(eval_iou_thr): eval_results[f'recall@{num}@{iou}'] = recalls[i, j] if recalls.shape[1] > 1: ar = recalls.mean(axis=1) for i, num in enumerate(proposal_nums): eval_results[f'AR@{num}'] = ar[i] return eval_results