From 30be97cbc6a4f8914f04235bcef5f24acff4a67a Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 24 May 2017 16:45:42 +0900 Subject: [PATCH 01/29] add coco_detection_dataset --- chainercv/datasets/__init__.py | 2 + chainercv/datasets/coco/__init__.py | 0 .../datasets/coco/coco_detection_dataset.py | 319 ++++++++++++++++++ docs/source/reference/datasets.rst | 7 + 4 files changed, 328 insertions(+) create mode 100644 chainercv/datasets/coco/__init__.py create mode 100644 chainercv/datasets/coco/coco_detection_dataset.py diff --git a/chainercv/datasets/__init__.py b/chainercv/datasets/__init__.py index ad2618ee73..405f50e6d5 100644 --- a/chainercv/datasets/__init__.py +++ b/chainercv/datasets/__init__.py @@ -2,6 +2,8 @@ from chainercv.datasets.camvid.camvid_dataset import camvid_label_colors # NOQA from chainercv.datasets.camvid.camvid_dataset import camvid_label_names # NOQA from chainercv.datasets.camvid.camvid_dataset import CamVidDataset # NOQA +from chainercv.datasets.coco.coco_detection_dataset import coco_detection_label_names # NOQA +from chainercv.datasets.coco.coco_detection_dataset import COCODetectionDataset # NOQA from chainercv.datasets.cub.cub_keypoint_dataset import CUBKeypointDataset # NOQA from chainercv.datasets.cub.cub_label_dataset import CUBLabelDataset # NOQA from chainercv.datasets.cub.cub_utils import cub_label_names # NOQA diff --git a/chainercv/datasets/coco/__init__.py b/chainercv/datasets/coco/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/chainercv/datasets/coco/coco_detection_dataset.py b/chainercv/datasets/coco/coco_detection_dataset.py new file mode 100644 index 0000000000..c43300e9d8 --- /dev/null +++ b/chainercv/datasets/coco/coco_detection_dataset.py @@ -0,0 +1,319 @@ +from collections import defaultdict +import json +import numpy as np +import os + +import chainer +from chainer.dataset import download + +from chainercv import utils + +# How you can get the labels +# >>> from pycocotools.coco import COCO +# >>> coco = COCO('instances_train2014.json') +# >>> cat_dict = coco.loadCats(coco.getCatIds()) +# >>> coco_detection_labels = [c['name'] for c in cat_dict] +coco_detection_label_names = ( + 'person', + 'bicycle', + 'car', + 'motorcycle', + 'airplane', + 'bus', + 'train', + 'truck', + 'boat', + 'traffic light', + 'fire hydrant', + 'stop sign', + 'parking meter', + 'bench', + 'bird', + 'cat', + 'dog', + 'horse', + 'sheep', + 'cow', + 'elephant', + 'bear', + 'zebra', + 'giraffe', + 'backpack', + 'umbrella', + 'handbag', + 'tie', + 'suitcase', + 'frisbee', + 'skis', + 'snowboard', + 'sports ball', + 'kite', + 'baseball bat', + 'baseball glove', + 'skateboard', + 'surfboard', + 'tennis racket', + 'bottle', + 'wine glass', + 'cup', + 'fork', + 'knife', + 'spoon', + 'bowl', + 'banana', + 'apple', + 'sandwich', + 'orange', + 'broccoli', + 'carrot', + 'hot dog', + 'pizza', + 'donut', + 'cake', + 'chair', + 'couch', + 'potted plant', + 'bed', + 'dining table', + 'toilet', + 'tv', + 'laptop', + 'mouse', + 'remote', + 'keyboard', + 'cell phone', + 'microwave', + 'oven', + 'toaster', + 'sink', + 'refrigerator', + 'book', + 'clock', + 'vase', + 'scissors', + 'teddy bear', + 'hair drier', + 'toothbrush') + + +root = 'pfnet/chainercv/coco' +img_urls = { + 'train': 'http://msvocds.blob.core.windows.net/coco2014/train2014.zip', + 'val': 'http://msvocds.blob.core.windows.net/coco2014/val2014.zip' +} +anno_urls = { + 'train': 'http://msvocds.blob.core.windows.net/annotations-1-0-3/' + 'instances_train-val2014.zip', + 'val': 'http://msvocds.blob.core.windows.net/annotations-1-0-3/' + 'instances_train-val2014.zip', + 'valminusminival': 'https://dl.dropboxusercontent.com/s/s3tw5zcg7395368/' + 'instances_valminusminival2014.json.zip', + 'minval': 'https://dl.dropboxusercontent.com/s/o43o90bna78omob/' + 'instances_minival2014.json.zip' +} + + +def _get_coco(split, img_split): + + url = img_urls[img_split] + data_dir = download.get_dataset_directory(root) + img_root = os.path.join(data_dir, 'images') + created_img_root = os.path.join(img_root, '{}2014'.format(img_split)) + annos_root = os.path.join(data_dir, 'annotations') + anno_fn = os.path.join(annos_root, 'instances_{}2014.json'.format(split)) + if not os.path.exists(created_img_root): + download_file_path = utils.cached_download(url) + ext = os.path.splitext(url)[1] + utils.extractall(download_file_path, img_root, ext) + if not os.path.exists(anno_fn): + anno_url = anno_urls[split] + download_file_path = utils.cached_download(anno_url) + ext = os.path.splitext(anno_url)[1] + utils.extractall(download_file_path, data_dir, ext) + return data_dir + + +class COCODetectionDataset(chainer.dataset.DatasetMixin): + + """Dataset class for the detection task of `MS COCO`_. + + .. _`MS COCO`: http://mscoco.org/dataset/#detections-challenge2015 + + When queried by an index, if :obj:`return_crowded == False`, + this dataset returns a corresponding + :obj:`img, bbox, label`, a tuple of an image, bounding boxes and labels. + This is the default behaviour. + If :obj:`return_crowded == True`, this dataset returns corresponding + :obj:`img, bbox, label, crowded`. :obj:`crowded` is a boolean array + that indicates whether bounding boxes are for crowd labeling. + When there are more than ten objects from the same category, + bounding boxes correspond to crowd of instances instead of individual + instances. Please see more detail in the Fig. 12 (e) of the summary + paper [#]_. + + There are total of 82,783 training and 40,504 validation images. + 'minval' split is a subset of validation images that constitutes + 5000 images in the validation images. The remaining validation + images are called 'minvalminus'. Concrete list of image ids and + annotations for these splits are found `here`_. + + .. _`here`: https://github.com/rbgirshick/py-faster-rcnn/tree/master/data + + The bounding boxes are packed into a two dimensional tensor of shape + :math:`(R, 4)`, where :math:`R` is the number of bounding boxes in + the image. The second axis represents attributes of the bounding box. + They are :obj:`(x_min, y_min, x_max, y_max)`, where the + four attributes are coordinates of the top left and the bottom right + vertices. + + The labels are packed into a one dimensional tensor of shape :math:`(R,)`. + :math:`R` is the number of bounding boxes in the image. + The class name of the label :math:`l` is :math:`l` th element of + :obj:`chainercv.datasets.coco_detection_label_names`. + + The array :obj:`crowded` is a one dimensional boolean array of shape + :math:`(R,)`. :math:`R` is the number of bounding boxes in the image. + + * :obj:`img.dtype == numpy.float32` + * :obj:`bbox.dtype == numpy.float32` + * :obj:`label.dtype == numpy.int32` + * :obj:`crowded.dtype == numpy.bool` + + .. [#] Tsung-Yi Lin, Michael Maire, Serge Belongie, Lubomir Bourdev, \ + Ross Girshick, James Hays, Pietro Perona, Deva Ramanan, \ + C. Lawrence Zitnick, Piotr Dollar. + `Microsoft COCO: Common Objects in Context \ + `_. arXiv 2014. + + Args: + data_dir (string): Path to the root of the training data. If this is + :obj:`auto`, this class will automatically download data for you + under :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/coco`. + split ({'train', 'val', 'minval', 'minvalminus'}): Select + a split of the dataset. + use_crowded (bool): If true, use bounding boxes that are labeled as + crowded in the original annotation. + return_crowded (bool): If true, this dataset returns a boolean array + that indicates whether bounding boxes are labeled as crowded + or not. The default value is :obj:`False`. + + """ + + def __init__(self, data_dir='auto', split='train', + use_crowded=False, return_crowded=False): + self.use_crowded = use_crowded + self.return_crowded = return_crowded + if split in ['val', 'minval', 'minvalminus']: + img_split = 'val' + else: + img_split = 'train' + if data_dir == 'auto': + data_dir = _get_coco(split, img_split) + + self.img_root = os.path.join( + data_dir, 'images', '{}2014'.format(img_split)) + anno_fn = os.path.join( + data_dir, 'annotations', 'instances_{}2014.json'.format(split)) + + self.data_dir = data_dir + anno = json.load(open(anno_fn, 'r')) + + self.imgs = dict() + for img in anno['images']: + self.imgs[img['id']] = img + self.ids = list(self.imgs.keys()) + + cats = anno['categories'] + self.cat_ids = [cat['id'] for cat in cats] + + self.anns = dict() + self.imgToAnns = defaultdict(list) + for ann in anno['annotations']: + self.imgToAnns[ann['image_id']].append(ann) + self.anns[ann['id']] = ann + + def __len__(self): + return len(self.ids) + + def get_example(self, i): + img_id = self.ids[i] + + img_fn = os.path.join(self.img_root, self.imgs[img_id]['file_name']) + img = utils.read_image(img_fn, dtype=np.float32, color=True) + _, H, W = img.shape + + # List[{'segmentation', 'area', 'iscrowd', + # 'image_id', 'bbox', 'category_id', 'id'}] + annotation = self.imgToAnns[img_id] + bbox = np.array([ann['bbox'] for ann in annotation], dtype=np.float32) + if len(bbox) == 0: + bbox = np.zeros((0, 4), dtype=np.float32) + + label = np.array( + [self.cat_ids.index(ann['category_id']) + for ann in annotation], + dtype=np.int32) + # (x, y, width, height) -> (x_min, y_min, x_max, y_max) + bbox[:, 2] = bbox[:, 0] + bbox[:, 2] + bbox[:, 3] = bbox[:, 1] + bbox[:, 3] + # (x_min, y_min, x_max, y_max) -> (y_min, x_min, y_max, x_max) + bbox = bbox[:, [1, 0, 3, 2]] + + crowded = np.array([ann['iscrowd'] + for ann in annotation], dtype=np.bool) + if not self.use_crowded: + bbox = bbox[np.logical_not(crowded)] + label = label[np.logical_not(crowded)] + + if self.return_crowded: + return img, bbox, label, crowded + return img, bbox, label + + # # Sanitize boxes + # bbox[:, :2] = np.maximum(bbox[:, :2], 0) + # bbox[:, 2] = np.minimum(bbox[:, 2], W) + # bbox[:, 3] = np.minimum(bbox[:, 3], H) + + # # Remove invalid boxes + # area = np.prod(bbox[:, 2:] - bbox[:, :2], axis=1) + # keep_mask = np.logical_and(bbox[:, 0] <= bbox[:, 2], + # bbox[:, 1] <= bbox[:, 3]) + # keep_mask = np.logical_and(keep_mask, area > 0) + # bbox = bbox[keep_mask] + # label = label[keep_mask] + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + from chainercv.visualizations import vis_bbox + from chainercv.visualizations import vis_image + + dataset = COCODetectionDataset(split='val') + img, bbox, label = dataset[3] + # for i in range(len(dataset)): + # if i % 100 == 0: + # print 'finish {}'.format(i) + # img, bbox, label = dataset[i] + # if len(bbox) == 0: + # continue + # _, H, W = img.shape + + # # keep_mask = np.logical_or(bbox[:, 0] >= bbox[:, 2], + # # bbox[:, 1] >= bbox[:, 3]) + # # if np.sum(keep_mask) > 0: + # # print bbox[keep_mask] + # # raise ValueError(i, bbox, H, W) + + # if not np.min(bbox) >= 0: + # raise ValueError(i, bbox) + # if not np.max(bbox[:, 2]) <= H: + # raise ValueError(i, bbox, H, W) + # if not np.max(bbox[:, 3]) <= W: + # raise ValueError(i, bbox, H, W) + + + + + img, bbox, label = dataset[3] + vis_bbox(img, bbox, label, label_names=coco_detection_label_names) + plt.show() diff --git a/docs/source/reference/datasets.rst b/docs/source/reference/datasets.rst index 0809ff2821..7d18043202 100644 --- a/docs/source/reference/datasets.rst +++ b/docs/source/reference/datasets.rst @@ -18,6 +18,13 @@ CamVidDataset ~~~~~~~~~~~~~ .. autoclass:: CamVidDataset +COCO +---- + +COCODetectionDataset +~~~~~~~~~~~~~~~~~~~~ +.. autofunction:: COCODetectionDataset + CUB --- From 6119d55a9a4ed19ff5961683b738d9d0d4b9ffd2 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 12:46:43 +0900 Subject: [PATCH 02/29] use bbox_dataset notation and add labels method --- chainercv/datasets/__init__.py | 4 +- ...ection_dataset.py => coco_bbox_dataset.py} | 237 ++++-------------- chainercv/datasets/coco/coco_utils.py | 128 ++++++++++ 3 files changed, 175 insertions(+), 194 deletions(-) rename chainercv/datasets/coco/{coco_detection_dataset.py => coco_bbox_dataset.py} (52%) create mode 100644 chainercv/datasets/coco/coco_utils.py diff --git a/chainercv/datasets/__init__.py b/chainercv/datasets/__init__.py index 405f50e6d5..e619309864 100644 --- a/chainercv/datasets/__init__.py +++ b/chainercv/datasets/__init__.py @@ -2,8 +2,8 @@ from chainercv.datasets.camvid.camvid_dataset import camvid_label_colors # NOQA from chainercv.datasets.camvid.camvid_dataset import camvid_label_names # NOQA from chainercv.datasets.camvid.camvid_dataset import CamVidDataset # NOQA -from chainercv.datasets.coco.coco_detection_dataset import coco_detection_label_names # NOQA -from chainercv.datasets.coco.coco_detection_dataset import COCODetectionDataset # NOQA +from chainercv.datasets.coco.coco_utils import coco_bbox_label_names # NOQA +from chainercv.datasets.coco.coco_bbox_dataset import COCOBboxDataset # NOQA from chainercv.datasets.cub.cub_keypoint_dataset import CUBKeypointDataset # NOQA from chainercv.datasets.cub.cub_label_dataset import CUBLabelDataset # NOQA from chainercv.datasets.cub.cub_utils import cub_label_names # NOQA diff --git a/chainercv/datasets/coco/coco_detection_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py similarity index 52% rename from chainercv/datasets/coco/coco_detection_dataset.py rename to chainercv/datasets/coco/coco_bbox_dataset.py index c43300e9d8..5d59eb7e63 100644 --- a/chainercv/datasets/coco/coco_detection_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -4,136 +4,13 @@ import os import chainer -from chainer.dataset import download from chainercv import utils -# How you can get the labels -# >>> from pycocotools.coco import COCO -# >>> coco = COCO('instances_train2014.json') -# >>> cat_dict = coco.loadCats(coco.getCatIds()) -# >>> coco_detection_labels = [c['name'] for c in cat_dict] -coco_detection_label_names = ( - 'person', - 'bicycle', - 'car', - 'motorcycle', - 'airplane', - 'bus', - 'train', - 'truck', - 'boat', - 'traffic light', - 'fire hydrant', - 'stop sign', - 'parking meter', - 'bench', - 'bird', - 'cat', - 'dog', - 'horse', - 'sheep', - 'cow', - 'elephant', - 'bear', - 'zebra', - 'giraffe', - 'backpack', - 'umbrella', - 'handbag', - 'tie', - 'suitcase', - 'frisbee', - 'skis', - 'snowboard', - 'sports ball', - 'kite', - 'baseball bat', - 'baseball glove', - 'skateboard', - 'surfboard', - 'tennis racket', - 'bottle', - 'wine glass', - 'cup', - 'fork', - 'knife', - 'spoon', - 'bowl', - 'banana', - 'apple', - 'sandwich', - 'orange', - 'broccoli', - 'carrot', - 'hot dog', - 'pizza', - 'donut', - 'cake', - 'chair', - 'couch', - 'potted plant', - 'bed', - 'dining table', - 'toilet', - 'tv', - 'laptop', - 'mouse', - 'remote', - 'keyboard', - 'cell phone', - 'microwave', - 'oven', - 'toaster', - 'sink', - 'refrigerator', - 'book', - 'clock', - 'vase', - 'scissors', - 'teddy bear', - 'hair drier', - 'toothbrush') - - -root = 'pfnet/chainercv/coco' -img_urls = { - 'train': 'http://msvocds.blob.core.windows.net/coco2014/train2014.zip', - 'val': 'http://msvocds.blob.core.windows.net/coco2014/val2014.zip' -} -anno_urls = { - 'train': 'http://msvocds.blob.core.windows.net/annotations-1-0-3/' - 'instances_train-val2014.zip', - 'val': 'http://msvocds.blob.core.windows.net/annotations-1-0-3/' - 'instances_train-val2014.zip', - 'valminusminival': 'https://dl.dropboxusercontent.com/s/s3tw5zcg7395368/' - 'instances_valminusminival2014.json.zip', - 'minval': 'https://dl.dropboxusercontent.com/s/o43o90bna78omob/' - 'instances_minival2014.json.zip' -} - - -def _get_coco(split, img_split): - - url = img_urls[img_split] - data_dir = download.get_dataset_directory(root) - img_root = os.path.join(data_dir, 'images') - created_img_root = os.path.join(img_root, '{}2014'.format(img_split)) - annos_root = os.path.join(data_dir, 'annotations') - anno_fn = os.path.join(annos_root, 'instances_{}2014.json'.format(split)) - if not os.path.exists(created_img_root): - download_file_path = utils.cached_download(url) - ext = os.path.splitext(url)[1] - utils.extractall(download_file_path, img_root, ext) - if not os.path.exists(anno_fn): - anno_url = anno_urls[split] - download_file_path = utils.cached_download(anno_url) - ext = os.path.splitext(anno_url)[1] - utils.extractall(download_file_path, data_dir, ext) - return data_dir - - -class COCODetectionDataset(chainer.dataset.DatasetMixin): +from chainercv.datasets.coco.coco_utils import get_coco + + +class COCOBboxDataset(chainer.dataset.DatasetMixin): """Dataset class for the detection task of `MS COCO`_. @@ -169,7 +46,7 @@ class COCODetectionDataset(chainer.dataset.DatasetMixin): The labels are packed into a one dimensional tensor of shape :math:`(R,)`. :math:`R` is the number of bounding boxes in the image. The class name of the label :math:`l` is :math:`l` th element of - :obj:`chainercv.datasets.coco_detection_label_names`. + :obj:`chainercv.datasets.coco_bbox_label_names`. The array :obj:`crowded` is a one dimensional boolean array of shape :math:`(R,)`. :math:`R` is the number of bounding boxes in the image. @@ -208,7 +85,7 @@ def __init__(self, data_dir='auto', split='train', else: img_split = 'train' if data_dir == 'auto': - data_dir = _get_coco(split, img_split) + data_dir = get_coco(split, img_split) self.img_root = os.path.join( data_dir, 'images', '{}2014'.format(img_split)) @@ -232,35 +109,60 @@ def __init__(self, data_dir='auto', split='train', self.imgToAnns[ann['image_id']].append(ann) self.anns[ann['id']] = ann - def __len__(self): - return len(self.ids) + @property + def labels(self): + labels = list() + for i in range(len(self)): + _, label, _ = self._get_annotations(i) + labels.append(label) + return labels - def get_example(self, i): + def _get_annotations(self, i): img_id = self.ids[i] - - img_fn = os.path.join(self.img_root, self.imgs[img_id]['file_name']) - img = utils.read_image(img_fn, dtype=np.float32, color=True) - _, H, W = img.shape - # List[{'segmentation', 'area', 'iscrowd', # 'image_id', 'bbox', 'category_id', 'id'}] annotation = self.imgToAnns[img_id] - bbox = np.array([ann['bbox'] for ann in annotation], dtype=np.float32) + bbox = np.array([ann['bbox'] for ann in annotation], + dtype=np.float32) if len(bbox) == 0: bbox = np.zeros((0, 4), dtype=np.float32) - - label = np.array( - [self.cat_ids.index(ann['category_id']) - for ann in annotation], - dtype=np.int32) # (x, y, width, height) -> (x_min, y_min, x_max, y_max) bbox[:, 2] = bbox[:, 0] + bbox[:, 2] bbox[:, 3] = bbox[:, 1] + bbox[:, 3] # (x_min, y_min, x_max, y_max) -> (y_min, x_min, y_max, x_max) bbox = bbox[:, [1, 0, 3, 2]] + label = np.array([self.cat_ids.index(ann['category_id']) + for ann in annotation], dtype=np.int32) crowded = np.array([ann['iscrowd'] for ann in annotation], dtype=np.bool) + + # Remove invalid boxes + area = np.prod(bbox[:, 2:] - bbox[:, :2], axis=1) + keep_mask = np.logical_and(bbox[:, 0] <= bbox[:, 2], + bbox[:, 1] <= bbox[:, 3]) + keep_mask = np.logical_and(keep_mask, area > 0) + bbox = bbox[keep_mask] + label = label[keep_mask] + crowded = crowded[keep_mask] + return bbox, label, crowded + + def __len__(self): + return len(self.ids) + + def get_example(self, i): + img_id = self.ids[i] + img_fn = os.path.join(self.img_root, self.imgs[img_id]['file_name']) + img = utils.read_image(img_fn, dtype=np.float32, color=True) + _, H, W = img.shape + + bbox, label, crowded = self._get_annotations(i) + + # Sanitize boxes using image shape + bbox[:, :2] = np.maximum(bbox[:, :2], 0) + bbox[:, 2] = np.minimum(bbox[:, 2], H) + bbox[:, 3] = np.minimum(bbox[:, 3], W) + if not self.use_crowded: bbox = bbox[np.logical_not(crowded)] label = label[np.logical_not(crowded)] @@ -268,52 +170,3 @@ def get_example(self, i): if self.return_crowded: return img, bbox, label, crowded return img, bbox, label - - # # Sanitize boxes - # bbox[:, :2] = np.maximum(bbox[:, :2], 0) - # bbox[:, 2] = np.minimum(bbox[:, 2], W) - # bbox[:, 3] = np.minimum(bbox[:, 3], H) - - # # Remove invalid boxes - # area = np.prod(bbox[:, 2:] - bbox[:, :2], axis=1) - # keep_mask = np.logical_and(bbox[:, 0] <= bbox[:, 2], - # bbox[:, 1] <= bbox[:, 3]) - # keep_mask = np.logical_and(keep_mask, area > 0) - # bbox = bbox[keep_mask] - # label = label[keep_mask] - - -if __name__ == '__main__': - import matplotlib.pyplot as plt - from chainercv.visualizations import vis_bbox - from chainercv.visualizations import vis_image - - dataset = COCODetectionDataset(split='val') - img, bbox, label = dataset[3] - # for i in range(len(dataset)): - # if i % 100 == 0: - # print 'finish {}'.format(i) - # img, bbox, label = dataset[i] - # if len(bbox) == 0: - # continue - # _, H, W = img.shape - - # # keep_mask = np.logical_or(bbox[:, 0] >= bbox[:, 2], - # # bbox[:, 1] >= bbox[:, 3]) - # # if np.sum(keep_mask) > 0: - # # print bbox[keep_mask] - # # raise ValueError(i, bbox, H, W) - - # if not np.min(bbox) >= 0: - # raise ValueError(i, bbox) - # if not np.max(bbox[:, 2]) <= H: - # raise ValueError(i, bbox, H, W) - # if not np.max(bbox[:, 3]) <= W: - # raise ValueError(i, bbox, H, W) - - - - - img, bbox, label = dataset[3] - vis_bbox(img, bbox, label, label_names=coco_detection_label_names) - plt.show() diff --git a/chainercv/datasets/coco/coco_utils.py b/chainercv/datasets/coco/coco_utils.py new file mode 100644 index 0000000000..69114c85bd --- /dev/null +++ b/chainercv/datasets/coco/coco_utils.py @@ -0,0 +1,128 @@ +import os + +from chainer.dataset import download + +from chainercv import utils + + +root = 'pfnet/chainercv/coco' +img_urls = { + 'train': 'http://msvocds.blob.core.windows.net/coco2014/train2014.zip', + 'val': 'http://msvocds.blob.core.windows.net/coco2014/val2014.zip' +} +anno_urls = { + 'train': 'http://msvocds.blob.core.windows.net/annotations-1-0-3/' + 'instances_train-val2014.zip', + 'val': 'http://msvocds.blob.core.windows.net/annotations-1-0-3/' + 'instances_train-val2014.zip', + 'valminusminival': 'https://dl.dropboxusercontent.com/s/s3tw5zcg7395368/' + 'instances_valminusminival2014.json.zip', + 'minval': 'https://dl.dropboxusercontent.com/s/o43o90bna78omob/' + 'instances_minival2014.json.zip' +} + +def get_coco(split, img_split): + url = img_urls[img_split] + data_dir = download.get_dataset_directory(root) + img_root = os.path.join(data_dir, 'images') + created_img_root = os.path.join(img_root, '{}2014'.format(img_split)) + annos_root = os.path.join(data_dir, 'annotations') + anno_fn = os.path.join(annos_root, 'instances_{}2014.json'.format(split)) + if not os.path.exists(created_img_root): + download_file_path = utils.cached_download(url) + ext = os.path.splitext(url)[1] + utils.extractall(download_file_path, img_root, ext) + if not os.path.exists(anno_fn): + anno_url = anno_urls[split] + download_file_path = utils.cached_download(anno_url) + ext = os.path.splitext(anno_url)[1] + utils.extractall(download_file_path, data_dir, ext) + return data_dir + + +# How you can get the labels +# >>> from pycocotools.coco import COCO +# >>> coco = COCO('instances_train2014.json') +# >>> cat_dict = coco.loadCats(coco.getCatIds()) +# >>> coco_bbox_label_names = [c['name'] for c in cat_dict] +coco_bbox_label_names = ( + 'person', + 'bicycle', + 'car', + 'motorcycle', + 'airplane', + 'bus', + 'train', + 'truck', + 'boat', + 'traffic light', + 'fire hydrant', + 'stop sign', + 'parking meter', + 'bench', + 'bird', + 'cat', + 'dog', + 'horse', + 'sheep', + 'cow', + 'elephant', + 'bear', + 'zebra', + 'giraffe', + 'backpack', + 'umbrella', + 'handbag', + 'tie', + 'suitcase', + 'frisbee', + 'skis', + 'snowboard', + 'sports ball', + 'kite', + 'baseball bat', + 'baseball glove', + 'skateboard', + 'surfboard', + 'tennis racket', + 'bottle', + 'wine glass', + 'cup', + 'fork', + 'knife', + 'spoon', + 'bowl', + 'banana', + 'apple', + 'sandwich', + 'orange', + 'broccoli', + 'carrot', + 'hot dog', + 'pizza', + 'donut', + 'cake', + 'chair', + 'couch', + 'potted plant', + 'bed', + 'dining table', + 'toilet', + 'tv', + 'laptop', + 'mouse', + 'remote', + 'keyboard', + 'cell phone', + 'microwave', + 'oven', + 'toaster', + 'sink', + 'refrigerator', + 'book', + 'clock', + 'vase', + 'scissors', + 'teddy bear', + 'hair drier', + 'toothbrush') From 403fe5d4aed82687506d3eaf5a63903c0eaca386 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 12:56:46 +0900 Subject: [PATCH 03/29] be explict about year --- chainercv/datasets/coco/coco_bbox_dataset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 5d59eb7e63..d61213448f 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -12,9 +12,9 @@ class COCOBboxDataset(chainer.dataset.DatasetMixin): - """Dataset class for the detection task of `MS COCO`_. + """Dataset class for the detection task of `MS COCO2014`_. - .. _`MS COCO`: http://mscoco.org/dataset/#detections-challenge2015 + .. _`MS COCO2014`: http://mscoco.org/dataset/#detections-challenge2015 When queried by an index, if :obj:`return_crowded == False`, this dataset returns a corresponding From ba331d559452c874b4b09d23486cd8990ee669be Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 13:28:38 +0900 Subject: [PATCH 04/29] add test and modify to pass the test --- chainercv/datasets/coco/coco_bbox_dataset.py | 4 +- chainercv/datasets/coco/coco_utils.py | 4 +- .../coco_tests/test_coco_bbox_dataset.py | 48 +++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index d61213448f..ef78c2eb86 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -66,7 +66,7 @@ class COCOBboxDataset(chainer.dataset.DatasetMixin): data_dir (string): Path to the root of the training data. If this is :obj:`auto`, this class will automatically download data for you under :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/coco`. - split ({'train', 'val', 'minval', 'minvalminus'}): Select + split ({'train', 'val', 'minival', 'valminusminival'}): Select a split of the dataset. use_crowded (bool): If true, use bounding boxes that are labeled as crowded in the original annotation. @@ -80,7 +80,7 @@ def __init__(self, data_dir='auto', split='train', use_crowded=False, return_crowded=False): self.use_crowded = use_crowded self.return_crowded = return_crowded - if split in ['val', 'minval', 'minvalminus']: + if split in ['val', 'minival', 'valminusminival']: img_split = 'val' else: img_split = 'train' diff --git a/chainercv/datasets/coco/coco_utils.py b/chainercv/datasets/coco/coco_utils.py index 69114c85bd..561b118db7 100644 --- a/chainercv/datasets/coco/coco_utils.py +++ b/chainercv/datasets/coco/coco_utils.py @@ -17,7 +17,7 @@ 'instances_train-val2014.zip', 'valminusminival': 'https://dl.dropboxusercontent.com/s/s3tw5zcg7395368/' 'instances_valminusminival2014.json.zip', - 'minval': 'https://dl.dropboxusercontent.com/s/o43o90bna78omob/' + 'minival': 'https://dl.dropboxusercontent.com/s/o43o90bna78omob/' 'instances_minival2014.json.zip' } @@ -36,7 +36,7 @@ def get_coco(split, img_split): anno_url = anno_urls[split] download_file_path = utils.cached_download(anno_url) ext = os.path.splitext(anno_url)[1] - utils.extractall(download_file_path, data_dir, ext) + utils.extractall(download_file_path, annos_root, ext) return data_dir diff --git a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py new file mode 100644 index 0000000000..750b85f81a --- /dev/null +++ b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py @@ -0,0 +1,48 @@ +import unittest + +import numpy as np + +from chainer import testing +from chainer.testing import attr +from chainer.testing import condition + +from chainercv.datasets import coco_bbox_label_names +from chainercv.datasets import COCOBboxDataset +from chainercv.utils import assert_is_bbox_dataset + + +@testing.parameterize(*testing.product({ + 'split': ['train', 'val', 'minival', 'valminusminival'], + 'use_crowded': [False, True], + 'return_crowded': [False, True] +})) +class TestCOCOBboxDataset(unittest.TestCase): + + def setUp(self): + self.dataset = COCOBboxDataset( + split=self.split, + use_crowded=self.use_crowded, return_crowded=self.return_crowded) + + @attr.slow + def test_as_bbox_dataset(self): + assert_is_bbox_dataset( + self.dataset, len(coco_bbox_label_names), n_example=30) + + @attr.slow + def test_crowded(self): + if not self.return_crowded: + return + + for _ in range(10): + i = np.random.randint(0, len(self.dataset)) + _, bbox, _, crowded = self.dataset[i] + self.assertIsInstance(crowded, np.ndarray) + self.assertEqual(crowded.dtype, np.bool) + self.assertEqual(crowded.shape, (bbox.shape[0],)) + + if not self.use_crowded: + np.testing.assert_equal(crowded, 0) + + + +testing.run_module(__name__, __file__) From 281fe55006d403735f5517e6c36d639717db51cb Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 13:29:11 +0900 Subject: [PATCH 05/29] fix doc --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index ef78c2eb86..716984f87c 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -12,7 +12,7 @@ class COCOBboxDataset(chainer.dataset.DatasetMixin): - """Dataset class for the detection task of `MS COCO2014`_. + """Bounding box dataset for `MS COCO2014`_. .. _`MS COCO2014`: http://mscoco.org/dataset/#detections-challenge2015 From 27d44a98c024a1df11dda42a7d68838f42ce3cd8 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 13:30:19 +0900 Subject: [PATCH 06/29] flake8 --- chainercv/datasets/coco/coco_utils.py | 1 + tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/chainercv/datasets/coco/coco_utils.py b/chainercv/datasets/coco/coco_utils.py index 561b118db7..06e76db8e5 100644 --- a/chainercv/datasets/coco/coco_utils.py +++ b/chainercv/datasets/coco/coco_utils.py @@ -21,6 +21,7 @@ 'instances_minival2014.json.zip' } + def get_coco(split, img_split): url = img_urls[img_split] data_dir = download.get_dataset_directory(root) diff --git a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py index 750b85f81a..cb6a625ec4 100644 --- a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py +++ b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py @@ -4,7 +4,6 @@ from chainer import testing from chainer.testing import attr -from chainer.testing import condition from chainercv.datasets import coco_bbox_label_names from chainercv.datasets import COCOBboxDataset @@ -44,5 +43,4 @@ def test_crowded(self): np.testing.assert_equal(crowded, 0) - testing.run_module(__name__, __file__) From 25402dfb66fb92ad90d4ff9ed4d8e8dc94d2325d Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 13:34:52 +0900 Subject: [PATCH 07/29] fix failing test --- chainercv/datasets/coco/coco_bbox_dataset.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 716984f87c..d50ff08dae 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -166,6 +166,7 @@ def get_example(self, i): if not self.use_crowded: bbox = bbox[np.logical_not(crowded)] label = label[np.logical_not(crowded)] + crowded = crowded[np.logical_not(crowded)] if self.return_crowded: return img, bbox, label, crowded From c48937cae0c63b533074c234751f829b40799ffe Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 13:59:50 +0900 Subject: [PATCH 08/29] conduct sanitization inside _get_annotations --- chainercv/datasets/coco/coco_bbox_dataset.py | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index d50ff08dae..d5b014e519 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -95,10 +95,10 @@ def __init__(self, data_dir='auto', split='train', self.data_dir = data_dir anno = json.load(open(anno_fn, 'r')) - self.imgs = dict() + self.img_props = dict() for img in anno['images']: - self.imgs[img['id']] = img - self.ids = list(self.imgs.keys()) + self.img_props[img['id']] = img + self.ids = list(self.img_props.keys()) cats = anno['categories'] self.cat_ids = [cat['id'] for cat in cats] @@ -122,6 +122,8 @@ def _get_annotations(self, i): # List[{'segmentation', 'area', 'iscrowd', # 'image_id', 'bbox', 'category_id', 'id'}] annotation = self.imgToAnns[img_id] + H = self.img_props[img_id]['height'] + W = self.img_props[img_id]['width'] bbox = np.array([ann['bbox'] for ann in annotation], dtype=np.float32) if len(bbox) == 0: @@ -131,6 +133,11 @@ def _get_annotations(self, i): bbox[:, 3] = bbox[:, 1] + bbox[:, 3] # (x_min, y_min, x_max, y_max) -> (y_min, x_min, y_max, x_max) bbox = bbox[:, [1, 0, 3, 2]] + # Sanitize boxes using image shape + bbox[:, :2] = np.maximum(bbox[:, :2], 0) + bbox[:, 2] = np.minimum(bbox[:, 2], H) + bbox[:, 3] = np.minimum(bbox[:, 3], W) + label = np.array([self.cat_ids.index(ann['category_id']) for ann in annotation], dtype=np.int32) @@ -152,17 +159,13 @@ def __len__(self): def get_example(self, i): img_id = self.ids[i] - img_fn = os.path.join(self.img_root, self.imgs[img_id]['file_name']) + img_fn = os.path.join( + self.img_root, self.img_props[img_id]['file_name']) img = utils.read_image(img_fn, dtype=np.float32, color=True) _, H, W = img.shape bbox, label, crowded = self._get_annotations(i) - # Sanitize boxes using image shape - bbox[:, :2] = np.maximum(bbox[:, :2], 0) - bbox[:, 2] = np.minimum(bbox[:, 2], H) - bbox[:, 3] = np.minimum(bbox[:, 3], W) - if not self.use_crowded: bbox = bbox[np.logical_not(crowded)] label = label[np.logical_not(crowded)] From 2eb19d94eba93a21f9d12840c6bcf975383853fe Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 16:04:26 +0900 Subject: [PATCH 09/29] flake8 --- chainercv/datasets/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainercv/datasets/__init__.py b/chainercv/datasets/__init__.py index 9177c2145f..0fbd26cfe4 100644 --- a/chainercv/datasets/__init__.py +++ b/chainercv/datasets/__init__.py @@ -10,8 +10,8 @@ from chainercv.datasets.cityscapes.cityscapes_test_image_dataset import CityscapesTestImageDataset # NOQA from chainercv.datasets.cityscapes.cityscapes_utils import cityscapes_semantic_segmentation_label_colors # NOQA from chainercv.datasets.cityscapes.cityscapes_utils import cityscapes_semantic_segmentation_label_names # NOQA -from chainercv.datasets.coco.coco_utils import coco_bbox_label_names # NOQA from chainercv.datasets.coco.coco_bbox_dataset import COCOBboxDataset # NOQA +from chainercv.datasets.coco.coco_utils import coco_bbox_label_names # NOQA from chainercv.datasets.cub.cub_keypoint_dataset import CUBKeypointDataset # NOQA from chainercv.datasets.cub.cub_label_dataset import CUBLabelDataset # NOQA from chainercv.datasets.cub.cub_utils import cub_label_names # NOQA From 4d842fe93ca7db683a550d1b41348db2682b7647 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Fri, 13 Oct 2017 18:50:50 +0900 Subject: [PATCH 10/29] delete unnecessary sanitization --- chainercv/datasets/coco/coco_bbox_dataset.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index d5b014e519..eb4a7172d7 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -122,8 +122,6 @@ def _get_annotations(self, i): # List[{'segmentation', 'area', 'iscrowd', # 'image_id', 'bbox', 'category_id', 'id'}] annotation = self.imgToAnns[img_id] - H = self.img_props[img_id]['height'] - W = self.img_props[img_id]['width'] bbox = np.array([ann['bbox'] for ann in annotation], dtype=np.float32) if len(bbox) == 0: @@ -133,10 +131,6 @@ def _get_annotations(self, i): bbox[:, 3] = bbox[:, 1] + bbox[:, 3] # (x_min, y_min, x_max, y_max) -> (y_min, x_min, y_max, x_max) bbox = bbox[:, [1, 0, 3, 2]] - # Sanitize boxes using image shape - bbox[:, :2] = np.maximum(bbox[:, :2], 0) - bbox[:, 2] = np.minimum(bbox[:, 2], H) - bbox[:, 3] = np.minimum(bbox[:, 3], W) label = np.array([self.cat_ids.index(ann['category_id']) for ann in annotation], dtype=np.int32) From 326eb6d383031c7faf0db4d373e93a3e37bd0841 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Sat, 14 Oct 2017 14:25:40 +0900 Subject: [PATCH 11/29] sort ids --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index eb4a7172d7..394680cbb0 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -98,7 +98,7 @@ def __init__(self, data_dir='auto', split='train', self.img_props = dict() for img in anno['images']: self.img_props[img['id']] = img - self.ids = list(self.img_props.keys()) + self.ids = sorted(list(self.img_props.keys())) cats = anno['categories'] self.cat_ids = [cat['id'] for cat in cats] From ba070d72f128bd76eb2ec6a9dfd03b9a0700ff8b Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Sat, 14 Oct 2017 23:22:15 +0900 Subject: [PATCH 12/29] add return_area option --- chainercv/datasets/coco/coco_bbox_dataset.py | 41 +++++++++++++------ .../coco_tests/test_coco_bbox_dataset.py | 38 +++++++++-------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 394680cbb0..94793bf514 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -18,10 +18,11 @@ class COCOBboxDataset(chainer.dataset.DatasetMixin): When queried by an index, if :obj:`return_crowded == False`, this dataset returns a corresponding - :obj:`img, bbox, label`, a tuple of an image, bounding boxes and labels. - This is the default behaviour. - If :obj:`return_crowded == True`, this dataset returns corresponding - :obj:`img, bbox, label, crowded`. :obj:`crowded` is a boolean array + :obj:`img, bbox, label, crowded, area`, a tuple of an image, bounding + boxes, labels, crowdness indicators and areas of masks. + The parameters :obj:`return_crowded` and :obj:`return_area` decide + whether to return :obj:`crowded` and :obj:`area`. + :obj:`crowded` is a boolean array that indicates whether bounding boxes are for crowd labeling. When there are more than ten objects from the same category, bounding boxes correspond to crowd of instances instead of individual @@ -44,17 +45,20 @@ class COCOBboxDataset(chainer.dataset.DatasetMixin): vertices. The labels are packed into a one dimensional tensor of shape :math:`(R,)`. - :math:`R` is the number of bounding boxes in the image. The class name of the label :math:`l` is :math:`l` th element of :obj:`chainercv.datasets.coco_bbox_label_names`. The array :obj:`crowded` is a one dimensional boolean array of shape - :math:`(R,)`. :math:`R` is the number of bounding boxes in the image. + :math:`(R,)`. + + The array :obj:`area` is a one dimensional flaot array of shape + :math:`(R,)`. * :obj:`img.dtype == numpy.float32` * :obj:`bbox.dtype == numpy.float32` * :obj:`label.dtype == numpy.int32` * :obj:`crowded.dtype == numpy.bool` + * :obj:`area.dtype == np.float32` .. [#] Tsung-Yi Lin, Michael Maire, Serge Belongie, Lubomir Bourdev, \ Ross Girshick, James Hays, Pietro Perona, Deva Ramanan, \ @@ -73,13 +77,16 @@ class COCOBboxDataset(chainer.dataset.DatasetMixin): return_crowded (bool): If true, this dataset returns a boolean array that indicates whether bounding boxes are labeled as crowded or not. The default value is :obj:`False`. + return_area (bool): If true, this dataset returns areas of masks + around objects. """ def __init__(self, data_dir='auto', split='train', - use_crowded=False, return_crowded=False): + use_crowded=False, return_crowded=False, return_area=False): self.use_crowded = use_crowded self.return_crowded = return_crowded + self.return_area = return_area if split in ['val', 'minival', 'valminusminival']: img_split = 'val' else: @@ -138,15 +145,19 @@ def _get_annotations(self, i): crowded = np.array([ann['iscrowd'] for ann in annotation], dtype=np.bool) + area = np.array([ann['area'] + for ann in annotation], dtype=np.float32) + # Remove invalid boxes - area = np.prod(bbox[:, 2:] - bbox[:, :2], axis=1) + bbox_area = np.prod(bbox[:, 2:] - bbox[:, :2], axis=1) keep_mask = np.logical_and(bbox[:, 0] <= bbox[:, 2], bbox[:, 1] <= bbox[:, 3]) - keep_mask = np.logical_and(keep_mask, area > 0) + keep_mask = np.logical_and(keep_mask, bbox_area > 0) bbox = bbox[keep_mask] label = label[keep_mask] crowded = crowded[keep_mask] - return bbox, label, crowded + area = area[keep_mask] + return bbox, label, crowded, area def __len__(self): return len(self.ids) @@ -158,13 +169,17 @@ def get_example(self, i): img = utils.read_image(img_fn, dtype=np.float32, color=True) _, H, W = img.shape - bbox, label, crowded = self._get_annotations(i) + bbox, label, crowded, area = self._get_annotations(i) if not self.use_crowded: bbox = bbox[np.logical_not(crowded)] label = label[np.logical_not(crowded)] + area = area[np.logical_not(crowded)] crowded = crowded[np.logical_not(crowded)] + example = [img, bbox, label] if self.return_crowded: - return img, bbox, label, crowded - return img, bbox, label + example += [crowded] + if self.return_area: + example += [area] + return tuple(example) diff --git a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py index cb6a625ec4..c80e2fb4e5 100644 --- a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py +++ b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py @@ -13,7 +13,8 @@ @testing.parameterize(*testing.product({ 'split': ['train', 'val', 'minival', 'valminusminival'], 'use_crowded': [False, True], - 'return_crowded': [False, True] + 'return_crowded': [False, True], + 'return_area': [False, True] })) class TestCOCOBboxDataset(unittest.TestCase): @@ -23,24 +24,29 @@ def setUp(self): use_crowded=self.use_crowded, return_crowded=self.return_crowded) @attr.slow - def test_as_bbox_dataset(self): + def test_coco_bbox_dataset(self): assert_is_bbox_dataset( self.dataset, len(coco_bbox_label_names), n_example=30) - @attr.slow - def test_crowded(self): - if not self.return_crowded: - return - - for _ in range(10): - i = np.random.randint(0, len(self.dataset)) - _, bbox, _, crowded = self.dataset[i] - self.assertIsInstance(crowded, np.ndarray) - self.assertEqual(crowded.dtype, np.bool) - self.assertEqual(crowded.shape, (bbox.shape[0],)) - - if not self.use_crowded: - np.testing.assert_equal(crowded, 0) + if self.return_crowded: + for _ in range(10): + i = np.random.randint(0, len(self.dataset)) + _, bbox, _, crowded = self.dataset[i][:4] + self.assertIsInstance(crowded, np.ndarray) + self.assertEqual(crowded.dtype, np.bool) + self.assertEqual(crowded.shape, (bbox.shape[0],)) + + if not self.use_crowded: + np.testing.assert_equal(crowded, 0) + + if self.return_area: + for _ in range(10): + i = np.random.randint(0, len(self.dataset)) + example = self.dataset[i] + area = example[-1] + bbox = example[1] + self.assertIsInstance(area, np.ndarray) + self.assertEqual(area.dtype, np.float32) testing.run_module(__name__, __file__) From 5c11243351ce7dfb95be659ee343a74e262e614d Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Sat, 14 Oct 2017 23:27:07 +0900 Subject: [PATCH 13/29] fix failing test --- tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py index c80e2fb4e5..575d2ddef9 100644 --- a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py +++ b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py @@ -21,7 +21,9 @@ class TestCOCOBboxDataset(unittest.TestCase): def setUp(self): self.dataset = COCOBboxDataset( split=self.split, - use_crowded=self.use_crowded, return_crowded=self.return_crowded) + use_crowded=self.use_crowded, return_crowded=self.return_crowded, + return_area=self.return_area + ) @attr.slow def test_coco_bbox_dataset(self): From d5dfb836f52cae696830cd3dfae1af54cdb16a45 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Mon, 9 Apr 2018 14:10:42 +0900 Subject: [PATCH 14/29] WIP --- chainercv/datasets/coco/coco_bbox_dataset.py | 26 ++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 94793bf514..76d6964439 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -9,8 +9,10 @@ from chainercv.datasets.coco.coco_utils import get_coco +from chainercv.chainer_experimental.datasets.sliceable import GetterDataset -class COCOBboxDataset(chainer.dataset.DatasetMixin): + +class COCOBboxDataset(GetterDataset): """Bounding box dataset for `MS COCO2014`_. @@ -116,13 +118,19 @@ def __init__(self, data_dir='auto', split='train', self.imgToAnns[ann['image_id']].append(ann) self.anns[ann['id']] = ann - @property - def labels(self): - labels = list() - for i in range(len(self)): - _, label, _ = self._get_annotations(i) - labels.append(label) - return labels + self.add_getter('image', self._get_image) + self.add_getter(['bbox', 'label', 'crowded', 'area'], + self._get_annotations) + + def __len__(self): + return len(self.ids) + + def _get_image(self, i): + img_id = self.ids[i] + img_fn = os.path.join( + self.img_root, self.img_props[img_id]['file_name']) + img = utils.read_image(img_fn, dtype=np.float32, color=True) + return img def _get_annotations(self, i): img_id = self.ids[i] @@ -159,8 +167,6 @@ def _get_annotations(self, i): area = area[keep_mask] return bbox, label, crowded, area - def __len__(self): - return len(self.ids) def get_example(self, i): img_id = self.ids[i] From 53796f93402c46e53e105b89c4489d220d5b4c98 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 18 Apr 2018 10:52:10 +0900 Subject: [PATCH 15/29] change the default return values and update doc --- chainercv/datasets/coco/coco_bbox_dataset.py | 141 +++++++----------- .../coco_tests/test_coco_bbox_dataset.py | 30 ++-- 2 files changed, 72 insertions(+), 99 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 76d6964439..a61eab058c 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -3,8 +3,6 @@ import numpy as np import os -import chainer - from chainercv import utils from chainercv.datasets.coco.coco_utils import get_coco @@ -18,49 +16,53 @@ class COCOBboxDataset(GetterDataset): .. _`MS COCO2014`: http://mscoco.org/dataset/#detections-challenge2015 - When queried by an index, if :obj:`return_crowded == False`, - this dataset returns a corresponding - :obj:`img, bbox, label, crowded, area`, a tuple of an image, bounding - boxes, labels, crowdness indicators and areas of masks. - The parameters :obj:`return_crowded` and :obj:`return_area` decide - whether to return :obj:`crowded` and :obj:`area`. - :obj:`crowded` is a boolean array - that indicates whether bounding boxes are for crowd labeling. - When there are more than ten objects from the same category, - bounding boxes correspond to crowd of instances instead of individual - instances. Please see more detail in the Fig. 12 (e) of the summary - paper [#]_. - There are total of 82,783 training and 40,504 validation images. 'minval' split is a subset of validation images that constitutes 5000 images in the validation images. The remaining validation images are called 'minvalminus'. Concrete list of image ids and annotations for these splits are found `here`_. + Args: + data_dir (string): Path to the root of the training data. If this is + :obj:`auto`, this class will automatically download data for you + under :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/coco`. + split ({'train', 'val', 'minival', 'valminusminival'}): Select + a split of the dataset. + use_crowded (bool): If true, use bounding boxes that are labeled as + crowded in the original annotation. + return_area (bool): If true, this dataset returns areas of masks + around objects. + return_crowded (bool): If true, this dataset returns a boolean array + that indicates whether bounding boxes are labeled as crowded + or not. The default value is :obj:`False`. + .. _`here`: https://github.com/rbgirshick/py-faster-rcnn/tree/master/data - The bounding boxes are packed into a two dimensional tensor of shape - :math:`(R, 4)`, where :math:`R` is the number of bounding boxes in - the image. The second axis represents attributes of the bounding box. - They are :obj:`(x_min, y_min, x_max, y_max)`, where the - four attributes are coordinates of the top left and the bottom right - vertices. + This dataset returns the following data. - The labels are packed into a one dimensional tensor of shape :math:`(R,)`. - The class name of the label :math:`l` is :math:`l` th element of - :obj:`chainercv.datasets.coco_bbox_label_names`. + .. csv-table:: + :header: name, shape, dtype, format - The array :obj:`crowded` is a one dimensional boolean array of shape - :math:`(R,)`. + :obj:`img`, ":math:`(3, H, W)`", :obj:`float32`, \ + "RGB, :math:`[0, 255]`" + :obj:`bbox` [#coco_bbox_1]_, ":math:`(R, 4)`", :obj:`float32`, \ + ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`" + :obj:`label` [#coco_bbox_1]_, ":math:`(R,)`", :obj:`int32`, \ + ":math:`[0, n\_fg\_class - 1]`" + :obj:`area` [#coco_bbox_1]_ [#coco_bbox_2]_, ":math:`(R,)`", :obj:`float32`, -- + :obj:`crowded` [#coco_bbox_3]_, ":math:`(R,)`", :obj:`bool`, -- - The array :obj:`area` is a one dimensional flaot array of shape - :math:`(R,)`. + .. [#coco_bbox_1] If :obj:`use_crowded = True`, \ + :obj:`bbox`, :obj:`label` and :obj:`area` contain difficult instances. + .. [#coco_bbox_2] :obj:`area` is available \ + if :obj:`return_area = True`. + .. [#coco_bbox_3] :obj:`crowded` is available \ + if :obj:`return_crowded = True`. - * :obj:`img.dtype == numpy.float32` - * :obj:`bbox.dtype == numpy.float32` - * :obj:`label.dtype == numpy.int32` - * :obj:`crowded.dtype == numpy.bool` - * :obj:`area.dtype == np.float32` + When there are more than ten objects from the same category, + bounding boxes correspond to crowd of instances instead of individual + instances. Please see more detail in the Fig. 12 (e) of the summary + paper [#]_. .. [#] Tsung-Yi Lin, Michael Maire, Serge Belongie, Lubomir Bourdev, \ Ross Girshick, James Hays, Pietro Perona, Deva Ramanan, \ @@ -68,20 +70,6 @@ class COCOBboxDataset(GetterDataset): `Microsoft COCO: Common Objects in Context \ `_. arXiv 2014. - Args: - data_dir (string): Path to the root of the training data. If this is - :obj:`auto`, this class will automatically download data for you - under :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/coco`. - split ({'train', 'val', 'minival', 'valminusminival'}): Select - a split of the dataset. - use_crowded (bool): If true, use bounding boxes that are labeled as - crowded in the original annotation. - return_crowded (bool): If true, this dataset returns a boolean array - that indicates whether bounding boxes are labeled as crowded - or not. The default value is :obj:`False`. - return_area (bool): If true, this dataset returns areas of masks - around objects. - """ def __init__(self, data_dir='auto', split='train', @@ -104,7 +92,7 @@ def __init__(self, data_dir='auto', split='train', self.data_dir = data_dir anno = json.load(open(anno_fn, 'r')) - self.img_props = dict() + self.img_props = {} for img in anno['images']: self.img_props[img['id']] = img self.ids = sorted(list(self.img_props.keys())) @@ -112,31 +100,35 @@ def __init__(self, data_dir='auto', split='train', cats = anno['categories'] self.cat_ids = [cat['id'] for cat in cats] - self.anns = dict() + self.anns = {} self.imgToAnns = defaultdict(list) for ann in anno['annotations']: self.imgToAnns[ann['image_id']].append(ann) self.anns[ann['id']] = ann - self.add_getter('image', self._get_image) + self.add_getter('img', self._get_image) self.add_getter(['bbox', 'label', 'crowded', 'area'], self._get_annotations) + keys = ['img', 'bbox', 'label'] + if self.return_area: + keys.append('area') + if self.return_crowded: + keys.append('crowded') + def __len__(self): return len(self.ids) def _get_image(self, i): - img_id = self.ids[i] - img_fn = os.path.join( - self.img_root, self.img_props[img_id]['file_name']) - img = utils.read_image(img_fn, dtype=np.float32, color=True) + img_path = os.path.join( + self.img_root, self.img_props[self.ids[i]]['file_name']) + img = utils.read_image(img_path, dtype=np.float32, color=True) return img def _get_annotations(self, i): - img_id = self.ids[i] # List[{'segmentation', 'area', 'iscrowd', # 'image_id', 'bbox', 'category_id', 'id'}] - annotation = self.imgToAnns[img_id] + annotation = self.imgToAnns[self.ids[i]] bbox = np.array([ann['bbox'] for ann in annotation], dtype=np.float32) if len(bbox) == 0: @@ -150,42 +142,23 @@ def _get_annotations(self, i): label = np.array([self.cat_ids.index(ann['category_id']) for ann in annotation], dtype=np.int32) - crowded = np.array([ann['iscrowd'] - for ann in annotation], dtype=np.bool) - area = np.array([ann['area'] for ann in annotation], dtype=np.float32) + crowded = np.array([ann['iscrowd'] + for ann in annotation], dtype=np.bool) + # Remove invalid boxes bbox_area = np.prod(bbox[:, 2:] - bbox[:, :2], axis=1) keep_mask = np.logical_and(bbox[:, 0] <= bbox[:, 2], bbox[:, 1] <= bbox[:, 3]) keep_mask = np.logical_and(keep_mask, bbox_area > 0) - bbox = bbox[keep_mask] - label = label[keep_mask] - crowded = crowded[keep_mask] - area = area[keep_mask] - return bbox, label, crowded, area - - - def get_example(self, i): - img_id = self.ids[i] - img_fn = os.path.join( - self.img_root, self.img_props[img_id]['file_name']) - img = utils.read_image(img_fn, dtype=np.float32, color=True) - _, H, W = img.shape - - bbox, label, crowded, area = self._get_annotations(i) if not self.use_crowded: - bbox = bbox[np.logical_not(crowded)] - label = label[np.logical_not(crowded)] - area = area[np.logical_not(crowded)] - crowded = crowded[np.logical_not(crowded)] + keep_mask = np.logical_and(keep_mask, np.logical_not(crowded)) - example = [img, bbox, label] - if self.return_crowded: - example += [crowded] - if self.return_area: - example += [area] - return tuple(example) + bbox = bbox[keep_mask] + label = label[keep_mask] + area = area[keep_mask] + crowded = crowded[keep_mask] + return bbox, label, area, crowded diff --git a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py index 575d2ddef9..7335e8e025 100644 --- a/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py +++ b/tests/datasets_tests/coco_tests/test_coco_bbox_dataset.py @@ -13,27 +13,36 @@ @testing.parameterize(*testing.product({ 'split': ['train', 'val', 'minival', 'valminusminival'], 'use_crowded': [False, True], - 'return_crowded': [False, True], - 'return_area': [False, True] + 'return_area': [False, True], + 'return_crowded': [False, True] })) class TestCOCOBboxDataset(unittest.TestCase): def setUp(self): self.dataset = COCOBboxDataset( split=self.split, - use_crowded=self.use_crowded, return_crowded=self.return_crowded, - return_area=self.return_area - ) + use_crowded=self.use_crowded, return_area=self.return_area, + return_crowded=self.return_crowded) @attr.slow def test_coco_bbox_dataset(self): assert_is_bbox_dataset( self.dataset, len(coco_bbox_label_names), n_example=30) + if self.return_area: + for _ in range(10): + i = np.random.randint(0, len(self.dataset)) + _, bbox, _, area = self.dataset[i][:4] + self.assertIsInstance(area, np.ndarray) + self.assertEqual(area.dtype, np.float32) + self.assertEqual(area.shape, (bbox.shape[0],)) + if self.return_crowded: for _ in range(10): i = np.random.randint(0, len(self.dataset)) - _, bbox, _, crowded = self.dataset[i][:4] + example = self.dataset[i] + crowded = example[-1] + bbox = example[1] self.assertIsInstance(crowded, np.ndarray) self.assertEqual(crowded.dtype, np.bool) self.assertEqual(crowded.shape, (bbox.shape[0],)) @@ -41,14 +50,5 @@ def test_coco_bbox_dataset(self): if not self.use_crowded: np.testing.assert_equal(crowded, 0) - if self.return_area: - for _ in range(10): - i = np.random.randint(0, len(self.dataset)) - example = self.dataset[i] - area = example[-1] - bbox = example[1] - self.assertIsInstance(area, np.ndarray) - self.assertEqual(area.dtype, np.float32) - testing.run_module(__name__, __file__) From f9b6dd368987e1710de72addd084648e6d8de69b Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 18 Apr 2018 19:10:45 +0900 Subject: [PATCH 16/29] fix doc --- chainercv/datasets/coco/coco_bbox_dataset.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index a61eab058c..1eb77610b5 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -48,12 +48,13 @@ class COCOBboxDataset(GetterDataset): :obj:`bbox` [#coco_bbox_1]_, ":math:`(R, 4)`", :obj:`float32`, \ ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`" :obj:`label` [#coco_bbox_1]_, ":math:`(R,)`", :obj:`int32`, \ - ":math:`[0, n\_fg\_class - 1]`" - :obj:`area` [#coco_bbox_1]_ [#coco_bbox_2]_, ":math:`(R,)`", :obj:`float32`, -- + ":math:`[0, #fg\_class - 1]`" + :obj:`area` [#coco_bbox_1]_ [#coco_bbox_2]_, ":math:`(R,)`", \ + :obj:`float32`, -- :obj:`crowded` [#coco_bbox_3]_, ":math:`(R,)`", :obj:`bool`, -- - .. [#coco_bbox_1] If :obj:`use_crowded = True`, \ - :obj:`bbox`, :obj:`label` and :obj:`area` contain difficult instances. + .. [#coco_bbox_1] If :obj:`use_crowded = True`, :obj:`bbox`, \ + :obj:`label` and :obj:`area` contain difficult instances. .. [#coco_bbox_2] :obj:`area` is available \ if :obj:`return_area = True`. .. [#coco_bbox_3] :obj:`crowded` is available \ From 2309c54c52667a8f766a5d788f1793bc708155fc Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 18 Apr 2018 19:10:52 +0900 Subject: [PATCH 17/29] fix bug --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 1eb77610b5..9674cdab89 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -75,6 +75,7 @@ class COCOBboxDataset(GetterDataset): def __init__(self, data_dir='auto', split='train', use_crowded=False, return_crowded=False, return_area=False): + super(COCOBboxDataset, self).__init__() self.use_crowded = use_crowded self.return_crowded = return_crowded self.return_area = return_area @@ -116,6 +117,7 @@ def __init__(self, data_dir='auto', split='train', keys.append('area') if self.return_crowded: keys.append('crowded') + self.keys = keys def __len__(self): return len(self.ids) From 5b6a262f9b524efabad6e969e1c15378b35aa1dc Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Thu, 19 Apr 2018 12:54:55 +0900 Subject: [PATCH 18/29] use tuple to set keys --- chainercv/datasets/coco/coco_bbox_dataset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 9674cdab89..ba68be0038 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -112,11 +112,11 @@ def __init__(self, data_dir='auto', split='train', self.add_getter(['bbox', 'label', 'crowded', 'area'], self._get_annotations) - keys = ['img', 'bbox', 'label'] + keys = ('img', 'bbox', 'label') if self.return_area: - keys.append('area') + keys += ('area',) if self.return_crowded: - keys.append('crowded') + keys += ('crowded',) self.keys = keys def __len__(self): From 1749887aa3327dac68c8c72dc59bdb6eeb030845 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Thu, 19 Apr 2018 18:00:55 +0900 Subject: [PATCH 19/29] fix doc --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index ba68be0038..187930c2d6 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -54,7 +54,7 @@ class COCOBboxDataset(GetterDataset): :obj:`crowded` [#coco_bbox_3]_, ":math:`(R,)`", :obj:`bool`, -- .. [#coco_bbox_1] If :obj:`use_crowded = True`, :obj:`bbox`, \ - :obj:`label` and :obj:`area` contain difficult instances. + :obj:`label` and :obj:`area` contain crowded instances. .. [#coco_bbox_2] :obj:`area` is available \ if :obj:`return_area = True`. .. [#coco_bbox_3] :obj:`crowded` is available \ From b4f53b58db408f1d4a2d74a30c9ebdefc7cb0e3a Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Thu, 19 Apr 2018 18:02:24 +0900 Subject: [PATCH 20/29] clean up __init__ --- chainercv/datasets/coco/coco_bbox_dataset.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 187930c2d6..9fc44de073 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -88,11 +88,11 @@ def __init__(self, data_dir='auto', split='train', self.img_root = os.path.join( data_dir, 'images', '{}2014'.format(img_split)) - anno_fn = os.path.join( + anno_path = os.path.join( data_dir, 'annotations', 'instances_{}2014.json'.format(split)) self.data_dir = data_dir - anno = json.load(open(anno_fn, 'r')) + anno = json.load(open(anno_path, 'r')) self.img_props = {} for img in anno['images']: @@ -102,11 +102,9 @@ def __init__(self, data_dir='auto', split='train', cats = anno['categories'] self.cat_ids = [cat['id'] for cat in cats] - self.anns = {} - self.imgToAnns = defaultdict(list) + self.img_to_anno = defaultdict(list) for ann in anno['annotations']: - self.imgToAnns[ann['image_id']].append(ann) - self.anns[ann['id']] = ann + self.img_to_anno[ann['image_id']].append(ann) self.add_getter('img', self._get_image) self.add_getter(['bbox', 'label', 'crowded', 'area'], @@ -131,7 +129,7 @@ def _get_image(self, i): def _get_annotations(self, i): # List[{'segmentation', 'area', 'iscrowd', # 'image_id', 'bbox', 'category_id', 'id'}] - annotation = self.imgToAnns[self.ids[i]] + annotation = self.img_to_anno[self.ids[i]] bbox = np.array([ann['bbox'] for ann in annotation], dtype=np.float32) if len(bbox) == 0: From 393a4c45853262db8b8e6c1228611f53b2057a3b Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Thu, 19 Apr 2018 18:04:12 +0900 Subject: [PATCH 21/29] indentation csv --- chainercv/datasets/coco/coco_bbox_dataset.py | 38 ++++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 9fc44de073..a91a4bade6 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -40,25 +40,25 @@ class COCOBboxDataset(GetterDataset): This dataset returns the following data. - .. csv-table:: - :header: name, shape, dtype, format - - :obj:`img`, ":math:`(3, H, W)`", :obj:`float32`, \ - "RGB, :math:`[0, 255]`" - :obj:`bbox` [#coco_bbox_1]_, ":math:`(R, 4)`", :obj:`float32`, \ - ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`" - :obj:`label` [#coco_bbox_1]_, ":math:`(R,)`", :obj:`int32`, \ - ":math:`[0, #fg\_class - 1]`" - :obj:`area` [#coco_bbox_1]_ [#coco_bbox_2]_, ":math:`(R,)`", \ - :obj:`float32`, -- - :obj:`crowded` [#coco_bbox_3]_, ":math:`(R,)`", :obj:`bool`, -- - - .. [#coco_bbox_1] If :obj:`use_crowded = True`, :obj:`bbox`, \ - :obj:`label` and :obj:`area` contain crowded instances. - .. [#coco_bbox_2] :obj:`area` is available \ - if :obj:`return_area = True`. - .. [#coco_bbox_3] :obj:`crowded` is available \ - if :obj:`return_crowded = True`. + .. csv-table:: + :header: name, shape, dtype, format + + :obj:`img`, ":math:`(3, H, W)`", :obj:`float32`, \ + "RGB, :math:`[0, 255]`" + :obj:`bbox` [#coco_bbox_1]_, ":math:`(R, 4)`", :obj:`float32`, \ + ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`" + :obj:`label` [#coco_bbox_1]_, ":math:`(R,)`", :obj:`int32`, \ + ":math:`[0, #fg\_class - 1]`" + :obj:`area` [#coco_bbox_1]_ [#coco_bbox_2]_, ":math:`(R,)`", \ + :obj:`float32`, -- + :obj:`crowded` [#coco_bbox_3]_, ":math:`(R,)`", :obj:`bool`, -- + + .. [#coco_bbox_1] If :obj:`use_crowded = True`, :obj:`bbox`, \ + :obj:`label` and :obj:`area` contain crowded instances. + .. [#coco_bbox_2] :obj:`area` is available \ + if :obj:`return_area = True`. + .. [#coco_bbox_3] :obj:`crowded` is available \ + if :obj:`return_crowded = True`. When there are more than ten objects from the same category, bounding boxes correspond to crowd of instances instead of individual From 1d09d4eced8cc1c64f171f49d31bcf6d255a38b1 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Thu, 19 Apr 2018 18:09:07 +0900 Subject: [PATCH 22/29] clean up --- chainercv/datasets/coco/coco_bbox_dataset.py | 9 +++------ chainercv/datasets/coco/coco_utils.py | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index a91a4bade6..40ba59c0bb 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -77,8 +77,6 @@ def __init__(self, data_dir='auto', split='train', use_crowded=False, return_crowded=False, return_area=False): super(COCOBboxDataset, self).__init__() self.use_crowded = use_crowded - self.return_crowded = return_crowded - self.return_area = return_area if split in ['val', 'minival', 'valminusminival']: img_split = 'val' else: @@ -99,8 +97,7 @@ def __init__(self, data_dir='auto', split='train', self.img_props[img['id']] = img self.ids = sorted(list(self.img_props.keys())) - cats = anno['categories'] - self.cat_ids = [cat['id'] for cat in cats] + self.cat_ids = [cat['id'] for cat in anno['categories']] self.img_to_anno = defaultdict(list) for ann in anno['annotations']: @@ -111,9 +108,9 @@ def __init__(self, data_dir='auto', split='train', self._get_annotations) keys = ('img', 'bbox', 'label') - if self.return_area: + if return_area: keys += ('area',) - if self.return_crowded: + if return_crowded: keys += ('crowded',) self.keys = keys diff --git a/chainercv/datasets/coco/coco_utils.py b/chainercv/datasets/coco/coco_utils.py index 06e76db8e5..e33dc5acca 100644 --- a/chainercv/datasets/coco/coco_utils.py +++ b/chainercv/datasets/coco/coco_utils.py @@ -28,12 +28,12 @@ def get_coco(split, img_split): img_root = os.path.join(data_dir, 'images') created_img_root = os.path.join(img_root, '{}2014'.format(img_split)) annos_root = os.path.join(data_dir, 'annotations') - anno_fn = os.path.join(annos_root, 'instances_{}2014.json'.format(split)) + anno_path = os.path.join(annos_root, 'instances_{}2014.json'.format(split)) if not os.path.exists(created_img_root): download_file_path = utils.cached_download(url) ext = os.path.splitext(url)[1] utils.extractall(download_file_path, img_root, ext) - if not os.path.exists(anno_fn): + if not os.path.exists(anno_path): anno_url = anno_urls[split] download_file_path = utils.cached_download(anno_url) ext = os.path.splitext(anno_url)[1] From 787134794088f0e71ae8b729ad3d4a947b712b21 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Mon, 4 Jun 2018 13:30:23 +0900 Subject: [PATCH 23/29] fix order of data --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 40ba59c0bb..f5f59163f9 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -104,7 +104,7 @@ def __init__(self, data_dir='auto', split='train', self.img_to_anno[ann['image_id']].append(ann) self.add_getter('img', self._get_image) - self.add_getter(['bbox', 'label', 'crowded', 'area'], + self.add_getter(['bbox', 'label', 'area', 'crowded'], self._get_annotations) keys = ('img', 'bbox', 'label') From 8d361fceb1ab1b7ffbb600d671de102eb4860979 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Mon, 4 Jun 2018 13:40:43 +0900 Subject: [PATCH 24/29] change variable names --- chainercv/datasets/coco/coco_bbox_dataset.py | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index f5f59163f9..944c334bb9 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -29,9 +29,10 @@ class COCOBboxDataset(GetterDataset): split ({'train', 'val', 'minival', 'valminusminival'}): Select a split of the dataset. use_crowded (bool): If true, use bounding boxes that are labeled as - crowded in the original annotation. + crowded in the original annotation. The default value is + :obj:`False`. return_area (bool): If true, this dataset returns areas of masks - around objects. + around objects. The default value is :obj:`False`. return_crowded (bool): If true, this dataset returns a boolean array that indicates whether bounding boxes are labeled as crowded or not. The default value is :obj:`False`. @@ -92,16 +93,16 @@ def __init__(self, data_dir='auto', split='train', self.data_dir = data_dir anno = json.load(open(anno_path, 'r')) - self.img_props = {} - for img in anno['images']: - self.img_props[img['id']] = img - self.ids = sorted(list(self.img_props.keys())) + self.id_to_props = {} + for prop in anno['images']: + self.id_to_props[img['id']] = prop + self.ids = sorted(list(self.id_to_props.keys())) self.cat_ids = [cat['id'] for cat in anno['categories']] - self.img_to_anno = defaultdict(list) + self.id_to_anno = defaultdict(list) for ann in anno['annotations']: - self.img_to_anno[ann['image_id']].append(ann) + self.id_to_anno[ann['image_id']].append(ann) self.add_getter('img', self._get_image) self.add_getter(['bbox', 'label', 'area', 'crowded'], @@ -119,14 +120,14 @@ def __len__(self): def _get_image(self, i): img_path = os.path.join( - self.img_root, self.img_props[self.ids[i]]['file_name']) + self.img_root, self.id_to_props[self.ids[i]]['file_name']) img = utils.read_image(img_path, dtype=np.float32, color=True) return img def _get_annotations(self, i): # List[{'segmentation', 'area', 'iscrowd', # 'image_id', 'bbox', 'category_id', 'id'}] - annotation = self.img_to_anno[self.ids[i]] + annotation = self.id_to_anno[self.ids[i]] bbox = np.array([ann['bbox'] for ann in annotation], dtype=np.float32) if len(bbox) == 0: From 2025cd7d26f3c7966eb55f0ad310125b7e7e9318 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Mon, 4 Jun 2018 14:01:39 +0900 Subject: [PATCH 25/29] fix --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 944c334bb9..e73ab1cd62 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -95,7 +95,7 @@ def __init__(self, data_dir='auto', split='train', self.id_to_props = {} for prop in anno['images']: - self.id_to_props[img['id']] = prop + self.id_to_props[prop['id']] = prop self.ids = sorted(list(self.id_to_props.keys())) self.cat_ids = [cat['id'] for cat in anno['categories']] From 4fd177776d279b569e4db74ead3b6d60bf331cd9 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Tue, 5 Jun 2018 13:28:57 +0900 Subject: [PATCH 26/29] fix order or argument --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index e73ab1cd62..a9c986c75c 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -75,7 +75,7 @@ class COCOBboxDataset(GetterDataset): """ def __init__(self, data_dir='auto', split='train', - use_crowded=False, return_crowded=False, return_area=False): + use_crowded=False, return_area=False, return_crowded=False): super(COCOBboxDataset, self).__init__() self.use_crowded = use_crowded if split in ['val', 'minival', 'valminusminival']: From 81e0f941493cc60cc64f63cc33a36a794cd897c6 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Tue, 5 Jun 2018 13:30:41 +0900 Subject: [PATCH 27/29] fix var name --- chainercv/datasets/coco/coco_bbox_dataset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index a9c986c75c..ca4270ee92 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -93,10 +93,10 @@ def __init__(self, data_dir='auto', split='train', self.data_dir = data_dir anno = json.load(open(anno_path, 'r')) - self.id_to_props = {} + self.id_to_prop = {} for prop in anno['images']: - self.id_to_props[prop['id']] = prop - self.ids = sorted(list(self.id_to_props.keys())) + self.id_to_prop[prop['id']] = prop + self.ids = sorted(list(self.id_to_prop.keys())) self.cat_ids = [cat['id'] for cat in anno['categories']] @@ -120,7 +120,7 @@ def __len__(self): def _get_image(self, i): img_path = os.path.join( - self.img_root, self.id_to_props[self.ids[i]]['file_name']) + self.img_root, self.id_to_prop[self.ids[i]]['file_name']) img = utils.read_image(img_path, dtype=np.float32, color=True) return img From 53b5d971e9b38d23b6157159a11387e22286d7be Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Tue, 5 Jun 2018 13:31:37 +0900 Subject: [PATCH 28/29] fix var name --- chainercv/datasets/coco/coco_bbox_dataset.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index ca4270ee92..1d0cf2759c 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -91,18 +91,18 @@ def __init__(self, data_dir='auto', split='train', data_dir, 'annotations', 'instances_{}2014.json'.format(split)) self.data_dir = data_dir - anno = json.load(open(anno_path, 'r')) + annos = json.load(open(anno_path, 'r')) self.id_to_prop = {} - for prop in anno['images']: + for prop in annos['images']: self.id_to_prop[prop['id']] = prop self.ids = sorted(list(self.id_to_prop.keys())) - self.cat_ids = [cat['id'] for cat in anno['categories']] + self.cat_ids = [cat['id'] for cat in annos['categories']] self.id_to_anno = defaultdict(list) - for ann in anno['annotations']: - self.id_to_anno[ann['image_id']].append(ann) + for anno in annos['annotations']: + self.id_to_anno[anno['image_id']].append(anno) self.add_getter('img', self._get_image) self.add_getter(['bbox', 'label', 'area', 'crowded'], From e64d00d211e5e64f638e0834b235d701605ae877 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Tue, 5 Jun 2018 16:22:54 +0900 Subject: [PATCH 29/29] reflect comments --- chainercv/datasets/coco/coco_bbox_dataset.py | 2 +- docs/source/reference/datasets.rst | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/chainercv/datasets/coco/coco_bbox_dataset.py b/chainercv/datasets/coco/coco_bbox_dataset.py index 1d0cf2759c..c7eae44c4c 100644 --- a/chainercv/datasets/coco/coco_bbox_dataset.py +++ b/chainercv/datasets/coco/coco_bbox_dataset.py @@ -18,7 +18,7 @@ class COCOBboxDataset(GetterDataset): There are total of 82,783 training and 40,504 validation images. 'minval' split is a subset of validation images that constitutes - 5000 images in the validation images. The remaining validation + 5,000 images in the validation images. The remaining validation images are called 'minvalminus'. Concrete list of image ids and annotations for these splits are found `here`_. diff --git a/docs/source/reference/datasets.rst b/docs/source/reference/datasets.rst index 2fdb98d71d..d075c6b1b7 100644 --- a/docs/source/reference/datasets.rst +++ b/docs/source/reference/datasets.rst @@ -51,12 +51,6 @@ CityscapesTestImageDataset ~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: CityscapesTestImageDataset -COCO ----- - -COCOBboxDataset -~~~~~~~~~~~~~~~ -.. autoclass:: COCOBboxDataset CUB --- @@ -70,6 +64,14 @@ CUBPointDataset .. autoclass:: CUBPointDataset +MS COCO +------- + +COCOBboxDataset +~~~~~~~~~~~~~~~ +.. autoclass:: COCOBboxDataset + + OnlineProducts --------------