import json import random from collections import defaultdict from pathlib import Path import cv2 import numpy as np from isegm.data.base import ISDataset from isegm.data.sample import DSample class LvisDataset(ISDataset): def __init__(self, dataset_path, split='train', max_overlap_ratio=0.5, **kwargs): super(LvisDataset, self).__init__(**kwargs) dataset_path = Path(dataset_path) train_categories_path = dataset_path / 'train_categories.json' self._train_path = dataset_path / 'train' self._val_path = dataset_path / 'val' self.split = split self.max_overlap_ratio = max_overlap_ratio with open( dataset_path / split / f'lvis_{self.split}.json', 'r') as f: json_annotation = json.loads(f.read()) self.annotations = defaultdict(list) for x in json_annotation['annotations']: self.annotations[x['image_id']].append(x) if not train_categories_path.exists(): self.generate_train_categories(dataset_path, train_categories_path) self.dataset_samples = [x for x in json_annotation['images'] if len(self.annotations[x['id']]) > 0] def get_sample(self, index) -> DSample: image_info = self.dataset_samples[index] image_id, image_url = image_info['id'], image_info['coco_url'] image_filename = image_url.split('/')[-1] image_annotations = self.annotations[image_id] random.shuffle(image_annotations) # LVISv1 splits do not match older LVIS splits (some images in val may come from COCO train2017) if 'train2017' in image_url: image_path = self._train_path / 'images' / image_filename else: image_path = self._val_path / 'images' / image_filename image = cv2.imread(str(image_path)) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) instances_mask = None instances_area = defaultdict(int) objects_ids = [] for indx, obj_annotation in enumerate(image_annotations): mask = self.get_mask_from_polygon(obj_annotation, image) object_mask = mask > 0 object_area = object_mask.sum() if instances_mask is None: instances_mask = np.zeros_like(object_mask, dtype=np.int32) overlap_ids = np.bincount(instances_mask[object_mask].flatten()) overlap_areas = [overlap_area / instances_area[inst_id] for inst_id, overlap_area in enumerate(overlap_ids) if overlap_area > 0 and inst_id > 0] overlap_ratio = np.logical_and(object_mask, instances_mask > 0).sum() / object_area if overlap_areas: overlap_ratio = max(overlap_ratio, max(overlap_areas)) if overlap_ratio > self.max_overlap_ratio: continue instance_id = indx + 1 instances_mask[object_mask] = instance_id instances_area[instance_id] = object_area objects_ids.append(instance_id) return DSample(image, instances_mask, objects_ids=objects_ids) @staticmethod def get_mask_from_polygon(annotation, image): mask = np.zeros(image.shape[:2], dtype=np.int32) for contour_points in annotation['segmentation']: contour_points = np.array(contour_points).reshape((-1, 2)) contour_points = np.round(contour_points).astype(np.int32)[np.newaxis, :] cv2.fillPoly(mask, contour_points, 1) return mask @staticmethod def generate_train_categories(dataset_path, train_categories_path): with open(dataset_path / 'train/lvis_train.json', 'r') as f: annotation = json.load(f) with open(train_categories_path, 'w') as f: json.dump(annotation['categories'], f, indent=1)