coreml-community/ControlNet-v1-1-Annotators-cpu
15
1# Copyright (c) Facebook, Inc. and its affiliates.2import itertools3import json4import numpy as np5import os6import torch7from pycocotools.cocoeval import COCOeval, maskUtils8 9from annotator.oneformer.detectron2.structures import BoxMode, RotatedBoxes, pairwise_iou_rotated10from annotator.oneformer.detectron2.utils.file_io import PathManager11 12from .coco_evaluation import COCOEvaluator13 14 15class RotatedCOCOeval(COCOeval):16 @staticmethod17 def is_rotated(box_list):18 if type(box_list) == np.ndarray:19 return box_list.shape[1] == 520 elif type(box_list) == list:21 if box_list == []: # cannot decide the box_dim22 return False23 return np.all(24 np.array(25 [26 (len(obj) == 5) and ((type(obj) == list) or (type(obj) == np.ndarray))27 for obj in box_list28 ]29 )30 )31 return False32 33 @staticmethod34 def boxlist_to_tensor(boxlist, output_box_dim):35 if type(boxlist) == np.ndarray:36 box_tensor = torch.from_numpy(boxlist)37 elif type(boxlist) == list:38 if boxlist == []:39 return torch.zeros((0, output_box_dim), dtype=torch.float32)40 else:41 box_tensor = torch.FloatTensor(boxlist)42 else:43 raise Exception("Unrecognized boxlist type")44 45 input_box_dim = box_tensor.shape[1]46 if input_box_dim != output_box_dim:47 if input_box_dim == 4 and output_box_dim == 5:48 box_tensor = BoxMode.convert(box_tensor, BoxMode.XYWH_ABS, BoxMode.XYWHA_ABS)49 else:50 raise Exception(51 "Unable to convert from {}-dim box to {}-dim box".format(52 input_box_dim, output_box_dim53 )54 )55 return box_tensor56 57 def compute_iou_dt_gt(self, dt, gt, is_crowd):58 if self.is_rotated(dt) or self.is_rotated(gt):59 # TODO: take is_crowd into consideration60 assert all(c == 0 for c in is_crowd)61 dt = RotatedBoxes(self.boxlist_to_tensor(dt, output_box_dim=5))62 gt = RotatedBoxes(self.boxlist_to_tensor(gt, output_box_dim=5))63 return pairwise_iou_rotated(dt, gt)64 else:65 # This is the same as the classical COCO evaluation66 return maskUtils.iou(dt, gt, is_crowd)67 68 def computeIoU(self, imgId, catId):69 p = self.params70 if p.useCats:71 gt = self._gts[imgId, catId]72 dt = self._dts[imgId, catId]73 else:74 gt = [_ for cId in p.catIds for _ in self._gts[imgId, cId]]75 dt = [_ for cId in p.catIds for _ in self._dts[imgId, cId]]76 if len(gt) == 0 and len(dt) == 0:77 return []78 inds = np.argsort([-d["score"] for d in dt], kind="mergesort")79 dt = [dt[i] for i in inds]80 if len(dt) > p.maxDets[-1]:81 dt = dt[0 : p.maxDets[-1]]82 83 assert p.iouType == "bbox", "unsupported iouType for iou computation"84 85 g = [g["bbox"] for g in gt]86 d = [d["bbox"] for d in dt]87 88 # compute iou between each dt and gt region89 iscrowd = [int(o["iscrowd"]) for o in gt]90 91 # Note: this function is copied from cocoeval.py in cocoapi92 # and the major difference is here.93 ious = self.compute_iou_dt_gt(d, g, iscrowd)94 return ious95 96 97class RotatedCOCOEvaluator(COCOEvaluator):98 """99 Evaluate object proposal/instance detection outputs using COCO-like metrics and APIs,100 with rotated boxes support.101 Note: this uses IOU only and does not consider angle differences.102 """103 104 def process(self, inputs, outputs):105 """106 Args:107 inputs: the inputs to a COCO model (e.g., GeneralizedRCNN).108 It is a list of dict. Each dict corresponds to an image and109 contains keys like "height", "width", "file_name", "image_id".110 outputs: the outputs of a COCO model. It is a list of dicts with key111 "instances" that contains :class:`Instances`.112 """113 for input, output in zip(inputs, outputs):114 prediction = {"image_id": input["image_id"]}115 116 if "instances" in output:117 instances = output["instances"].to(self._cpu_device)118 119 prediction["instances"] = self.instances_to_json(instances, input["image_id"])120 if "proposals" in output:121 prediction["proposals"] = output["proposals"].to(self._cpu_device)122 self._predictions.append(prediction)123 124 def instances_to_json(self, instances, img_id):125 num_instance = len(instances)126 if num_instance == 0:127 return []128 129 boxes = instances.pred_boxes.tensor.numpy()130 if boxes.shape[1] == 4:131 boxes = BoxMode.convert(boxes, BoxMode.XYXY_ABS, BoxMode.XYWH_ABS)132 boxes = boxes.tolist()133 scores = instances.scores.tolist()134 classes = instances.pred_classes.tolist()135 136 results = []137 for k in range(num_instance):138 result = {139 "image_id": img_id,140 "category_id": classes[k],141 "bbox": boxes[k],142 "score": scores[k],143 }144 145 results.append(result)146 return results147 148 def _eval_predictions(self, predictions, img_ids=None): # img_ids: unused149 """150 Evaluate predictions on the given tasks.151 Fill self._results with the metrics of the tasks.152 """153 self._logger.info("Preparing results for COCO format ...")154 coco_results = list(itertools.chain(*[x["instances"] for x in predictions]))155 156 # unmap the category ids for COCO157 if hasattr(self._metadata, "thing_dataset_id_to_contiguous_id"):158 reverse_id_mapping = {159 v: k for k, v in self._metadata.thing_dataset_id_to_contiguous_id.items()160 }161 for result in coco_results:162 result["category_id"] = reverse_id_mapping[result["category_id"]]163 164 if self._output_dir:165 file_path = os.path.join(self._output_dir, "coco_instances_results.json")166 self._logger.info("Saving results to {}".format(file_path))167 with PathManager.open(file_path, "w") as f:168 f.write(json.dumps(coco_results))169 f.flush()170 171 if not self._do_evaluation:172 self._logger.info("Annotations are not available for evaluation.")173 return174 175 self._logger.info("Evaluating predictions ...")176 177 assert self._tasks is None or set(self._tasks) == {178 "bbox"179 }, "[RotatedCOCOEvaluator] Only bbox evaluation is supported"180 coco_eval = (181 self._evaluate_predictions_on_coco(self._coco_api, coco_results)182 if len(coco_results) > 0183 else None # cocoapi does not handle empty results very well184 )185 186 task = "bbox"187 res = self._derive_coco_results(188 coco_eval, task, class_names=self._metadata.get("thing_classes")189 )190 self._results[task] = res191 192 def _evaluate_predictions_on_coco(self, coco_gt, coco_results):193 """194 Evaluate the coco results using COCOEval API.195 """196 assert len(coco_results) > 0197 198 coco_dt = coco_gt.loadRes(coco_results)199 200 # Only bbox is supported for now201 coco_eval = RotatedCOCOeval(coco_gt, coco_dt, iouType="bbox")202 203 coco_eval.evaluate()204 coco_eval.accumulate()205 coco_eval.summarize()206 207 return coco_eval208 