Skip to content

Commit 47ba5f5

Browse files
committed
Merge branch 'develop' into friday
# Conflicts: # src/superannotate/lib/core/video_convertor.py # src/superannotate/version.py
2 parents 6ee988d + 501a1fa commit 47ba5f5

File tree

14 files changed

+820
-80
lines changed

14 files changed

+820
-80
lines changed

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
minversion = 3.0
33
log_cli=true
44
python_files = test_*.py
5-
addopts = -n auto --dist=loadscope
5+
;addopts = -n auto --dist=loadscope

src/superannotate/lib/app/interface/sdk_interface.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,7 +1540,7 @@ def create_annotation_class(
15401540
name: NotEmptyStr,
15411541
color: NotEmptyStr,
15421542
attribute_groups: Optional[List[AttributeGroup]] = None,
1543-
type: ClassType = "object",
1543+
class_type: ClassType = "object",
15441544
):
15451545
"""Create annotation class in project
15461546
@@ -1554,8 +1554,8 @@ def create_annotation_class(
15541554
[ { "name": "tall", "is_multiselect": 0, "attributes": [ { "name": "yes" }, { "name": "no" } ] },
15551555
{ "name": "age", "is_multiselect": 0, "attributes": [ { "name": "young" }, { "name": "old" } ] } ]
15561556
:type attribute_groups: list of dicts
1557-
:param type: class type
1558-
:type type: str
1557+
:param class_type: class type
1558+
:type class_type: str
15591559
15601560
:return: new class metadata
15611561
:rtype: dict
@@ -1570,7 +1570,7 @@ def create_annotation_class(
15701570
name=name,
15711571
color=color,
15721572
attribute_groups=attribute_groups,
1573-
class_type=type,
1573+
class_type=class_type,
15741574
)
15751575
return BaseSerializers(response.data).serialize()
15761576

@@ -1633,7 +1633,6 @@ def create_annotation_classes_from_classes_json(
16331633
:return: list of created annotation class metadatas
16341634
:rtype: list of dicts
16351635
"""
1636-
classes_json_initial = classes_json
16371636
if isinstance(classes_json, str) or isinstance(classes_json, Path):
16381637
if from_s3_bucket:
16391638
from_session = boto3.Session()
@@ -1650,11 +1649,7 @@ def create_annotation_classes_from_classes_json(
16501649
annotation_classes = parse_obj_as(List[AnnotationClassEntity], classes_json)
16511650
except ValidationError:
16521651
raise AppException("Couldn't validate annotation classes.")
1653-
logger.info(
1654-
"Creating annotation classes in project %s from %s.",
1655-
project,
1656-
classes_json_initial,
1657-
)
1652+
logger.info(f"Creating annotation classes in project {project}.")
16581653
response = Controller.get_default().create_annotation_classes(
16591654
project_name=project, annotation_classes=annotation_classes,
16601655
)

src/superannotate/lib/app/mixp/utils/parsers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,14 +974,17 @@ def add_annotation_point_to_image(*args, **kwargs):
974974

975975
def create_annotation_class(*args, **kwargs):
976976
project = kwargs.get("project", None)
977+
class_type = kwargs.get("class_type")
977978
if not project:
978979
project = args[0]
979-
980+
if not class_type and len(args) == 5:
981+
class_type = args[4]
980982
return {
981983
"event_name": "create_annotation_class",
982984
"properties": {
983985
"project_name": get_project_name(project),
984986
"Attributes": bool(args[3:4] or ("attribute_groups" in kwargs)),
987+
"class_type": class_type if class_type else "object"
985988
},
986989
}
987990

src/superannotate/lib/app/serializers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,4 @@ def serialize(self):
114114
if data["attribute"] == "ImageQuality":
115115
data["value"] = constance.ImageQuality.get_name(data["value"])
116116
return data
117+

src/superannotate/lib/core/conditions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ def build_query(self):
5454
return str(self) + "".join(
5555
[f"{condition[0]}{condition[1]}" for condition in self._condition_set]
5656
)
57+
c

src/superannotate/lib/core/data_handlers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ def convert_timestamp(timestamp):
298298
end_time = safe_time(convert_timestamp(parameter["end"]))
299299

300300
for timestamp_data in parameter["timestamps"]:
301-
timestamp = safe_time(
301+
timestamp = safeg_time(
302302
convert_timestamp(timestamp_data["timestamp"])
303303
)
304304
editor_instance["timeline"][timestamp] = {}

src/superannotate/lib/core/usecases/annotations.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ def __init__(
508508
self._item_names = item_names
509509
self._client = backend_service_provider
510510
self._show_process = show_process
511+
self._item_names_provided = True
511512

512513
def validate_project_type(self):
513514
if self._project.project_type == constances.ProjectType.PIXEL.value:
@@ -523,6 +524,7 @@ def validate_item_names(self):
523524
)
524525
self._item_names = item_names
525526
else:
527+
self._item_names_provided = False
526528
condition = (
527529
Condition("team_id", self._project.team_id, EQ)
528530
& Condition("project_id", self._project.uuid, EQ)
@@ -531,6 +533,18 @@ def validate_item_names(self):
531533

532534
self._item_names = [item.name for item in self._images.get_all(condition)]
533535

536+
def _prettify_annotations(self, annotations: List[dict]):
537+
538+
if self._item_names_provided:
539+
try:
540+
data = []
541+
for annotation in annotations:
542+
data.append((self._item_names.index(annotation["metadata"]["name"]), annotation))
543+
return [i[1] for i in sorted(data, key=lambda x: x[0])]
544+
except KeyError:
545+
raise AppException("Broken data.")
546+
return annotations
547+
534548
def execute(self):
535549
if self.is_valid():
536550
items_count = len(self._item_names)
@@ -552,7 +566,7 @@ def execute(self):
552566
self.reporter.log_warning(
553567
f"Could not find annotations for {items_count - received_items_count}/{items_count} items."
554568
)
555-
self._response.data = annotations
569+
self._response.data = self._prettify_annotations(annotations)
556570
return self._response
557571

558572

src/superannotate/lib/core/video_convertor.py

Lines changed: 85 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import math
21
from collections import defaultdict
32
from typing import Any
43
from typing import Dict
@@ -65,7 +64,7 @@ def interpolate_annotations(
6564
):
6665
for idx, frame_idx in enumerate(range(from_frame, to_frame), 1):
6766
keyframe = False
68-
if idx == 1:
67+
if idx in (1, len(range(from_frame, to_frame))):
6968
keyframe = True
7069
points = None
7170
if annotation_type == "bbox":
@@ -75,75 +74,96 @@ def interpolate_annotations(
7574
"x2": round(data["points"]["x2"] + steps["x2"] * idx, 2),
7675
"y2": round(data["points"]["y2"] + steps["y2"] * idx, 2),
7776
}
78-
frame = self.get_frame(frame_idx)
79-
frame.annotations.append(Annotation(
80-
type=annotation_type,
81-
className=class_name,
77+
self._add_annotation(
78+
frame_idx,
79+
annotation_type=annotation_type,
80+
class_name=class_name,
8281
points=points,
8382
attributes=data["attributes"],
8483
keyframe=keyframe
85-
))
84+
)
85+
86+
def _add_annotation(
87+
self,
88+
frame_no: int,
89+
annotation_type: str,
90+
class_name: str,
91+
points: list = None,
92+
attributes: list = None,
93+
keyframe: bool = False
94+
):
95+
frame = self.get_frame(frame_no)
96+
frame.annotations.append(Annotation(
97+
type=annotation_type,
98+
className=class_name,
99+
points=points,
100+
attributes=attributes,
101+
keyframe=keyframe
102+
))
86103

87104
def _process(self):
88105
for instance in self._annotation_data["instances"]:
89-
for parameter in instance["parameters"]:
90-
time_stamp_frame_map = []
91-
for timestamp in parameter["timestamps"]:
92-
time_stamp_frame_map.append((int(math.ceil(timestamp["timestamp"] / self.ratio)), timestamp))
93-
for idx, (frame_no, timestamp_data) in enumerate(time_stamp_frame_map):
94-
annotation_type = instance["meta"]["type"]
95-
try:
96-
next_frame_no, next_timestamp = time_stamp_frame_map[idx + 1]
97-
if frame_no == next_frame_no:
98-
median = (timestamp_data["timestamp"] // self.ratio) + (self.ratio / 2)
99-
if abs(median - timestamp_data["timestamp"]) < abs(median - next_timestamp["timestamp"]):
100-
time_stamp_frame_map[idx + 1] = (frame_no, timestamp_data)
101-
continue
102-
103-
frames_diff = next_frame_no - frame_no
104-
steps = None
105-
if annotation_type == "bbox":
106-
if not frames_diff:
107-
steps = {
108-
"y1": 0,
109-
"x2": 0,
110-
"x1": 0,
111-
"y2": 0
112-
}
113-
else:
114-
steps = {
115-
"y1": round(
116-
(next_timestamp["points"]["y1"] - timestamp_data["points"]["y1"]) / frames_diff,
117-
2),
118-
"x2": round(
119-
(next_timestamp["points"]["x2"] - timestamp_data["points"]["x2"]) / frames_diff,
120-
2),
121-
"x1": round(
122-
(next_timestamp["points"]["x1"] - timestamp_data["points"]["x1"]) / frames_diff,
123-
2),
124-
"y2": round(
125-
(next_timestamp["points"]["y2"] - timestamp_data["points"]["y2"]) / frames_diff,
126-
2),
127-
}
128-
self.interpolate_annotations(
129-
class_name=instance["meta"]["className"],
130-
from_frame=frame_no,
131-
to_frame=next_frame_no,
132-
data=timestamp_data,
133-
steps=steps,
134-
annotation_type=annotation_type
135-
)
136-
except IndexError:
137-
# print(frame_no)
138-
frame = self.get_frame(frame_no)
139-
points = timestamp_data.get("points")
140-
frame.annotations.append(Annotation(
141-
type=annotation_type,
142-
className=instance["meta"]["className"],
143-
points=points,
144-
attributes=timestamp_data.get("attributes"),
145-
keyframe=True
146-
))
106+
try:
107+
for parameter in instance["parameters"]:
108+
time_stamp_frame_map = []
109+
for timestamp in parameter["timestamps"]:
110+
time_stamp_frame_map.append((round(timestamp["timestamp"] / self.ratio) + 1, timestamp))
111+
for idx, (frame_no, timestamp_data) in enumerate(time_stamp_frame_map):
112+
annotation_type = instance["meta"]["type"]
113+
try:
114+
next_frame_no, next_timestamp = time_stamp_frame_map[idx + 1]
115+
if frame_no == next_frame_no:
116+
median = (timestamp_data["timestamp"] // self.ratio) + (self.ratio / 2)
117+
if abs(median - timestamp_data["timestamp"]) < abs(median - next_timestamp["timestamp"]):
118+
time_stamp_frame_map[idx + 1] = timestamp_data
119+
continue
120+
121+
frames_diff = next_frame_no - frame_no
122+
steps = None
123+
if annotation_type == "bbox":
124+
if not frames_diff:
125+
steps = {
126+
"y1": 0,
127+
"x2": 0,
128+
"x1": 0,
129+
"y2": 0
130+
}
131+
else:
132+
steps = {
133+
"y1": round(
134+
(next_timestamp["points"]["y1"] - timestamp_data["points"]["y1"]) / frames_diff,
135+
2),
136+
"x2": round(
137+
(next_timestamp["points"]["x2"] - timestamp_data["points"]["x2"]) / frames_diff,
138+
2),
139+
"x1": round(
140+
(next_timestamp["points"]["x1"] - timestamp_data["points"]["x1"]) / frames_diff,
141+
2),
142+
"y2": round(
143+
(next_timestamp["points"]["y2"] - timestamp_data["points"]["y2"]) / frames_diff,
144+
2),
145+
}
146+
self.interpolate_annotations(
147+
class_name=instance["meta"]["className"],
148+
from_frame=frame_no,
149+
to_frame=next_frame_no,
150+
data=timestamp_data,
151+
steps=steps,
152+
annotation_type=annotation_type
153+
)
154+
except IndexError:
155+
last_frame_no, last_timestamp = time_stamp_frame_map[-1]
156+
end = round(parameter["end"] / self.ratio)
157+
self.interpolate_annotations(
158+
annotation_type=annotation_type,
159+
class_name=instance["meta"]["className"],
160+
from_frame=last_frame_no,
161+
to_frame=end,
162+
data=last_timestamp,
163+
steps={"x1": 0, "y1": 0, "x2": 0, "y2": 0}
164+
)
165+
except Exception as e:
166+
pass
147167

148168
def __iter__(self):
149169
for frame_no in range(1, int(self.frames_count) + 1):

src/superannotate/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "4.3.0b14"
1+
__version__ = "4.3.0b17"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[
2+
{
3+
"id": 857627,
4+
"project_id": 150845,
5+
"name": "vid",
6+
"color": "#0fc1c9",
7+
"count": 0,
8+
"createdAt": "2021-10-01T13:03:51.000Z",
9+
"updatedAt": "2021-10-01T13:03:51.000Z",
10+
"attribute_groups": [
11+
{
12+
"id": 337487,
13+
"class_id": 857627,
14+
"name": "attr g",
15+
"is_multiselect": 0,
16+
"createdAt": "2021-10-04T07:01:29.000Z",
17+
"updatedAt": "2021-10-04T07:01:29.000Z",
18+
"attributes": [
19+
{
20+
"id": 1174520,
21+
"group_id": 337487,
22+
"project_id": 150845,
23+
"name": "attr",
24+
"count": 0,
25+
"createdAt": "2021-10-04T07:01:31.000Z",
26+
"updatedAt": "2021-10-04T07:01:31.000Z"
27+
}
28+
]
29+
}
30+
]
31+
}
32+
]

0 commit comments

Comments
 (0)