|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Script to generate test data for cityscapes.""" |
|
|
|
import collections |
|
import json |
|
import os |
|
|
|
from absl import app |
|
from absl import flags |
|
from absl import logging |
|
import numpy as np |
|
from PIL import Image |
|
import tensorflow as tf |
|
|
|
|
|
|
|
from deeplab2.data import data_utils |
|
from deeplab2.data import dataset |
|
|
|
flags.DEFINE_string( |
|
'panoptic_annotation_path', |
|
'deeplab2/data/testdata/' |
|
'dummy_prediction.png', |
|
'Path to annotated test image with cityscapes encoding.') |
|
flags.DEFINE_string( |
|
'panoptic_gt_output_path', |
|
'deeplab2/data/testdata/' |
|
'dummy_gt_for_vps.png', |
|
'Path to annotated test image with Video Panoptic Segmentation encoding.') |
|
flags.DEFINE_string( |
|
'output_cityscapes_root', |
|
'deeplab2/data/testdata/', |
|
'Path to output root directory.') |
|
|
|
FLAGS = flags.FLAGS |
|
|
|
|
|
_CITYSCAPES_IGNORE = 255 |
|
|
|
_CITYSCAPES_CAR = (13, 26) |
|
_CITYSCAPES_TREE = (8, 21) |
|
_CITYSCAPES_SKY = (10, 23) |
|
_CITYSCAPES_BUILDING = (2, 11) |
|
_CITYSCAPES_ROAD = (0, 7) |
|
|
|
_IS_CROWD = 'is_crowd' |
|
_NOT_CROWD = 'not_crowd' |
|
|
|
_CLASS_HAS_INSTANCES_LIST = dataset.CITYSCAPES_PANOPTIC_INFORMATION.class_has_instances_list |
|
_PANOPTIC_LABEL_DIVISOR = dataset.CITYSCAPES_PANOPTIC_INFORMATION.panoptic_label_divisor |
|
_FILENAME_PREFIX = 'dummy_000000_000000' |
|
|
|
|
|
def create_test_data(annotation_path): |
|
"""Creates cityscapes panoptic annotation, vps annotation and segment info. |
|
|
|
Our Video Panoptic Segmentation (VPS) encoding uses ID == semantic trainID * |
|
1000 + instance ID (starting at 1) with instance ID == 0 marking |
|
crowd regions. |
|
|
|
Args: |
|
annotation_path: The path to the annotation to be loaded. |
|
|
|
Returns: |
|
A tuple of cityscape annotation, vps annotation and segment infos. |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
panoptic_label_to_cityscapes_label = { |
|
0: (_CITYSCAPES_IGNORE, _NOT_CROWD), |
|
31110: (_CITYSCAPES_CAR, _NOT_CROWD), |
|
31354: (_CITYSCAPES_CAR, _IS_CROWD), |
|
35173: (_CITYSCAPES_CAR, _NOT_CROWD), |
|
488314: (_CITYSCAPES_CAR, _IS_CROWD), |
|
549788: (_CITYSCAPES_CAR, _IS_CROWD), |
|
1079689: (_CITYSCAPES_CAR, _IS_CROWD), |
|
1341301: (_CITYSCAPES_CAR, _NOT_CROWD), |
|
1544590: (_CITYSCAPES_CAR, _NOT_CROWD), |
|
1926498: (_CITYSCAPES_CAR, _NOT_CROWD), |
|
4218944: (_CITYSCAPES_TREE, _NOT_CROWD), |
|
4251840: (_CITYSCAPES_SKY, _NOT_CROWD), |
|
6959003: (_CITYSCAPES_BUILDING, _NOT_CROWD), |
|
|
|
8396960: (_CITYSCAPES_BUILDING, _NOT_CROWD), |
|
8413312: (_CITYSCAPES_ROAD, _NOT_CROWD), |
|
} |
|
with tf.io.gfile.GFile(annotation_path, 'rb') as f: |
|
panoptic = data_utils.read_image(f.read()) |
|
|
|
|
|
|
|
panoptic = np.dot(panoptic, [1, 256, 256 * 256]) |
|
|
|
|
|
|
|
|
|
cityscapes_panoptic = np.zeros_like(panoptic, dtype=np.int32) |
|
|
|
|
|
|
|
vps_panoptic = np.zeros_like(panoptic, dtype=np.int32) |
|
num_instances_per_class = collections.defaultdict(int) |
|
unique_labels = np.unique(panoptic) |
|
|
|
|
|
segments_info = {} |
|
for label in unique_labels: |
|
cityscapes_label, is_crowd = panoptic_label_to_cityscapes_label[label] |
|
selected_pixels = panoptic == label |
|
|
|
if cityscapes_label == _CITYSCAPES_IGNORE: |
|
vps_panoptic[selected_pixels] = ( |
|
_CITYSCAPES_IGNORE * _PANOPTIC_LABEL_DIVISOR) |
|
continue |
|
|
|
train_id, eval_id = tuple(cityscapes_label) |
|
cityscapes_id = eval_id |
|
vps_id = train_id * _PANOPTIC_LABEL_DIVISOR |
|
if train_id in _CLASS_HAS_INSTANCES_LIST: |
|
|
|
if is_crowd != _IS_CROWD: |
|
cityscapes_id = ( |
|
eval_id * _PANOPTIC_LABEL_DIVISOR + |
|
num_instances_per_class[train_id]) |
|
|
|
vps_id += num_instances_per_class[train_id] + 1 |
|
num_instances_per_class[train_id] += 1 |
|
|
|
cityscapes_panoptic[selected_pixels] = cityscapes_id |
|
vps_panoptic[selected_pixels] = vps_id |
|
pixel_area = int(np.sum(selected_pixels)) |
|
if cityscapes_id in segments_info: |
|
logging.info('Merging segments with label %d into segment %d', label, |
|
cityscapes_id) |
|
segments_info[cityscapes_id]['area'] += pixel_area |
|
else: |
|
segments_info[cityscapes_id] = { |
|
'area': pixel_area, |
|
'category_id': train_id, |
|
'id': cityscapes_id, |
|
'iscrowd': 1 if is_crowd == _IS_CROWD else 0, |
|
} |
|
|
|
cityscapes_panoptic = np.dstack([ |
|
cityscapes_panoptic % 256, cityscapes_panoptic // 256, |
|
cityscapes_panoptic // 256 // 256 |
|
]) |
|
vps_panoptic = np.dstack( |
|
[vps_panoptic % 256, vps_panoptic // 256, vps_panoptic // 256 // 256]) |
|
return (cityscapes_panoptic.astype(np.uint8), vps_panoptic.astype(np.uint8), |
|
list(segments_info.values())) |
|
|
|
|
|
def main(argv): |
|
if len(argv) > 1: |
|
raise app.UsageError('Too many command-line arguments.') |
|
|
|
data_path = FLAGS.panoptic_annotation_path |
|
panoptic_map, vps_map, segments_info = create_test_data(data_path) |
|
panoptic_map_filename = _FILENAME_PREFIX + '_gtFine_panoptic.png' |
|
panoptic_map_path = os.path.join(FLAGS.output_cityscapes_root, 'gtFine', |
|
'cityscapes_panoptic_dummy_trainId', |
|
panoptic_map_filename) |
|
|
|
gt_output_path = FLAGS.panoptic_gt_output_path |
|
with tf.io.gfile.GFile(gt_output_path, 'wb') as f: |
|
Image.fromarray(vps_map).save(f, format='png') |
|
|
|
panoptic_map_path = panoptic_map_path |
|
with tf.io.gfile.GFile(panoptic_map_path, 'wb') as f: |
|
Image.fromarray(panoptic_map).save(f, format='png') |
|
|
|
json_annotation = { |
|
'annotations': [{ |
|
'file_name': _FILENAME_PREFIX + '_gtFine_panoptic.png', |
|
'image_id': _FILENAME_PREFIX, |
|
'segments_info': segments_info |
|
}] |
|
} |
|
json_annotation_path = os.path.join(FLAGS.output_cityscapes_root, 'gtFine', |
|
'cityscapes_panoptic_dummy_trainId.json') |
|
json_annotation_path = json_annotation_path |
|
with tf.io.gfile.GFile(json_annotation_path, 'w') as f: |
|
json.dump(json_annotation, f, indent=2) |
|
|
|
|
|
if __name__ == '__main__': |
|
app.run(main) |
|
|