Skip to content

Commit 7b6122c

Browse files
authored
Merge pull request #37 from superannotateai/SAS-3383
Fix multi template coco conversion SAS-3383 - SAS-3401
2 parents 7b6c348 + da56c12 commit 7b6122c

File tree

9 files changed

+324
-10
lines changed

9 files changed

+324
-10
lines changed

superannotate/db/annotation_classes.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
)
1313
from .project_api import get_project_metadata_bare
1414
from ..mixp.decorators import Trackable
15+
from .utils import get_templates_mapping
1516

1617
logger = logging.getLogger("superannotate-python-sdk")
1718

@@ -344,7 +345,11 @@ def fill_class_and_attribute_ids(annotation_json, annotation_classes_dict):
344345
'attribute_groups': {}
345346
}
346347
annotation_classes_dict = {**annotation_classes_dict, **unknown_classes}
347-
348+
templates_map = get_templates_mapping()
349+
for ann in (
350+
i for i in annotation_json["instances"] if i['type'] == 'template'
351+
):
352+
ann['templateId'] = templates_map.get(ann['templateName'], -1)
348353
for ann in annotation_json["instances"]:
349354
if "className" not in ann:
350355
logger.warning("No className in annotation instance")

superannotate/db/utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,3 +747,19 @@ def __attach_image_urls_to_project_thread(
747747
logger.warning(e)
748748
else:
749749
uploaded[thread_id] += uploaded_imgs
750+
751+
752+
def get_templates_mapping():
753+
response = _api.send_request(
754+
req_type='GET', path=f'/templates', params={"team_id": _api.team_id}
755+
)
756+
if not response.ok:
757+
raise SABaseException(
758+
response.status_code, "Couldn't get templates " + response.text
759+
)
760+
res = response.json()
761+
templates = res['data']
762+
templates_map = {}
763+
for template in templates:
764+
templates_map[template['name']] = template['id']
765+
return templates_map

superannotate/input_converters/converters/coco_converters/coco_to_sa_vector.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ def coco_keypoint_detection_to_sa_vector(coco_path, output_dir):
171171
cat_id_to_cat[cat["id"]] = {
172172
"name": cat["name"],
173173
"keypoints": cat["keypoints"],
174-
"skeleton": cat["skeleton"]
174+
"skeleton": cat["skeleton"],
175+
"supercategory": cat["supercategory"]
175176
}
176177

177178
image_id_to_annotations = {}
@@ -218,11 +219,8 @@ def coco_keypoint_detection_to_sa_vector(coco_path, output_dir):
218219
for connection in cat_id_to_cat[annot["category_id"]
219220
]['skeleton']:
220221

221-
index = cat['skeleton'].index(connection)
222-
from_point = cat_id_to_cat[annot["category_id"]
223-
]['skeleton'][index][0]
224-
to_point = cat_id_to_cat[annot["category_id"]
225-
]['skeleton'][index][1]
222+
from_point = connection[0]
223+
to_point = connection[1]
226224

227225
if from_point in bad_points or to_point in bad_points:
228226
continue
@@ -242,8 +240,12 @@ def coco_keypoint_detection_to_sa_vector(coco_path, output_dir):
242240
pointLabels[id_mapping[kp_index + 1] - 1] = kp_name
243241

244242
sa_obj = _create_vector_instance(
245-
'template', points, pointLabels, [],
246-
cat_id_to_cat[annot["category_id"]]["name"], connections
243+
'template',
244+
points,
245+
pointLabels, [],
246+
cat_id_to_cat[annot["category_id"]]["supercategory"],
247+
connections,
248+
template_name=cat_id_to_cat[annot["category_id"]]["name"]
247249
)
248250
if str(annot['image_id']) not in image_id_to_annotations:
249251
image_id_to_annotations[str(annot['image_id'])] = [sa_obj]

superannotate/input_converters/converters/sa_json_helper.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ def _create_vector_instance(
88
pointLabels,
99
attributes,
1010
class_name='',
11-
connections=[]
11+
connections=[],
12+
template_name=''
1213
):
1314
sa_instance = {
1415
'type': instance_type,
@@ -20,6 +21,8 @@ def _create_vector_instance(
2021
if instance_type == 'template':
2122
sa_instance['points'] = points
2223
sa_instance['connections'] = connections
24+
sa_instance['className'] = class_name
25+
sa_instance['templateName'] = template_name
2326
elif instance_type == 'point':
2427
sa_instance['x'] = points[0]
2528
sa_instance['y'] = points[1]
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
{
2+
"info": {
3+
"description": "This is dataset.",
4+
"url": "https://superannotate.ai",
5+
"version": "1.0",
6+
"year": 2021,
7+
"contributor": "Superannotate AI",
8+
"date_created": "01/06/2021"
9+
},
10+
"licenses": [
11+
{
12+
"url": "https://superannotate.ai",
13+
"id": 1,
14+
"name": "Superannotate AI"
15+
}
16+
],
17+
"images": [
18+
{
19+
"id": 1,
20+
"file_name": "68307_47130_68308_47130_68307_47131_68308_47131_0.png",
21+
"height": 1000,
22+
"width": 1000,
23+
"license": 1
24+
}
25+
],
26+
"annotations": [
27+
{
28+
"id": 1,
29+
"image_id": 1,
30+
"iscrowd": 0,
31+
"bbox": [
32+
271,
33+
114,
34+
182,
35+
248
36+
],
37+
"area": 45136,
38+
"num_keypoints": 5,
39+
"keypoints": [
40+
271.99,
41+
114.9,
42+
2,
43+
419.26,
44+
137.22,
45+
2,
46+
279.01,
47+
351.5,
48+
2,
49+
453.32,
50+
362.66,
51+
2,
52+
349.13,
53+
233.2,
54+
2
55+
],
56+
"category_id": 1
57+
},
58+
{
59+
"id": 2,
60+
"image_id": 1,
61+
"iscrowd": 0,
62+
"bbox": [
63+
668,
64+
208,
65+
131,
66+
208
67+
],
68+
"area": 27248,
69+
"num_keypoints": 4,
70+
"keypoints": [
71+
668.76,
72+
219.62,
73+
2,
74+
763.61,
75+
208.26,
76+
2,
77+
799.82,
78+
377.39,
79+
2,
80+
713.64,
81+
416.52,
82+
2
83+
],
84+
"category_id": 2
85+
},
86+
{
87+
"id": 3,
88+
"image_id": 1,
89+
"iscrowd": 0,
90+
"bbox": [
91+
455,
92+
522,
93+
273,
94+
194
95+
],
96+
"area": 52962,
97+
"num_keypoints": 4,
98+
"keypoints": [
99+
455.12,
100+
533.02,
101+
2,
102+
652.62,
103+
522.44,
104+
2,
105+
728.01,
106+
679.91,
107+
2,
108+
548.56,
109+
716.34,
110+
2
111+
],
112+
"category_id": 2
113+
}
114+
],
115+
"categories": [
116+
{
117+
"name": "custom",
118+
"supercategory": "class1",
119+
"skeleton": [
120+
[
121+
1,
122+
5
123+
],
124+
[
125+
2,
126+
5
127+
],
128+
[
129+
5,
130+
3
131+
],
132+
[
133+
5,
134+
4
135+
]
136+
],
137+
"keypoints": [
138+
"ca",
139+
"cb",
140+
"cd",
141+
"cc",
142+
"ce"
143+
],
144+
"id": 1
145+
},
146+
{
147+
"name": "template2",
148+
"supercategory": "class1",
149+
"skeleton": [
150+
[
151+
1,
152+
4
153+
],
154+
[
155+
2,
156+
4
157+
],
158+
[
159+
3,
160+
4
161+
]
162+
],
163+
"keypoints": [
164+
"ta",
165+
"tb",
166+
"tc",
167+
"td"
168+
],
169+
"id": 2
170+
}
171+
]
172+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"instances": [{"type": "template", "pointLabels": {"0": "ca", "1": "cb", "2": "cd", "3": "cc", "4": "ce"}, "attributes": [], "creationType": "Pre-annotation", "points": [{"id": 1, "x": 271.99, "y": 114.9}, {"id": 2, "x": 419.26, "y": 137.22}, {"id": 3, "x": 279.01, "y": 351.5}, {"id": 4, "x": 453.32, "y": 362.66}, {"id": 5, "x": 349.13, "y": 233.2}], "connections": [{"id": 7, "from": 1, "to": 5}, {"id": 7, "from": 2, "to": 5}, {"id": 7, "from": 5, "to": 3}, {"id": 7, "from": 5, "to": 4}], "className": "class1", "templateName": "custom"}, {"type": "template", "pointLabels": {"0": "ta", "1": "tb", "2": "tc", "3": "td"}, "attributes": [], "creationType": "Pre-annotation", "points": [{"id": 1, "x": 668.76, "y": 219.62}, {"id": 2, "x": 763.61, "y": 208.26}, {"id": 3, "x": 799.82, "y": 377.39}, {"id": 4, "x": 713.64, "y": 416.52}], "connections": [{"id": 6, "from": 1, "to": 4}, {"id": 6, "from": 2, "to": 4}, {"id": 6, "from": 3, "to": 4}], "className": "class1", "templateName": "template2"}, {"type": "template", "pointLabels": {"0": "ta", "1": "tb", "2": "tc", "3": "td"}, "attributes": [], "creationType": "Pre-annotation", "points": [{"id": 1, "x": 455.12, "y": 533.02}, {"id": 2, "x": 652.62, "y": 522.44}, {"id": 3, "x": 728.01, "y": 679.91}, {"id": 4, "x": 548.56, "y": 716.34}], "connections": [{"id": 6, "from": 1, "to": 4}, {"id": 6, "from": 2, "to": 4}, {"id": 6, "from": 3, "to": 4}], "className": "class1", "templateName": "template2"}], "metadata": {"name": "68307_47130_68308_47130_68307_47131_68308_47131_0.png", "width": 1000, "height": 1000}, "tags": [], "comments": []}

tests/converter_test/test_conversion.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,32 @@ def test_keypoint_detection_coco2sa(tmpdir):
2929
)
3030

3131

32+
def test_keypoint_detection_coco2sa_multi_template(tmpdir):
33+
input_dir = Path(
34+
"tests"
35+
) / "converter_test" / "COCO" / "input" / "toSuperAnnotate" / "keypoint_detection_multi_template"
36+
out_path = Path(
37+
tmpdir
38+
) / "toSuperAnnotate" / "keypoint_detection_multi_template"
39+
40+
sa.import_annotation(
41+
input_dir, out_path, "COCO", "keypoint_multi_template_test", "Vector",
42+
"keypoint_detection"
43+
)
44+
import json
45+
with open(str(Path(input_dir) / "truth.json")) as f:
46+
truth = json.loads(f.read())
47+
48+
with open(
49+
str(
50+
Path(out_path) /
51+
"68307_47130_68308_47130_68307_47131_68308_47131_0.png___objects.json"
52+
)
53+
) as f:
54+
data = json.loads(f.read())
55+
assert data == truth
56+
57+
3258
# test instance segmentation
3359
def test_instance_segmentation_coco2sa(tmpdir):
3460
input_dir = Path(
@@ -121,3 +147,26 @@ def test_instance_segmentation_sa2coco_vector_empty_name(tmpdir):
121147
input_dir, out_path, "COCO", "instance_test_vector", "Vector",
122148
"instance_segmentation"
123149
)
150+
151+
152+
def test_upload_annotations_with_template_id(tmpdir):
153+
tmpdir = Path(tmpdir)
154+
project_name = "test_templates"
155+
for project in sa.search_projects(project_name):
156+
sa.delete_project(project)
157+
project = sa.create_project(project_name, "test", "Vector")
158+
sa.upload_images_from_folder_to_project(
159+
project, "./tests/sample_coco_with_templates"
160+
)
161+
input_dir = Path("tests") / "sample_coco_with_templates"
162+
out_path = Path(
163+
tmpdir
164+
) / "toSuperAnnotate" / "keypoint_detection_multi_template"
165+
166+
sa.import_annotation(
167+
input_dir, out_path, "COCO", "sample_coco", "Vector",
168+
"keypoint_detection"
169+
)
170+
sa.upload_annotations_from_folder_to_project(project, out_path)
171+
image_metadata = sa.get_image_annotations(project_name, "t.png")
172+
assert image_metadata['annotation_json']['instances'][0]['templateId'] == -1

0 commit comments

Comments
 (0)