Use z_order as a class property (#1589)

* Use z_order as a class property

* Fix z_order use in voc

* Update changelog
main
zhiltsov-max 6 years ago committed by GitHub
parent 485bc8d91a
commit e2dedb2f83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -56,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Synchronization with remote git repo (<https://github.com/opencv/cvat/pull/1582>) - Synchronization with remote git repo (<https://github.com/opencv/cvat/pull/1582>)
- A problem with mask to polygons conversion when polygons are too small (<https://github.com/opencv/cvat/pull/1581>) - A problem with mask to polygons conversion when polygons are too small (<https://github.com/opencv/cvat/pull/1581>)
- Unable to upload video with uneven size (<https://github.com/opencv/cvat/pull/1594>) - Unable to upload video with uneven size (<https://github.com/opencv/cvat/pull/1594>)
- Fixed an issue with `z_order` having no effect on segmentations (<https://github.com/opencv/cvat/pull/1589>)
### Security ### Security
- -

@ -498,7 +498,6 @@ class CvatTaskDataExtractor(datumaro.SourceExtractor):
anno_label = map_label(shape_obj.label) anno_label = map_label(shape_obj.label)
anno_attr = convert_attrs(shape_obj.label, shape_obj.attributes) anno_attr = convert_attrs(shape_obj.label, shape_obj.attributes)
anno_attr['occluded'] = shape_obj.occluded anno_attr['occluded'] = shape_obj.occluded
anno_attr['z_order'] = shape_obj.z_order
if hasattr(shape_obj, 'track_id'): if hasattr(shape_obj, 'track_id'):
anno_attr['track_id'] = shape_obj.track_id anno_attr['track_id'] = shape_obj.track_id
@ -507,17 +506,21 @@ class CvatTaskDataExtractor(datumaro.SourceExtractor):
anno_points = shape_obj.points anno_points = shape_obj.points
if shape_obj.type == ShapeType.POINTS: if shape_obj.type == ShapeType.POINTS:
anno = datumaro.Points(anno_points, anno = datumaro.Points(anno_points,
label=anno_label, attributes=anno_attr, group=anno_group) label=anno_label, attributes=anno_attr, group=anno_group,
z_order=shape_obj.z_order)
elif shape_obj.type == ShapeType.POLYLINE: elif shape_obj.type == ShapeType.POLYLINE:
anno = datumaro.PolyLine(anno_points, anno = datumaro.PolyLine(anno_points,
label=anno_label, attributes=anno_attr, group=anno_group) label=anno_label, attributes=anno_attr, group=anno_group,
z_order=shape_obj.z_order)
elif shape_obj.type == ShapeType.POLYGON: elif shape_obj.type == ShapeType.POLYGON:
anno = datumaro.Polygon(anno_points, anno = datumaro.Polygon(anno_points,
label=anno_label, attributes=anno_attr, group=anno_group) label=anno_label, attributes=anno_attr, group=anno_group,
z_order=shape_obj.z_order)
elif shape_obj.type == ShapeType.RECTANGLE: elif shape_obj.type == ShapeType.RECTANGLE:
x0, y0, x1, y1 = anno_points x0, y0, x1, y1 = anno_points
anno = datumaro.Bbox(x0, y0, x1 - x0, y1 - y0, anno = datumaro.Bbox(x0, y0, x1 - x0, y1 - y0,
label=anno_label, attributes=anno_attr, group=anno_group) label=anno_label, attributes=anno_attr, group=anno_group,
z_order=shape_obj.z_order)
elif shape_obj.type == ShapeType.CUBOID: elif shape_obj.type == ShapeType.CUBOID:
continue # Datumaro does not support cuboids continue # Datumaro does not support cuboids
else: else:
@ -590,6 +593,7 @@ def import_dm_annotations(dm_dataset, task_data):
label=label_cat.items[ann.label].name, label=label_cat.items[ann.label].name,
points=ann.points, points=ann.points,
occluded=ann.attributes.get('occluded') == True, occluded=ann.attributes.get('occluded') == True,
z_order=ann.z_order,
group=group_map.get(ann.group, 0), group=group_map.get(ann.group, 0),
attributes=[task_data.Attribute(name=n, value=str(v)) attributes=[task_data.Attribute(name=n, value=str(v))
for n, v in ann.attributes.items()], for n, v in ann.attributes.items()],

@ -270,21 +270,22 @@ class CompiledMask:
if instance_ids is not None: if instance_ids is not None:
assert len(instance_ids) == len(instance_masks) assert len(instance_ids) == len(instance_masks)
else: else:
instance_ids = range(1, len(instance_masks) + 1) instance_ids = [None] * len(instance_masks)
if instance_labels is not None: if instance_labels is not None:
assert len(instance_labels) == len(instance_masks) assert len(instance_labels) == len(instance_masks)
else: else:
instance_labels = [None] * len(instance_masks) instance_labels = [None] * len(instance_masks)
instance_masks = sorted(instance_masks, key=lambda m: m.z_order) instance_masks = sorted(
zip(instance_masks, instance_ids, instance_labels),
key=lambda m: m[0].z_order)
instance_mask = [m.as_instance_mask(id) for m, id in instance_mask = [m.as_instance_mask(id if id is not None else 1 + idx)
zip(instance_masks, instance_ids)] for idx, (m, id, _) in enumerate(instance_masks)]
instance_mask = merge_masks(instance_mask) instance_mask = merge_masks(instance_mask)
cls_mask = [m.as_class_mask(c) for m, c in cls_mask = [m.as_class_mask(c) for m, _, c in instance_masks]
zip(instance_masks, instance_labels)]
cls_mask = merge_masks(cls_mask) cls_mask = merge_masks(cls_mask)
return __class__(class_mask=cls_mask, instance_mask=instance_mask) return __class__(class_mask=cls_mask, instance_mask=instance_mask)

@ -271,7 +271,7 @@ class _SubsetWriter:
)), )),
])) ]))
shape_data['z_order'] = str(int(shape.attributes.get('z_order', 0))) shape_data['z_order'] = str(int(shape.z_order))
if shape.group: if shape.group:
shape_data['group_id'] = str(shape.group) shape_data['group_id'] = str(shape.group)

