""" COCO dataset parser Copyright 2020 Ross Wightman """ import numpy as np from pycocotools.coco import COCO from .parser import Parser from .parser_config import CocoParserCfg class CocoParser(Parser): def __init__(self, cfg: CocoParserCfg): super().__init__( bbox_yxyx=cfg.bbox_yxyx, has_labels=cfg.has_labels, include_masks=cfg.include_masks, include_bboxes_ignore=cfg.include_bboxes_ignore, ignore_empty_gt=cfg.has_labels and cfg.ignore_empty_gt, min_img_size=cfg.min_img_size ) self.cat_ids_as_labels = True # this is the default for original TF EfficientDet models self.coco = None self._load_annotations(cfg.ann_filename) def get_ann_info(self, idx): img_id = self.img_ids[idx] return self._parse_img_ann(img_id) def _load_annotations(self, ann_file): assert self.coco is None self.coco = COCO(ann_file) self.cat_ids = self.coco.getCatIds() self.cat_names = [c['name'] for c in self.coco.loadCats(ids=self.cat_ids)] if not self.cat_ids_as_labels: self.cat_id_to_label = {cat_id: i + self.label_offset for i, cat_id in enumerate(self.cat_ids)} img_ids_with_ann = set(_['image_id'] for _ in self.coco.anns.values()) for img_id in sorted(self.coco.imgs.keys()): info = self.coco.loadImgs([img_id])[0] if (min(info['width'], info['height']) < self.min_img_size or (self.ignore_empty_gt and img_id not in img_ids_with_ann)): self.img_ids_invalid.append(img_id) continue self.img_ids.append(img_id) self.img_infos.append(info) def _parse_img_ann(self, img_id): ann_ids = self.coco.getAnnIds(imgIds=[img_id]) ann_info = self.coco.loadAnns(ann_ids) bboxes = [] bboxes_ignore = [] cls = [] for i, ann in enumerate(ann_info): if ann.get('ignore', False): continue x1, y1, w, h = ann['bbox'] if self.include_masks and ann['area'] <= 0: continue if w < 1 or h < 1: continue if self.yxyx: bbox = [y1, x1, y1 + h, x1 + w] else: bbox = [x1, y1, x1 + w, y1 + h] if ann.get('iscrowd', False): if self.include_bboxes_ignore: bboxes_ignore.append(bbox) else: bboxes.append(bbox) cls.append(self.cat_id_to_label[ann['category_id']] if self.cat_id_to_label else ann['category_id']) if bboxes: bboxes = np.array(bboxes, ndmin=2, dtype=np.float32) cls = np.array(cls, dtype=np.int64) else: bboxes = np.zeros((0, 4), dtype=np.float32) cls = np.array([], dtype=np.int64) if self.include_bboxes_ignore: if bboxes_ignore: bboxes_ignore = np.array(bboxes_ignore, ndmin=2, dtype=np.float32) else: bboxes_ignore = np.zeros((0, 4), dtype=np.float32) ann = dict(bbox=bboxes, cls=cls) if self.include_bboxes_ignore: ann['bbox_ignore'] = bboxes_ignore return ann