def __init__(self, root_dir, coco_dir, set_dir, preproc=None, target_transform=None, dataset_name='COCO'): self.root = root_dir self.root_dir = root_dir self.coco_dir = coco_dir self.set_dir = set_dir self.coco_name = root_dir.replace("/", "") + "_" + coco_dir.replace( "/", "") + "_" + set_dir.replace("/", "") self.data_path = os.getcwd() self.cache_path = os.path.join(self.data_path, 'coco_cache') if (not os.path.isdir(self.cache_path)): os.mkdir(self.cache_path) self.image_set = set_dir self.preproc = preproc self.target_transform = target_transform self.name = dataset_name self.ids = list() self.annotations = list() annofile = self._get_ann_file(set_dir) _COCO = COCO(annofile) self._COCO = _COCO self._classes = ['__background__'] self._classes_file = os.path.join(self.root_dir, self.coco_dir, 'annotations', 'classes.txt') f = open(self._classes_file) lines = f.readlines() f.close() for i in range(len(lines)): self._classes.append(lines[i][:len(lines[i]) - 1]) self._classes = tuple(self._classes) self.num_classes = len(self._classes) cats = _COCO.loadCats(_COCO.getCatIds()) self._class_to_ind = dict(zip(self._classes, range(self.num_classes))) self._class_to_coco_cat_id = dict( zip([c['name'] for c in cats], _COCO.getCatIds())) indexes = _COCO.getImgIds() self.image_indexes = indexes self.ids.extend( [self.image_path_from_index(index) for index in indexes]) self.annotations.extend( self._load_coco_annotations(self.coco_name, indexes, _COCO))
def __init__(self, root, image_sets, preproc=None, target_transform=None, dataset_name='COCO'): self.root = root # self.data_path = os.path.join(os.path.expanduser("~"),'datasets') self.data_path = os.path.join(self.root, "data") self.cache_path = os.path.join(self.data_path, 'coco_cache') self.image_set = image_sets self.preproc = preproc self.target_transform = target_transform self.name = dataset_name self.img_paths = list() self.annotations = list() self._view_map = { 'minival2014': 'val2014', # 5k val2014 subset 'valminusminival2014': 'val2014', # val2014 \setminus minival2014 'test-dev2015': 'test2015', } for (year, image_set) in image_sets: coco_name = image_set + year data_name = (self._view_map[coco_name] if coco_name in self._view_map else coco_name) annofile = self._get_ann_file(coco_name) _COCO = COCO(annofile) self._COCO = _COCO self.coco_name = coco_name cats = _COCO.loadCats(_COCO.getCatIds()) self._classes = tuple(['__background__'] + [c['name'] for c in cats]) self.num_classes = len(self._classes) self._class_to_ind = dict( zip(self._classes, range(self.num_classes))) self._class_to_coco_cat_id = dict( zip([c['name'] for c in cats], _COCO.getCatIds())) indexes = _COCO.getImgIds() self.image_indexes = indexes self.img_paths.extend([ self.image_path_from_index(data_name, index) for index in indexes ]) if image_set.find('test') != -1: print('test set will not load annotations!') else: self.annotations.extend( self._load_coco_annotations(coco_name, indexes, _COCO))
class COCODetection(data.Dataset): """VOC Detection Dataset Object input is image, target is annotation Arguments: root (string): filepath to VOCdevkit folder. image_set (string): imageset to use (eg. 'train', 'val', 'test') transform (callable, optional): transformation to perform on the input image target_transform (callable, optional): transformation to perform on the target `annotation` (eg: take in caption string, return tensor of word indices) dataset_name (string, optional): which dataset to load (default: 'VOC2007') """ def __init__(self, root, image_sets, preproc=None, target_transform=None, dataset_name='COCO'): self.root = root self.cache_path = os.path.join(self.root, 'cache') self.image_set = image_sets self.preproc = preproc self.target_transform = target_transform self.name = dataset_name self.ids = list() self.annotations = list() for (year, image_set) in image_sets: coco_name = image_set + year image_root = os.path.join(root, 'images', _PREDEFINED_SPLITS_COCO[coco_name][0]) annofile = os.path.join(root, _PREDEFINED_SPLITS_COCO[coco_name][1]) self._COCO = COCO(annofile) self.coco_name = coco_name self.class_name = self._get_coco_instances_meta() self.num_classes = len(self.class_name) self.img_ids = sorted(self._COCO.imgs.keys()) imgs = self._COCO.loadImgs(self.img_ids) self.ids.extend( [os.path.join(image_root, img["file_name"]) for img in imgs]) self.annotations.extend( self._load_coco_annotations(coco_name, self.img_ids, self._COCO)) def _load_coco_annotations(self, coco_name, indexes, _COCO): cache_file = os.path.join(self.cache_path, coco_name + '_gt_roidb.pkl') if os.path.exists(cache_file): with open(cache_file, 'rb') as fid: roidb = pickle.load(fid) print('{} gt roidb loaded from {}'.format(coco_name, cache_file)) return roidb gt_roidb = [ self._annotation_from_index(index, _COCO) for index in indexes ] if not os.path.exists(os.path.dirname(cache_file)): os.makedirs(os.path.dirname(cache_file)) with open(cache_file, 'wb') as fid: pickle.dump(gt_roidb, fid, pickle.HIGHEST_PROTOCOL) print('wrote gt roidb to {}'.format(cache_file)) return gt_roidb def _get_coco_instances_meta(self): thing_ids = self._COCO.getCatIds() cats = self._COCO.loadCats(thing_ids) cats_name = [c['name'] for c in cats] self._class_to_coco_cat_id = dict(zip(cats_name, thing_ids)) voc_inds = (0, 1, 2, 3, 4, 5, 6, 8, 14, 15, 16, 17, 18, 19, 39, 56, 57, 58, 60, 62) nonvoc_inds = tuple([i for i in range(80) if i not in voc_inds]) if 'nonvoc' in self.coco_name: self.id_map = nonvoc_inds thing_ids = [thing_ids[i] for i in self.id_map] thing_classes = [cats_name[k] for k in self.id_map] elif 'voc' in self.coco_name: self.id_map = voc_inds thing_ids = [thing_ids[i] for i in self.id_map] thing_classes = [cats_name[k] for k in self.id_map] self._thing_dataset_id_to_contiguous_id = { k: i for i, k in enumerate(thing_ids, 1) } return thing_classes def _annotation_from_index(self, index, _COCO): """ Loads COCO bounding-box instance annotations. Crowd instances are handled by marking their overlaps (with all categories) to -1. This overlap value means that crowd "instances" are excluded from training. """ im_ann = _COCO.loadImgs(index)[0] width = im_ann['width'] height = im_ann['height'] annIds = _COCO.getAnnIds(imgIds=index, iscrowd=None) objs = _COCO.loadAnns(annIds) # Sanitize bboxes -- some are invalid valid_objs = [] for obj in objs: x1 = np.max((0, obj['bbox'][0])) y1 = np.max((0, obj['bbox'][1])) x2 = np.min((width - 1, x1 + np.max((0, obj['bbox'][2] - 1)))) y2 = np.min((height - 1, y1 + np.max((0, obj['bbox'][3] - 1)))) if obj['area'] > 0 and x2 >= x1 and y2 >= y1: obj['clean_bbox'] = [x1, y1, x2, y2] valid_objs.append(obj) objs = valid_objs num_objs = len(objs) res = np.zeros((num_objs, 5)) # Lookup table to map from COCO category ids to our internal class # indices for ix, obj in enumerate(objs): cls = self._thing_dataset_id_to_contiguous_id[obj['category_id']] res[ix, 0:4] = obj['clean_bbox'] res[ix, 4] = cls return res def __getitem__(self, index): img_id = self.ids[index] target = self.annotations[index] img = cv2.imread(img_id, cv2.IMREAD_COLOR) height, width, _ = img.shape if self.target_transform is not None: target = self.target_transform(target) if self.preproc is not None: img, target = self.preproc(img, target) # in order to be compatible with mixup weight = np.ones((target.shape[0], 1)) target = np.hstack((target, weight)) return img, target def __len__(self): return len(self.ids) def pull_image(self, index): '''Returns the original image object at index in PIL form Note: not using self.__getitem__(), as any transformations passed in could mess up this functionality. Argument: index (int): index of img to show Return: PIL img ''' img_id = self.ids[index] return cv2.imread(img_id, cv2.IMREAD_COLOR) def pull_tensor(self, index): '''Returns the original image at an index in tensor form Note: not using self.__getitem__(), as any transformations passed in could mess up this functionality. Argument: index (int): index of img to show Return: tensorized version of img, squeezed ''' return torch.Tensor(self.pull_image(index)).unsqueeze_(0) def _do_detection_eval(self, res_file): coco_dt = self._COCO.loadRes(res_file) coco_eval = COCOeval(self._COCO, coco_dt, 'bbox') coco_eval.evaluate() coco_eval.accumulate() coco_eval.summarize() results = OrderedDict() results['bbox'] = self._derive_coco_results( coco_eval, 'bbox', class_names=self.class_name) print_csv_format(results) def _coco_results_one_category(self, boxes, cat_id): results = [] for im_ind, index in enumerate(self.img_ids): dets = boxes[im_ind].astype(np.float) if dets == []: continue scores = dets[:, -1] xs = dets[:, 0] ys = dets[:, 1] ws = dets[:, 2] - xs + 1 hs = dets[:, 3] - ys + 1 results.extend([{ 'image_id': index, 'category_id': cat_id, 'bbox': [xs[k], ys[k], ws[k], hs[k]], 'score': scores[k] } for k in range(dets.shape[0])]) return results def _write_coco_results_file(self, all_boxes, res_file): # [{"image_id": 42, # "category_id": 18, # "bbox": [258.15,41.29,348.26,243.78], # "score": 0.236}, ...] results = [] for cls_ind, cls in enumerate(self.class_name, 1): print('Collecting {} results ({:d}/{:d})'.format( cls, cls_ind, self.num_classes)) coco_cat_id = self._class_to_coco_cat_id[cls] results.extend( self._coco_results_one_category(all_boxes[cls_ind], coco_cat_id)) print('Writing results json to {}'.format(res_file)) with open(res_file, 'w') as fid: json.dump(results, fid) fid.flush() def evaluate_detections(self, all_boxes, output_dir): res_file = os.path.join(output_dir, 'detections_' + self.coco_name + '_results') res_file += '.json' self._write_coco_results_file(all_boxes, res_file) # Only do evaluation on non-test sets if self.coco_name.find('test') == -1: self._do_detection_eval(res_file) def _derive_coco_results(self, coco_eval, iou_type, class_names=None): """ Derive the desired score numbers from summarized COCOeval. Args: coco_eval (None or COCOEval): None represents no predictions from model. iou_type (str): class_names (None or list[str]): if provided, will use it to predict per-category AP. Returns: a dict of {metric name: score} """ metrics = { "bbox": ["AP", "AP50", "AP75", "APs", "APm", "APl"], "segm": ["AP", "AP50", "AP75", "APs", "APm", "APl"], "keypoints": ["AP", "AP50", "AP75", "APm", "APl"], }[iou_type] if coco_eval is None: print("No predictions from the model! Set scores to -1") return {metric: -1 for metric in metrics} # the standard metrics results = { metric: float(coco_eval.stats[idx] * 100) for idx, metric in enumerate(metrics) } print("Evaluation results for {}: \n".format(iou_type) + create_small_table(results)) if class_names is None or len(class_names) <= 1: return results # Compute per-category AP # from https://github.com/facebookresearch/Detectron/blob/a6a835f5b8208c45d0dce217ce9bbda915f44df7/detectron/datasets/json_dataset_evaluator.py#L222-L252 # noqa precisions = coco_eval.eval["precision"] # precision has dims (iou, recall, cls, area range, max dets) # assert len(class_names) == precisions.shape[2] results_per_category = [] for idx, name in zip(self.id_map, class_names): # area range index 0: all area ranges # max dets index -1: typically 100 per image precision = precisions[:, :, idx, 0, -1] precision = precision[precision > -1] ap = np.mean(precision) if precision.size else float("nan") results_per_category.append(("{}".format(name), float(ap * 100))) # tabulate it N_COLS = min(6, len(results_per_category) * 2) results_flatten = list(itertools.chain(*results_per_category)) results_2d = itertools.zip_longest( *[results_flatten[i::N_COLS] for i in range(N_COLS)]) table = tabulate( results_2d, tablefmt="pipe", floatfmt=".3f", headers=["category", "AP"] * (N_COLS // 2), numalign="left", ) print("Per-category {} AP: \n".format(iou_type) + table) results.update({"AP-" + name: ap for name, ap in results_per_category}) return results
def coco_to_roidb(annotation_path, save_roidb_path, task='det', data_dir='', need_mask=True): assert task in ['det', 'kps'] coco = COCO(annotation_path) image_ids = coco.getImgIds() cats = [cat['name'] for cat in coco.loadCats(coco.getCatIds())] classes = ['__background__'] + cats num_classes = len(classes) class_to_ind = dict(zip(classes, xrange(num_classes))) class_to_coco_ind = dict(zip(cats, coco.getCatIds())) coco_ind_to_class_ind = dict([(class_to_coco_ind[cls], class_to_ind[cls]) for cls in classes[1:]]) roidb = [] for i, image_id in enumerate(image_ids): if i % 1000 == 0: print('{}/{}'.format(i, len(image_ids))) im_ann = coco.loadImgs(image_id)[0] width = im_ann['width'] height = im_ann['height'] annIds = coco.getAnnIds(imgIds=image_id, iscrowd=None) objs = coco.loadAnns(annIds) # sanitize bboxes valid_objs = [] areas_ = [] for obj in objs: if task == 'kps': assert obj['category_id'] == 1 assert obj['area'] > 0 x, y, w, h = obj['bbox'] x1 = np.max((0, x)) y1 = np.max((0, y)) x2 = np.min((width - 1, x1 + np.max((0, w - 1)))) y2 = np.min((height - 1, y1 + np.max((0, h - 1)))) if obj['area'] > 0 and x2 >= x1 and y2 >= y1: obj['clean_bbox'] = [x1, y1, x2, y2] valid_objs.append(obj) areas_.append(obj['area']) # x, y, w, h = obj['bbox'] # x1 = x # y1 = y # x2 = x1 + w - 1 # y2 = y1 + h - 1 # assert 0 <= x1 < width # assert 0 <= y1 < height # assert 0 <= x2 < width # assert 0 <= y2 < height # assert x2 >= x1 and y2 >= y1 # obj['clean_bbox'] = [x1, y1, x2, y2] # valid_objs.append(obj) # areas_.append(obj['area']) objs = valid_objs num_objs = len(objs) boxes = np.zeros((num_objs, 4), dtype=np.float32) gt_classes = np.zeros((num_objs, ), dtype=np.int32) keypoints = np.zeros((num_objs, 51), dtype=np.float32) areas = np.array(areas_, dtype=np.float32) iscrowd = [] for ix, obj in enumerate(objs): cls = -coco_ind_to_class_ind[obj['category_id']]\ if obj['iscrowd'] else coco_ind_to_class_ind[obj['category_id']] iscrowd.append(obj['iscrowd']) boxes[ix, :] = obj['clean_bbox'] gt_classes[ix] = cls if task == 'kps': keypoints[ix, :] = obj['keypoints'] roi_rec = { 'image': data_dir + im_ann['file_name'], 'id': im_ann['id'], 'height': height, 'width': width, 'boxes': boxes, 'area': areas, 'iscrowd': np.array(iscrowd, dtype=np.float32), 'gt_classes': gt_classes } if task == 'kps': roi_rec['keypoints'] = keypoints if need_mask: roi_rec['gt_masks'] = [x['segmentation'] for x in objs] roidb.append(roi_rec) with open(save_roidb_path, 'wb') as fid: cPickle.dump(roidb, fid, cPickle.HIGHEST_PROTOCOL)
# dataset = COCODetection(COCOroot, train_sets, preproc( 300, (104, 117, 123), 0.6)) # epoch_size = len(dataset) # iiter = data.DataLoader(dataset, 32,shuffle=True, num_workers=2, collate_fn=detection_collate) dirname = "/media/trans/mnt/data/coco/" annodir = "annotations" annofile = "instances_valminusminival2014.json" _COCO = COCO(os.path.join(dirname, annodir, annofile)) catids = _COCO.getCatIds() imgids = _COCO.getImgIds() annids = _COCO.getAnnIds(imgids[0]) cats = _COCO.loadCats(_COCO.getCatIds()) print("# ------------------------------------- # ") # print(cats) print(len(cats)) print("# ------------------------------------- # ") print("catids:", catids) print("# ------------------------------------- # ") print("annids: ", annids) print("# ------------------------------------- # ") print("imgids: ", imgids[:30]) # ids2 = list() # ids = list(range(100)) # for t in cats: # ids2.append(t['id'])
def __init__(self, root, image_sets, preproc=None, target_transform=None, dataset_name='COCO', classes=None, box_num=1000000000): self.root = root self.cache_path = os.path.join(self.root, 'cache') self.image_set = image_sets self.preproc = preproc self.target_transform = target_transform self.name = dataset_name self.classes = classes self.ids = list() self.annotations = list() self.box_num = int(box_num) self._view_map = { 'minival2014': 'val2014', # 5k val2014 subset 'valminusminival2014': 'val2014', # val2014 \setminus minival2014 'test-dev2015': 'test2015', } for (year, image_set) in image_sets: coco_name = image_set + year data_name = (self._view_map[coco_name] if coco_name in self._view_map else coco_name) annofile = self._get_ann_file(coco_name) _COCO = COCO(annofile) self._COCO = _COCO self.coco_name = coco_name if self.classes == "youtube_bb": cats = _COCO.loadCats( _COCO.getCatIds(catNms=classes_youtubebb)) elif self.classes == "youtube_bb_sub": cats = _COCO.loadCats( _COCO.getCatIds(catNms=classes_youtubebb_sub)) else: cats = _COCO.loadCats(_COCO.getCatIds()) self._classes = tuple(['__background__'] + [c['name'] for c in cats]) self._classesids = tuple([0] + [c['id'] for c in cats]) self.num_classes = len(self._classes) self._class_to_ind = dict( zip(self._classes, range(self.num_classes))) if self.classes == "youtube_bb": self._class_to_coco_cat_id = dict( zip([c['name'] for c in cats], _COCO.getCatIds(catNms=classes_youtubebb))) elif self.classes == "youtube_bb_sub": self._class_to_coco_cat_id = dict( zip([c['name'] for c in cats], _COCO.getCatIds(catNms=classes_youtubebb_sub))) else: self._class_to_coco_cat_id = dict( zip([c['name'] for c in cats], _COCO.getCatIds())) indexes = [] self.indexes_limit = [] for cat in cats: indexes.extend(_COCO.getImgIds(catIds=cat["id"])) indexes = set(indexes) indexes = list(indexes) random.seed(box_num) random.shuffle(indexes) if image_set.find('test') != -1: print('test set will not load annotations!') else: self.annotations.extend( self._load_coco_annotations(coco_name, indexes, _COCO, self.box_num)) self.image_indexes = self.indexes_limit self.ids.extend([ self.image_path_from_index(data_name, index) for index in self.indexes_limit ])