KyanChen's picture
init
f549064
# Copyright (c) OpenMMLab. All rights reserved.
import xml.etree.ElementTree as ET
from typing import List, Optional, Union
from mmengine import get_file_backend, list_from_file
from mmcls.registry import DATASETS
from .base_dataset import expanduser
from .categories import VOC2007_CATEGORIES
from .multi_label import MultiLabelDataset
@DATASETS.register_module()
class VOC(MultiLabelDataset):
"""`Pascal VOC <http://host.robots.ox.ac.uk/pascal/VOC/>`_ Dataset.
After decompression, the dataset directory structure is as follows:
VOC dataset directory: ::
VOC2007 (data_root)/
β”œβ”€β”€ JPEGImages (data_prefix['img_path'])
β”‚ β”œβ”€β”€ xxx.jpg
β”‚ β”œβ”€β”€ xxy.jpg
β”‚ └── ...
β”œβ”€β”€ Annotations (data_prefix['ann_path'])
β”‚ β”œβ”€β”€ xxx.xml
β”‚ β”œβ”€β”€ xxy.xml
β”‚ └── ...
└── ImageSets (directory contains various imageset file)
Extra difficult label is in VOC annotations, we will use
`gt_label_difficult` to record the difficult labels in each sample
and corresponding evaluation should take care of this field
to calculate metrics. Usually, difficult labels are reckoned as
negative in defaults.
Args:
data_root (str): The root directory for VOC dataset.
image_set_path (str): The path of image set, The file which
lists image ids of the sub dataset, and this path is relative
to ``data_root``.
data_prefix (dict): Prefix for data and annotation, keyword
'img_path' and 'ann_path' can be set. Defaults to be
``dict(img_path='JPEGImages', ann_path='Annotations')``.
test_mode (bool): ``test_mode=True`` means in test phase.
It determines to use the training set or test set.
metainfo (dict, optional): Meta information for dataset, such as
categories information. Defaults to None.
**kwargs: Other keyword arguments in :class:`BaseDataset`.
""" # noqa: E501
METAINFO = {'classes': VOC2007_CATEGORIES}
def __init__(self,
data_root: str,
image_set_path: str,
data_prefix: Union[str, dict] = dict(
img_path='JPEGImages', ann_path='Annotations'),
test_mode: bool = False,
metainfo: Optional[dict] = None,
**kwargs):
if isinstance(data_prefix, str):
data_prefix = dict(img_path=expanduser(data_prefix))
assert isinstance(data_prefix, dict) and 'img_path' in data_prefix, \
'`data_prefix` must be a dict with key img_path'
if test_mode is False:
assert 'ann_path' in data_prefix and data_prefix[
'ann_path'] is not None, \
'"ann_path" must be set in `data_prefix` if `test_mode` is' \
' False.'
self.data_root = data_root
self.backend = get_file_backend(data_root, enable_singleton=True)
self.image_set_path = self.backend.join_path(data_root, image_set_path)
super().__init__(
ann_file='',
metainfo=metainfo,
data_root=data_root,
data_prefix=data_prefix,
test_mode=test_mode,
**kwargs)
@property
def ann_prefix(self):
"""The prefix of images."""
if 'ann_path' in self.data_prefix:
return self.data_prefix['ann_path']
else:
return None
def _get_labels_from_xml(self, img_id):
"""Get gt_labels and labels_difficult from xml file."""
xml_path = self.backend.join_path(self.ann_prefix, f'{img_id}.xml')
content = self.backend.get(xml_path)
root = ET.fromstring(content)
labels, labels_difficult = set(), set()
for obj in root.findall('object'):
label_name = obj.find('name').text
# in case customized dataset has wrong labels
# or CLASSES has been override.
if label_name not in self.CLASSES:
continue
label = self.class_to_idx[label_name]
difficult = int(obj.find('difficult').text)
if difficult:
labels_difficult.add(label)
else:
labels.add(label)
return list(labels), list(labels_difficult)
def load_data_list(self):
"""Load images and ground truth labels."""
data_list = []
img_ids = list_from_file(self.image_set_path)
for img_id in img_ids:
img_path = self.backend.join_path(self.img_prefix, f'{img_id}.jpg')
labels, labels_difficult = None, None
if self.ann_prefix is not None:
labels, labels_difficult = self._get_labels_from_xml(img_id)
info = dict(
img_path=img_path,
gt_label=labels,
gt_label_difficult=labels_difficult)
data_list.append(info)
return data_list
def extra_repr(self) -> List[str]:
"""The extra repr information of the dataset."""
body = [
f'Prefix of dataset: \t{self.data_root}',
f'Path of image set: \t{self.image_set_path}',
f'Prefix of images: \t{self.img_prefix}',
f'Prefix of annotations: \t{self.ann_prefix}'
]
return body