CoolFace
Apppublic

coreml-community/ControlNet-v1-1-Annotators-cpu

sourceHugging Facemitupdated 2y agoView on Hugging Face
15likes
rotated_coco_evaluation.py208 linesDownload Raw Back to evaluation
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