1616from ...annotation_types .ner import DocumentEntity , DocumentTextSelection , TextEntity
1717from ...annotation_types .types import Cuid
1818from ...annotation_types .geometry import Rectangle , Polygon , Line , Point , Mask
19- from ...annotation_types .annotation import ClassificationAnnotation , ObjectAnnotation , VideoObjectAnnotation
19+ from ...annotation_types .annotation import ClassificationAnnotation , ObjectAnnotation , VideoObjectAnnotation , DICOMObjectAnnotation
2020from .classification import NDSubclassification , NDSubclassificationType
2121from .base import DataRow , NDAnnotation
2222
@@ -30,6 +30,10 @@ class VideoSupported(BaseModel):
3030 frame : int
3131
3232
33+ class DicomSupported (BaseModel ):
34+ group_key : str
35+
36+
3337class _Point (BaseModel ):
3438 x : float
3539 y : float
@@ -136,6 +140,20 @@ def from_common(cls, frame: int, line: Line):
136140 } for pt in line .points ])
137141
138142
143+ class NDDicomLine (NDFrameLine ):
144+
145+ def to_common (self , name : str , feature_schema_id : Cuid , segment_index : int ,
146+ group_key : str ) -> DICOMObjectAnnotation :
147+ return DICOMObjectAnnotation (
148+ frame = self .frame ,
149+ segment_index = segment_index ,
150+ keyframe = True ,
151+ name = name ,
152+ feature_schema_id = feature_schema_id ,
153+ value = Line (points = [Point (x = pt .x , y = pt .y ) for pt in self .line ]),
154+ group_key = group_key )
155+
156+
139157class NDPolygon (NDBaseObject , ConfidenceMixin ):
140158 polygon : List [_Point ]
141159
@@ -259,6 +277,31 @@ def from_common(cls, segment):
259277 ])
260278
261279
280+ class NDDicomSegment (NDSegment ):
281+ keyframes : List [NDDicomLine ]
282+
283+ @staticmethod
284+ def lookup_segment_object_type (segment : List ) -> "NDDicomObjectType" :
285+ """Used for determining which object type the annotation contains
286+ returns the object type"""
287+ segment_class = type (segment [0 ].value )
288+ if segment_class == Line :
289+ return NDDicomLine
290+ else :
291+ raise ValueError ('DICOM segments only support Line objects' )
292+
293+ def to_common (self , name : str , feature_schema_id : Cuid , uuid : str ,
294+ segment_index : int , group_key : str ):
295+ return [
296+ self .segment_with_uuid (
297+ keyframe .to_common (name = name ,
298+ feature_schema_id = feature_schema_id ,
299+ segment_index = segment_index ,
300+ group_key = group_key ), uuid )
301+ for keyframe in self .keyframes
302+ ]
303+
304+
262305class NDSegments (NDBaseObject ):
263306 segments : List [NDSegment ]
264307
@@ -287,6 +330,36 @@ def from_common(cls, segments: List[VideoObjectAnnotation], data: VideoData,
287330 uuid = extra .get ('uuid' ))
288331
289332
333+ class NDDicomSegments (NDBaseObject , DicomSupported ):
334+ segments : List [NDDicomSegment ]
335+
336+ def to_common (self , name : str , feature_schema_id : Cuid ):
337+ result = []
338+ for idx , segment in enumerate (self .segments ):
339+ result .extend (
340+ NDDicomSegment .to_common (segment ,
341+ name = name ,
342+ feature_schema_id = feature_schema_id ,
343+ segment_index = idx ,
344+ uuid = self .uuid ,
345+ group_key = self .group_key ))
346+ return result
347+
348+ @classmethod
349+ def from_common (cls , segments : List [DICOMObjectAnnotation ], data : VideoData ,
350+ name : str , feature_schema_id : Cuid , extra : Dict [str , Any ],
351+ group_key : str ) -> "NDDicomSegments" :
352+
353+ segments = [NDDicomSegment .from_common (segment ) for segment in segments ]
354+
355+ return cls (segments = segments ,
356+ dataRow = DataRow (id = data .uid ),
357+ name = name ,
358+ schema_id = feature_schema_id ,
359+ uuid = extra .get ('uuid' ),
360+ group_key = group_key )
361+
362+
290363class _URIMask (BaseModel ):
291364 instanceURI : str
292365 colorRGB : Tuple [int , int , int ]
@@ -460,13 +533,21 @@ def from_common(
460533 obj = cls .lookup_object (annotation )
461534
462535 # if it is video segments
463- if (obj == NDSegments ):
464- return obj .from_common (
465- annotation ,
466- data ,
467- name = annotation [0 ][0 ].name ,
468- feature_schema_id = annotation [0 ][0 ].feature_schema_id ,
469- extra = annotation [0 ][0 ].extra )
536+ if (obj == NDSegments or obj == NDDicomSegments ):
537+
538+ first_video_annotation = annotation [0 ][0 ]
539+ args = dict (
540+ segments = annotation ,
541+ data = data ,
542+ name = first_video_annotation .name ,
543+ feature_schema_id = first_video_annotation .feature_schema_id ,
544+ extra = first_video_annotation .extra )
545+
546+ if isinstance (first_video_annotation , DICOMObjectAnnotation ):
547+ group_key = first_video_annotation .group_key .value
548+ args .update (dict (group_key = group_key ))
549+
550+ return obj .from_common (** args )
470551
471552 subclasses = [
472553 NDSubclassification .from_common (annot )
@@ -483,7 +564,15 @@ def from_common(
483564 def lookup_object (
484565 annotation : Union [ObjectAnnotation , List ]) -> "NDObjectType" :
485566 if isinstance (annotation , list ):
486- result = NDSegments
567+ try :
568+ first_annotation = annotation [0 ][0 ]
569+ except IndexError :
570+ raise ValueError ("Annotation list cannot be empty" )
571+
572+ if isinstance (first_annotation , DICOMObjectAnnotation ):
573+ result = NDDicomSegments
574+ else :
575+ result = NDSegments
487576 else :
488577 result = {
489578 Line : NDLine ,
@@ -510,3 +599,4 @@ def lookup_object(
510599 NDEntityType , NDDocumentEntity ]
511600
512601NDFrameObjectType = NDFrameRectangle , NDFramePoint , NDFrameLine
602+ NDDicomObjectType = NDDicomLine
0 commit comments