Spaces:
Runtime error
Runtime error
| # coding=utf-8 | |
| # Copyright 2021 The Deeplab2 Authors. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """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 | |
| # resources dependency | |
| 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 label, using `TrainId`. | |
| _CITYSCAPES_IGNORE = 255 | |
| # Each valid (not ignored) label below is a tuple of (TrainId, EvalId) | |
| _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. | |
| """ | |
| # Convert panoptic labels to cityscapes label format. | |
| # Dictionary mapping converted panoptic annotation to its corresponding | |
| # Cityscapes label. Here the key is encoded by converting each RGB pixel | |
| # value to 1 * R + 256 * G + 256 * 256 * B. | |
| 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), | |
| # To be merged with the building segment above. | |
| 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()) | |
| # Input panoptic annotation is RGB color coded, here we convert each pixel | |
| # to a unique number to avoid comparing 3-tuples. | |
| panoptic = np.dot(panoptic, [1, 256, 256 * 256]) | |
| # Creates cityscapes panoptic map. Cityscapes use ID == semantic EvalId for | |
| # `stuff` segments and `thing` segments with `iscrowd` label, and | |
| # ID == semantic EvalId * 1000 + instance ID (starting from 0) for other | |
| # `thing` segments. | |
| cityscapes_panoptic = np.zeros_like(panoptic, dtype=np.int32) | |
| # Creates Video Panoptic Segmentation (VPS) map. We use ID == semantic | |
| # trainID * 1000 + instance ID (starting at 1) with instance ID == 0 marking | |
| # crowd regions. | |
| vps_panoptic = np.zeros_like(panoptic, dtype=np.int32) | |
| num_instances_per_class = collections.defaultdict(int) | |
| unique_labels = np.unique(panoptic) | |
| # Dictionary that maps segment id to segment info. | |
| 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: | |
| # `thing` class. | |
| if is_crowd != _IS_CROWD: | |
| cityscapes_id = ( | |
| eval_id * _PANOPTIC_LABEL_DIVISOR + | |
| num_instances_per_class[train_id]) | |
| # First instance should have ID 1. | |
| 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 # OSS: removed internal filename loading. | |
| 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 # OSS: removed internal filename loading. | |
| 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 # OSS: removed internal filename loading. | |
| 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 # OSS: removed internal filename loading. | |
| with tf.io.gfile.GFile(json_annotation_path, 'w') as f: | |
| json.dump(json_annotation, f, indent=2) | |
| if __name__ == '__main__': | |
| app.run(main) | |