Spaces:
Sleeping
Sleeping
File size: 7,761 Bytes
b34d1d6 |
1 2 3 4 5 6 7 8 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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
#!/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()
|