VOC2012 Segmentation

This topic describes how to manage the VOC2012 Segmentation dataset, which is a dataset with SemanticMask and InstanceMask labels (Fig. 4 and Fig. 5).

../../_images/example-semanticmask.png

Fig. 4 The preview of a semantic mask from “VOC2012 Segmentation”.

../../_images/example-instancemask.png

Fig. 5 The preview of a instance mask from “VOC2012 Segmentation”.

Authorize a Client Instance

An accesskey is needed to authenticate identity when using TensorBay.

from tensorbay import GAS

ACCESS_KEY = "Accesskey-*****"
gas = GAS(ACCESS_KEY)

Create Dataset

gas.create_dataset("VOC2012Segmentation")

Organize Dataset

Normally, dataloader.py and catalog.json are required to organize the “VOC2012 Segmentation” dataset into the Dataset instance. In this example, they are stored in the same directory like:

VOC2012 Segmentation/
    catalog.json
    dataloader.py

It takes the following steps to organize “VOC2012 Segmentation” dataset by the Dataset instance.

Step 1: Write the Catalog

A Catalog contains all label information of one dataset, which is typically stored in a json file like catalog.json.

 1{
 2    "SEMANTIC_MASK": {
 3        "categories": [
 4            { "name": "background", "categoryId": 0 },
 5            { "name": "aeroplane", "categoryId": 1 },
 6            { "name": "bicycle", "categoryId": 2 },
 7            { "name": "bird", "categoryId": 3 },
 8            { "name": "boat", "categoryId": 4 },
 9            { "name": "bottle", "categoryId": 5 },
10            { "name": "bus", "categoryId": 6 },
11            { "name": "car", "categoryId": 7 },
12            { "name": "cat", "categoryId": 8 },
13            { "name": "chair", "categoryId": 9 },
14            { "name": "cow", "categoryId": 10 },
15            { "name": "diningtable", "categoryId": 11 },
16            { "name": "dog", "categoryId": 12 },
17            { "name": "horse", "categoryId": 13 },
18            { "name": "motorbike", "categoryId": 14 },
19            { "name": "person", "categoryId": 15 },
20            { "name": "pottedplant", "categoryId": 16 },
21            { "name": "sheep", "categoryId": 17 },
22            { "name": "sofa", "categoryId": 18 },
23            { "name": "train", "categoryId": 19 },
24            { "name": "tvmonitor", "categoryId": 20 },
25            { "name": "void", "categoryId": 255 }
26        ]
27    },
28    "INSTANCE_MASK": {
29        "categories": [
30            { "name": "background", "categoryId": 0 },
31            { "name": "void", "categoryId": 255 }
32        ]
33    }
34}

The annotation types for “VOC2012 Segmentation” are SemanticMask and InstanceMask, and there are 22 category types for SemanticMask. There are 2 category types for InstanceMask, category 0 represents the background, and category 255 represents the border of instances.

Note

  • By passing the path of the catalog.json, load_catalog() supports loading the catalog into dataset.

  • The categories in InstanceMaskSubcatalog are for pixel values which are not instance ids.

Important

See catalog table for more catalogs with different label types.

Step 2: Write the Dataloader

A dataloader is needed to organize the dataset into a Dataset instance.

 1#!/usr/bin/env python3
 2#
 3# Copyright 2021 Graviti. Licensed under MIT License.
 4#
 5# pylint: disable=invalid-name
 6
 7"""Dataloader of VOC2012Segmentation dataset."""
 8
 9import os
