|
|
|
import json
|
|
import logging
|
|
import os
|
|
|
|
from detectron2.data import DatasetCatalog, MetadataCatalog
|
|
from detectron2.data.datasets.builtin_meta import CITYSCAPES_CATEGORIES
|
|
from detectron2.utils.file_io import PathManager
|
|
|
|
"""
|
|
This file contains functions to register the Cityscapes panoptic dataset to the DatasetCatalog.
|
|
"""
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_cityscapes_panoptic_files(image_dir, gt_dir, json_info):
|
|
files = []
|
|
|
|
cities = PathManager.ls(image_dir)
|
|
logger.info(f"{len(cities)} cities found in '{image_dir}'.")
|
|
image_dict = {}
|
|
for city in cities:
|
|
city_img_dir = os.path.join(image_dir, city)
|
|
for basename in PathManager.ls(city_img_dir):
|
|
image_file = os.path.join(city_img_dir, basename)
|
|
|
|
suffix = "_leftImg8bit.png"
|
|
assert basename.endswith(suffix), basename
|
|
basename = os.path.basename(basename)[: -len(suffix)]
|
|
|
|
image_dict[basename] = image_file
|
|
|
|
for ann in json_info["annotations"]:
|
|
image_file = image_dict.get(ann["image_id"], None)
|
|
assert image_file is not None, "No image {} found for annotation {}".format(
|
|
ann["image_id"], ann["file_name"]
|
|
)
|
|
label_file = os.path.join(gt_dir, ann["file_name"])
|
|
segments_info = ann["segments_info"]
|
|
|
|
files.append((image_file, label_file, segments_info))
|
|
|
|
assert len(files), "No images found in {}".format(image_dir)
|
|
assert PathManager.isfile(files[0][0]), files[0][0]
|
|
assert PathManager.isfile(files[0][1]), files[0][1]
|
|
return files
|
|
|
|
|
|
def load_cityscapes_panoptic(image_dir, gt_dir, gt_json, meta):
|
|
"""
|
|
Args:
|
|
image_dir (str): path to the raw dataset. e.g., "~/cityscapes/leftImg8bit/train".
|
|
gt_dir (str): path to the raw annotations. e.g.,
|
|
"~/cityscapes/gtFine/cityscapes_panoptic_train".
|
|
gt_json (str): path to the json file. e.g.,
|
|
"~/cityscapes/gtFine/cityscapes_panoptic_train.json".
|
|
meta (dict): dictionary containing "thing_dataset_id_to_contiguous_id"
|
|
and "stuff_dataset_id_to_contiguous_id" to map category ids to
|
|
contiguous ids for training.
|
|
|
|
Returns:
|
|
list[dict]: a list of dicts in Detectron2 standard format. (See
|
|
`Using Custom Datasets </tutorials/datasets.html>`_ )
|
|
"""
|
|
|
|
def _convert_category_id(segment_info, meta):
|
|
if segment_info["category_id"] in meta["thing_dataset_id_to_contiguous_id"]:
|
|
segment_info["category_id"] = meta["thing_dataset_id_to_contiguous_id"][
|
|
segment_info["category_id"]
|
|
]
|
|
else:
|
|
segment_info["category_id"] = meta["stuff_dataset_id_to_contiguous_id"][
|
|
segment_info["category_id"]
|
|
]
|
|
return segment_info
|
|
|
|
assert os.path.exists(
|
|
gt_json
|
|
), "Please run `python cityscapesscripts/preparation/createPanopticImgs.py` to generate label files."
|
|
with open(gt_json) as f:
|
|
json_info = json.load(f)
|
|
files = get_cityscapes_panoptic_files(image_dir, gt_dir, json_info)
|
|
ret = []
|
|
for image_file, label_file, segments_info in files:
|
|
sem_label_file = (
|
|
image_file.replace("leftImg8bit", "gtFine").split(".")[0] + "_labelTrainIds.png"
|
|
)
|
|
segments_info = [_convert_category_id(x, meta) for x in segments_info]
|
|
ret.append(
|
|
{
|
|
"file_name": image_file,
|
|
"image_id": "_".join(
|
|
os.path.splitext(os.path.basename(image_file))[0].split("_")[:3]
|
|
),
|
|
"sem_seg_file_name": sem_label_file,
|
|
"pan_seg_file_name": label_file,
|
|
"segments_info": segments_info,
|
|
}
|
|
)
|
|
assert len(ret), f"No images found in {image_dir}!"
|
|
assert PathManager.isfile(
|
|
ret[0]["sem_seg_file_name"]
|
|
), "Please generate labelTrainIds.png with cityscapesscripts/preparation/createTrainIdLabelImgs.py"
|
|
assert PathManager.isfile(
|
|
ret[0]["pan_seg_file_name"]
|
|
), "Please generate panoptic annotation with python cityscapesscripts/preparation/createPanopticImgs.py"
|
|
return ret
|
|
|
|
|
|
_RAW_CITYSCAPES_PANOPTIC_SPLITS = {
|
|
"cityscapes_fine_panoptic_train": (
|
|
"cityscapes/leftImg8bit/train",
|
|
"cityscapes/gtFine/cityscapes_panoptic_train",
|
|
"cityscapes/gtFine/cityscapes_panoptic_train.json",
|
|
),
|
|
"cityscapes_fine_panoptic_val": (
|
|
"cityscapes/leftImg8bit/val",
|
|
"cityscapes/gtFine/cityscapes_panoptic_val",
|
|
"cityscapes/gtFine/cityscapes_panoptic_val.json",
|
|
),
|
|
|
|
}
|
|
|
|
|
|
def register_all_cityscapes_panoptic(root):
|
|
meta = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
thing_classes = [k["name"] for k in CITYSCAPES_CATEGORIES]
|
|
thing_colors = [k["color"] for k in CITYSCAPES_CATEGORIES]
|
|
stuff_classes = [k["name"] for k in CITYSCAPES_CATEGORIES]
|
|
stuff_colors = [k["color"] for k in CITYSCAPES_CATEGORIES]
|
|
|
|
meta["thing_classes"] = thing_classes
|
|
meta["thing_colors"] = thing_colors
|
|
meta["stuff_classes"] = stuff_classes
|
|
meta["stuff_colors"] = stuff_colors
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
thing_dataset_id_to_contiguous_id = {}
|
|
stuff_dataset_id_to_contiguous_id = {}
|
|
|
|
for k in CITYSCAPES_CATEGORIES:
|
|
if k["isthing"] == 1:
|
|
thing_dataset_id_to_contiguous_id[k["id"]] = k["trainId"]
|
|
else:
|
|
stuff_dataset_id_to_contiguous_id[k["id"]] = k["trainId"]
|
|
|
|
meta["thing_dataset_id_to_contiguous_id"] = thing_dataset_id_to_contiguous_id
|
|
meta["stuff_dataset_id_to_contiguous_id"] = stuff_dataset_id_to_contiguous_id
|
|
|
|
for key, (image_dir, gt_dir, gt_json) in _RAW_CITYSCAPES_PANOPTIC_SPLITS.items():
|
|
image_dir = os.path.join(root, image_dir)
|
|
gt_dir = os.path.join(root, gt_dir)
|
|
gt_json = os.path.join(root, gt_json)
|
|
|
|
DatasetCatalog.register(
|
|
key, lambda x=image_dir, y=gt_dir, z=gt_json: load_cityscapes_panoptic(x, y, z, meta)
|
|
)
|
|
MetadataCatalog.get(key).set(
|
|
panoptic_root=gt_dir,
|
|
image_root=image_dir,
|
|
panoptic_json=gt_json,
|
|
gt_dir=gt_dir.replace("cityscapes_panoptic_", ""),
|
|
evaluator_type="cityscapes_panoptic_seg",
|
|
ignore_label=255,
|
|
label_divisor=1000,
|
|
**meta,
|
|
)
|
|
|