Skip to content

Commit 44f7beb

Browse files
committed
cli upload preannotations
1 parent fd4f6d9 commit 44f7beb

File tree

6 files changed

+255
-22
lines changed

6 files changed

+255
-22
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ clean:
2525
coverage: test_coverage
2626

2727
test_coverage:
28-
$(COVERAGE) run -m --source=./superannotate/ $(PYTESTS)
28+
$(COVERAGE) run -m --source=./superannotate/ $(PYTESTS) -n 8
2929
$(COVERAGE) html
3030
@echo "\033[95m\n\nCoverage successful! View the output at file://htmlcov/index.html.\n\033[0m"
3131

docs/source/cli.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,41 @@ default is 0.0.
8484
*end-time* specifies time (in seconds) up to which to extract frames.
8585
If it is not specified, then up to end is assumed.
8686

87+
----------
88+
89+
.. _ref_upload_preannotations:
90+
91+
Uploading preannotations
92+
~~~~~~~~~~~~~~~~~~~~~~~~
93+
94+
To upload preannotations from folder to project use:
95+
96+
.. code-block:: bash
97+
98+
superannotate upload-preannotations --project <project_name> --folder <folder_path>
99+
[--format "COCO" or "SA"]
100+
101+
102+
Optional argument *format* accepts input preannotation format. It can have COCO or SuperAnnotate values.
103+
If the argument is not given then SuperAnnotate (the native preannotation format) assumed.
104+
105+
----------
106+
107+
.. _ref_upload_annotations:
108+
109+
Uploading annotations
110+
~~~~~~~~~~~~~~~~~~~~~~~~
111+
112+
To upload annotations from folder to project use:
113+
114+
.. code-block:: bash
115+
116+
superannotate upload-preannotations --project <project_name> --folder <folder_path>
117+
[--recursive]
118+
119+
If optional argument *recursive* is given then subfolders of :file:`<folder_path>` are also recursively
120+
scanned for available preannotations.
121+
87122

88123
----------
89124

superannotate/__main__.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import sys
55
from pathlib import Path
6+
import tempfile
67

78
import superannotate as sa
89

@@ -47,6 +48,8 @@ def main():
4748
image_upload(further_args)
4849
elif command == "upload-videos":
4950
video_upload(further_args)
51+
elif command == "upload-preannotations":
52+
preannotations_upload(further_args)
5053
elif command == "init":
5154
ask_token(further_args)
5255
elif command == "export-project":
@@ -61,6 +64,70 @@ def _list_str(values):
6164
return values.split(',')
6265

6366

