Skip to content

Commit

Permalink
Label "face" for bounding boxes in Wider Face (#215)
Browse files Browse the repository at this point in the history
* add face label

* update changelog
  • Loading branch information
yasakova-anastasia authored Apr 13, 2021
1 parent 989f990 commit d549952
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 47 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for auto-merging (joining) of datasets with no labels and having labels (<https://github.com/openvinotoolkit/datumaro/pull/200>)
- Allowed explicit label removal in `remap_labels` transform (<https://github.com/openvinotoolkit/datumaro/pull/203>)
- Image extension in CVAT format export (<https://github.com/openvinotoolkit/datumaro/pull/214>)
- Added a label "face" for bounding boxes in Wider Face (<https://github.com/openvinotoolkit/datumaro/pull/215>)

### Security
-
Expand Down
37 changes: 22 additions & 15 deletions datumaro/plugins/widerface_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class WiderFacePath:
IMAGES_DIR_NO_LABEL = 'no_label'
BBOX_ATTRIBUTES = ['blur', 'expression', 'illumination',
'occluded', 'pose', 'invalid']
DEFAULT_LABEL = 'face'

class WiderFaceExtractor(SourceExtractor):
def __init__(self, path, subset=None):
Expand All @@ -40,13 +41,13 @@ def __init__(self, path, subset=None):

def _load_categories(self):
label_cat = LabelCategories()

path = osp.join(self._dataset_dir, WiderFacePath.LABELS_FILE)
if osp.isfile(path):
with open(path, encoding='utf-8') as labels_file:
for line in labels_file:
label_cat.add(line.strip())
else:
label_cat.add(WiderFacePath.DEFAULT_LABEL)
subset_path = osp.join(self._dataset_dir,
WiderFacePath.SUBSET_DIR + self._subset,
WiderFacePath.IMAGES_DIR)
Expand All @@ -56,12 +57,15 @@ def _load_categories(self):
images_dir != WiderFacePath.IMAGES_DIR_NO_LABEL:
if '--' in images_dir:
images_dir = images_dir.split('--')[1]
label_cat.add(images_dir)

if images_dir != WiderFacePath.DEFAULT_LABEL:
label_cat.add(images_dir)
if len(label_cat) == 1:
label_cat = LabelCategories()
return { AnnotationType.label: label_cat }

def _load_items(self, path):
items = {}
label_categories = self._categories[AnnotationType.label]

with open(path, 'r', encoding='utf-8') as f:
lines = f.readlines()
Expand All @@ -73,6 +77,7 @@ def _load_items(self, path):
for line_idx in line_ids:
image_path = lines[line_idx].strip()
item_id = osp.splitext(image_path)[0]
item_id = item_id.replace('\\', '/')

image_path = osp.join(self._dataset_dir,
WiderFacePath.SUBSET_DIR + self._subset,
Expand All @@ -84,9 +89,9 @@ def _load_items(self, path):
if '--' in label_name:
label_name = label_name.split('--')[1]
if label_name != WiderFacePath.IMAGES_DIR_NO_LABEL:
label = \
self._categories[AnnotationType.label].find(label_name)[0]
annotations.append(Label(label=label))
label = label_categories.find(label_name)[0]
if label != None:
annotations.append(Label(label=label))
item_id = item_id[len(item_id.split('/')[0]) + 1:]

items[item_id] = DatasetItem(id=item_id, subset=self._subset,
Expand All @@ -101,21 +106,22 @@ def _load_items(self, path):
for bbox in bbox_lines:
bbox_list = bbox.split()
if 4 <= len(bbox_list):
attributes = {}
label = None
label = label_categories.find(WiderFacePath.DEFAULT_LABEL)[0]
if len(bbox_list) == 5 or len(bbox_list) == 11:
if len(bbox_list) == 5:
label_name = bbox_list[4]
else:
label_name = bbox_list[10]
label = \
self._categories[AnnotationType.label].find(label_name)[0]
label_name = bbox_list[-1]
label = label_categories.find(label_name)[0]
if label == None and len(label_categories) == 0:
label_categories.add(WiderFacePath.DEFAULT_LABEL)
label = label_categories.find(WiderFacePath.DEFAULT_LABEL)[0]

attributes = {}
if 10 <= len(bbox_list):
i = 4
for attr in WiderFacePath.BBOX_ATTRIBUTES:
if bbox_list[i] != '-':
attributes[attr] = bbox_list[i]
i += 1

annotations.append(Bbox(
float(bbox_list[0]), float(bbox_list[1]),
float(bbox_list[2]), float(bbox_list[3]),
Expand Down Expand Up @@ -180,7 +186,8 @@ def apply(self):
wider_attr += '- '
if 0 < attr_counter:
wider_annotation += wider_attr
if bbox.label is not None:
if label_categories[bbox.label].name != WiderFacePath.DEFAULT_LABEL and \
bbox.label is not None:
wider_annotation += '%s' % label_categories[bbox.label].name
wider_annotation += '\n'

Expand Down
55 changes: 23 additions & 32 deletions tests/test_widerface_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,44 @@ def test_can_save_and_load(self):
source_dataset = Dataset.from_iterable([
DatasetItem(id='1', subset='train', image=np.ones((8, 8, 3)),
annotations=[
Bbox(0, 2, 4, 2),
Bbox(0, 1, 2, 3, attributes={
Bbox(0, 2, 4, 2, label=0),
Bbox(0, 1, 2, 3, label=0, attributes={
'blur': '2', 'expression': '0', 'illumination': '0',
'occluded': '0', 'pose': '2', 'invalid': '0'}),
Label(0),
Label(1),
]
),
DatasetItem(id='2', subset='train', image=np.ones((10, 10, 3)),
annotations=[
Bbox(0, 2, 4, 2, attributes={
Bbox(0, 2, 4, 2, label=0, attributes={
'blur': '2', 'expression': '0', 'illumination': '1',
'occluded': '0', 'pose': '1', 'invalid': '0'}),
Bbox(3, 3, 2, 3, attributes={
Bbox(3, 3, 2, 3, label=0, attributes={
'blur': '0', 'expression': '1', 'illumination': '0',
'occluded': '0', 'pose': '2', 'invalid': '0'}),
Bbox(2, 1, 2, 3, attributes={
Bbox(2, 1, 2, 3, label=0, attributes={
'blur': '2', 'expression': '0', 'illumination': '0',
'occluded': '0', 'pose': '0', 'invalid': '1'}),
Label(1),
Label(2),
]
),

DatasetItem(id='3', subset='val', image=np.ones((8, 8, 3)),
annotations=[
Bbox(0, 1.1, 5.3, 2.1, attributes={
Bbox(0, 1.1, 5.3, 2.1, label=0, attributes={
'blur': '2', 'expression': '1', 'illumination': '0',
'occluded': '0', 'pose': '1', 'invalid': '0'}),
Bbox(0, 2, 3, 2, attributes={
Bbox(0, 2, 3, 2, label=0, attributes={
'occluded': 'False'}),
Bbox(0, 2, 4, 2),
Bbox(0, 7, 3, 2, attributes={
Bbox(0, 2, 4, 2, label=0),
Bbox(0, 7, 3, 2, label=0, attributes={
'blur': '2', 'expression': '1', 'illumination': '0',
'occluded': '0', 'pose': '1', 'invalid': '0'}),
]
),

DatasetItem(id='4', subset='val', image=np.ones((8, 8, 3))),
], categories={
AnnotationType.label: LabelCategories.from_iterable(
'label_' + str(i) for i in range(3)),
})
], categories=['face', 'label_0', 'label_1'])

with TestDir() as test_dir:
WiderFaceConverter.convert(source_dataset, test_dir, save_images=True)
Expand All @@ -73,10 +70,7 @@ def test_can_save_dataset_with_no_subsets(self):
'occluded': '0', 'pose': '2', 'invalid': '0'}),
]
),
], categories={
AnnotationType.label: LabelCategories.from_iterable(
'label_' + str(i) for i in range(3)),
})
], categories=['face', 'label_0', 'label_1'])

with TestDir() as test_dir:
WiderFaceConverter.convert(source_dataset, test_dir, save_images=True)
Expand All @@ -88,15 +82,12 @@ def test_can_save_dataset_with_cyrillic_and_spaces_in_filename(self):
source_dataset = Dataset.from_iterable([
DatasetItem(id='кириллица с пробелом', image=np.ones((8, 8, 3)),
annotations=[
Bbox(0, 1, 2, 3, label=1, attributes = {
Bbox(0, 1, 2, 3, label=0, attributes = {
'blur': '2', 'expression': '0', 'illumination': '0',
'occluded': '0', 'pose': '2', 'invalid': '0'}),
]
),
], categories={
AnnotationType.label: LabelCategories.from_iterable(
'label_' + str(i) for i in range(3)),
})
], categories=['face'])

with TestDir() as test_dir:
WiderFaceConverter.convert(source_dataset, test_dir, save_images=True)
Expand All @@ -109,26 +100,26 @@ def test_can_save_dataset_with_non_widerface_attributes(self):
source_dataset = Dataset.from_iterable([
DatasetItem(id='a/b/1', image=np.ones((8, 8, 3)),
annotations=[
Bbox(0, 2, 4, 2),
Bbox(0, 1, 2, 3, attributes={
Bbox(0, 2, 4, 2, label=0),
Bbox(0, 1, 2, 3, label=0, attributes={
'non-widerface attribute': '0',
'blur': 1, 'invalid': '1'}),
Bbox(1, 1, 2, 2, attributes={
Bbox(1, 1, 2, 2, label=0, attributes={
'non-widerface attribute': '0'}),
]
),
], categories=[])
], categories=['face'])

target_dataset = Dataset.from_iterable([
DatasetItem(id='a/b/1', image=np.ones((8, 8, 3)),
annotations=[
Bbox(0, 2, 4, 2),
Bbox(0, 1, 2, 3, attributes={
Bbox(0, 2, 4, 2, label=0),
Bbox(0, 1, 2, 3, label=0, attributes={
'blur': '1', 'invalid': '1'}),
Bbox(1, 1, 2, 2),
Bbox(1, 1, 2, 2, label=0),
]
),
], categories=[])
], categories=['face'])

with TestDir() as test_dir:
WiderFaceConverter.convert(source_dataset, test_dir, save_images=True)
Expand Down

0 comments on commit d549952

Please sign in to comment.