@ -238,8 +238,6 @@ class CvatExtractor(SourceExtractor):
"Expected 'meta' section in the annotation file, path: %s" % states "Expected 'meta' section in the annotation file, path: %s" % states
common_attrs = ['occluded'] common_attrs = ['occluded']
if has_z_order:
common_attrs.append('z_order')
if mode == 'interpolation': if mode == 'interpolation':
common_attrs.append('keyframe') common_attrs.append('keyframe')
common_attrs.append('outside') common_attrs.append('outside')
@ -260,8 +258,6 @@ class CvatExtractor(SourceExtractor):
attributes = ann.get('attributes', {}) attributes = ann.get('attributes', {})
if 'occluded' in categories[AnnotationType.label].attributes: if 'occluded' in categories[AnnotationType.label].attributes:
attributes['occluded'] = ann.get('occluded', False) attributes['occluded'] = ann.get('occluded', False)
if 'z_order' in categories[AnnotationType.label].attributes:
attributes['z_order'] = ann.get('z_order', 0)
if 'outside' in categories[AnnotationType.label].attributes: if 'outside' in categories[AnnotationType.label].attributes:
attributes['outside'] = ann.get('outside', False) attributes['outside'] = ann.get('outside', False)
if 'keyframe' in categories[AnnotationType.label].attributes: if 'keyframe' in categories[AnnotationType.label].attributes:
@ -272,24 +268,25 @@ class CvatExtractor(SourceExtractor):
label = ann.get('label') label = ann.get('label')
label_id = categories[AnnotationType.label].find(label)[0] label_id = categories[AnnotationType.label].find(label)[0]
z_order = ann.get('z_order', 0)
points = ann.get('points', []) points = ann.get('points', [])
if ann_type == 'polyline': if ann_type == 'polyline':
return PolyLine(points, label=label_id, return PolyLine(points, label=label_id, z_order=z_order,
id=ann_id, attributes=attributes, group=group) id=ann_id, attributes=attributes, group=group)
elif ann_type == 'polygon': elif ann_type == 'polygon':
return Polygon(points, label=label_id, return Polygon(points, label=label_id, z_order=z_order,
id=ann_id, attributes=attributes, group=group) id=ann_id, attributes=attributes, group=group)
elif ann_type == 'points': elif ann_type == 'points':
return Points(points, label=label_id, return Points(points, label=label_id, z_order=z_order,
id=ann_id, attributes=attributes, group=group) id=ann_id, attributes=attributes, group=group)
elif ann_type == 'box': elif ann_type == 'box':
x, y = points[0], points[1] x, y = points[0], points[1]
w, h = points[2] - x, points[3] - y w, h = points[2] - x, points[3] - y
return Bbox(x, y, w, h, label=label_id, return Bbox(x, y, w, h, label=label_id, z_order=z_order,
id=ann_id, attributes=attributes, group=group) id=ann_id, attributes=attributes, group=group)
else: else:

