@@ -805,7 +805,7 @@ def __init__(
805805 ):
806806 super ().__init__ (),
807807 self ._project = project
808- self ._folder_names = list (folder_names )
808+ self ._folder_names = list (folder_names ) if folder_names else None
809809 self ._backend_service = backend_service_provider
810810 self ._annotation_statuses = annotation_statuses
811811 self ._include_fuse = include_fuse
@@ -2284,12 +2284,12 @@ def annotation_classes_id_name_map(self) -> dict:
22842284 classes_data = defaultdict (dict )
22852285 annotation_classes = self ._annotation_classes .get_all ()
22862286 for annotation_class in annotation_classes :
2287- class_info = {"name" : annotation_class .name }
2287+ class_info = {"name" : annotation_class .name , "attribute_groups" : {} }
22882288 if annotation_class .attribute_groups :
22892289 for attribute_group in annotation_class .attribute_groups :
22902290 attribute_group_data = defaultdict (dict )
22912291 for attribute in attribute_group ["attributes" ]:
2292- attribute_group_data [attribute ["name " ]] = attribute ["id " ]
2292+ attribute_group_data [attribute ["id " ]] = attribute ["name " ]
22932293 class_info ["attribute_groups" ] = {
22942294 attribute_group ["id" ]: {
22952295 "name" : attribute_group ["name" ],
@@ -2312,49 +2312,39 @@ def fill_classes_data(self, annotations: dict):
23122312 annotation_classes = self .annotation_classes_id_name_map
23132313 if "instances" not in annotations :
23142314 return
2315- unknown_classes = {}
2316- # for annotation in [i for i in annotations["instances"] if "className" in i]:
2317- for annotation in [i for i in annotations ["instances" ] if "classId" in i ]:
2318- annotation_class_id = annotation ["classId" ]
2319- if annotation_class_id not in annotation_classes :
2320- if annotation_class_id not in unknown_classes :
2321- unknown_classes [annotation_class_id ] = {
2322- "name" : "unknown_class" ,
2323- "attribute_groups" : {},
2324- }
2325- # annotation_classes.update(unknown_classes)
23262315 templates = self .get_templates_mapping ()
23272316 for annotation in (
23282317 i for i in annotations ["instances" ] if i .get ("type" , None ) == "template"
23292318 ):
23302319 template_name = templates .get (annotation .get ("templateId" ), None )
23312320 if template_name :
23322321 annotation ["templateName" ] = template_name
2333-
2334- for annotation in [i for i in annotations ["instances" ] if "classId" in i ]:
2335- annotation_class_id = annotation ["classId" ]
2336- if annotation_class_id not in annotation_classes :
2337- continue
2338- annotation ["className" ] = annotation_classes [annotation_class_id ]["name" ]
2339- for attribute in [i for i in annotation ["attributes" ] if "groupId" in i ]:
2340- if (
2322+ for annotation in [
2323+ i
2324+ for i in annotations ["instances" ]
2325+ if "classId" in i and i ["classId" ] in annotation_classes
2326+ ]:
2327+ annotation_class = annotation_classes [annotation ["classId" ]]
2328+ annotation ["className" ] = annotation_class ["name" ]
2329+ for attribute in [
2330+ i
2331+ for i in annotation ["attributes" ]
2332+ if "groupId" in i
2333+ and i ["groupId" ] in annotation_class ["attribute_groups" ].keys ()
2334+ ]:
2335+ attribute ["groupName" ] = annotation_class ["attribute_groups" ][
23412336 attribute ["groupId" ]
2342- not in annotation_classes [annotation_class_id ]["attribute_groups" ]
2343- ):
2344- continue
2345- attribute ["groupName" ] = annotation_classes [annotation_class_id ][
2346- "attribute_groups"
2347- ][attribute ["groupId" ]]["name" ]
2337+ ]["name" ]
23482338 if (
2349- attribute ["groupId " ]
2350- not in annotation_classes [ annotation_class_id ][ "attribute_groups" ][
2351- attribute [ "groupId" ]
2352- ][ "attributes" ]
2339+ attribute ["id " ]
2340+ not in list ( annotation_class [ "attribute_groups" ][ attribute [ "groupId" ] ][
2341+ "attributes"
2342+ ]. keys ())
23532343 ):
23542344 continue
2355- attribute ["name" ] = annotation_classes [ annotation_class_id ][
2356- "attribute_groups"
2357- ][attribute [ "groupId" ]][ "name" ]
2345+ attribute ["name" ] = annotation_class [ "attribute_groups" ][
2346+ attribute [ "groupId" ]
2347+ ]["attributes" ][ attribute [ "id" ] ]
23582348
23592349 def execute (self ):
23602350 if self .is_valid ():
@@ -3117,7 +3107,9 @@ def execute(self):
31173107 weight , height = image .get_size ()
31183108 empty_image_arr = np .full ((height , weight , 4 ), [0 , 0 , 0 , 255 ], np .uint8 )
31193109 for annotation in self .annotations ["instances" ]:
3120- if not class_color_map .get (annotation ["className" ]):
3110+ if annotation .get ("className" ) and not class_color_map .get (
3111+ annotation ["className" ]
3112+ ):
31213113 continue
31223114 fill_color = * class_color_map [annotation ["className" ]], 255
31233115 for part in annotation ["parts" ]:
@@ -3336,6 +3328,41 @@ def annotation_classes_name_map(self) -> dict:
33363328 classes_data [annotation_class .name ] = class_info
33373329 return classes_data
33383330
3331+ @property
3332+ def get_annotation_classes_name_to_id (self ):
3333+ annotation_classes = self ._annotation_classes
3334+ annotation_classes_dict = {}
3335+ for annotation_class in annotation_classes :
3336+ class_id = annotation_class ["id" ]
3337+ class_name = annotation_class ["name" ]
3338+ class_info = {"id" : class_id , "attribute_groups" : {}}
3339+ if "attribute_groups" in annotation_class :
3340+ for attribute_group in annotation_class ["attribute_groups" ]:
3341+ attribute_group_info = {}
3342+ for attribute in attribute_group ["attributes" ]:
3343+ if attribute ["name" ] in attribute_group_info :
3344+ logger .warning (
3345+ "Duplicate annotation class attribute name %s in attribute group %s. Only one of the annotation classe attributes will be used. This will result in errors in annotation upload." ,
3346+ attribute ["name" ], attribute_group ["name" ]
3347+ )
3348+ attribute_group_info [attribute ["name" ]] = attribute ["id" ]
3349+ if attribute_group ["name" ] in class_info ["attribute_groups" ]:
3350+ logger .warning (
3351+ "Duplicate annotation class attribute group name %s. Only one of the annotation classe attribute groups will be used. This will result in errors in annotation upload." ,
3352+ attribute_group ["name" ]
3353+ )
3354+ class_info ["attribute_groups" ][attribute_group ["name" ]] = {
3355+ "id" : attribute_group ["id" ],
3356+ "attributes" : attribute_group_info
3357+ }
3358+ if class_name in annotation_classes_dict :
3359+ logger .warning (
3360+ "Duplicate annotation class name %s. Only one of the annotation classes will be used. This will result in errors in annotation upload." ,
3361+ class_name
3362+ )
3363+ annotation_classes_dict [class_name ] = class_info
3364+ return annotation_classes_dict
3365+
33393366 def get_templates_mapping (self ):
33403367 templates = self ._backend_service .get_templates (
33413368 team_id = self ._project .team_id
@@ -3382,7 +3409,7 @@ def fill_classes_data(self, annotations: dict):
33823409 attribute ["groupName" ]
33833410 not in annotation_classes [annotation_class_name ]["attribute_groups" ]
33843411 ):
3385- self .unknown_attributes .append (attribute ["groupName" ])
3412+ self .unknown_attribute_groups .append (attribute ["groupName" ])
33863413 continue
33873414 attribute ["groupId" ] = annotation_classes [annotation_class_name ][
33883415 "attribute_groups"
@@ -3437,7 +3464,8 @@ def execute(self):
34373464 resource = session .resource ("s3" )
34383465 bucket = resource .Bucket (response .data .bucket )
34393466 self .fill_classes_data (self ._annotations )
3440- self .report_unknown_data ()
3467+ # skipped report
3468+ # self.report_unknown_data()
34413469 bucket .put_object (
34423470 Key = response .data .images [image_data ["id" ]]["annotation_json_path" ],
34433471 Body = json .dumps (self ._annotations ),
@@ -4922,52 +4950,57 @@ def _upload_image(self, image_path: str):
49224950 uploaded = False , path = image_path , entity = None , name = Path (image_path ).name
49234951 )
49244952
4953+ def filter_paths (self , paths : List [str ]):
4954+ paths = [
4955+ path
4956+ for path in paths
4957+ if not any (
4958+ [extension in path for extension in self .exclude_file_patterns ]
4959+ )
4960+ ]
4961+ name_path_map = defaultdict (list )
4962+ for path in paths :
4963+ name_path_map [Path (path ).name ].append (path )
4964+
4965+ filtered_paths = []
4966+ duplicated_paths = []
4967+ for file_name in name_path_map :
4968+ if len (name_path_map [file_name ]) > 1 :
4969+ duplicated_paths .append (name_path_map [file_name ][1 :])
4970+ filtered_paths .append (name_path_map [file_name ][0 ])
4971+
4972+ image_entities = (
4973+ GetBulkImages (
4974+ service = self ._backend_client ,
4975+ project_id = self ._project .uuid ,
4976+ team_id = self ._project .team_id ,
4977+ folder_id = self ._folder .uuid ,
4978+ images = [image .split ("/" )[- 1 ] for image in filtered_paths ],
4979+ ).execute ().data
4980+ )
4981+ images_to_upload = []
4982+ image_list = [image .name for image in image_entities ]
4983+
4984+ for path in filtered_paths :
4985+ if Path (path ).name not in image_list :
4986+ images_to_upload .append (path )
4987+ else :
4988+ duplicated_paths .append (path )
4989+ return list (set (images_to_upload )), duplicated_paths
4990+
49254991 @property
49264992 def images_to_upload (self ):
49274993 if not self ._images_to_upload :
4928- paths = self ._paths
4929- filtered_paths = []
4930- duplicated_paths = []
4931- for path in paths :
4932- if path .split ("/" )[- 1 ] not in [
4933- path_name .split ("/" )[- 1 ] for path_name in filtered_paths
4934- ]:
4935- filtered_paths .append (path )
4936- else :
4937- duplicated_paths .append (path )
4938- filtered_paths = [
4939- path
4940- for path in paths
4941- if not any (
4942- [extension in path for extension in self .exclude_file_patterns ]
4943- )
4944- ]
4945- image_entities = (
4946- GetBulkImages (
4947- service = self ._backend_client ,
4948- project_id = self ._project .uuid ,
4949- team_id = self ._project .team_id ,
4950- folder_id = self ._folder .uuid ,
4951- images = [image .split ("/" )[- 1 ] for image in filtered_paths ],
4952- )
4953- .execute ()
4954- .data
4955- )
4956- images_to_upload = []
4957- image_list = [image .name for image in image_entities ]
4958-
4959- for path in filtered_paths :
4960- if path not in image_list :
4961- images_to_upload .append (path )
4962- else :
4963- duplicated_paths .append (path )
4964- self ._images_to_upload = list (set (images_to_upload )), duplicated_paths
4994+ self ._images_to_upload = self .filter_paths (self ._paths )
49654995 return self ._images_to_upload
49664996
49674997 def execute (self ):
49684998 if self .is_valid ():
49694999 images_to_upload , duplications = self .images_to_upload
49705000 images_to_upload = images_to_upload [: self .auth_data ["availableImageCount" ]]
5001+ if not images_to_upload :
5002+ return self ._response
5003+
49715004 uploaded_images = []
49725005 failed_images = []
49735006 with concurrent .futures .ThreadPoolExecutor (
0 commit comments