10
11from tensorbay.dataset import Data, Dataset
12from tensorbay.label import InstanceMask, SemanticMask
13
14_SEGMENT_NAMES = ("train", "val")
15DATASET_NAME = "VOC2012Segmentation"
16
17
18def VOC2012Segmentation(path: str) -> Dataset:
19    """`VOC2012Segmentation <http://host.robots.ox.ac.uk/pascal/VOC/voc2012/>`_ dataset.
20
21    The file structure should be like::
22
23        <path>/
24            JPEGImages/
25                <image_name>.jpg
26                ...
27            SegmentationClass/
28                <mask_name>.png
29                ...
30            SegmentationObject/
31                <mask_name>.png
32                ...
33            ImageSets/
34                Segmentation/
35                    train.txt
36                    val.txt
37                    ...
38                ...
39            ...
40
41    Arguments:
42        path: The root directory of the dataset.
43
44    Returns:
45        Loaded :class: `~tensorbay.dataset.dataset.Dataset` instance.
46
47    """
48    root_path = os.path.abspath(os.path.expanduser(path))
49
50    image_path = os.path.join(root_path, "JPEGImages")
51    semantic_mask_path = os.path.join(root_path, "SegmentationClass")
52    instance_mask_path = os.path.join(root_path, "SegmentationObject")
53    image_set_path = os.path.join(root_path, "ImageSets", "Segmentation")
54
55    dataset = Dataset(DATASET_NAME)
56    dataset.load_catalog(os.path.join(os.path.dirname(__file__), "catalog.json"))
57
58    for segment_name in _SEGMENT_NAMES:
59        segment = dataset.create_segment(segment_name)
60        with open(os.path.join(image_set_path, f"{segment_name}.txt"), encoding="utf-8") as fp:
61            for stem in fp:
62                stem = stem.strip()
63                data = Data(os.path.join(image_path, f"{stem}.jpg"))
64                label = data.label
65                mask_filename = f"{stem}.png"
66                label.semantic_mask = SemanticMask(os.path.join(semantic_mask_path, mask_filename))
67                label.instance_mask = InstanceMask(os.path.join(instance_mask_path, mask_filename))
68
69                segment.append(data)
70
71    return dataset

See SemanticMask annotation and InstanceMask annotation for more details.

There are already a number of dataloaders in TensorBay SDK provided by the community. Thus, instead of writing, importing an available dataloader is also feasible.

from tensorbay.opendataset import VOC2012Segmentation

dataset = VOC2012Segmentation("path/to/dataset/directory")

Note

Note that catalogs are automatically loaded in available dataloaders, users do not have to write them again.

Important

See dataloader table for dataloaders with different label types.

Upload Dataset

The organized “VOC2012 Segmentation” dataset can be uploaded to tensorBay for sharing, reuse, etc.

dataset_client = gas.upload_dataset(dataset, jobs=8)
dataset_client.commit("initial commit")

Similar with Git, the commit step after uploading can record changes to the dataset as a version. If needed, do the modifications and commit again. Please see Version Control for more details.

See the visualization on TensorBay website.

Read Dataset

Now “VOC2012 Segmentation” dataset can be read from TensorBay.

dataset = Dataset("VOC2012Segmentation", gas)

In dataset “VOC2012 Segmentation”, there are two segments: train and val. Get a segment by passing the required segment name or the index.

segment_names = dataset.keys()
segment = dataset[0]

In the train segment, there is a sequence of data, which can be obtained by index.

data = segment[0]

In each data, there are one SemanticMask annotation and one InstanceMask annotation.

from PIL import Image

label_semantic_mask = data.label.semantic_mask
semantic_all_attributes = label_semantic_mask.all_attributes
semantic_mask = Image.open(label_semantic_mask.open())
semantic_mask.show()

label_instance_mask = data.label.instance_mask
instance_all_attributes = label_instance_mask.all_attributes
instance_mask_url = label_instance_mask.get_url()

There are two label types in “VOC2012 Segmentation” dataset, which are semantic_mask and instance_mask. We can get the mask by Image.open() or get the mask url by get_url(). The information stored in SemanticMask.all_attributes is attributes for every category in categories list of SEMANTIC_MASK. The information stored in InstanceMask.all_attributes is attributes for every instance. See SemanticMask and InstanceMask label formats for more details.

Delete Dataset

gas.delete_dataset("VOC2012Segmentation")