@ -12,7 +12,7 @@ import os.path as osp
from datumaro.components.converter import Converter from datumaro.components.converter import Converter
from datumaro.components.extractor import ( from datumaro.components.extractor import (
DEFAULT_SUBSET_NAME, Annotation, DEFAULT_SUBSET_NAME, Annotation, _Shape,
Label, Mask, RleMask, Points, Polygon, PolyLine, Bbox, Caption, Label, Mask, RleMask, Points, Polygon, PolyLine, Bbox, Caption,
LabelCategories, MaskCategories, PointsCategories LabelCategories, MaskCategories, PointsCategories
) )
@ -131,43 +131,38 @@ class _SubsetWriter:
# serialize as compressed COCO mask # serialize as compressed COCO mask
'counts': rle['counts'].decode('ascii'), 'counts': rle['counts'].decode('ascii'),
'size': list(int(c) for c in rle['size']), 'size': list(int(c) for c in rle['size']),
} },
'z_order': obj.z_order,
}) })
return converted return converted
def _convert_polyline_object(self, obj): def _convert_shape_object(self, obj):
assert isinstance(obj, _Shape)
converted = self._convert_annotation(obj) converted = self._convert_annotation(obj)
converted.update({ converted.update({
'label_id': cast(obj.label, int), 'label_id': cast(obj.label, int),
'points': [float(p) for p in obj.points], 'points': [float(p) for p in obj.points],
'z_order': obj.z_order,
}) })
return converted return converted
def _convert_polygon_object(self, obj): def _convert_polyline_object(self, obj):
converted = self._convert_annotation(obj) return self._convert_shape_object(obj)
converted.update({ def _convert_polygon_object(self, obj):
'label_id': cast(obj.label, int), return self._convert_shape_object(obj)
'points': [float(p) for p in obj.points],
})
return converted
def _convert_bbox_object(self, obj): def _convert_bbox_object(self, obj):
converted = self._convert_annotation(obj) converted = self._convert_shape_object(obj)
converted.pop('points', None)
converted.update({ converted['bbox'] = [float(p) for p in obj.get_bbox()]
'label_id': cast(obj.label, int),
'bbox': [float(p) for p in obj.get_bbox()],
})
return converted return converted
def _convert_points_object(self, obj): def _convert_points_object(self, obj):
converted = self._convert_annotation(obj) converted = self._convert_shape_object(obj)
converted.update({ converted.update({
'label_id': cast(obj.label, int),
'points': [float(p) for p in obj.points],
'visibility': [int(v.value) for v in obj.visibility], 'visibility': [int(v.value) for v in obj.visibility],
}) })
return converted return converted

