14
14
from datumaro .components .extractor import (
15
15
DEFAULT_SUBSET_NAME , AnnotationType , PointsObject , BboxObject
16
16
)
17
- from datumaro .components .formats .ms_coco import CocoAnnotationType , CocoPath
17
+ from datumaro .components .formats .ms_coco import CocoTask , CocoPath
18
18
from datumaro .util import find
19
19
from datumaro .util .image import save_image
20
20
import datumaro .util .mask_tools as mask_tools
@@ -29,8 +29,9 @@ def _cast(value, type_conv, default=None):
29
29
return default
30
30
31
31
class _TaskConverter :
32
- def __init__ (self ):
32
+ def __init__ (self , context ):
33
33
self ._min_ann_id = 1
34
+ self ._context = context
34
35
35
36
data = {
36
37
'licenses' : [],
@@ -191,6 +192,13 @@ def save_annotations(self, item):
191
192
rle = mask_utils .merge (rles )
192
193
area = mask_utils .area (rle )
193
194
195
+ if self ._context ._merge_polygons :
196
+ binary_mask = mask_utils .decode (rle ).astype (np .bool )
197
+ binary_mask = np .asfortranarray (binary_mask , dtype = np .uint8 )
198
+ segmentation = mask_tools .convert_mask_to_rle (binary_mask )
199
+ is_crowd = True
200
+ bbox = [int (i ) for i in mask_utils .toBbox (rle )]
201
+
194
202
if ann .group is not None :
195
203
# Mark the group as visited to prevent repeats
196
204
for a in annotations [:]:
@@ -201,6 +209,18 @@ def save_annotations(self, item):
201
209
is_crowd = False
202
210
segmentation = [ann .get_polygon ()]
203
211
area = ann .area ()
212
+
213
+ if self ._context ._merge_polygons :
214
+ h , w , _ = item .image .shape
215
+ rles = mask_utils .frPyObjects (segmentation , h , w )
216
+ rle = mask_utils .merge (rles )
217
+ area = mask_utils .area (rle )
218
+ binary_mask = mask_utils .decode (rle ).astype (np .bool )
219
+ binary_mask = np .asfortranarray (binary_mask , dtype = np .uint8 )
220
+ segmentation = mask_tools .convert_mask_to_rle (binary_mask )
221
+ is_crowd = True
222
+ bbox = [int (i ) for i in mask_utils .toBbox (rle )]
223
+
204
224
if bbox is None :
205
225
bbox = ann .get_bbox ()
206
226
@@ -340,22 +360,30 @@ def save_annotations(self, item):
340
360
341
361
class _Converter :
342
362
_TASK_CONVERTER = {
343
- CocoAnnotationType .image_info : _ImageInfoConverter ,
344
- CocoAnnotationType .instances : _InstancesConverter ,
345
- CocoAnnotationType .person_keypoints : _KeypointsConverter ,
346
- CocoAnnotationType .captions : _CaptionsConverter ,
347
- CocoAnnotationType .labels : _LabelsConverter ,
363
+ CocoTask .image_info : _ImageInfoConverter ,
364
+ CocoTask .instances : _InstancesConverter ,
365
+ CocoTask .person_keypoints : _KeypointsConverter ,
366
+ CocoTask .captions : _CaptionsConverter ,
367
+ CocoTask .labels : _LabelsConverter ,
348
368
}
349
369
350
- def __init__ (self , extractor , save_dir , save_images = False , task = None ):
351
- if not task :
352
- task = list (self ._TASK_CONVERTER .keys ())
353
- elif task in CocoAnnotationType :
354
- task = [task ]
355
- self ._task = task
370
+ def __init__ (self , extractor , save_dir ,
371
+ tasks = None , save_images = False , merge_polygons = False ):
372
+ assert tasks is None or isinstance (tasks , (CocoTask , list ))
373
+ if tasks is None :
374
+ tasks = list (self ._TASK_CONVERTER )
375
+ elif isinstance (tasks , CocoTask ):
376
+ tasks = [tasks ]
377
+ else :
378
+ for t in tasks :
379
+ assert t in CocoTask
380
+ self ._tasks = tasks
381
+
356
382
self ._extractor = extractor
357
383
self ._save_dir = save_dir
384
+
358
385
self ._save_images = save_images
386
+ self ._merge_polygons = merge_polygons
359
387
360
388
def make_dirs (self ):
361
389
self ._images_dir = osp .join (self ._save_dir , CocoPath .IMAGES_DIR )
@@ -365,11 +393,13 @@ def make_dirs(self):
365
393
os .makedirs (self ._ann_dir , exist_ok = True )
366
394
367
395
def make_task_converter (self , task ):
368
- return self ._TASK_CONVERTER [task ]()
396
+ if task not in self ._TASK_CONVERTER :
397
+ raise NotImplementedError ()
398
+ return self ._TASK_CONVERTER [task ](self )
369
399
370
400
def make_task_converters (self ):
371
401
return {
372
- task : self .make_task_converter (task ) for task in self ._task
402
+ task : self .make_task_converter (task ) for task in self ._tasks
373
403
}
374
404
375
405
def save_image (self , item , filename ):
@@ -411,32 +441,56 @@ def convert(self):
411
441
'%s_%s.json' % (task .name , subset_name )))
412
442
413
443
class CocoConverter (Converter ):
414
- def __init__ (self , task = None , save_images = False ):
444
+ def __init__ (self ,
445
+ tasks = None , save_images = False , merge_polygons = False ,
446
+ cmdline_args = None ):
415
447
super ().__init__ ()
416
- self ._task = task
417
- self ._save_images = save_images
448
+
449
+ self ._options = {
450
+ 'tasks' : tasks ,
451
+ 'save_images' : save_images ,
452
+ 'merge_polygons' : merge_polygons ,
453
+ }
454
+
455
+ if cmdline_args is not None :
456
+ self ._options .update (self ._parse_cmdline (cmdline_args ))
457
+
458
+ @staticmethod
459
+ def _split_tasks_string (s ):
460
+ return [CocoTask [i .strip ()] for i in s .split (',' )]
461
+
462
+ @classmethod
463
+ def build_cmdline_parser (cls , parser = None ):
464
+ import argparse
465
+ if not parser :
466
+ parser = argparse .ArgumentParser ()
467
+
468
+ parser .add_argument ('--save-images' , action = 'store_true' ,
469
+ help = "Save images (default: %(default)s)" )
470
+ parser .add_argument ('--merge-polygons' , action = 'store_true' ,
471
+ help = "Merge instance polygons into a mask (default: %(default)s)" )
472
+ parser .add_argument ('--tasks' , type = cls ._split_tasks_string ,
473
+ default = None ,
474
+ help = "COCO task filter, comma-separated list of {%s} "
475
+ "(default: all)" % ', ' .join ([t .name for t in CocoTask ]))
476
+
477
+ return parser
418
478
419
479
def __call__ (self , extractor , save_dir ):
420
- converter = _Converter (extractor , save_dir ,
421
- save_images = self ._save_images , task = self ._task )
480
+ converter = _Converter (extractor , save_dir , ** self ._options )
422
481
converter .convert ()
423
482
424
- def CocoInstancesConverter (save_images = False ):
425
- return CocoConverter (CocoAnnotationType .instances ,
426
- save_images = save_images )
483
+ def CocoInstancesConverter (** kwargs ):
484
+ return CocoConverter (CocoTask .instances , ** kwargs )
427
485
428
- def CocoImageInfoConverter (save_images = False ):
429
- return CocoConverter (CocoAnnotationType .image_info ,
430
- save_images = save_images )
486
+ def CocoImageInfoConverter (** kwargs ):
487
+ return CocoConverter (CocoTask .image_info , ** kwargs )
431
488
432
- def CocoPersonKeypointsConverter (save_images = False ):
433
- return CocoConverter (CocoAnnotationType .person_keypoints ,
434
- save_images = save_images )
489
+ def CocoPersonKeypointsConverter (** kwargs ):
490
+ return CocoConverter (CocoTask .person_keypoints , ** kwargs )
435
491
436
- def CocoCaptionsConverter (save_images = False ):
437
- return CocoConverter (CocoAnnotationType .captions ,
438
- save_images = save_images )
492
+ def CocoCaptionsConverter (** kwargs ):
493
+ return CocoConverter (CocoTask .captions , ** kwargs )
439
494
440
- def CocoLabelsConverter (save_images = False ):
441
- return CocoConverter (CocoAnnotationType .labels ,
442
- save_images = save_images )
495
+ def CocoLabelsConverter (** kwargs ):
496
+ return CocoConverter (CocoTask .labels , ** kwargs )
0 commit comments