Don't export outside annotations (#1729)

* Add option to omit outside annotations

* update changelog

* Fix mot format and test

* Fix outside in mot

* fix repo problem

* t

* Update CHANGELOG.md

Co-authored-by: Nikita Manovich <40690625+nmanovic@users.noreply.github.com>
main
zhiltsov-max 6 years ago committed by GitHub
parent 18f6b2f95d
commit fc2fb6156a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Some objects aren't shown on canvas sometimes. For example after propagation on of objects is invisible (<https://github.com/opencv/cvat/pull/1834>)
- `outside` annotations should not be in exported images (<https://github.com/opencv/cvat/issues/1620>)
### Security
-

@ -442,9 +442,10 @@ class TaskData:
return None
class CvatTaskDataExtractor(datumaro.SourceExtractor):
def __init__(self, task_data, include_images=False):
def __init__(self, task_data, include_images=False, include_outside=False):
super().__init__()
self._categories = self._load_categories(task_data)
self._include_outside = include_outside
dm_items = []
@ -541,6 +542,9 @@ class CvatTaskDataExtractor(datumaro.SourceExtractor):
anno_attr['track_id'] = shape_obj.track_id
anno_attr['keyframe'] = shape_obj.keyframe
if not self._include_outside and shape_obj.outside:
continue
anno_points = shape_obj.points
if shape_obj.type == ShapeType.POINTS:
anno = datumaro.Points(anno_points,

@ -63,7 +63,7 @@ def _import(src_file, task_data):
points=ann.points,
occluded=ann.attributes.get('occluded') == True,
outside=False,
keyframe=False,
keyframe=True,
z_order=ann.z_order,
frame=frame_number,
attributes=[],
@ -78,6 +78,11 @@ def _import(src_file, task_data):
for track in tracks.values():
# MOT annotations do not require frames to be ordered
track.shapes.sort(key=lambda t: t.frame)
# Set outside=True for the last shape in a track to finish the track
track.shapes[-1] = track.shapes[-1]._replace(outside=True)
# Append a shape with outside=True to finish the track
last_shape = track.shapes[-1]
if last_shape.frame + task_data.frame_step <= \
int(task_data.meta['task']['stop_frame']):
track.shapes.append(last_shape._replace(outside=True,
frame=last_shape.frame + task_data.frame_step)
)
task_data.add_track(track)

@ -77,7 +77,8 @@ from cvat.apps.engine.models import Task
_setUpModule()
from cvat.apps.dataset_manager.annotation import AnnotationIR
from cvat.apps.dataset_manager.bindings import TaskData
from cvat.apps.dataset_manager.bindings import TaskData, CvatTaskDataExtractor
from cvat.apps.dataset_manager.task import TaskAnnotation
from cvat.apps.engine.models import Task
@ -406,6 +407,22 @@ class TaskExportTest(_DbTestBase):
self.assertEqual(len(dataset), task["size"])
self._test_export(check, task, format_name, save_images=False)
def test_can_skip_outside(self):
images = self._generate_task_images(3)
task = self._generate_task(images)
self._generate_annotations(task)
task_ann = TaskAnnotation(task["id"])
task_ann.init_from_db()
task_data = TaskData(task_ann.ir_data, Task.objects.get(pk=task["id"]))
extractor = CvatTaskDataExtractor(task_data, include_outside=False)
dm_dataset = datumaro.components.project.Dataset.from_extractors(extractor)
self.assertEqual(4, len(dm_dataset.get("image_1").annotations))
extractor = CvatTaskDataExtractor(task_data, include_outside=True)
dm_dataset = datumaro.components.project.Dataset.from_extractors(extractor)
self.assertEqual(5, len(dm_dataset.get("image_1").annotations))
def test_cant_make_rel_frame_id_from_unknown(self):
images = self._generate_task_images(3)
images['frame_filter'] = 'step=2'

@ -2965,6 +2965,19 @@ class TaskAnnotationAPITestCase(JobAnnotationAPITestCase):
"points": [2.0, 2.1, 77.2, 36.22],
"type": "rectangle",
"occluded": True,
"outside": False,
"attributes": [
{
"spec_id": task["labels"][0]["attributes"][1]["id"],
"value": task["labels"][0]["attributes"][1]["default_value"]
}
]
},
{
"frame": 2,
"points": [2.0, 2.1, 77.2, 36.22],
"type": "rectangle",
"occluded": True,
"outside": True,
"attributes": [
{
@ -2976,19 +2989,27 @@ class TaskAnnotationAPITestCase(JobAnnotationAPITestCase):
]
}]
rectangle_tracks_wo_attrs = [{
"frame": 1,
"frame": 0,
"label_id": task["labels"][1]["id"],
"group": 0,
"attributes": [],
"shapes": [
{
"frame": 1,
"frame": 0,
"attributes": [],
"points": [1.0, 2.1, 50.2, 36.6],
"type": "rectangle",
"occluded": False,
"outside": False
},
{
"frame": 1,
"attributes": [],
"points": [1.0, 2.1, 51, 36.6],
"type": "rectangle",
"occluded": False,
"outside": False
},
{
"frame": 2,
"attributes": [],

@ -104,7 +104,7 @@ class GitWrapper:
def __init__(self, config=None):
self.repo = None
if config is not None and osp.isdir(config.project_dir):
if config is not None and config.project_dir:
self.init(config.project_dir)
@staticmethod
@ -116,8 +116,12 @@ class GitWrapper:
spawn = not osp.isdir(cls._git_dir(path))
repo = git.Repo.init(path=path)
if spawn:
author = git.Actor("Nobody", "nobody@example.com")
repo.index.commit('Initial commit', author=author)
repo.config_writer().set_value("user", "name", "User") \
.set_value("user", "email", "user@nowhere.com") \
.release()
# gitpython does not support init, use git directly
repo.git.init()
repo.git.commit('-m', 'Initial commit', '--allow-empty')
return repo
def init(self, path):
@ -377,9 +381,10 @@ class Dataset(Extractor):
def get(self, item_id, subset=None, path=None):
if path:
raise KeyError("Requested dataset item path is not found")
if subset is None:
subset = ''
return self._subsets[subset].items[item_id]
item_id = str(item_id)
subset = subset or ''
subset = self._subsets[subset]
return subset.items[item_id]
def put(self, item, item_id=None, subset=None, path=None):
if path:
@ -567,7 +572,7 @@ class ProjectDataset(Dataset):
rest_path = path[1:]
return self._sources[source].get(
item_id=item_id, subset=subset, path=rest_path)
return self._subsets[subset].items[item_id]
return super().get(item_id, subset)
def put(self, item, item_id=None, subset=None, path=None):
if path is None:
@ -754,9 +759,10 @@ class Project:
@staticmethod
def generate(save_dir, config=None):
config = Config(config)
config.project_dir = save_dir
project = Project(config)
project.save(save_dir)
project.config.project_dir = save_dir
return project
@staticmethod

Loading…
Cancel
Save