karolmajek/Axial-DeepLab-SWideRNet
0
1# coding=utf-82# Copyright 2021 The Deeplab2 Authors.3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.15 16"""Wrappers and conversions for third party pycocotools.17 18This is derived from code in the Tensorflow Object Detection API:19https://github.com/tensorflow/models/tree/master/research/object_detection20 21Huang et. al. "Speed/accuracy trade-offs for modern convolutional object22detectors" CVPR 2017.23"""24 25from typing import Any, Collection, Dict, List, Optional, Union26 27import numpy as np28from pycocotools import mask29 30 31COCO_METRIC_NAMES_AND_INDEX = (32 ('Precision/mAP', 0),33 ('Precision/mAP@.50IOU', 1),34 ('Precision/mAP@.75IOU', 2),35 ('Precision/mAP (small)', 3),36 ('Precision/mAP (medium)', 4),37 ('Precision/mAP (large)', 5),38 ('Recall/AR@1', 6),39 ('Recall/AR@10', 7),40 ('Recall/AR@100', 8),41 ('Recall/AR@100 (small)', 9),42 ('Recall/AR@100 (medium)', 10),43 ('Recall/AR@100 (large)', 11)44)45 46 47def _ConvertBoxToCOCOFormat(box: np.ndarray) -> List[float]:48 """Converts a box in [ymin, xmin, ymax, xmax] format to COCO format.49 50 This is a utility function for converting from our internal51 [ymin, xmin, ymax, xmax] convention to the convention used by the COCO API52 i.e., [xmin, ymin, width, height].53 54 Args:55 box: a [ymin, xmin, ymax, xmax] numpy array56 57 Returns:58 a list of floats representing [xmin, ymin, width, height]59 """60 return [float(box[1]), float(box[0]), float(box[3] - box[1]),61 float(box[2] - box[0])]62 63 64def ExportSingleImageGroundtruthToCoco(65 image_id: Union[int, str],66 next_annotation_id: int,67 category_id_set: Collection[int],68 groundtruth_boxes: np.ndarray,69 groundtruth_classes: np.ndarray,70 groundtruth_masks: np.ndarray,71 groundtruth_is_crowd: Optional[np.ndarray] = None) -> List[Dict[str, Any]]:72 """Exports groundtruth of a single image to COCO format.73 74 This function converts groundtruth detection annotations represented as numpy75 arrays to dictionaries that can be ingested by the COCO evaluation API. Note76 that the image_ids provided here must match the ones given to77 ExportSingleImageDetectionsToCoco. We assume that boxes and classes are in78 correspondence - that is: groundtruth_boxes[i, :], and79 groundtruth_classes[i] are associated with the same groundtruth annotation.80 81 In the exported result, "area" fields are always set to the foregorund area of82 the mask.83 84 Args:85 image_id: a unique image identifier either of type integer or string.86 next_annotation_id: integer specifying the first id to use for the87 groundtruth annotations. All annotations are assigned a continuous integer88 id starting from this value.89 category_id_set: A set of valid class ids. Groundtruth with classes not in90 category_id_set are dropped.91 groundtruth_boxes: numpy array (float32) with shape [num_gt_boxes, 4]92 groundtruth_classes: numpy array (int) with shape [num_gt_boxes]93 groundtruth_masks: uint8 numpy array of shape [num_detections, image_height,94 image_width] containing detection_masks.95 groundtruth_is_crowd: optional numpy array (int) with shape [num_gt_boxes]96 indicating whether groundtruth boxes are crowd.97 98 Returns:99 a list of groundtruth annotations for a single image in the COCO format.100 101 Raises:102 ValueError: if (1) groundtruth_boxes and groundtruth_classes do not have the103 right lengths or (2) if each of the elements inside these lists do not104 have the correct shapes or (3) if image_ids are not integers105 """106 107 if len(groundtruth_classes.shape) != 1:108 raise ValueError('groundtruth_classes is '109 'expected to be of rank 1.')110 if len(groundtruth_boxes.shape) != 2:111 raise ValueError('groundtruth_boxes is expected to be of '112 'rank 2.')113 if groundtruth_boxes.shape[1] != 4:114 raise ValueError('groundtruth_boxes should have '115 'shape[1] == 4.')116 num_boxes = groundtruth_classes.shape[0]117 if num_boxes != groundtruth_boxes.shape[0]:118 raise ValueError('Corresponding entries in groundtruth_classes, '119 'and groundtruth_boxes should have '120 'compatible shapes (i.e., agree on the 0th dimension).'121 'Classes shape: %d. Boxes shape: %d. Image ID: %s' % (122 groundtruth_classes.shape[0],123 groundtruth_boxes.shape[0], image_id))124 has_is_crowd = groundtruth_is_crowd is not None125 if has_is_crowd and len(groundtruth_is_crowd.shape) != 1:126 raise ValueError('groundtruth_is_crowd is expected to be of rank 1.')127 groundtruth_list = []128 for i in range(num_boxes):129 if groundtruth_classes[i] in category_id_set:130 iscrowd = groundtruth_is_crowd[i] if has_is_crowd else 0131 segment = mask.encode(np.asfortranarray(groundtruth_masks[i]))132 area = mask.area(segment)133 export_dict = {134 'id': next_annotation_id + i,135 'image_id': image_id,136 'category_id': int(groundtruth_classes[i]),137 'bbox': list(_ConvertBoxToCOCOFormat(groundtruth_boxes[i, :])),138 'segmentation': segment,139 'area': area,140 'iscrowd': iscrowd141 }142 143 groundtruth_list.append(export_dict)144 return groundtruth_list145 146 147def ExportSingleImageDetectionMasksToCoco(148 image_id: Union[int, str], category_id_set: Collection[int],149 detection_masks: np.ndarray, detection_scores: np.ndarray,150 detection_classes: np.ndarray) -> List[Dict[str, Any]]:151 """Exports detection masks of a single image to COCO format.152 153 This function converts detections represented as numpy arrays to dictionaries154 that can be ingested by the COCO evaluation API. We assume that155 detection_masks, detection_scores, and detection_classes are in correspondence156 - that is: detection_masks[i, :], detection_classes[i] and detection_scores[i]157 are associated with the same annotation.158 159 Args:160 image_id: unique image identifier either of type integer or string.161 category_id_set: A set of valid class ids. Detections with classes not in162 category_id_set are dropped.163 detection_masks: uint8 numpy array of shape [num_detections, image_height,164 image_width] containing detection_masks.165 detection_scores: float numpy array of shape [num_detections] containing166 scores for detection masks.167 detection_classes: integer numpy array of shape [num_detections] containing168 the classes for detection masks.169 170 Returns:171 a list of detection mask annotations for a single image in the COCO format.172 173 Raises:174 ValueError: if (1) detection_masks, detection_scores and detection_classes175 do not have the right lengths or (2) if each of the elements inside these176 lists do not have the correct shapes or (3) if image_ids are not integers.177 """178 179 if len(detection_classes.shape) != 1 or len(detection_scores.shape) != 1:180 raise ValueError('All entries in detection_classes and detection_scores'181 'expected to be of rank 1.')182 num_boxes = detection_classes.shape[0]183 if not num_boxes == len(detection_masks) == detection_scores.shape[0]:184 raise ValueError('Corresponding entries in detection_classes, '185 'detection_scores and detection_masks should have '186 'compatible lengths and shapes '187 'Classes length: %d. Masks length: %d. '188 'Scores length: %d' % (189 detection_classes.shape[0], len(detection_masks),190 detection_scores.shape[0]191 ))192 detections_list = []193 for i in range(num_boxes):194 if detection_classes[i] in category_id_set:195 detections_list.append({196 'image_id': image_id,197 'category_id': int(detection_classes[i]),198 'segmentation': mask.encode(np.asfortranarray(detection_masks[i])),199 'score': float(detection_scores[i])200 })201 return detections_list202 