@ -107,41 +107,41 @@ class DatumaroExtractor(SourceExtractor):
attributes = ann.get('attributes') attributes = ann.get('attributes')
group = ann.get('group') group = ann.get('group')
label_id = ann.get('label_id')
z_order = ann.get('z_order')
points = ann.get('points')
if ann_type == AnnotationType.label: if ann_type == AnnotationType.label:
label_id = ann.get('label_id')
loaded.append(Label(label=label_id, loaded.append(Label(label=label_id,
id=ann_id, attributes=attributes, group=group)) id=ann_id, attributes=attributes, group=group))
elif ann_type == AnnotationType.mask: elif ann_type == AnnotationType.mask:
label_id = ann.get('label_id')
rle = ann['rle'] rle = ann['rle']
rle['counts'] = rle['counts'].encode('ascii') rle['counts'] = rle['counts'].encode('ascii')
loaded.append(RleMask(rle=rle, label=label_id, loaded.append(RleMask(rle=rle, label=label_id,
id=ann_id, attributes=attributes, group=group)) id=ann_id, attributes=attributes, group=group,
z_order=z_order))
elif ann_type == AnnotationType.polyline: elif ann_type == AnnotationType.polyline:
label_id = ann.get('label_id')
points = ann.get('points')
loaded.append(PolyLine(points, label=label_id, loaded.append(PolyLine(points, label=label_id,
id=ann_id, attributes=attributes, group=group)) id=ann_id, attributes=attributes, group=group,
z_order=z_order))
elif ann_type == AnnotationType.polygon: elif ann_type == AnnotationType.polygon:
label_id = ann.get('label_id')
points = ann.get('points')
loaded.append(Polygon(points, label=label_id, loaded.append(Polygon(points, label=label_id,
id=ann_id, attributes=attributes, group=group)) id=ann_id, attributes=attributes, group=group,
z_order=z_order))
elif ann_type == AnnotationType.bbox: elif ann_type == AnnotationType.bbox:
label_id = ann.get('label_id') x, y, w, h = ann['bbox']
x, y, w, h = ann.get('bbox')
loaded.append(Bbox(x, y, w, h, label=label_id, loaded.append(Bbox(x, y, w, h, label=label_id,
id=ann_id, attributes=attributes, group=group)) id=ann_id, attributes=attributes, group=group,
z_order=z_order))
elif ann_type == AnnotationType.points: elif ann_type == AnnotationType.points:
label_id = ann.get('label_id')
points = ann.get('points')
loaded.append(Points(points, label=label_id, loaded.append(Points(points, label=label_id,
id=ann_id, attributes=attributes, group=group)) id=ann_id, attributes=attributes, group=group,
z_order=z_order))
elif ann_type == AnnotationType.caption: elif ann_type == AnnotationType.caption:
caption = ann.get('caption') caption = ann.get('caption')

