def load_ss_data(coco_dir, data_name, cache_dir, input_size=None): """セマンティックセグメンテーションのデータの読み込み。""" from pycocotools import coco, mask as cocomask coco_dir = pathlib.Path(coco_dir) cache_dir = pathlib.Path(cache_dir) if isinstance(input_size, int): input_size = (input_size, input_size) coco = coco.COCO( str(coco_dir / "annotations" / f"instances_{data_name}.json")) class_names = [c["name"] for c in coco.loadCats(coco.getCatIds())] jsonclassid_to_index = { c["id"]: class_names.index(c["name"]) for c in coco.loadCats(coco.getCatIds()) } X, y = [], [] for entry in utils.tqdm(coco.loadImgs(coco.getImgIds()), desc="load_ss_data"): dirname, filename = entry["coco_url"].split("/")[-2:] save_path = cache_dir / dirname / (filename + ".npy") X.append(coco_dir / dirname / filename) y.append(save_path) if not save_path.exists(): # 読み込み objs = coco.loadAnns( coco.getAnnIds(imgIds=entry["id"], iscrowd=None)) mask = np.zeros( (entry["height"], entry["width"], len(class_names)), dtype=np.uint8) for obj in objs: if obj.get("ignore", 0) == 1: continue rle = cocomask.frPyObjects(obj["segmentation"], entry["height"], entry["width"]) m = cocomask.decode(rle) class_id = jsonclassid_to_index[obj["category_id"]] mask[:, :, class_id] |= m mask = np.where(mask, np.uint8(255), np.uint8(0)) # リサイズ if input_size is not None: mask = ndimage.resize(mask, input_size[1], input_size[0]) # 保存 save_path.parent.mkdir(parents=True, exist_ok=True) np.save(str(save_path), mask) return np.array(X), np.array(y), class_names
def load_od_data(coco_dir, data_name, use_crowded): """物体検出のデータの読み込み。""" import pycocotools.coco coco_dir = pathlib.Path(coco_dir) coco = pycocotools.coco.COCO( str(coco_dir / "annotations" / f"instances_{data_name}.json")) class_names = [c["name"] for c in coco.loadCats(coco.getCatIds())] jsonclassid_to_index = { c["id"]: class_names.index(c["name"]) for c in coco.loadCats(coco.getCatIds()) } labels = [] for entry in coco.loadImgs(coco.getImgIds()): dirname, filename = entry["coco_url"].split("/")[-2:] objs = coco.loadAnns( coco.getAnnIds(imgIds=entry["id"], iscrowd=None if use_crowded else False)) bboxes, classes, areas, crowdeds = [], [], [], [] width, height = entry["width"], entry["height"] for obj in objs: if obj.get("ignore", 0) == 1: continue x, y, w, h = obj["bbox"] bbox = np.array([x, y, x + w, y + h]) / np.array( [width, height, width, height]) bbox = np.clip(bbox, 0, 1) if (bbox[:2] < bbox[2:]).all(): bboxes.append(bbox) classes.append(jsonclassid_to_index[obj["category_id"]]) areas.append(obj["area"]) crowdeds.append(obj["iscrowd"]) labels.append( tk.od.ObjectsAnnotation( path=coco_dir / dirname / filename, width=width, height=height, classes=classes, bboxes=bboxes, areas=areas, crowdeds=crowdeds, )) return tk.od.ObjectsAnnotation.create_dataset(labels, class_names=class_names)
def coco(writer, name_index, profile, row, verify=False): root = os.path.expanduser(os.path.expandvars(row['root'])) year = str(row['year']) name = profile + year path = os.path.join(root, 'annotations', 'instances_%s.json' % name) if not os.path.exists(path): tf.logging.warn(path + ' not exists') return False import pycocotools.coco coco = pycocotools.coco.COCO(path) catIds = coco.getCatIds(catNms=list(name_index.keys())) cats = coco.loadCats(catIds) id_index = dict((cat['id'], name_index[cat['name']]) for cat in cats) imgIds = coco.getImgIds() path = os.path.join(root, name) imgs = coco.loadImgs(imgIds) _imgs = list(filter(lambda img: os.path.exists(os.path.join(path, img['file_name'])), imgs)) if len(imgs) > len(_imgs): tf.logging.warn('%d of %d images not exists' % (len(imgs) - len(_imgs), len(imgs))) cnt_noobj = 0 for img in tqdm.tqdm(_imgs): annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None) anns = coco.loadAnns(annIds) if len(anns) <= 0: cnt_noobj += 1 continue imagepath = os.path.join(path, img['file_name']) width, height = img['width'], img['height'] imageshape = [height, width, 3] objects_class = np.array([id_index[ann['category_id']] for ann in anns], dtype=np.int64) objects_coord = [ann['bbox'] for ann in anns] objects_coord = [(x, y, x + w, y + h) for x, y, w, h in objects_coord] objects_coord = np.array(objects_coord, dtype=np.float32) if verify: if not verify_coords(objects_coord, imageshape): tf.logging.error('failed to verify coordinates of ' + imagepath) continue if not verify_image_jpeg(imagepath, imageshape): tf.logging.error('failed to decode ' + imagepath) continue assert len(objects_class) == len(objects_coord) example = tf.train.Example(features=tf.train.Features(feature={ 'imagepath': tf.train.Feature(bytes_list=tf.train.BytesList(value=[tf.compat.as_bytes(imagepath)])), 'imageshape': tf.train.Feature(int64_list=tf.train.Int64List(value=imageshape)), 'objects': tf.train.Feature(bytes_list=tf.train.BytesList(value=[objects_class.tostring(), objects_coord.tostring()])), })) writer.write(example.SerializeToString()) if cnt_noobj > 0: tf.logging.warn('%d of %d images have no object' % (cnt_noobj, len(_imgs))) return True
def get_keypoint_names(parameters): """ Return the keypoint names for persons category. :param parameters: Dict with: parameters = { 'coco-data-dir': pathlib.Path(...), 'annotations': Path to annotations file with keypoints } :return: List of keypoint names. """ coco = pycocotools.coco.COCO( str(parameters['coco-data-dir'] / parameters['annotations'])) category_id = coco.getCatIds('person') category_info = coco.loadCats(category_id)[0] keypoint_names = category_info['keypoints'] return keypoint_names
return bbox _cat_ids = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90 ] num_classes = 80 _classes = {ind + 1: cat_id for ind, cat_id in enumerate(_cat_ids)} _to_order = {cat_id: ind for ind, cat_id in enumerate(_cat_ids)} coco = coco.COCO(ANN_PATH) CAT_NAMES = [ coco.loadCats([_classes[i + 1]])[0]['name'] for i in range(num_classes) ] COLORS = [((np.random.random((3, )) * 0.6 + 0.4) * 255).astype(np.uint8) for _ in range(num_classes)] def add_box(image, bbox, sc, cat_id): cat_id = _to_order[cat_id] cat_name = CAT_NAMES[cat_id] cat_size = cv2.getTextSize(cat_name + '0', cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2)[0] color = np.array(COLORS[cat_id]).astype(np.int32).tolist() txt = '{}{:.0f}'.format(cat_name, sc * 10) if bbox[1] - cat_size[1] - 2 < 0: cv2.rectangle(image, (bbox[0], bbox[1] + 2), (bbox[0] + cat_size[0], bbox[1] + cat_size[1] + 2),
raise Exception('Cant find directory with images [%s]' % dirImg) dirOut = '%s/%s-food2' % (dataDir, dataType) makeDirIfNotExists(pathToDir=dirOut, isCleanIfExists=False) # annFile = '%s/annotations/instances_%s.json' % (dataDir, dataType) imgDir = '%s/%s' % (dataDir, dataType) if not os.path.isdir(imgDir): raise Exception('Cant find directory with MS-COCO images [%s]' % dataDir) # coco = COCO(annFile) # listCatsFoodIdx = coco.getCatIds(supNms=['food']) assert (set(listCatsFoodIdx) == set(listSortedFoodIds)) for ii, idx in enumerate(listCatsFoodIdx): tmpCat = coco.loadCats(ids=idx)[0] print('%d [%d] : %s (%s)' % (ii, idx, tmpCat['name'], tmpCat['supercategory'])) # tmpDictFoodImgIds = {} for ii, idx in enumerate(listSortedFoodIds): tmpImgIds = coco.getImgIds(catIds=idx) for timgId in tmpImgIds: if tmpDictFoodImgIds.has_key(timgId): tmpDictFoodImgIds[timgId].append(idx) else: tmpDictFoodImgIds[timgId] = [idx] setAllFoodImgIds = sorted(tmpDictFoodImgIds.keys()) print('#list/#set = %d' % len(tmpDictFoodImgIds.keys())) numImages = len(setAllFoodImgIds) for ii, kk in enumerate(setAllFoodImgIds):
dtype=np.int32) return bbox _cat_ids = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90 ] num_classes = 80 _classes = {ind + 1: cat_id for ind, cat_id in enumerate(_cat_ids)} _to_order = {cat_id: ind for ind, cat_id in enumerate(_cat_ids)} coco = coco.COCO(ANN_PATH) CAT_NAMES = [coco.loadCats([_classes[i + 1]])[0]['name'] \ for i in range(num_classes)] COLORS = [((np.random.random((3,)) * 0.6 + 0.4) * 255).astype(np.uint8) \ for _ in range(num_classes)] def add_box(image, bbox, sc, cat_id): cat_id = _to_order[cat_id] cat_name = CAT_NAMES[cat_id] cat_size = cv2.getTextSize(cat_name + '0', cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2)[0] color = np.array(COLORS[cat_id]).astype(np.int32).tolist() txt = '{}{:.0f}'.format(cat_name, sc * 10) if bbox[1] - cat_size[1] - 2 < 0: cv2.rectangle(image, (bbox[0], bbox[1] + 2), (bbox[0] + cat_size[0], bbox[1] + cat_size[1] + 2),
def cache(config, path, category_index): phase = os.path.splitext(os.path.basename(path))[0] data = [] for i, row in pd.read_csv(os.path.splitext(__file__)[0] + '.tsv', sep='\t').iterrows(): logging.info('loading data %d (%s)' % (i, ', '.join([k + '=' + str(v) for k, v in row.items()]))) root = os.path.expanduser(os.path.expandvars(row['root'])) year = str(row['year']) suffix = phase + year path = os.path.join(root, 'annotations', 'instances_%s.json' % suffix) if not os.path.exists(path): logging.warning(path + ' not exists') continue coco = pycocotools.coco.COCO(path) catIds = coco.getCatIds(catNms=list(category_index.keys())) cats = coco.loadCats(catIds) id_index = dict( (cat['id'], category_index[cat['name']]) for cat in cats) imgIds = coco.getImgIds() path = os.path.join(root, suffix) imgs = coco.loadImgs(imgIds) _imgs = list( filter( lambda img: os.path.exists(os.path.join( path, img['file_name'])), imgs)) if len(imgs) > len(_imgs): logging.warning('%d of %d images not exists' % (len(imgs) - len(_imgs), len(imgs))) for img in tqdm.tqdm(_imgs): annIds = coco.getAnnIds(imgIds=img['id'], catIds=catIds, iscrowd=None) anns = coco.loadAnns(annIds) if len(anns) <= 0: continue path = os.path.join(path, img['file_name']) width, height = img['width'], img['height'] bbox = np.array([ann['bbox'] for ann in anns], dtype=np.float32) yx_min = bbox[:, 1::-1] hw = bbox[:, -1:1:-1] yx_max = yx_min + hw cls = np.array([id_index[ann['category_id']] for ann in anns], dtype=np.int) difficult = np.zeros(cls.shape, dtype=np.uint8) try: if config.getboolean('cache', 'verify'): size = (height, width) image = cv2.imread(path) assert image is not None assert image.shape[:2] == size[:2] utils.cache.verify_coords(yx_min, yx_max, size[:2]) except configparser.NoOptionError: pass assert len(yx_min) == len(cls) assert yx_min.shape == yx_max.shape assert len(yx_min.shape) == 2 and yx_min.shape[-1] == 2 data.append( dict(path=path, yx_min=yx_min, yx_max=yx_max, cls=cls, difficult=difficult)) logging.warning('%d of %d images are saved' % (len(data), len(_imgs))) return data
def main(input_json: str, image_dir: str, coco_output_dir: Optional[str], tfrecords_output_dir: Optional[str], detection_output: str, detection_input: Optional[str], split_by: str, exclude_categories: List[str], detection_threshold: float, padding_factor: float, test_fraction: float, ims_per_record: int) -> None: """ Args: input_json: str, path to JSON file with COCO-style dataset annotations image_dir: str, path to root folder of images coco_output_dir: str, path to output directory for a dataset in COCO format tfrecords_output_dir: str, path to output directory for a dataset in TFRecords format detection_output: str, path to pickle file for saving detections detection_input: str, path to pickle file of existing detections generated by this script, used to continue a partially processed dataset split_by: str, key in image-level annotations that specifies the splitting criteria exclude_categories: list of str, names of categories to ignore during detection detection_threshold: float, in [0, 1] padding_factor: float, padding around detected objects when cropping test_fraction: float, in [0, 1] ims_per_record: int """ graph = load_frozen_graph(args.frozen_graph) # Load COCO style annotations from the input dataset coco = pycocotools.coco.COCO(input_json) # Get all categories, their names, and create updated ID for the json file categories = coco.loadCats(coco.getCatIds()) cat_id_to_names = {cat['id']: cat['name'] for cat in categories} cat_id_to_new_id = { old_key: idx for idx, old_key in enumerate(cat_id_to_names.keys()) } print('All categories:', list(cat_id_to_names.values())) for ignore_cat in exclude_categories: if ignore_cat not in cat_id_to_names.values(): raise ValueError(f'Category {ignore_cat} does not exist in dataset') # Prepare the coco-style json files train_json = dict(images=[], categories=[], annotations=[]) test_json = dict(images=[], categories=[], annotations=[]) for old_cat_id in cat_id_to_names.keys(): train_json['categories'].append(dict( id=cat_id_to_new_id[old_cat_id], name=cat_id_to_names[old_cat_id], supercategory='entity')) test_json['categories'] = train_json['categories'] # Split the dataset by locations random.seed(0) print('Example of the annotation of a single image:') print(list(coco.imgs.items())[0]) print('The corresponding category annoation:') print(coco.imgToAnns[list(coco.imgs.items())[0][0]]) locations = sorted(set(ann[split_by] for ann in coco.imgs.values())) test_locations = sorted( random.sample(locations, max(1, int(test_fraction * len(locations))))) train_locations = sorted(set(locations) - set(test_locations)) print('{} locations in total, {} for training, {} for testing'.format( len(locations), len(train_locations), len(test_locations))) print('Training uses locations ', train_locations) print('Testing uses locations ', test_locations) # Load detections if detection_input is not None: print(f'Loading existing detections from {detection_input}') with open(detection_input, 'rb') as f: detections = pickle.load(f) else: detections = dict() train_tfr_writer = None test_tfr_writer = None if tfrecords_output_dir is not None: train_tfr_writer = TFRecordsWriter( os.path.join(tfrecords_output_dir, 'train-{:05d}'), ims_per_record) test_tfr_writer = TFRecordsWriter( os.path.join(tfrecords_output_dir, 'test-{:05d}'), ims_per_record) with graph.as_default(): with tf.Session() as sess: run_detection( sess, coco, cat_id_to_names, cat_id_to_new_id, detections, train_locations, train_json, test_json, train_tfr_writer, test_tfr_writer, image_dir, coco_output_dir, split_by, exclude_categories, detection_threshold, padding_factor) if tfrecords_output_dir is not None: train_tfr_writer.close() test_tfr_writer.close() label_map = [ 'item {{name: "{}" id: {}}}\n'.format(cat['name'], cat['id']) for cat in train_json['categories']] pbtxt_path = os.path.join(tfrecords_output_dir, 'label_map.pbtxt') with open(pbtxt_path, 'w') as f: f.write(''.join(label_map)) if coco_output_dir is not None: # Write out COCO-style json files to the output directory with open(os.path.join(coco_output_dir, 'train.json'), 'wt') as fi: json.dump(train_json, fi) with open(os.path.join(coco_output_dir, 'test.json'), 'wt') as fi: json.dump(test_json, fi) # Write detections to file with pickle with open(detection_output, 'wb') as f: pickle.dump(detections, f, pickle.HIGHEST_PROTOCOL)
def load_coco(self, dataset_dir, subset, year=DEFAULT_DATASET_YEAR, class_ids=None, class_map=None, return_coco=False, auto_download=False): """Load a subset of the COCO dataset. dataset_dir: The root directory of the COCO dataset. subset: What to load (train, val, minival, valminusminival) year: What dataset year to load (2014, 2017) as a string, not an integer class_ids: If provided, only loads images that have the given classes. class_map: TODO: Not implemented yet. Supports maping classes from different datasets to the same class ID. return_coco: If True, returns the COCO object. auto_download: Automatically download and unzip MS-COCO images and annotations """ if auto_download is True: self.auto_download(dataset_dir, subset, year) coco = COCO("{}/annotations/instances_{}{}.json".format( dataset_dir, subset, year)) if subset == "minival" or subset == "valminusminival": subset = "val" image_dir = "{}/{}{}".format(dataset_dir, subset, year) # Load all classes or a subset? if not class_ids: # All classes class_ids = sorted(coco.getCatIds()) # All images or a subset? if class_ids: image_ids = [] for id in class_ids: image_ids.extend(list(coco.getImgIds(catIds=[id]))) # Remove duplicates image_ids = list(set(image_ids)) else: # All images image_ids = list(coco.imgs.keys()) # Add classes for i in class_ids: self.add_class("coco", i, coco.loadCats(i)[0]["name"]) # Add images for i in image_ids: self.add_image("coco", image_id=i, path=os.path.join(image_dir, coco.imgs[i]['file_name']), width=coco.imgs[i]["width"], height=coco.imgs[i]["height"], annotations=coco.loadAnns( coco.getAnnIds(imgIds=[i], catIds=class_ids, iscrowd=None))) if return_coco: return coco
def visualize_coco_annotations(image, annotations, coco, show_label=True, show_bbox=True, show_segm=True): ''' Draws the segmentation, bounding box, and label of each annotation. ''' import PIL.ImageDraw, PIL.ImageFont if 'posix' == os.name: font_dir_path = '/home/sangwook/work/font' else: font_dir_path = 'D:/work/font' font_filepath = font_dir_path + '/DejaVuSans.ttf' try: font = PIL.ImageFont.truetype(font_filepath, 15) except Exception as ex: print('Invalid font, {}: {}.'.format(font_filepath, ex)) raise # Define color codes. colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (0, 255, 255), (255, 0, 255), (255, 255, 0)] draw = PIL.ImageDraw.Draw(image, 'RGBA') for annotation in annotations: cat_name = coco.loadCats(ids=[annotation['category_id']])[0]['name'] bbox = annotation['bbox'] # (left, top, width, height). color = colors[(annotation['category_id'] - 1) % len(colors)] if show_segm and 'segmentation' in annotation and annotation[ 'segmentation']: # Draw segmentation. draw.polygon(annotation['segmentation'][0], fill=color + (64, )) if show_bbox: # Draw bbox. draw.rectangle( (bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3]), outline=color + (255, ), width=2) if show_label: # Draw label. tw, th = draw.textsize(text=cat_name, font=font) if bbox[3] < th: draw.rectangle((bbox[0] + bbox[2], bbox[1], bbox[0] + bbox[2] + tw, bbox[1] + th), fill=(64, 64, 64, 255)) draw.text((bbox[0] + bbox[2], bbox[1]), text=cat_name, fill=(255, 255, 255, 255), font=font) else: draw.rectangle((bbox[0], bbox[1], bbox[0] + tw, bbox[1] + th), fill=(64, 64, 64, 255)) draw.text((bbox[0], bbox[1]), text=cat_name, fill=(255, 255, 255, 255), font=font) return np.asarray(image)