├── .vscode └── launch.json ├── Figure_1.png ├── Figure_2.png ├── README.md ├── check.py ├── transcityscapes2coco.py └── visualize_coco.py /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: check.py", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/check.py", 12 | "console": "integratedTerminal" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /Figure_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinJia1212/cityscapes2coco/cbd59a51663cbb8286e8a79bf45a07c15698b4e4/Figure_1.png -------------------------------------------------------------------------------- /Figure_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinJia1212/cityscapes2coco/cbd59a51663cbb8286e8a79bf45a07c15698b4e4/Figure_2.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cityscapes2coco 2 | some Python scripts which can be used to convert the cityscapes dataset to the annotation style of coco dataset for instance segmentation task. 3 | 4 | transcityscapes2coco.py has some details that users should modify, like class definations and file paths of your cityscapes data. 5 | 6 | visualize_coco.py can be used to visualize pictures and annotations of your converted dataset. 7 | 8 | check.py helps to count instance amount of each category by reading the .json annotation file. 9 | 10 | USAGE: 11 | 1.Before to run the scripts, you need to modify ROOT_DIR, IMAGE_DIR, ANNOTATION_DIR and create a INSTANCE_DIR under the ROOT_DIR to save binary masks of each instances. 12 | 13 | 2.According to the category defination of cityscapes dataset, we only keep 5 classes from all. If you want to define your own categories, you should modify the CATAGORY and corresponding scripts. That will be easy, because the scripts are simple. 14 | 15 | 3.Modify the file name of the .json output file at the end of transform script. 16 | 17 | 4.Run the three functions of the script in order , and you can see some outputs in the terminal. 18 | 19 | 5.When finished, you can visualize the converted dataset by modify some path of files you just created 20 | -------------------------------------------------------------------------------- /check.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | if "/opt/ros/kinetic/lib/python2.7/dist-packages" in sys.path: 4 | sys.path.remove("/opt/ros/kinetic/lib/python2.7/dist-packages") 5 | import cv2 6 | import numpy as np 7 | from skimage import io 8 | from matplotlib import pyplot as plt 9 | from matplotlib import patches, lines 10 | from matplotlib.patches import Polygon, Rectangle 11 | from matplotlib.collections import PatchCollection 12 | import json 13 | from pycocotools.coco import COCO 14 | 15 | class CityScapes: 16 | def __init__(self, trainimages, trainann, valimages, valann): 17 | self.train_image_path = trainimages 18 | train_ann = trainann 19 | self.val_image_path = valimages 20 | val_ann = valann 21 | # self.train_data = COCO(train_ann) 22 | self.val_data = COCO(val_ann) 23 | 24 | def ann_check(self, dataset): 25 | output_list = [] 26 | imgids = dataset.getImgIds() 27 | for imgid in imgids: 28 | img = dataset.loadImgs(imgid)[0] 29 | annids = dataset.getAnnIds(imgIds=img['id']) 30 | # anns = coco.loadAnns(annids) 31 | if len(annids) == 0: 32 | print(img['file_name']) 33 | output_list.append(img['file_name']) 34 | return output_list 35 | 36 | def class_count(self, dataset): 37 | counts = {"car": 0, "pedestrian": 0, "truck": 0, "bus": 0, "rider": 0 } 38 | imgids = dataset.getImgIds() 39 | for imgid in imgids: 40 | img = dataset.loadImgs(imgid)[0] 41 | annids = dataset.getAnnIds(imgIds=img['id']) 42 | 43 | if len(annids) == 0: 44 | continue 45 | else: 46 | for id in annids: 47 | ann = dataset.loadAnns(id)[0] 48 | if ann['category_id'] == 1: 49 | counts['car'] += 1 50 | elif ann['category_id'] == 2: 51 | counts['pedestrian'] += 1 52 | elif ann['category_id'] == 3: 53 | counts['truck'] += 1 54 | elif ann['category_id'] == 4: 55 | counts['bus'] += 1 56 | elif ann['category_id'] == 5: 57 | counts['rider'] += 1 58 | print(counts) 59 | 60 | if __name__ == "__main__": 61 | cityscapes_root = '/home/kun/cityscapes_val' 62 | train_images = os.path.join(cityscapes_root, "train/training_images") 63 | train_anns = os.path.join(cityscapes_root, "train/train.json") 64 | val_images = os.path.join(cityscapes_root, "images") 65 | val_anns = os.path.join(cityscapes_root, "val.json") 66 | 67 | cityscapes = CityScapes(train_images, train_anns, val_images, val_anns) 68 | cityscapes.class_count(cityscapes.val_data) 69 | # no_anns = cityscapes.ann_check(cityscapes.val_data) 70 | # for img in no_anns: 71 | # os.remove(os.path.join(val_images, img)) -------------------------------------------------------------------------------- /transcityscapes2coco.py: -------------------------------------------------------------------------------- 1 | import sys 2 | if "/opt/ros/kinetic/lib/python2.7/dist-packages" in sys.path: 3 | sys.path.remove("/opt/ros/kinetic/lib/python2.7/dist-packages") 4 | 5 | import cv2 6 | import numpy as np 7 | import os, glob 8 | from shutil import copyfile 9 | import datetime 10 | import json 11 | import os 12 | import re 13 | import fnmatch 14 | from PIL import Image 15 | import numpy as np 16 | from pycococreatortools import pycococreatortools 17 | 18 | ROOT_DIR = '/home/kun/cityscapes_val' 19 | IMAGE_DIR = os.path.join(ROOT_DIR, "images") 20 | ANNOTATION_DIR = os.path.join(ROOT_DIR, "gt") 21 | ANNOTATION_SAVE_DIR = os.path.join(ROOT_DIR, "annotations") 22 | INSTANCE_DIR = os.path.join(ROOT_DIR, "instances") 23 | IMAGE_SAVE_DIR = os.path.join(ROOT_DIR, "val_images") 24 | 25 | INFO = { 26 | "description": "Cityscapes_Instance Dataset", 27 | "url": "https://github.com/waspinator/pycococreator", 28 | "version": "0.1.0", 29 | "year": "2020", 30 | "contributor": "Kevin_Jia", 31 | "date_created": "2020-1-23 19:19:19.123456" 32 | } 33 | 34 | LICENSES = [ 35 | { 36 | "id": 1, 37 | "name": "Attribution-NonCommercial-ShareAlike License", 38 | "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/" 39 | } 40 | ] 41 | 42 | CATEGORIES = [ 43 | { 44 | 'id': 1, 45 | 'name': 'car', 46 | 'supercategory': 'cityscapes', 47 | }, 48 | { 49 | 'id': 2, 50 | 'name': 'pedestrian', 51 | 'supercategory': 'cityscapes', 52 | }, 53 | { 54 | 'id': 3, 55 | 'name': 'truck', 56 | 'supercategory': 'cityscapes', 57 | }, 58 | { 59 | 'id': 4, 60 | 'name': 'bus', 61 | 'supercategory': 'cityscapes', 62 | }, 63 | { 64 | 'id': 5, 65 | 'name': 'rider', 66 | 'supercategory': 'cityscapes', 67 | } 68 | ] 69 | 70 | background_label = list(range(-1, 24, 1)) + list(range(29, 34, 1)) 71 | idx=0 72 | pic_scale = 1.0 73 | h_bias = 1.0 74 | 75 | def image_trans(): 76 | img_subfolders = os.listdir(IMAGE_DIR) 77 | image_count = 0 78 | for sub in img_subfolders: 79 | # sub_path = sub + '/' + sub 80 | image_sub_path = os.path.join(IMAGE_DIR, sub) 81 | for image in os.listdir(image_sub_path): 82 | img_path = os.path.join(image_sub_path, image) 83 | ann_name = image.split('_')[0] + '_' + image.split('_')[1] + '_' + image.split('_')[2] + '_gtFine_instanceIds.png' 84 | ann_sub_path = os.path.join(ANNOTATION_DIR, sub) 85 | ann_path = os.path.join(ann_sub_path, ann_name) 86 | if os.path.exists(ann_path): 87 | pic = cv2.imread(img_path) 88 | h, w = pic.shape[:2] 89 | new_w = w * pic_scale 90 | new_h = new_w / 2 91 | top = int((h_bias*h-new_h)/2) 92 | bottom = int((h_bias*h+new_h)/2) 93 | left = int((w-new_w)/2) 94 | right = int((w+new_w)/2) 95 | roi = pic[top:bottom, left:right] 96 | img_save_path = os.path.join(IMAGE_SAVE_DIR, image) 97 | cv2.imwrite(img_save_path, roi) 98 | annotation = cv2.imread(ann_path, -1) 99 | ann_roi = annotation[top:bottom, left:right] 100 | ann_save_path = os.path.join(ANNOTATION_SAVE_DIR, ann_name) 101 | cv2.imwrite(ann_save_path, ann_roi) 102 | else: 103 | print(image + ' do not have instance annotation') 104 | print(image_count) 105 | image_count += 1 106 | 107 | def data_loader(): 108 | imgs = os.listdir(IMAGE_SAVE_DIR) 109 | masks_generator(imgs, ANNOTATION_SAVE_DIR) 110 | 111 | def masks_generator(imges, ann_path): 112 | global idx 113 | pic_count = 0 114 | for pic_name in imges: 115 | image_name = pic_name.split('.')[0] 116 | ann_folder = os.path.join(INSTANCE_DIR, image_name) 117 | os.mkdir(ann_folder) 118 | annotation_name = pic_name.split('_')[0] + '_' + pic_name.split('_')[1] + '_' + pic_name.split('_')[2] + '_gtFine_instanceIds.png' 119 | # annotation_name = image_name + '_instanceIds.png' 120 | print(annotation_name) 121 | annotation = cv2.imread(os.path.join(ann_path, annotation_name), -1) 122 | h, w = annotation.shape[:2] 123 | ids = np.unique(annotation) 124 | for id in ids: 125 | if id in background_label: 126 | continue 127 | else: 128 | class_id = id // 1000 129 | if class_id == 26: 130 | instance_class = 'car' 131 | elif class_id == 24: 132 | instance_class = 'pedestrian' 133 | elif class_id == 27: 134 | instance_class = 'truck' 135 | elif class_id == 28: 136 | instance_class = 'bus' 137 | elif class_id == 25: 138 | instance_class = 'rider' 139 | else: 140 | continue 141 | instance_mask = np.zeros((h, w, 3),dtype=np.uint8) 142 | mask = annotation == id 143 | instance_mask[mask] = 255 144 | mask_name = image_name + '_' + instance_class + '_' + str(idx) + '.png' 145 | cv2.imwrite(os.path.join(ann_folder, mask_name), instance_mask) 146 | idx += 1 147 | pic_count += 1 148 | print(pic_count) 149 | 150 | def json_generate(): 151 | car = 0 152 | pedestrian = 0 153 | truck = 0 154 | bus = 0 155 | rider = 0 156 | files = os.listdir(IMAGE_SAVE_DIR) 157 | 158 | coco_output = { 159 | "info": INFO, 160 | "licenses": LICENSES, 161 | "categories": CATEGORIES, 162 | "images": [], 163 | "annotations": [] 164 | } 165 | 166 | image_id = 1 167 | segmentation_id = 1 168 | 169 | # go through each image 170 | for image_filename in files: 171 | image_name = image_filename.split('.')[0] 172 | image_path = os.path.join(IMAGE_SAVE_DIR, image_filename) 173 | image = Image.open(image_path) 174 | image_info = pycococreatortools.create_image_info( 175 | image_id, os.path.basename(image_filename), image.size) 176 | coco_output["images"].append(image_info) 177 | print(image_filename) 178 | annotation_sub_path = os.path.join(INSTANCE_DIR, image_name) 179 | ann_files = os.listdir(annotation_sub_path) 180 | if len(ann_files) == 0: 181 | print("ao avaliable annotation") 182 | continue 183 | else: 184 | for annotation_filename in ann_files: 185 | annotation_path = os.path.join(annotation_sub_path, annotation_filename) 186 | for x in CATEGORIES: 187 | if x['name'] in annotation_filename: 188 | class_id = x['id'] 189 | break 190 | # class_id = [x['id'] for x in CATEGORIES if x['name'] in annotation_filename][0] 191 | if class_id == 1: 192 | car += 1 193 | elif class_id == 2: 194 | pedestrian += 1 195 | elif class_id == 3: 196 | truck += 1 197 | elif class_id == 4: 198 | bus += 1 199 | elif class_id == 5: 200 | rider += 1 201 | else: 202 | print('illegal class id') 203 | category_info = {'id': class_id, 'is_crowd': 'crowd' in image_filename} 204 | binary_mask = np.asarray(Image.open(annotation_path) 205 | .convert('1')).astype(np.uint8) 206 | 207 | annotation_info = pycococreatortools.create_annotation_info( 208 | segmentation_id, image_id, category_info, binary_mask, 209 | image.size, tolerance=2) 210 | 211 | if annotation_info is not None: 212 | coco_output["annotations"].append(annotation_info) 213 | 214 | segmentation_id = segmentation_id + 1 215 | 216 | image_id = image_id + 1 217 | print(image_id) 218 | 219 | with open('{}/val_modified.json'.format(ROOT_DIR), 'w') as output_json_file: 220 | json.dump(coco_output, output_json_file) 221 | print(car, pedestrian, truck, bus, rider) 222 | 223 | 224 | if __name__ == "__main__": 225 | # image_trans() 226 | # data_loader() 227 | # json_generate() 228 | 229 | 230 | -------------------------------------------------------------------------------- /visualize_coco.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | if "/opt/ros/kinetic/lib/python2.7/dist-packages" in sys.path: 4 | sys.path.remove("/opt/ros/kinetic/lib/python2.7/dist-packages") 5 | import cv2 6 | import numpy as np 7 | from skimage import io 8 | from matplotlib import pyplot as plt 9 | from matplotlib import patches, lines 10 | from matplotlib.patches import Polygon, Rectangle 11 | from matplotlib.collections import PatchCollection 12 | 13 | from pycocotools.coco import COCO 14 | 15 | def showAnns(anns): 16 | if len(anns) == 0: 17 | return 0 18 | ax = plt.gca() 19 | ax.set_autoscale_on(False) 20 | captions = [] 21 | polygons = [] 22 | rectangles = [] 23 | color = [] 24 | for ann in anns: 25 | c = (np.random.random((1, 3))*0.6+0.4).tolist()[0] 26 | if 'segmentation' in ann: 27 | if type(ann['segmentation']) == list: 28 | # polygon 29 | for seg in ann['segmentation']: 30 | captions.append(cat_names[ann['category_id']-1]) 31 | poly = np.array(seg).reshape((int(len(seg)/2), 2)) 32 | l_corner, w, h = (ann['bbox'][0], ann['bbox'][1]), ann['bbox'][2], ann['bbox'][3] 33 | rectangles.append(Rectangle(l_corner, w, h)) 34 | polygons.append(Polygon(poly)) 35 | color.append(c) 36 | 37 | p = PatchCollection(rectangles, facecolor='none', edgecolors=color, alpha=1, linestyle='--', linewidths=2) 38 | ax.add_collection(p) 39 | 40 | for i in range(len(captions)): 41 | x = rectangles[i].xy[0] 42 | y = rectangles[i].xy[1] 43 | ax.text(x, y, captions[i], size=10, verticalalignment='top', color='w', backgroundcolor="none") 44 | 45 | p = PatchCollection(polygons, facecolor=color, linewidths=0, alpha=0.3) 46 | ax.add_collection(p) 47 | p = PatchCollection(polygons, facecolor='none', edgecolors=color, linewidths=2) 48 | ax.add_collection(p) 49 | 50 | annfile = '/home/d205-kun/cityscapes/train/train.json' 51 | imgroot = '/home/d205-kun/cityscapes/train/training_images' 52 | coco = COCO(annfile) 53 | cats = coco.loadCats(coco.getCatIds()) 54 | cat_names = [cat['name'] for cat in cats] 55 | catids = coco.getCatIds(catNms='truck') 56 | imgids = coco.getImgIds(catIds=catids) 57 | img = coco.loadImgs(imgids[np.random.randint(0, len(imgids))])[0] 58 | I = io.imread(os.path.join(imgroot, img['file_name'])) 59 | plt.imshow(I) 60 | annids = coco.getAnnIds(imgIds=img['id']) 61 | anns = coco.loadAnns(annids) 62 | showAnns(anns) 63 | plt.show() 64 | 65 | --------------------------------------------------------------------------------