44from dataclasses import dataclass
55from typing import Dict , Generator , List , Optional , Tuple , TypeVar , Union , cast , overload
66
7+ from kili .core .helpers import get_video_and_frame_dimensions
78from kili .domain .annotation import (
89 ClassicAnnotation ,
910 ClassificationAnnotation ,
2324ASSET_LEVEL_KEY = "assetLevel"
2425
2526
27+ def convert_from_normalized_to_absolute (
28+ vertices : List [Vertice ], width : int , height : int
29+ ) -> List [Vertice ]:
30+ """Convert normalized vertices to absolute coordinates."""
31+ return [
32+ Vertice (
33+ x = vertex ["x" ] * width ,
34+ y = vertex ["y" ] * height ,
35+ )
36+ for vertex in vertices
37+ ]
38+
39+
40+ def convert_from_absolute_to_normalized (
41+ vertices : List [Vertice ], width : int , height : int
42+ ) -> List [Vertice ]:
43+ """Convert absolute vertices to normalized coordinates."""
44+ return [
45+ Vertice (
46+ x = vertex ["x" ] / width ,
47+ y = vertex ["y" ] / height ,
48+ )
49+ for vertex in vertices
50+ ]
51+
52+
2653class AnnotationsToJsonResponseConverter :
2754 """Convert annotations to JSON response."""
2855
@@ -47,7 +74,10 @@ def _label_has_json_response_data(self, label: Dict) -> bool:
4774 return False
4875
4976 def patch_label_json_response (
50- self , label : Dict , annotations : Union [List [VideoAnnotation ], List [ClassicAnnotation ]]
77+ self ,
78+ asset : Optional [Dict ],
79+ label : Dict ,
80+ annotations : Union [List [VideoAnnotation ], List [ClassicAnnotation ]],
5181 ) -> None :
5282 """Patch the label json response using the annotations.
5383
@@ -58,9 +88,17 @@ def patch_label_json_response(
5888 return
5989
6090 if self ._project_input_type == "VIDEO" :
91+ if not asset :
92+ raise ValueError (
93+ "Asset is required for video annotations to compute dimensions."
94+ )
95+ width , height = get_video_and_frame_dimensions (asset )
6196 annotations = cast (List [VideoAnnotation ], annotations )
6297 converted_json_resp = _video_annotations_to_json_response (
63- annotations = annotations , json_interface = self ._project_json_interface
98+ annotations = annotations ,
99+ json_interface = self ._project_json_interface ,
100+ width = width ,
101+ height = height ,
64102 )
65103 else :
66104 annotations = cast (List [ClassicAnnotation ], annotations )
@@ -91,7 +129,7 @@ def _fill_empty_frames(json_response: Dict) -> None:
91129
92130
93131def _video_annotations_to_json_response (
94- annotations : List [VideoAnnotation ], json_interface : Dict
132+ annotations : List [VideoAnnotation ], json_interface : Dict , width : int , height : int
95133) -> Dict [str , Dict [JobName , Dict ]]:
96134 """Convert video label annotations to a video json response."""
97135 json_resp = defaultdict (dict )
@@ -110,7 +148,7 @@ def _video_annotations_to_json_response(
110148 elif ann ["__typename" ] == "VideoObjectDetectionAnnotation" :
111149 ann = cast (VideoObjectDetectionAnnotation , ann )
112150 ann_json_resp = _video_object_detection_annotation_to_json_response (
113- ann , other_annotations , json_interface = json_interface
151+ ann , other_annotations , json_interface = json_interface , width = width , height = height
114152 )
115153 for frame_id , frame_json_resp in ann_json_resp .items ():
116154 for job_name , job_resp in frame_json_resp .items ():
@@ -532,6 +570,8 @@ def _video_object_detection_annotation_to_json_response(
532570 annotation : VideoObjectDetectionAnnotation ,
533571 other_annotations : List [VideoAnnotation ],
534572 json_interface : Dict ,
573+ width : int ,
574+ height : int ,
535575) -> Dict [str , Dict [JobName , Dict ]]:
536576 # get the child annotations of the current annotation
537577 # and compute the json response of those child jobs
@@ -569,6 +609,8 @@ def _video_object_detection_annotation_to_json_response(
569609 object_final_state = object_final_state ,
570610 final_state_frame_index = next_key_ann ["frame" ],
571611 at_frame = frame_id ,
612+ width = width ,
613+ height = height ,
572614 )
573615
574616 if json_interface ["jobs" ][annotation ["job" ]]["tools" ][0 ] == "marker" :
@@ -616,6 +658,8 @@ def _interpolate_object(
616658 object_final_state : List [List [List [Vertice ]]],
617659 final_state_frame_index : int ,
618660 at_frame : int ,
661+ width : int ,
662+ height : int ,
619663) -> List [List [List [Vertice ]]]:
620664 """Interpolate an object between two key frames."""
621665 # if the two frames are consecutive, we do not interpolate
@@ -648,6 +692,8 @@ def _interpolate_object(
648692 next_vertices = object_final_state [0 ][0 ],
649693 weight = (at_frame - initial_state_frame_index )
650694 / (final_state_frame_index - initial_state_frame_index ),
695+ width = width ,
696+ height = height ,
651697 )
652698 ]
653699 ]
@@ -674,6 +720,8 @@ def _interpolate_rectangle(
674720 previous_vertices : List [Vertice ],
675721 next_vertices : List [Vertice ],
676722 weight : float ,
723+ width : int ,
724+ height : int ,
677725) -> List [Vertice ]:
678726 """Interpolate a rectangle.
679727
@@ -683,9 +731,18 @@ def _interpolate_rectangle(
683731 The interpolated properties are used to reconstruct the vertices of the interpolated rectangle,
684732 which are then converted back to normalized coordinates.
685733 """
686- permuted_new_vertices = _find_rectangle_vertices_bijection (previous_vertices , next_vertices )
734+ previous_absolute_vertices = convert_from_normalized_to_absolute (
735+ previous_vertices , height = height , width = width
736+ )
737+ next_absolute_vertices = convert_from_normalized_to_absolute (
738+ next_vertices , height = height , width = width
739+ )
740+
741+ permuted_new_vertices = _find_rectangle_vertices_bijection (
742+ previous_absolute_vertices , next_absolute_vertices
743+ )
687744
688- previous_rectangle_properties = _find_rectangle_properties (previous_vertices )
745+ previous_rectangle_properties = _find_rectangle_properties (previous_absolute_vertices )
689746 next_rectangle_properties = _find_rectangle_properties (permuted_new_vertices )
690747
691748 interpolated_angle = _interpolate_angle (
@@ -712,7 +769,7 @@ def _interpolate_rectangle(
712769 interpolated_rectangle_properties
713770 )
714771
715- return interpolated_rectangle
772+ return convert_from_absolute_to_normalized ( interpolated_rectangle , height = height , width = width )
716773
717774
718775def _find_rectangle_vertices_bijection (
0 commit comments