Function for converting segmentation polygons in MS-COCO
object detection dataset to segmentation masks. The seg-
mentation masks are stored with a colour palette that's
randomly assigned based on class if specified. Change
the seed if you want to change colours.
Parameters:
Name |
Type |
Description |
Default |
cann |
dict
|
COCO annotation object |
required
|
output_dir |
str
|
Directory to store segmentation masks |
required
|
palette |
bool
|
Use palette. Defaults to True. |
True
|
Raises:
Type |
Description |
AssertionError
|
Incorrect shape for colour map array |
AssertionError
|
Muliple images have same image id |
Source code in coco_assistant/utils/det2seg.py
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 | def det2seg(cann, output_dir, palette=True):
"""
Function for converting segmentation polygons in MS-COCO
object detection dataset to segmentation masks. The seg-
mentation masks are stored with a colour palette that's
randomly assigned based on class if specified. Change
the seed if you want to change colours.
Args:
cann (dict): COCO annotation object
output_dir (str): Directory to store segmentation masks
palette (bool, optional): Use palette. Defaults to True.
Raises:
AssertionError: Incorrect shape for colour map array
AssertionError: Muliple images have same image id
"""
output_dir = Path(output_dir)
if not output_dir.is_dir():
output_dir.mkdir(parents=True, exist_ok=True)
imids = cann.getImgIds()
cats = cann.loadCats(cann.getCatIds())
cat_colours = {0: (0, 0, 0)}
# Set seed for palette colour
np.random.seed(121)
# Create category colourmap
for c in cats:
cat_colours[c["id"]] = (
np.random.randint(0, 256),
np.random.randint(0, 256),
np.random.randint(0, 256),
)
colour_map = np.array(list(cat_colours.values()))
if colour_map.shape != (len(cats) + 1, 3):
raise AssertionError("Incorrect shape of color map array")
for imid in tqdm(imids):
img = cann.loadImgs(imid)
if len(img) > 1:
raise AssertionError("Multiple images with same id")
h, w = img[0]["height"], img[0]["width"]
name = img[0]["file_name"]
name = Path(name)
if name.suffix.lower() != ".png":
name = name.stem + ".png"
im = np.zeros((h, w), dtype=np.uint8)
annids = cann.getAnnIds(imgIds=[imid])
if not annids:
# No annotations
res = Image.fromarray(im)
else:
anns = cann.loadAnns(annids)
areas = [i["area"] for i in anns]
area_ids = [i for i in range(1, len(areas) + 1)][::-1]
area_id_map = dict(zip(sorted(areas), area_ids))
area_cat_map = {}
# Assumption: area of objects are unique
for ann in anns:
aid = area_id_map[ann["area"]]
bMask = cann.annToMask(ann)
aMask = bMask * aid
im = np.maximum(im, aMask)
area_cat_map[aid] = ann["category_id"]
# Ref: https://stackoverflow.com/questions/55949809/efficiently-replace-elements-in-array-based-on-dictionary-numpy-python/55950051#55950051
k = np.array(list(area_cat_map.keys()))
v = np.array(list(area_cat_map.values()))
mapping_ar = np.zeros(k.max() + 1, dtype=np.uint8)
mapping_ar[k] = v
res = mapping_ar[im]
res = Image.fromarray(res)
if palette:
res.putpalette(colour_map.astype(np.uint8))
res.save(output_dir / f"{name}")
|