67+
def preannotations_upload(args):
68+
parser = argparse.ArgumentParser()
69+
parser.add_argument(
70+
'--project', required=True, help='Project name to upload'
71+
)
72+
parser.add_argument(
73+
'--folder',
74+
required=True,
75+
help=
76+
'Folder (SuperAnnotate format) or JSON path (COCO format) from which to upload'
77+
)
78+
parser.add_argument(
79+
'--format',
80+
required=False,
81+
default="SuperAnnotate",
82+
help='Input preannotations format.'
83+
)
84+
parser.add_argument(
85+
'--dataset-name',
86+
required=False,
87+
help='Input preannotations dataset name for COCO projects'
88+
)
89+
parser.add_argument(
90+
'--task',
91+
required=False,
92+
help=
93+
'Task type for COCO projects can be panoptic_segmentation (Pixel), instance_segmentation (Pixel), instance_segmentation (Vector), keypoint_detection (Vector)'
94+
)
95+
args = parser.parse_args(args)
96+
97+
if args.format != "SuperAnnotate":
98+
if args.format != "COCO":
99+
raise sa.SABaseException(
100+
0, "Not supported preannotations format " + args.format
101+
)
102+
if args.dataset_name is None:
103+
raise sa.SABaseException(
104+
0, "Dataset name should be present for COCO format upload."
105+
)
106+
if args.task is None:
107+
raise sa.SABaseException(
108+
0, "Task name should be present for COCO format upload."
109+
)
110+
logger.info("Preannotations in format %s.", args.format)
111+
project_type = sa.project_type_int_to_str(
112+
sa.get_project_metadata(args.project)["type"]
113+
)
114+
115+
tempdir = tempfile.TemporaryDirectory()
116+
tempdir_path = Path(tempdir.name)
117+
sa.import_annotation_format(
118+
args.folder, tempdir_path, "COCO", args.dataset_name, project_type,
119+
args.task
120+
)
121+
sa.create_annotation_classes_from_classes_json(
122+
args.project, tempdir_path / "classes" / "classes.json"
123+
)
124+
args.folder = tempdir_path
125+
126+
sa.upload_preannotations_from_folder_to_project(
127+
project=args.project, folder_path=args.folder
128+
)
129+
130+
64131
def video_upload(args):
65132
parser = argparse.ArgumentParser()
66133
parser.add_argument(

superannotate/input_converters/import_to_sa_conversions.py

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,28 +60,12 @@ def import_to_sa(args):
6060
# logging.error(log_msg)
6161
# sys.exit()
6262

63-
try:
64-
images, masks = _load_files(args.input_dir, args.project_type)
65-
except Exception as e:
66-
log_msg = "Can't load images or masks"
67-
logging.error(log_msg)
68-
logging.error(e)
69-
70-
try:
71-
_move_files(images, masks, args.output_dir, args.platform)
72-
except Exception as e:
73-
log_msg = 'Something went wrong while moving or copying files from source folder'
74-
logging.error(log_msg)
75-
logging.error(e)
63+
images, masks = _load_files(args.input_dir, args.project_type)
64+
_move_files(images, masks, args.output_dir, args.platform)
7665

7766
args.__dict__.update({'direction': 'from', 'export_root': args.input_dir})
7867
converter = Converter(args)
7968

80-
try:
81-
converter.convert_to_sa(args.platform)
82-
except Exception as e:
83-
log_msg = "Something went wrong while converting"
84-
logging.error(log_msg)
85-
sys.exit()
69+
converter.convert_to_sa(args.platform)
8670

8771
logging.info('Conversion completed successfully')

tests/test_preannotation_upload.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from pathlib import Path
2+
import subprocess
3+
import time
24

35
import pytest
46

57
import superannotate as sa
68

7-
sa.init(Path.home() / ".superannotate" / "config.json")
89

910

1011
@pytest.mark.parametrize(
@@ -16,7 +17,7 @@
1617
(
1718
"Pixel", "Example Project test pixel preannotation upload",
1819
"test pixel", Path("./tests/sample_project_pixel")
19-
),
20+
)
2021
]
2122
)
2223
def test_preannotation_folder_upload_download(
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from pathlib import Path
2+
import subprocess
3+
import time
4+
5+
import pytest
6+
7+
import superannotate as sa
8+
9+
10+
@pytest.mark.parametrize(
11+
"project_type,name,description,from_folder", [
12+
(
13+
"Vector", "Example Project test vector preannotation cli upload",
14+
"test vector", Path("./tests/sample_project_vector")
15+
),
16+
(
17+
"Pixel", "Example Project test pixel preannotation cli upload",
18+
"test pixel", Path("./tests/sample_project_pixel")
19+
)
20+
]
21+
)
22+
def test_preannotation_folder_upload_download_cli(
23+
project_type, name, description, from_folder, tmpdir
24+
):
25+
projects_found = sa.search_projects(name, return_metadata=True)
26+
for pr in projects_found:
27+
sa.delete_project(pr)
28+
29+
project = sa.create_project(name, description, project_type)
30+
sa.upload_images_from_folder_to_project(
31+
project, from_folder, annotation_status="InProgress"
32+
)
33+
sa.create_annotation_classes_from_classes_json(
34+
project, from_folder / "classes" / "classes.json"
35+
)
36+
subprocess.run(
37+
[
38+
f"superannotate upload-preannotations --project '{name}' --folder '{from_folder}'"
39+
],
40+
check=True,
41+
shell=True
42+
)
43+
time.sleep(5)
44+
count_in = len(list(from_folder.glob("*.json")))
45+
46+
images = sa.search_images(project)
47+
for image_name in images:
48+
sa.download_image_preannotations(project, image_name, tmpdir)
49+
50+
count_out = len(list(Path(tmpdir).glob("*.json")))
51+
52+
assert count_in == count_out
53+
54+
55+
def test_preannotation_folder_upload_download_cli_vector_COCO(tmpdir):
56+
project_type = "Vector"
57+
name = "Example Project test vector preannotation cli upload coco vector"
58+
description = "test"
59+
from_folder = "./tests/converter_test/COCO/input/toSuperAnnotate/keypoint_detection"
60+
task = "keypoint_detection"
61+
dataset_name = "person_keypoints_test"
62+
63+
projects_found = sa.search_projects(name, return_metadata=True)
64+
for pr in projects_found:
65+
sa.delete_project(pr)
66+
67+
project = sa.create_project(name, description, project_type)
68+
sa.upload_images_from_folder_to_project(
69+
project, from_folder, annotation_status="InProgress"
70+
)
71+
# sa.create_annotation_classes_from_classes_json(
72+
# project, from_folder / "classes" / "classes.json"
73+
# )
74+
subprocess.run(
75+
[
76+
f"superannotate upload-preannotations --project '{name}' --folder '{from_folder}' --format COCO --task {task} --dataset-name {dataset_name}"
77+
],
78+
check=True,
79+
shell=True
80+
)
81+
# time.sleep(5)
82+
# count_in = len(list(from_folder.glob("*.json")))
83+
84+
# images = sa.search_images(project)
85+
# for image_name in images:
86+
# sa.download_image_preannotations(project, image_name, tmpdir)
87+
88+
# count_out = len(list(Path(tmpdir).glob("*.json")))
89+
90+
# assert count_in == count_out
91+
92+
93+
def test_preannotation_folder_upload_download_cli_vector_object_COCO(tmpdir):
94+
project_type = "Vector"
95+
name = "Example Project test vector preannotation cli upload coco object vector"
96+
description = "test"
97+
from_folder = "./tests/converter_test/COCO/input/toSuperAnnotate/instance_segmentation"
98+
task = "instance_segmentation"
99+
dataset_name = "instances_test"
100+
101+
projects_found = sa.search_projects(name, return_metadata=True)
102+
for pr in projects_found:
103+
sa.delete_project(pr)
104+
105+
project = sa.create_project(name, description, project_type)
106+
sa.upload_images_from_folder_to_project(
107+
project, from_folder, annotation_status="InProgress"
108+
)
109+
# sa.create_annotation_classes_from_classes_json(
110+
# project, from_folder / "classes" / "classes.json"
111+
# )
112+
subprocess.run(
113+
[
114+
f"superannotate upload-preannotations --project '{name}' --folder '{from_folder}' --format COCO --task {task} --dataset-name {dataset_name}"
115+
],
116+
check=True,
117+
shell=True
118+
)
119+
120+
121+
def test_preannotation_folder_upload_download_cli_pixel_object_COCO(tmpdir):
122+
project_type = "Pixel"
123+
name = "Example Project test pixel preannotation cli upload coco object pixel"
124+
description = "test"
125+
from_folder = "./tests/converter_test/COCO/input/toSuperAnnotate/panoptic_segmentation"
126+
task = "panoptic_segmentation"
127+
dataset_name = "panoptic_test"
128+
129+
projects_found = sa.search_projects(name, return_metadata=True)
130+
for pr in projects_found:
131+
sa.delete_project(pr)
132+
133+
project = sa.create_project(name, description, project_type)
134+
sa.upload_images_from_folder_to_project(
135+
project, from_folder, annotation_status="InProgress"
136+
)
137+
# sa.create_annotation_classes_from_classes_json(
138+
# project, from_folder / "classes" / "classes.json"
139+
# )
140+
subprocess.run(
141+
[
142+
f"superannotate upload-preannotations --project '{name}' --folder '{from_folder}' --format COCO --task {task} --dataset-name {dataset_name}"
143+
],
144+
check=True,
145+
shell=True
146+
)

0 commit comments

Comments
 (0)