6
6
"name" : "MASK" ,
7
7
"dumpers" : [
8
8
{
9
- "display_name" : "{name} {format} {version}" ,
9
+ "display_name" : "{name} (by class) {format} {version}" ,
10
10
"format" : "ZIP" ,
11
11
"version" : "1.0" ,
12
- "handler" : "dump"
12
+ "handler" : "dump_by_class"
13
+ },
14
+ {
15
+ "display_name" : "{name} (by instance) {format} {version}" ,
16
+ "format" : "ZIP" ,
17
+ "version" : "1.0" ,
18
+ "handler" : "dump_by_instance"
13
19
},
14
20
],
15
21
"loaders" : [
16
22
],
17
23
}
18
24
19
- def dump (file_object , annotations ):
20
- from zipfile import ZipFile
21
- import numpy as np
22
- import os
23
- from pycocotools import mask as maskUtils
24
- import matplotlib .image
25
- import io
26
- from collections import OrderedDict
27
-
28
- # RGB format, (0, 0, 0) used for background
29
- def genearte_pascal_colormap (size = 256 ):
30
- colormap = np .zeros ((size , 3 ), dtype = int )
31
- ind = np .arange (size , dtype = int )
32
-
33
- for shift in reversed (range (8 )):
34
- for channel in range (3 ):
35
- colormap [:, channel ] |= ((ind >> channel ) & 1 ) << shift
36
- ind >>= 3
37
-
38
- return colormap
25
+ MASK_BY_CLASS = 0
26
+ MASK_BY_INSTANCE = 1
39
27
40
- def convert_box_to_polygon (points ):
28
+ def convert_box_to_polygon (shape ):
41
29
xtl = shape .points [0 ]
42
30
ytl = shape .points [1 ]
43
31
xbr = shape .points [2 ]
44
32
ybr = shape .points [3 ]
45
33
46
34
return [xtl , ytl , xbr , ytl , xbr , ybr , xtl , ybr ]
47
35
48
- colormap = genearte_pascal_colormap ()
49
- labels = [label [1 ]["name" ] for label in annotations .meta ["task" ]["labels" ] if label [1 ]["name" ] != 'background' ]
50
- labels .insert (0 , 'background' )
51
- label_colors = OrderedDict ((label , colormap [idx ]) for idx , label in enumerate (labels ))
36
+ def create_mask_colorizer (annotations , colorize_type ):
37
+ import numpy as np
38
+ from collections import OrderedDict
39
+
40
+ class MaskColorizer :
41
+
42
+ def __init__ (self , annotations , colorize_type ):
43
+
44
+ if colorize_type == MASK_BY_CLASS :
45
+ self .colors = self .gen_class_mask_colors (annotations )
46
+ elif colorize_type == MASK_BY_INSTANCE :
47
+ self .colors = self .gen_instance_mask_colors ()
48
+
49
+ def generate_pascal_colormap (self , size = 256 ):
50
+ # RGB format, (0, 0, 0) used for background
51
+ colormap = np .zeros ((size , 3 ), dtype = int )
52
+ ind = np .arange (size , dtype = int )
53
+
54
+ for shift in reversed (range (8 )):
55
+ for channel in range (3 ):
56
+ colormap [:, channel ] |= ((ind >> channel ) & 1 ) << shift
57
+ ind >>= 3
52
58
53
- with ZipFile (file_object , "w" ) as output_zip :
59
+ return colormap
60
+
61
+ def gen_class_mask_colors (self , annotations ):
62
+ colormap = self .generate_pascal_colormap ()
63
+ labels = [label [1 ]["name" ] for label in annotations .meta ["task" ]["labels" ] if label [1 ]["name" ] != 'background' ]
64
+ labels .insert (0 , 'background' )
65
+ label_colors = OrderedDict ((label , colormap [idx ]) for idx , label in enumerate (labels ))
66
+
67
+ return label_colors
68
+
69
+ def gen_instance_mask_colors (self ):
70
+ colormap = self .generate_pascal_colormap ()
71
+ # The first color is black
72
+ instance_colors = OrderedDict ((idx , colormap [idx ]) for idx in range (len (colormap )))
73
+
74
+ return instance_colors
75
+
76
+ return MaskColorizer (annotations , colorize_type )
77
+
78
+ def dump (file_object , annotations , colorize_type ):
79
+
80
+ from zipfile import ZipFile , ZIP_STORED
81
+ import numpy as np
82
+ import os
83
+ from pycocotools import mask as maskUtils
84
+ import matplotlib .image
85
+ import io
86
+
87
+ colorizer = create_mask_colorizer (annotations , colorize_type = colorize_type )
88
+ if colorize_type == MASK_BY_CLASS :
89
+ save_dir = "SegmentationClass"
90
+ elif colorize_type == MASK_BY_INSTANCE :
91
+ save_dir = "SegmentationObject"
92
+
93
+ with ZipFile (file_object , "w" , ZIP_STORED ) as output_zip :
54
94
for frame_annotation in annotations .group_by_frame ():
55
95
image_name = frame_annotation .name
56
96
annotation_name = "{}.png" .format (os .path .splitext (os .path .basename (image_name ))[0 ])
@@ -63,18 +103,33 @@ def convert_box_to_polygon(points):
63
103
if not shapes :
64
104
continue
65
105
shapes = sorted (shapes , key = lambda x : int (x .z_order ))
66
- img = np .zeros ((height , width , 3 ))
67
- buf = io .BytesIO ()
68
- for shape in shapes :
69
- points = shape .points if shape .type != 'rectangle' else convert_box_to_polygon (shape . points )
106
+ img_mask = np .zeros ((height , width , 3 ))
107
+ buf_mask = io .BytesIO ()
108
+ for shape_index , shape in enumerate ( shapes ) :
109
+ points = shape .points if shape .type != 'rectangle' else convert_box_to_polygon (shape )
70
110
rles = maskUtils .frPyObjects ([points ], height , width )
71
111
rle = maskUtils .merge (rles )
72
112
mask = maskUtils .decode (rle )
73
- color = label_colors [shape .label ] / 255
74
113
idx = (mask > 0 )
75
- img [idx ] = color
114
+ # get corresponding color
115
+ if colorize_type == MASK_BY_CLASS :
116
+ color = colorizer .colors [shape .label ] / 255
117
+ elif colorize_type == MASK_BY_INSTANCE :
118
+ color = colorizer .colors [shape_index + 1 ] / 255
119
+
120
+ img_mask [idx ] = color
76
121
77
- matplotlib .image .imsave (buf , img , format = 'png' )
78
- output_zip .writestr (annotation_name , buf .getvalue ())
79
- labels = '\n ' .join ('{}:{}' .format (label , ',' .join (str (i ) for i in color )) for label , color in label_colors .items ())
122
+ # write mask
123
+ matplotlib .image .imsave (buf_mask , img_mask , format = 'png' )
124
+ output_zip .writestr (os .path .join (save_dir , annotation_name ), buf_mask .getvalue ())
125
+ # Store color map for each class
126
+ labels = '\n ' .join ('{}:{}' .format (label , ',' .join (str (i ) for i in color )) for label , color in colorizer .colors .items ())
80
127
output_zip .writestr ('colormap.txt' , labels )
128
+
129
+ def dump_by_class (file_object , annotations ):
130
+
131
+ return dump (file_object , annotations , MASK_BY_CLASS )
132
+
133
+ def dump_by_instance (file_object , annotations ):
134
+
135
+ return dump (file_object , annotations , MASK_BY_INSTANCE )
0 commit comments