Skip to content

Det2seg

coco_assistant.utils.det2seg

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.

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}")