🙆
unity.perceptionで作ったデータセットをdeeplab用に変換する
この記事ではUnity-Technologies/com.unity.perceptionを使って作ったデータセットをtensorflow/modelsにあるdeeplab
の学習用にデータセットを作る方法を紹介します。
まずperception
を2回動かして生成したデータセットをtrain
、val
と名前を変更して、MyFirstPerception
というディレクトリに入れます。これをdeeplab
用のデータセット(変換前)とします。
$ cd /path/to/MyFirstPerception
$ tree .
.
├── train
│ ├── Datasetd188fe0a-3b9e-4949-909c-0cbb8f0e01b5
│ ├── Logs
│ ├── RGB3f8b2e26-38b9-4486-99a5-510ce22ce75b
│ └── SemanticSegmentation02ceeb36-7c09-40e9-a2d6-e775b593d8c6
└── val
├── Dataset9efc96bd-e87a-4abf-a039-e31642f98590
├── Logs
├── RGBafd20565-3872-45ce-907c-b2a7bc044ca3
└── SemanticSegmentation8834cfd9-3b67-4abb-b12b-5c0667f5bd7c
これを次のPythonスクリプトで変換します。
transform-dataset.py
from PIL import Image
import itertools
import numpy as np
import json
from glob import glob
import os
import sys
def load_palette(specs):
colors = [[0, 0, 0]]
for s in specs:
v = s['pixel_value']
colors.append([int(v['r']*0xff), int(v['g']*0xff), int(v['b']*0xff)])
NUM_ENTRIES_IN_PILLOW_PALETTE = 256
palette_arr = list(itertools.chain.from_iterable(colors))
palette_arr.extend(
[0, 0, 0] * (NUM_ENTRIES_IN_PILLOW_PALETTE - len(colors)))
palette_img = Image.new('P', (0, 0))
palette_img.getdata().putpalette('RGB', bytes(palette_arr))
return palette_img
if len(sys.argv) != 2:
print(f"{sys.argv[0]} DATASET_DIR", file=sys.stderr)
sys.exit(1)
dataset_dir = sys.argv[1]
if dataset_dir[-1] == "/":
dataset_dir = dataset_dir[:-1]
dataset = os.path.basename(dataset_dir)
os.makedirs(os.path.join(dataset, 'ImageSets'), exist_ok=True)
os.makedirs(os.path.join(dataset, 'JPEGImages'), exist_ok=True)
os.makedirs(os.path.join(dataset, 'SegmentationClass'), exist_ok=True)
for path in glob(os.path.join(dataset_dir, '*')):
variant = os.path.basename(path)
for path in glob(os.path.join(path, 'Dataset*')):
with open(os.path.join(path, 'annotation_definitions.json')) as f:
d = json.load(f)
assert d['version'] == '0.0.1'
for definition in d['annotation_definitions']:
if definition['name'] == 'semantic segmentation':
palette = load_palette(definition['spec'])
break
file_ids = []
img_size = None
for path in glob(os.path.join(dataset_dir, variant, 'SemanticSegmentation*')):
for src in glob(os.path.join(path, '*.png')):
name, _ = os.path.splitext(os.path.basename(src))
_, img_id = name.split('_')
file_id = f"{variant}_{img_id}"
img = Image.open(src).convert(
'RGB').quantize(palette=palette, dither=0)
annotation = Image.fromarray(
np.array(img, dtype=np.uint8), mode='L')
if img_size is None:
img_size = img.size
annotation.save(os.path.join('MyFirstPerception',
'SegmentationClass', f"{file_id}.png"))
for path in glob(os.path.join(dataset_dir, variant, 'RGB*')):
for src in glob(os.path.join(path, '*.png')):
name, _ = os.path.splitext(os.path.basename(src))
_, img_id = name.split('_')
file_id = f"{variant}_{img_id}"
file_ids.append(file_id)
img = Image.open(src).convert('RGB')
img = img.resize(img_size)
img.save(os.path.join('MyFirstPerception',
'JPEGImages', f"{file_id}.jpg"))
with open(os.path.join('MyFirstPerception', 'ImageSets', f"{variant}.txt"), 'w') as w:
w.write("\n".join(file_ids))
使い方は引数にデータセットまでのパスを指定するだけです。
$ python transform-dataset.py /path/to/MyFirstPerception
するとカレンとディレクトリにMyFirstPerception
ができます。これをさらにbuild_voc2012_data.py
でTFRecord形式に変換したものを使います。
python ../build_voc2012_data.py \
--image_folder=./MyFirstPerception/JPEGImages \
--list_folder=./MyFirstPerception/ImageSets \
--semantic_segmentation_folder=./MyFirstPerception/SegmentationClass \
--image_format=jpg
transform-dataset.py
がやっていることは、ほぼファイルをbuild_voc2012_data.py
で使えるように配置し直しているだけですが、アノテーションファイルだけはRGBAから、各ピクセルを0を背景とし、1以降を各ラベルに順に振ったグレースケールの画像に変換しています。Image.fromarray(np.array(img, dtype=np.uint8), mode='L')
は遅そうですが、Image.frombytes('L', img.size, bytes(img.getdata()), "raw", "L", 0, 1)
より2倍くらい早いことは確認しています。詳しく調べていませんが、numpy.ndarray.tobytes
よりもbytes
が遅いのかなと思っています。
Discussion