@ -110,20 +110,20 @@ class CvatExtractorTest(TestCase):
return iter([ return iter([
DatasetItem(id=0, subset='train', image=np.ones((8, 8, 3)), DatasetItem(id=0, subset='train', image=np.ones((8, 8, 3)),
annotations=[ annotations=[
Bbox(0, 2, 4, 2, label=0, Bbox(0, 2, 4, 2, label=0, z_order=1,
attributes={ attributes={
'occluded': True, 'z_order': 1, 'occluded': True,
'a1': True, 'a2': 'v3' 'a1': True, 'a2': 'v3'
}), }),
PolyLine([1, 2, 3, 4, 5, 6, 7, 8], PolyLine([1, 2, 3, 4, 5, 6, 7, 8], z_order=0,
attributes={'occluded': False, 'z_order': 0}), attributes={'occluded': False}),
]), ]),
DatasetItem(id=1, subset='train', image=np.ones((10, 10, 3)), DatasetItem(id=1, subset='train', image=np.ones((10, 10, 3)),
annotations=[ annotations=[
Polygon([1, 2, 3, 4, 6, 5], Polygon([1, 2, 3, 4, 6, 5], z_order=1,
attributes={'occluded': False, 'z_order': 1}), attributes={'occluded': False}),
Points([1, 2, 3, 4, 5, 6], label=1, Points([1, 2, 3, 4, 5, 6], label=1, z_order=2,
attributes={'occluded': False, 'z_order': 2}), attributes={'occluded': False}),
]), ]),
]) ])
@ -163,7 +163,7 @@ class CvatConverterTest(TestCase):
for i in range(10): for i in range(10):
label_categories.add(str(i)) label_categories.add(str(i))
label_categories.items[2].attributes.update(['a1', 'a2']) label_categories.items[2].attributes.update(['a1', 'a2'])
label_categories.attributes.update(['z_order', 'occluded']) label_categories.attributes.update(['occluded'])
class SrcExtractor(Extractor): class SrcExtractor(Extractor):
def __iter__(self): def __iter__(self):
@ -194,9 +194,9 @@ class CvatConverterTest(TestCase):
DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)), DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)),
annotations=[ annotations=[
Polygon([0, 0, 4, 0, 4, 4], Polygon([0, 0, 4, 0, 4, 4], z_order=1,
label=3, group=4, label=3, group=4,
attributes={ 'z_order': 1, 'occluded': False }), attributes={ 'occluded': False }),
PolyLine([5, 0, 9, 0, 5, 5]), # will be skipped as no label PolyLine([5, 0, 9, 0, 5, 5]), # will be skipped as no label
] ]
), ),
@ -213,15 +213,15 @@ class CvatConverterTest(TestCase):
return iter([ return iter([
DatasetItem(id=0, subset='s1', image=np.zeros((5, 10, 3)), DatasetItem(id=0, subset='s1', image=np.zeros((5, 10, 3)),
annotations=[ annotations=[
Polygon([0, 0, 4, 0, 4, 4], Polygon([0, 0, 4, 0, 4, 4], z_order=0,
label=1, group=4, label=1, group=4,
attributes={ 'z_order': 0, 'occluded': True }), attributes={ 'occluded': True }),
Polygon([5, 0, 9, 0, 5, 5], Polygon([5, 0, 9, 0, 5, 5], z_order=0,
label=2, group=4, label=2, group=4,
attributes={ 'z_order': 0, 'occluded': False }), attributes={ 'occluded': False }),
Points([1, 1, 3, 2, 2, 3], Points([1, 1, 3, 2, 2, 3], z_order=0,
label=2, label=2,
attributes={ 'z_order': 0, 'occluded': False, attributes={ 'occluded': False,
'a1': 'x', 'a2': 42 }), 'a1': 'x', 'a2': 42 }),
Label(1), Label(1),
Label(2, attributes={ 'a1': 'y', 'a2': 44 }), Label(2, attributes={ 'a1': 'y', 'a2': 44 }),
@ -229,20 +229,20 @@ class CvatConverterTest(TestCase):
), ),
DatasetItem(id=1, subset='s1', DatasetItem(id=1, subset='s1',
annotations=[ annotations=[
PolyLine([0, 0, 4, 0, 4, 4], PolyLine([0, 0, 4, 0, 4, 4], z_order=0,
label=3, group=4, label=3, group=4,
attributes={ 'z_order': 0, 'occluded': False }), attributes={ 'occluded': False }),
Bbox(5, 0, 1, 9, Bbox(5, 0, 1, 9, z_order=0,
label=3, group=4, label=3, group=4,
attributes={ 'z_order': 0, 'occluded': False }), attributes={ 'occluded': False }),
] ]
), ),
DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)), DatasetItem(id=2, subset='s2', image=np.ones((5, 10, 3)),
annotations=[ annotations=[
Polygon([0, 0, 4, 0, 4, 4], Polygon([0, 0, 4, 0, 4, 4], z_order=1,
label=3, group=4, label=3, group=4,
attributes={ 'z_order': 1, 'occluded': False }), attributes={ 'occluded': False }),
] ]
), ),

@ -27,12 +27,12 @@ class DatumaroConverterTest(TestCase):
'x': 1, 'x': 1,
'y': '2', 'y': '2',
}), }),
Bbox(1, 2, 3, 4, label=4, id=4, attributes={ Bbox(1, 2, 3, 4, label=4, id=4, z_order=1, attributes={
'score': 1.0, 'score': 1.0,
}), }),
Bbox(5, 6, 7, 8, id=5, group=5), Bbox(5, 6, 7, 8, id=5, group=5),
Points([1, 2, 2, 0, 1, 1], label=0, id=5), Points([1, 2, 2, 0, 1, 1], label=0, id=5, z_order=4),
Mask(label=3, id=5, image=np.ones((2, 3))), Mask(label=3, id=5, z_order=2, image=np.ones((2, 3))),
]), ]),
DatasetItem(id=21, subset='train', DatasetItem(id=21, subset='train',
annotations=[ annotations=[
@ -43,8 +43,8 @@ class DatumaroConverterTest(TestCase):
DatasetItem(id=2, subset='val', DatasetItem(id=2, subset='val',
annotations=[ annotations=[
PolyLine([1, 2, 3, 4, 5, 6, 7, 8], id=11), PolyLine([1, 2, 3, 4, 5, 6, 7, 8], id=11, z_order=1),
Polygon([1, 2, 3, 4, 5, 6, 7, 8], id=12), Polygon([1, 2, 3, 4, 5, 6, 7, 8], id=12, z_order=4),
]), ]),
DatasetItem(id=42, subset='test'), DatasetItem(id=42, subset='test'),

@ -417,12 +417,12 @@ class VocConverterTest(TestCase):
DatasetItem(id=1, subset='a', annotations=[ DatasetItem(id=1, subset='a', annotations=[
# overlapping masks, the first should be truncated # overlapping masks, the first should be truncated
# the second and third are different instances # the second and third are different instances
Mask(image=np.array([[0, 0, 0, 1, 0]]), label=3,
z_order=3),
Mask(image=np.array([[0, 1, 1, 1, 0]]), label=4, Mask(image=np.array([[0, 1, 1, 1, 0]]), label=4,
z_order=1), z_order=1),
Mask(image=np.array([[1, 1, 0, 0, 0]]), label=3, Mask(image=np.array([[1, 1, 0, 0, 0]]), label=3,
z_order=2), z_order=2),
Mask(image=np.array([[0, 0, 0, 1, 0]]), label=3,
z_order=2),
]), ]),
]) ])
@ -451,12 +451,12 @@ class VocConverterTest(TestCase):
DatasetItem(id=1, subset='a', annotations=[ DatasetItem(id=1, subset='a', annotations=[
# overlapping masks, the first should be truncated # overlapping masks, the first should be truncated
# the second and third are different instances # the second and third are different instances
Mask(image=np.array([[0, 0, 0, 1, 0]]), label=3,
z_order=3),
Mask(image=np.array([[0, 1, 1, 1, 0]]), label=4, Mask(image=np.array([[0, 1, 1, 1, 0]]), label=4,
z_order=1), z_order=1),
Mask(image=np.array([[1, 1, 0, 0, 0]]), label=3, Mask(image=np.array([[1, 1, 0, 0, 0]]), label=3,
z_order=2), z_order=2),
Mask(image=np.array([[0, 0, 0, 1, 0]]), label=3,
z_order=2),
]), ]),
]) ])

Loading…
Cancel
Save