11# https://cocodataset.org/#format-data
22
33from concurrent .futures import ProcessPoolExecutor , as_completed
4- from typing import Any , Dict , List , Tuple
4+ from typing import Any , Dict , List , Tuple , Optional
55from pathlib import Path
66
77import numpy as np
1515from .image import CocoImage , get_image , get_image_id
1616
1717
18- def mask_to_coco_object_annotation (annotation : ObjectAnnotation , annot_idx : int ,
19- image_id : int ,
20- category_id : int ) -> COCOObjectAnnotation :
18+ def mask_to_coco_object_annotation (
19+ annotation : ObjectAnnotation , annot_idx : int , image_id : int ,
20+ category_id : int ) -> Optional [ COCOObjectAnnotation ] :
2121 # This is going to fill any holes into the multipolygon
2222 # If you need to support holes use the panoptic data format
2323 shapely = annotation .value .shapely .simplify (1 ).buffer (0 )
24+
2425 if shapely .is_empty :
25- shapely = annotation .value .shapely .simplify (1 ).buffer (0.01 )
26+ return
27+
2628 xmin , ymin , xmax , ymax = shapely .bounds
2729 # Iterate over polygon once or multiple polygon for each item
2830 area = shapely .area
@@ -89,6 +91,19 @@ def segmentations_to_common(class_annotations: COCOObjectAnnotation,
8991 return annotations
9092
9193
94+ def object_annotation_to_coco (
95+ annotation : ObjectAnnotation , annot_idx : int , image_id : int ,
96+ category_id : int ) -> Optional [COCOObjectAnnotation ]:
97+ if isinstance (annotation .value , Mask ):
98+ return mask_to_coco_object_annotation (annotation , annot_idx , image_id ,
99+ category_id )
100+ elif isinstance (annotation .value , (Polygon , Rectangle )):
101+ return vector_to_coco_object_annotation (annotation , annot_idx , image_id ,
102+ category_id )
103+ else :
104+ return None
105+
106+
92107def process_label (
93108 label : Label ,
94109 idx : int ,
@@ -103,20 +118,16 @@ def process_label(
103118 categories = {}
104119 for class_name in annotation_lookup :
105120 for annotation in annotation_lookup [class_name ]:
106- if annotation .name not in categories :
107- categories [annotation .name ] = hash_category_name (
108- annotation .name )
109- if isinstance (annotation .value , Mask ):
110- coco_annotations .append (
111- mask_to_coco_object_annotation (annotation , annot_idx ,
112- image_id ,
113- categories [annotation .name ]))
114- elif isinstance (annotation .value , (Polygon , Rectangle )):
115- coco_annotations .append (
116- vector_to_coco_object_annotation (
117- annotation , annot_idx , image_id ,
118- categories [annotation .name ]))
119- annot_idx += 1
121+ category_id = categories .get (annotation .name ) or hash_category_name (
122+ annotation .name )
123+ coco_annotation = object_annotation_to_coco (annotation , annot_idx ,
124+ image_id , category_id )
125+ if coco_annotation is not None :
126+ coco_annotations .append (coco_annotation )
127+ if annotation .name not in categories :
128+ categories [annotation .name ] = category_id
129+ annot_idx += 1
130+
120131 return image , coco_annotations , categories
121132
122133
@@ -147,6 +158,7 @@ def from_common(cls,
147158 future .result () for future in tqdm (as_completed (futures ))
148159 ]
149160 else :
161+
150162 results = [
151163 process_label (label , idx , image_root )
152164 for idx , label in enumerate (labels )
0 commit comments