33from dagshub_annotation_converter .formats .label_studio .task import LabelStudioTask , parse_ls_task
44from dagshub_annotation_converter .formats .yolo import YoloContext , import_lookup , import_yolo_result
55from dagshub_annotation_converter .formats .yolo .categories import Categories
6+ from dagshub_annotation_converter .ir .base import IRAnnotationBase , IRTaskAnnotation
67from dagshub_annotation_converter .ir .image import (
78 CoordinateStyle ,
89 IRBBoxImageAnnotation ,
1112 IRSegmentationImageAnnotation ,
1213 IRSegmentationPoint ,
1314)
14- from dagshub_annotation_converter .ir .image .annotations .base import IRAnnotationBase , IRImageAnnotationBase
15+ from dagshub_annotation_converter .ir .image .annotations .base import IRImageAnnotationBase
16+ from dagshub_annotation_converter .ir .video import IRVideoAnnotationTrack
1517
1618from dagshub .common .api import UserAPI
1719from dagshub .common .helpers import log_message
2224
2325 from dagshub .data_engine .model .datapoint import Datapoint
2426
27+ from dagshub_annotation_converter .formats .label_studio .videorectangle import VideoRectangleAnnotation
28+
2529
2630class AnnotationMetaDict (dict ):
2731 def __init__ (self , annotation : "MetadataAnnotations" , * args , ** kwargs ):
@@ -63,13 +67,13 @@ def __init__(
6367 self ,
6468 datapoint : "Datapoint" ,
6569 field : str ,
66- annotations : Optional [Sequence ["IRAnnotationBase " ]] = None ,
70+ annotations : Optional [Sequence ["IRTaskAnnotation " ]] = None ,
6771 meta : Optional [Dict ] = None ,
6872 original_value : Optional [bytes ] = None ,
6973 ):
7074 self .datapoint = datapoint
7175 self .field = field
72- self .annotations : list ["IRAnnotationBase " ]
76+ self .annotations : list ["IRTaskAnnotation " ]
7377 if annotations is None :
7478 annotations = []
7579 self .annotations = list (annotations )
@@ -94,12 +98,34 @@ def to_ls_task(self) -> Optional[bytes]:
9498 task = LabelStudioTask (
9599 user_id = UserAPI .get_current_user (self .datapoint .datasource .source .repoApi .host ).user_id ,
96100 )
97- task .data ["image" ] = self .datapoint .download_url
98- # TODO: need to filter out non-image annotations here maybe?
99- task .add_ir_annotations (self .annotations )
101+ if any (isinstance (ann , IRVideoAnnotationTrack ) for ann in self .annotations ):
102+ task .data ["video" ] = self .datapoint .download_url
103+ frames_count = self ._get_video_frames_count ()
104+ for ann in self .annotations :
105+ if isinstance (ann , IRVideoAnnotationTrack ):
106+ ls_ann = VideoRectangleAnnotation .from_ir_track (ann , frames_count = frames_count )
107+ if ann .__pydantic_extra__ is not None :
108+ ls_ann .__pydantic_extra__ = ann .__pydantic_extra__ .copy ()
109+ task .add_annotation (ls_ann )
110+ else :
111+ task .add_ir_annotation (ann )
112+ else :
113+ task .data ["image" ] = self .datapoint .download_url
114+ task .add_ir_annotations (self .annotations )
100115 task .meta .update (self .meta )
101116 return task .model_dump_json ().encode ("utf-8" )
102117
118+ def _get_video_frames_count (self ) -> Optional [int ]:
119+ max_frame : Optional [int ] = None
120+ for ann in self .annotations :
121+ if not isinstance (ann , IRVideoAnnotationTrack ):
122+ continue
123+ for track_ann in ann .annotations :
124+ max_frame = track_ann .frame_number if max_frame is None else max (max_frame , track_ann .frame_number )
125+ if max_frame is None :
126+ return None
127+ return max_frame + 1
128+
103129 @property
104130 def value (self ) -> Optional [bytes ]:
105131 """
0 commit comments