OMG_Seg / ext /cityscapes_scripts /createPanopticImgs.py
Haobo Yuan
add omg code
b34d1d6
raw
history blame
7.76 kB
#!/usr/bin/python
#
# Converts the *instanceIds.png annotations of the Cityscapes dataset
# to COCO-style panoptic segmentation format (http://cocodataset.org/#format-data).
# The convertion is working for 'fine' set of the annotations.
#
# By default with this tool uses IDs specified in labels.py. You can use flag
# --use-train-id to get train ids for categories. 'ignoreInEval' categories are
# removed during the conversion.
#
# In panoptic segmentation format image_id is used to match predictions and ground truth.
# For cityscapes image_id has form <city>_123456_123456 and corresponds to the prefix
# of cityscapes image files.
#
# python imports
from __future__ import print_function, absolute_import, division, unicode_literals
import os
import glob
import sys
import argparse
import json
import numpy as np
# Image processing
from PIL import Image
# cityscapes imports
from ext.cityscapes_scripts.helpers.csHelpers import printError
from ext.cityscapes_scripts.helpers.labels import id2label, labels
import mmengine
# The main method
def convert2panoptic(cityscapesPath=None, outputFolder=None, useTrainId=False, setNames=["val", "train", "test"]):
# Where to look for Cityscapes
if cityscapesPath is None:
if 'CITYSCAPES_DATASET' in os.environ:
cityscapesPath = os.environ['CITYSCAPES_DATASET']
else:
cityscapesPath = 'data/cityscapes'
cityscapesPath = os.path.join(cityscapesPath, "gtFine")
if outputFolder is None:
outputFolder = cityscapesPath.replace('gtFine', "annotations")
mmengine.mkdir_or_exist(outputFolder)
categories = []
for label in labels:
if label.ignoreInEval:
continue
categories.append({'id': int(label.trainId) if useTrainId else int(label.id),
'name': label.name,
'color': label.color,
'supercategory': label.category,
'isthing': 1 if label.hasInstances else 0})
categories = sorted(categories, key=lambda x:x['id'])
for setName in setNames:
# how to search for all ground truth
searchFine = os.path.join(cityscapesPath, setName, "*", "*_instanceIds.png")
# search files
filesFine = glob.glob(searchFine)
filesFine.sort()
files = filesFine
# quit if we did not find anything
if not files:
printError(
"Did not find any files for {} set using matching pattern {}. Please consult the README.".format(setName, searchFine)
)
# a bit verbose
print("Converting {} annotation files for {} set.".format(len(files), setName))
trainIfSuffix = "_trainId" if useTrainId else ""
outputBaseFile = "cityscapes_panoptic_{}{}".format(setName, trainIfSuffix)
outFile = os.path.join(outputFolder, "{}.json".format(outputBaseFile))
print("Json file with the annotations in panoptic format will be saved in {}".format(outFile))
panopticFolder = os.path.join(outputFolder, outputBaseFile)
if not os.path.isdir(panopticFolder):
print("Creating folder {} for panoptic segmentation PNGs".format(panopticFolder))
os.mkdir(panopticFolder)
print("Corresponding segmentations in .png format will be saved in {}".format(panopticFolder))
images = []
annotations = []
for progress, f in enumerate(files):
originalFormat = np.array(Image.open(f))
fileName = os.path.basename(f)
location = fileName.split('_')[0]
imageId = fileName.replace("_gtFine_instanceIds.png", "")
fileName = os.path.join(location, fileName)
inputFileName = fileName.replace("_gtFine_instanceIds.png", "_leftImg8bit.png")
outputFileName = fileName.replace("_gtFine_instanceIds.png", "_panoptic.png")
# image entry, id for image is its filename without extension
images.append({"id": imageId,
"width": int(originalFormat.shape[1]),
"height": int(originalFormat.shape[0]),
"file_name": inputFileName})
pan_format = np.zeros(
(originalFormat.shape[0], originalFormat.shape[1], 3), dtype=np.uint8
)
segmentIds = np.unique(originalFormat)
segmInfo = []
for segmentId in segmentIds:
if segmentId < 1000:
semanticId = segmentId
isCrowd = 1
else:
semanticId = segmentId // 1000
isCrowd = 0
labelInfo = id2label[semanticId]
categoryId = labelInfo.trainId if useTrainId else labelInfo.id
if labelInfo.ignoreInEval:
continue
if not labelInfo.hasInstances:
isCrowd = 0
mask = originalFormat == segmentId
color = [segmentId % 256, segmentId // 256, segmentId // 256 // 256]
pan_format[mask] = color
area = np.sum(mask) # segment area computation
# bbox computation for a segment
hor = np.sum(mask, axis=0)
hor_idx = np.nonzero(hor)[0]
x = hor_idx[0]
width = hor_idx[-1] - x + 1
vert = np.sum(mask, axis=1)
vert_idx = np.nonzero(vert)[0]
y = vert_idx[0]
height = vert_idx[-1] - y + 1
bbox = [int(x), int(y), int(width), int(height)]
segmInfo.append({"id": int(segmentId),
"category_id": int(categoryId),
"area": int(area),
"bbox": bbox,
"iscrowd": isCrowd})
annotations.append({'image_id': imageId,
'file_name': outputFileName,
"segments_info": segmInfo})
mmengine.mkdir_or_exist(os.path.dirname(os.path.join(panopticFolder, outputFileName)))
Image.fromarray(pan_format).save(os.path.join(panopticFolder, outputFileName))
print("\rProgress: {:>3.2f} %".format((progress + 1) * 100 / len(files)), end=' ')
sys.stdout.flush()
print("\nSaving the json file {}".format(outFile))
d = {'images': images,
'annotations': annotations,
'categories': categories}
with open(outFile, 'w') as f:
json.dump(d, f, sort_keys=True, indent=4)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--dataset-folder",
dest="cityscapesPath",
help="path to the Cityscapes dataset 'gtFine' folder",
default=None,
type=str)
parser.add_argument("--output-folder",
dest="outputFolder",
help="path to the output folder.",
default=None,
type=str)
parser.add_argument("--use-train-id", default=True,action="store_true", dest="useTrainId")
parser.add_argument("--set-names",
dest="setNames",
help="set names to which apply the function to",
nargs='+',
default=["val", "train"],
type=str)
args = parser.parse_args()
convert2panoptic(args.cityscapesPath, args.outputFolder, args.useTrainId, args.setNames)
# call the main
if __name__ == "__main__":
main()