11import os
22import glob
3+ import json
34from logging import getLogger
45
6+ import xmltodict
7+
58from .exceptions import FastLabelInvalidException
69from .api import Api
710from fastlabel import converters , utils
@@ -246,7 +249,7 @@ def get_task_id_name_map(
246249 self , project : str ,
247250 offset : int = None ,
248251 limit : int = 1000 ,
249- ) -> list :
252+ ) -> dict :
250253 """
251254 Returns a map of task ids and names.
252255 e.g.) {
@@ -447,12 +450,58 @@ def delete_task(self, task_id: str) -> None:
447450
448451 # Task Convert
449452
450- def to_coco (self , tasks : list ) -> dict :
453+ def export_coco (self , tasks : list , output_dir : str = os .path .join ("output" , "coco" )) -> None :
454+ """
455+ Convert tasks to COCO format and export as a file.
456+
457+ tasks is a list of tasks. (Required)
458+ output_dir is output directory(default: output/coco). (Optional)
459+ """
460+ coco = converters .to_coco (tasks )
461+ os .makedirs (output_dir , exist_ok = True )
462+ file_path = os .path .join (output_dir , "annotations.json" )
463+ with open (file_path , 'w' ) as f :
464+ json .dump (coco , f , indent = 4 , ensure_ascii = False )
465+
466+ def export_yolo (self , tasks : list , output_dir : str = os .path .join ("output" , "yolo" )) -> None :
467+ """
468+ Convert tasks to YOLO format and export as files.
469+
470+ tasks is a list of tasks. (Required)
471+ output_dir is output directory(default: output/yolo). (Optional)
451472 """
452- Convert tasks to COCO format.
473+ annos , categories = converters .to_yolo (tasks )
474+ for anno in annos :
475+ file_name = anno ["filename" ]
476+ basename = utils .get_basename (file_name )
477+ file_path = os .path .join (
478+ output_dir , "annotations" , basename + ".txt" )
479+ os .makedirs (os .path .dirname (file_path ), exist_ok = True )
480+ with open (file_path , 'w' , encoding = "utf8" ) as f :
481+ for obj in anno ["object" ]:
482+ f .write (obj )
483+ f .write ("\n " )
484+ with open (os .path .join (output_dir , "classes.txt" ), 'w' , encoding = "utf8" ) as f :
485+ for category in categories :
486+ f .write (category ["name" ])
487+ f .write ("\n " )
488+
489+ def export_pascalvoc (self , tasks : list , output_dir : str = os .path .join ("output" , "pascalvoc" )) -> None :
453490 """
491+ Convert tasks to Pascal VOC format as files.
454492
455- return converters .to_coco (tasks )
493+ tasks is a list of tasks. (Required)
494+ output_dir is output directory(default: output/pascalvoc). (Optional)
495+ """
496+ pascalvoc = converters .to_pascalvoc (tasks )
497+ for voc in pascalvoc :
498+ file_name = voc ["annotation" ]["filename" ]
499+ basename = utils .get_basename (file_name )
500+ file_path = os .path .join (output_dir , basename + ".xml" )
501+ os .makedirs (os .path .dirname (file_path ), exist_ok = True )
502+ xml = xmltodict .unparse (voc , pretty = True , full_document = False )
503+ with open (file_path , 'w' , encoding = "utf8" ) as f :
504+ f .write (xml )
456505
457506 # Annotation
458507
@@ -507,7 +556,7 @@ def create_annotation(
507556 type : str ,
508557 value : str ,
509558 title : str ,
510- color : str ,
559+ color : str = None ,
511560 attributes : list = []
512561 ) -> str :
513562 """
@@ -517,7 +566,7 @@ def create_annotation(
517566 type can be 'bbox', 'polygon', 'keypoint', 'classification', 'line', 'segmentation'. (Required)
518567 value is an unique identifier of annotation in your project. (Required)
519568 title is a display name of value. (Required)
520- color is hex color code like #ffffff. (Required )
569+ color is hex color code like #ffffff. (Optional )
521570 attributes is a list of attribute. (Optional)
522571 """
523572 endpoint = "annotations"
@@ -526,8 +575,9 @@ def create_annotation(
526575 "type" : type ,
527576 "value" : value ,
528577 "title" : title ,
529- "color" : color
530578 }
579+ if color :
580+ payload ["color" ] = color
531581 if attributes :
532582 payload ["attributes" ] = attributes
533583 return self .api .post_request (endpoint , payload = payload )
0 commit comments