「TensorFlow 2 による物体検出」で、アノテーション作成ツール「VoTT」を使用して、動画から教師データや検証用データとして使用するアノテーションデータを作成しました。今回は出力されたアノテーションデータについて、詳しく調べます。
【実行環境】
- tensorflow 2.6.0
- tensorflow-addons 0.14.0
- tensorflow-datasets 4.4.0
- tensorflow-estimator 2.6.0
- tensorflow-gpu 2.6.0
- tensorflow-hub 0.12.0
- tensorflow-metadata 1.2.0
- tensorflow-model-optimization 0.6.0
- tensorflow-text 2.6.0
TFRecordファイルの可視化
アノテーション作成ツール「VoTT」で、フォルダ「TensorTest-TFRecords-export」にエクスポートしたTFRecordファイルの構造について、次のスクリプト「TFRecordToImg.py」により可視化します。ファイル「signalmp4.tfrecord」は、アノテーション作成ツール「VoTT」でエクスポートしたTFRecordファイルです。詳細については「TFRecords と tf.Example の使用法」の「TFRecord ファイルの読み込み」を参照してください。
TFRecordToImg.py
import tensorflow as tf import numpy as np import IPython.display as display loaded_ds_train = tf.data.TFRecordDataset("signalmp4.tfrecord") print(loaded_ds_train) for raw_record in loaded_ds_train.take(1): # print(repr(raw_record)) example = tf.train.Example() example.ParseFromString(raw_record.numpy()) print(example)
スクリプト「TFRecordToImg.py」を実行した結果を次に示します。
- 9行目の「image/encoded」で、 画像のバイナリデータが定義されます。
- 49行目の「image/object/bbox/xmax」,58行目の「image/object/bbox/xmin」,67行目の「image/object/bbox/ymax」,76行目の「image/object/bbox/ymin」で、 アノテーションした座標位置が定義されます。アノテーションした数だけ値が含みます。
- 85行目の「class/label で、タグ名に付与された番号「0」「1」が定義されます。
- 94行目の「class/text」で、タグの名前「signalA_red」「signalB_green」が定義されます。
2021-10-08 08:18:33.422875: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX AVX2 To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags. 2021-10-08 08:18:34.861523: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1510] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 1335 MB memory: -> device: 0, name: NVIDIA GeForce GT 1030, pci bus id: 0000:01:00.0, compute capability: 6.1 <TFRecordDatasetV2 shapes: (), types: tf.string> 2021-10-08 08:18:34.966740: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2) features { feature { key: "image/encoded" value { bytes_list { value: "\377\330\37 ・・・・・(シリアライズされた画像データ) } } } feature { key: "image/filename" value { bytes_list { value: "signal.mp4#t=0.2.jpg" } } } feature { key: "image/format" value { bytes_list { value: "jpg" } } } feature { key: "image/height" value { int64_list { value: 480 } } } feature { key: "image/key/sha256" value { bytes_list { value: "TqXFCKZWbnYkBUP4/rBv1Fd3e+OVScQBZDav2mXSMw4=" } } } feature { key: "image/object/bbox/xmax" value { float_list { value: 0.6279257535934448 value: 0.4789402186870575 } } } feature { key: "image/object/bbox/xmin" value { float_list { value: 0.48531702160835266 value: 0.37633150815963745 } } } feature { key: "image/object/bbox/ymax" value { float_list { value: 0.3261205554008484 value: 0.645285964012146 } } } feature { key: "image/object/bbox/ymin" value { float_list { value: 0.2047913372516632 value: 0.515455961227417 } } } feature { key: "image/object/class/label" value { int64_list { value: 0 value: 1 } } } feature { key: "image/object/class/text" value { bytes_list { value: "signalA_red" value: "signalB_green" } } } feature { key: "image/object/difficult" value { int64_list { value: 0 value: 0 } } } feature { key: "image/object/truncated" value { int64_list { value: 0 value: 0 } } } feature { key: "image/object/view" value { bytes_list { value: "Unspecified" value: "Unspecified" } } } feature { key: "image/source_id" value { bytes_list { value: "signal.mp4#t=0.2.jpg" } } } feature { key: "image/width" value { int64_list { value: 640 } } } } Process finished with exit code 0
アノテーション画像の取得
アノテーション作成ツール「VoTT」で、フォルダ「Target」に出力されたjsonファイルを用いて、入力した動画ファイルから作成したアノテーション画像を、次のスクリプト「cutimg.py」により取得します。
cutimg.py
import json import os import fnmatch import cv2 JSON_DIR = 'vott-json/' IMG_DIR = 'vott-json/' CUT_IMAGE = 'cut_images/' IMAGE_FORMAT = '.jpg' class Check(): def filepath_checker(self, dir): if not (os.path.exists(dir)): print('No such directory > ' + dir) exit() def directory_init(self, dir): if not (os.path.exists(dir)): os.makedirs(dir, exist_ok=True) def save_frame_sec(video_path, sec, result_path): cap = cv2.VideoCapture(video_path) if not cap.isOpened(): return os.makedirs(os.path.dirname(result_path), exist_ok=True) fps = cap.get(cv2.CAP_PROP_FPS) cap.set(cv2.CAP_PROP_POS_FRAMES, round(fps * sec)) ret, frame = cap.read() if ret: cv2.imwrite(result_path, frame) return frame def main(): check = Check() # jsonファイルを格納したディレクトリが存在するかチェック check.filepath_checker(JSON_DIR) # 'CUTした画像の格納場所を準備' check.directory_init(CUT_IMAGE) # jsonを解析し、画像とアノテーション座標から切り出しをしていく count = 0 for jsonName in fnmatch.filter(os.listdir(JSON_DIR), '*.json'): # jsonを開く with open(JSON_DIR + jsonName) as f: result = json.load(f) # 画像のファイル名の取得 imgName = result['asset']['name'] print('jsonName = {}, imgName = {} '.format(jsonName, imgName)) # img = cv2.imread(IMG_DIR + imgName) if 'timestamp' not in result['asset'] : print('<timestamp is NULL> imgName = ', imgName) continue img = save_frame_sec(IMG_DIR + 'signal.mp4', result['asset']['timestamp'], 'temp/result_10sec.jpg') if img is None: print('cv.imread Error') exit() # アノテーションした数だけループ for region in result['regions']: height = int(region['boundingBox']['height']) width = int(region['boundingBox']['width']) left = int(region['boundingBox']['left']) top = int(region['boundingBox']['top']) cutImage = img[top: top + height, left: left + width] # アノテーション中に誤って1点クリックしてしまった情報は避ける if height == 0 or width == 0: print('<height or width is 0> imgName = ', imgName) continue # 書き出す前にリサイズする場合はコメントアウトを外しましょう # cutImage = cv.resize(cutImage, (300,300)) # 「cut_images/cat0000.jpg」と連番でファイルを書き出す filename =region['tags'][0] cv2.imwrite(CUT_IMAGE + filename + "{0:04d}".format(count + 1) + IMAGE_FORMAT, cutImage) print("{0:04d}".format(count + 1)) count += 1 if __name__ == "__main__": main()
スクリプト「cutimg.py」を実行した結果を次に示します。
jsonName = 001475cdcbe31e6b07da7f7b59f53cdc-asset.json, imgName = signal.mp4#t=8.933333 0001 0002 jsonName = 01c6357f4521d5ce878d8c95d02b3474-asset.json, imgName = signal.mp4#t=4.133333 0003 0004 jsonName = 01e94c050e6819a2962903bbedd2d5e8-asset.json, imgName = signal.mp4#t=27.8 ・・・ 0229 jsonName = fce141e62a7ccfbdcab982e3b24fe07a-asset.json, imgName = signal.mp4#t=32.866667 0230 0231 jsonName = fd4633d1b9b6441bce9d327cf3f1a034-asset.json, imgName = signal.mp4#t=14.133333 0232 Process finished with exit code 0
取得したアノテーション画像を次に示します。アノテーション作成ツール「VoTT」でアノテーション範囲を指定した画像が表示されます。