33
33
convert_annotation_to_yolo ,
34
34
convert_annotation_to_yolo_obb ,
35
35
)
36
+ from label_studio_sdk ._extensions .label_studio_tools .core .utils .io import get_local_path
36
37
37
38
logger = logging .getLogger (__name__ )
38
39
@@ -55,6 +56,9 @@ class Format(Enum):
55
56
YOLO = 11
56
57
YOLO_OBB = 12
57
58
CSV_OLD = 13
59
+ YOLO_WITH_IMAGES = 14
60
+ COCO_WITH_IMAGES = 15
61
+ YOLO_OBB_WITH_IMAGES = 16
58
62
59
63
def __str__ (self ):
60
64
return self .name
@@ -106,6 +110,12 @@ class Converter(object):
106
110
"link" : "https://labelstud.io/guide/export.html#COCO" ,
107
111
"tags" : ["image segmentation" , "object detection" ],
108
112
},
113
+ Format .COCO_WITH_IMAGES : {
114
+ "title" : "COCO with Images" ,
115
+ "description" : "COCO format with images downloaded." ,
116
+ "link" : "https://labelstud.io/guide/export.html#COCO" ,
117
+ "tags" : ["image segmentation" , "object detection" ],
118
+ },
109
119
Format .VOC : {
110
120
"title" : "Pascal VOC XML" ,
111
121
"description" : "Popular XML format used for object detection and polygon image segmentation tasks." ,
@@ -119,6 +129,12 @@ class Converter(object):
119
129
"link" : "https://labelstud.io/guide/export.html#YOLO" ,
120
130
"tags" : ["image segmentation" , "object detection" ],
121
131
},
132
+ Format .YOLO_WITH_IMAGES : {
133
+ "title" : "YOLO with Images" ,
134
+ "description" : "YOLO format with images downloaded." ,
135
+ "link" : "https://labelstud.io/guide/export.html#YOLO" ,
136
+ "tags" : ["image segmentation" , "object detection" ],
137
+ },
122
138
Format .YOLO_OBB : {
123
139
"title" : "YOLOv8 OBB" ,
124
140
"description" : "Popular TXT format is created for each image file. Each txt file contains annotations for "
@@ -127,6 +143,12 @@ class Converter(object):
127
143
"link" : "https://labelstud.io/guide/export.html#YOLO" ,
128
144
"tags" : ["image segmentation" , "object detection" ],
129
145
},
146
+ Format .YOLO_OBB_WITH_IMAGES : {
147
+ "title" : "YOLOv8 OBB with Images" ,
148
+ "description" : "YOLOv8 OBB format with images downloaded." ,
149
+ "link" : "https://labelstud.io/guide/export.html#YOLO" ,
150
+ "tags" : ["image segmentation" , "object detection" ],
151
+ },
130
152
Format .BRUSH_TO_NUMPY : {
131
153
"title" : "Brush labels to NumPy" ,
132
154
"description" : "Export your brush labels as NumPy 2d arrays. Each label outputs as one image." ,
@@ -158,6 +180,8 @@ def __init__(
158
180
output_tags = None ,
159
181
upload_dir = None ,
160
182
download_resources = True ,
183
+ access_token = None ,
184
+ hostname = None ,
161
185
):
162
186
"""Initialize Label Studio Converter for Exports
163
187
@@ -171,6 +195,8 @@ def __init__(
171
195
self .upload_dir = upload_dir
172
196
self .download_resources = download_resources
173
197
self ._schema = None
198
+ self .access_token = access_token
199
+ self .hostname = hostname
174
200
175
201
if isinstance (config , dict ):
176
202
self ._schema = config
@@ -216,21 +242,23 @@ def convert(self, input_data, output_data, format, is_dir=True, **kwargs):
216
242
)
217
243
elif format == Format .CONLL2003 :
218
244
self .convert_to_conll2003 (input_data , output_data , is_dir = is_dir )
219
- elif format == Format .COCO :
245
+ elif format in [ Format .COCO , Format . COCO_WITH_IMAGES ] :
220
246
image_dir = kwargs .get ("image_dir" )
247
+ self .download_resources = format == Format .COCO_WITH_IMAGES
221
248
self .convert_to_coco (
222
249
input_data , output_data , output_image_dir = image_dir , is_dir = is_dir
223
250
)
224
- elif format == Format .YOLO or format == Format .YOLO_OBB :
251
+ elif format in [ Format .YOLO , Format . YOLO_OBB , Format . YOLO_OBB_WITH_IMAGES , Format .YOLO_WITH_IMAGES ] :
225
252
image_dir = kwargs .get ("image_dir" )
226
253
label_dir = kwargs .get ("label_dir" )
254
+ self .download_resources = format in [Format .YOLO_WITH_IMAGES , Format .YOLO_OBB_WITH_IMAGES ]
227
255
self .convert_to_yolo (
228
256
input_data ,
229
257
output_data ,
230
258
output_image_dir = image_dir ,
231
259
output_label_dir = label_dir ,
232
260
is_dir = is_dir ,
233
- is_obb = (format == Format .YOLO_OBB ),
261
+ is_obb = (format in [ Format .YOLO_OBB , Format . YOLO_OBB_WITH_IMAGES ] ),
234
262
)
235
263
elif format == Format .VOC :
236
264
image_dir = kwargs .get ("image_dir" )
@@ -334,7 +362,9 @@ def _get_supported_formats(self):
334
362
and "Labels" in output_tag_types
335
363
):
336
364
all_formats .remove (Format .COCO .name )
365
+ all_formats .remove (Format .COCO_WITH_IMAGES .name )
337
366
all_formats .remove (Format .YOLO .name )
367
+ all_formats .remove (Format .YOLO_WITH_IMAGES .name )
338
368
if not (
339
369
"Image" in input_tag_types
340
370
and (
@@ -353,6 +383,7 @@ def _get_supported_formats(self):
353
383
all_formats .remove (Format .ASR_MANIFEST .name )
354
384
if is_mig or ('Video' in input_tag_types and 'TimelineLabels' in output_tag_types ):
355
385
all_formats .remove (Format .YOLO_OBB .name )
386
+ all_formats .remove (Format .YOLO_OBB_WITH_IMAGES .name )
356
387
357
388
return all_formats
358
389
@@ -593,20 +624,25 @@ def add_image(images, width, height, image_id, image_path):
593
624
)
594
625
for item_idx , item in enumerate (item_iterator ):
595
626
image_path = item ["input" ][data_key ]
627
+ task_id = item ["id" ]
596
628
image_id = len (images )
597
629
width = None
598
630
height = None
599
631
# download all images of the dataset, including the ones without annotations
600
632
if not os .path .exists (image_path ):
601
633
try :
602
- image_path = download (
603
- image_path ,
604
- output_image_dir ,
634
+ image_path = get_local_path (
635
+ url = image_path ,
636
+ hostname = self . hostname ,
605
637
project_dir = self .project_dir ,
606
- return_relative_path = True ,
607
- upload_dir = self . upload_dir ,
638
+ image_dir = self . upload_dir ,
639
+ cache_dir = output_image_dir ,
608
640
download_resources = self .download_resources ,
641
+ access_token = self .access_token ,
642
+ task_id = task_id ,
609
643
)
644
+ # make path relative to output_image_dir
645
+ image_path = os .path .relpath (image_path , output_dir )
610
646
except :
611
647
logger .info (
612
648
"Unable to download {image_path}. The image of {item} will be skipped" .format (
@@ -801,19 +837,24 @@ def convert_to_yolo(
801
837
image_paths = [image_paths ] if isinstance (image_paths , str ) else image_paths
802
838
# download image(s)
803
839
image_path = None
840
+ task_id = item ["id" ]
804
841
# TODO: for multi-page annotation, this code won't produce correct relationships between page and annotated shapes
805
842
# fixing the issue in RND-84
806
843
for image_path in reversed (image_paths ):
807
844
if not os .path .exists (image_path ):
808
845
try :
809
- image_path = download (
810
- image_path ,
811
- output_image_dir ,
846
+ image_path = get_local_path (
847
+ url = image_path ,
848
+ hostname = self . hostname ,
812
849
project_dir = self .project_dir ,
813
- return_relative_path = True ,
814
- upload_dir = self . upload_dir ,
850
+ image_dir = self . upload_dir ,
851
+ cache_dir = output_image_dir ,
815
852
download_resources = self .download_resources ,
853
+ access_token = self .access_token ,
854
+ task_id = task_id ,
816
855
)
856
+ # make path relative to output_image_dir
857
+ image_path = os .path .relpath (image_path , output_dir )
817
858
except :
818
859
logger .info (
819
860
"Unable to download {image_path}. The item {item} will be skipped" .format (
0 commit comments