概要
Tensorflowのmodelsのresearchのところにいる物体検知(object detection)系のコードで、data augmentation周りの処理がいろいろ用意されていたのでそれぞれの動きを確認しておく。
バージョン情報
- Python 3.7.3
- tensorflow-gpu==1.13.1
- tensorflow/models v1.13.0
- matplotlib==3.1.0
Tensorflow/modelsのclone
下記URLからclone。
https://github.com/tensorflow/models/
reseachに移動。
$ cd models/research
下記ファイルにdata augmentation用の関数が記述してある。
- object_detection/core/preprocessor.py
import
下記のライブラリを利用しています。eager_executionもしておきます。
from matplotlib import pylab as plt import numpy as np import cv2 from object_detection.core import preprocessor as proc import tensorflow as tf tf.enable_eager_execution()
サンプル画像のロード
512x512の画像を用意してOpenCVで読み込みます。
img = cv2.imread('dog.jpg')
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
かわいい。
normalize_image
0〜255の画像の特徴を0〜1.0の間に変換する用途などで使える。
変換前の画像データの前3行。
img[0:3, 0] #=> array([[109, 144, 77], #=> [172, 208, 138], #=> [165, 202, 132]], dtype=uint8)
0〜255を0〜1.0に変換。
new_img = proc.normalize_image(img, 0, 255, 0, 1).numpy() new_img[0:3, 0] #=> array([[0.427451 , 0.5647059 , 0.3019608 ], #=> [0.6745098 , 0.81568635, 0.5411765 ], #=> [0.64705884, 0.79215693, 0.5176471 ]], dtype=float32)
random_horizontal_flip
50%の確率で水平方向に反転する。サンプルでは引数をnumpyのarrayで渡しているので反転させた場合はTensorが返り、させなかった場合はndarrayが返る。
f, ax_list = plt.subplots(1, 7, figsize=(10, 2)) for i in range(7): new_img = proc.random_horizontal_flip(img)[0] if not isinstance(new_img, np.ndarray): new_img = new_img.numpy() ax_list[i].imshow(cv2.cvtColor(new_img, cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_vertical_flip
50%の確率で垂直方向に反転する。
f, ax_list = plt.subplots(1, 7, figsize=(10, 2)) for i in range(7): new_img = proc.random_vertical_flip(img)[0] if not isinstance(new_img, np.ndarray): new_img = new_img.numpy() ax_list[i].imshow(cv2.cvtColor(new_img, cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_rotation90
50%の確率で90度回展する。
f, ax_list = plt.subplots(1, 7, figsize=(10, 2)) for i in range(7): new_img = proc.random_rotation90(img)[0] if not isinstance(new_img, np.ndarray): new_img = new_img.numpy() ax_list[i].imshow(cv2.cvtColor(new_img, cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_pixel_value_scale
ランダムで画像のサイズを変更する。下記は0.5〜2.0の間でサイズ変更を実行した際のshapeを出力した例。
for i in range(5): new_img = proc.random_image_scale( img, min_scale_ratio=0.5, max_scale_ratio=2.0)[0] print(new_img.shape) #=> (270, 270, 3) #=> (917, 917, 3) #=> (703, 703, 3) #=> (464, 464, 3) #=> (905, 905, 3)
random_rgb_to_gray
ランダムでグレースケール画像に変換する。デフォルトのprobabilityは0.1。
f, ax_list = plt.subplots(1, 7, figsize=(10, 2)) for i in range(7): new_img = proc.random_rgb_to_gray(img, probability=0.5) if not isinstance(new_img, np.ndarray): new_img = new_img.numpy() ax_list[i].imshow(cv2.cvtColor(new_img, cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_adjust_brightness
ランダムで明度を変更する。
f, ax_list = plt.subplots(1, 7, figsize=(12, 3)) for i in range(7): new_img = proc.random_adjust_brightness(img).numpy() ax_list[i].imshow(cv2.cvtColor(new_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_adjust_contrast
ランダムでコントラストを変更する。デフォルト値はmin_deltaが0.8、max_deltaが1.25。効果が見やすいように下記は強めに設定。
f, ax_list = plt.subplots(1, 7, figsize=(12, 3)) for i in range(7): new_img = proc.random_adjust_contrast( img, min_delta=0.3, max_delta=1.5).numpy() ax_list[i].imshow(cv2.cvtColor(new_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_adjust_hue
ランダムで色相を変更する。ランダムの範囲は -max_delta 〜 max_delta の間。
max_deltaのデフォルト値は0.02。効果が見やすいように下記は0.2まで上げて指定。
f, ax_list = plt.subplots(1, 7, figsize=(12, 3)) for i in range(7): new_img = proc.random_adjust_hue( img, max_delta=0.2).numpy() ax_list[i].imshow(cv2.cvtColor(new_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_adjust_saturation
ランダムで彩度を変更する。デフォルト値はmin_delta=0.8, max_delta=1.25。
f, ax_list = plt.subplots(1, 7, figsize=(12, 3)) for i in range(7): new_img = proc.random_adjust_saturation( img, min_delta=0.3, max_delta=2.0).numpy() ax_list[i].imshow(cv2.cvtColor(new_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_distort_color
ランダムでいろいろ効果をつける。
color_ordering=0の場合は、random_adjust_brightness, random_adjust_saturation, random_adjust_hue, random_adjust_contrastの順で実行する。
color_ordering=1の場合は、random_adjust_brightness, random_adjust_contrast, random_adjust_saturation, random_adjust_hueの順で実行する。
f, ax_list = plt.subplots(1, 7, figsize=(12, 3)) for i in range(7): new_img = proc.random_distort_color( img, color_ordering=0).numpy() ax_list[i].imshow(cv2.cvtColor(new_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_jitter_boxes
ランダムでboxesの指定を変更する。下記は0.1, 0.1, 0.2, 0.2が指定されたRectangleに対してrandom_jitter_boxesを実行している。4点の位置が少しズレて結果が返る。
proc.random_jitter_boxes( np.array([[0.1, 0.1, 0.2, 0.2]], np.float32), ratio=0.05) #=> array([[0.09792455, 0.10045671, 0.20128286, 0.20494111]]
random_crop_image
ランダムで画像をトリミングする。
まず顔を括るような矩形を用意する。
new_img = img.copy() box = np.array([0.55, 0.1, 0.9, 0.5], np.float32) left_top = tuple((box[0:2] * 512).astype(np.int)) right_bottom = tuple((box[2:4] * 512).astype(np.int)) cv2.rectangle(new_img, left_top, right_bottom, (255,0,0), 5) plt.imshow(cv2.cvtColor(new_img.astype(np.uint8), cv2.COLOR_BGR2RGB))
作成した矩形と画像を引数に渡して、random cropしてみる。
注意点として、用意した矩形波 (xmin, ymin), (xmax, ymax)だが、引数で渡す際は (ymin, xmin), (ymax, xmax)で扱う必要がある。
# 引数に渡すtensorを用意 new_img = tf.convert_to_tensor((img.copy() / 255).astype(np.float32)) tf_boxes = tf.convert_to_tensor(np.array([[box[1], box[0], box[3], box[2]]])) labels = tf.convert_to_tensor(np.array([1])) label_weights = tf.convert_to_tensor(np.array([1.0], np.float32)) # 5枚作ってみる f, ax_list = plt.subplots(1, 5, figsize=(12, 4)) for i in range(5): # random_crop_image(の呼び出し crop_img, crop_boxes, crop_labels, crop_label_weights = \ proc.random_crop_image(new_img, tf_boxes, labels, label_weights) # 画像とboxの生成 crop_img = (crop_img.numpy() * 255).astype(np.uint8) crop_boxes = crop_boxes.numpy() left_top = tuple(np.array([crop_boxes[0][1] * crop_img.shape[1], crop_boxes[0][0] * crop_img.shape[0]]).astype(np.int)) right_bottom = tuple(np.array([crop_boxes[0][3] * crop_img.shape[1], crop_boxes[0][2] * crop_img.shape[0]]).astype(np.int)) # 描画 cv2.rectangle(crop_img, left_top, right_bottom, (255,0,0), 5) ax_list[i].imshow(cv2.cvtColor(crop_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_black_patches
ランダムで黒点のノイズを入れる。
f, ax_list = plt.subplots(1, 7, figsize=(12, 3)) for i in range(7): new_img = proc.random_black_patches( img, max_black_patches=5).numpy() if not isinstance(new_img, np.ndarray): new_img = new_img.numpy() ax_list[i].imshow(cv2.cvtColor(new_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_self_concat_image
ランダムで自身の画像を縦か横にconcatする。
デフォルトだとprobability=0.1だが、下記ではvertical, horizontalともに0.3を指定している。
# random_self_concat_image new_img = tf.convert_to_tensor((img.copy() / 255).astype(np.float32)) tf_boxes = tf.convert_to_tensor(np.array([[box[1], box[0], box[3], box[2]]])) labels = tf.convert_to_tensor(np.array([1])) label_weights = tf.convert_to_tensor(np.array([1.0], np.float32)) f, ax_list = plt.subplots(1, 5, figsize=(12, 4)) for i in range(5): crop_img, crop_boxes, crop_labels, crop_label_weights = \ proc.random_self_concat_image( new_img, tf_boxes, labels, label_weights, concat_vertical_probability=0.3, concat_horizontal_probability=0.3) crop_img = (crop_img.numpy() * 255).astype(np.uint8) crop_boxes = crop_boxes.numpy() for crop_box in crop_boxes: left_top = tuple(np.array([crop_box[1] * crop_img.shape[1], crop_box[0] * crop_img.shape[0]]).astype(np.int)) right_bottom = tuple(np.array([crop_box[3] * crop_img.shape[1], crop_box[2] * crop_img.shape[0]]).astype(np.int)) cv2.rectangle(crop_img, left_top, right_bottom, (255,0,0), 5) ax_list[i].imshow(cv2.cvtColor(crop_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
random_absolute_pad_image
ランダムでpaddingを入れる。
new_img = tf.convert_to_tensor((img.copy() / 255).astype(np.float32)) tf_boxes = tf.convert_to_tensor(np.array([[box[1], box[0], box[3], box[2]]])) # 0〜200ピクセルの間でランダムになる引数を用意 max_height_padding = tf.convert_to_tensor(200) max_width_padding = tf.convert_to_tensor(200) f, ax_list = plt.subplots(1, 5, figsize=(12, 4)) for i in range(5): # random_absolute_pad_imageの呼び出し crop_img, crop_boxes = proc.random_absolute_pad_image( new_img, tf_boxes, max_width_padding, max_width_padding) crop_img = (crop_img.numpy() * 255).astype(np.uint8) crop_boxes = crop_boxes.numpy() left_top = tuple(np.array([crop_boxes[0][1] * crop_img.shape[1], crop_boxes[0][0] * crop_img.shape[0]]).astype(np.int)) right_bottom = tuple(np.array([crop_boxes[0][3] * crop_img.shape[1], crop_boxes[0][2] * crop_img.shape[0]]).astype(np.int)) cv2.rectangle(crop_img, left_top, right_bottom, (255,0,0), 5) ax_list[i].imshow(cv2.cvtColor(crop_img.astype(np.uint8), cv2.COLOR_BGR2RGB)) ax_list[i].axis('off')
改定履歴
Author: Masato Watanabe, Date: 2019-07-20, 記事投稿