コンピュータ・ビジョンの主な問題は、十分なデータが得られないことです。ほとんどの機械学習アプリケーションでは問題ありませんが、コンピュータビジョンでは十分なデータがありません。つまり、コンピュータビジョンモデルをトレーニングする際には、データの増強が有効であり、それは、転移学習を使用する場合でも、誰かが事前にトレーニングしたモデルから始める場合でも、ソースコードからモデルをトレーニングする場合でも、実現可能です。
以下は、データ強化方法の詳細とコード実装の説明です。
データ強化
例えば、あなたのデータセットには左のような写真しかありませんが、それに対して階調演算と反転演算を実行すると、異なる猫を含む4つの新しい写真を得ることができます。データセットが拡張され、データセットのサンプルがより多様になるため、猫の認識がより良くなり、それらをニューラルネットワークの学習に投入することで、ネットワークの頑健性を向上させることができ、明るさや形態などの追加要因の影響を軽減することができます。明るさや形態など、様々な付加的要因が認識に与える影響を減らすことができ、あなたのデータセットにはすでに異なる形態の猫の写真が含まれています。
明るさ、イメージの歪み、より多様なイメージを作るために他の方法を変更することにより、上の写真に示すように、明るさ、微妙な変化の形状が、本質的にターゲットのイメージはまだ猫です。
ターゲット検出におけるデータ拡張
あなただけの単純にターゲット分類タスクを実行したい場合は、ネットワークモデルは、データセットにイメージを保存した後、ネットワーク学習にそれを供給することができ、上記のデータ拡張のように、それが猫であるかどうかを判断するためにイメージをトラバースしてみましょうが、ターゲット検出だけでなく、ターゲットの分類を実行する必要がありますが、また、ターゲットフレームの調整を伴うターゲットローカリゼーション。
一般的なデータ強化アプローチ:
- イメージの縦横の拡大縮小と歪曲
- イメージの反転
- イメージに色域歪みを適用
ターゲット検出では、単にイメージを直接強調するだけでなく、歪みと反転後のボックスの位置を考慮します。
右のイメージは私のVOC2007データセットからのイメージで、人間と犬の2つのターゲットとそれに対応するフレームが含まれています。 左のイメージはデータエンハンスメント後に得られた新しいイメージで、ご覧の通り、元のイメージの幅と高さが歪み、サイズが縮小され、イメージが反転し、イメージの色域が変更されていますが、ターゲットとターゲットを縁取るフレームはそのまま残っています。
実施コード
以下のコードを使用すると、VOC2007データセットのデータ拡張を行うことができます。
from PIL import Image, ImageDraw
import numpy as np
from matplotlib.colors import rgb_to_hsv, hsv_to_rgb
"""
データ強調のアプローチ:
データエンハンスメントは実際にはイメージをより多様にすることであり、データエンハンスメントはターゲット検出アルゴリズム手段のロバスト性を向上させるために非常に重要である。
あなたは、明るさ、イメージの歪みとイメージをより多様になるように他の方法を変更することができ、ニューラルネットワークの訓練にイメージの変更後に、側面の認識への追加要因の影響を低減するために、ネットワークの堅牢性を向上させることができる.
"""
def rand(a=0, b=1): # の値域を生成する。[a,b)乱数
return np.random.rand() * (b - a) + a
# get_random_dataデータエンハンスメント
def get_random_data(annotation_line, input_shape, random=True, max_boxes=20, jitter=.5, hue=.1, sat=1.5, val=1.5, proc_img=True):
"""
ランダム前処理のリアルタイムデータ強調
random preprocessing for real-time data augmentation
:param annotation_line: イメージに対応するデータセットの行
:param input_shape: yoloネットワークの入力イメージサイズ
:param random:
:param max_boxes:
:param jitter:歪曲率のイメージの幅と高さを制御する。,jitter=.5 0.5 1.5歪みの間
:param hue: hsvの色域を代表して、歪みの色相の3つのチャンネルで、色相を調整する。=.1
:param sat: hsvの色域を代表して、歪みの彩度の3つのチャンネルで、彩度(S)=1.5
:param val: hsvの色域を代表して、歪みの明るさの3つのチャンネルで、明るさ=1.5
:param proc_img:
:return:
"""
line = annotation_line.split()
image = Image.open(line[0])
iw, ih = image.size # 元のイメージサイズ
h, w = input_shape # 入力イメージのサイズをモデル化する
box = np.array([np.array(list(map(int, box.split(',')))) for box in line[1:]]) # イメージの分割のためのターゲットボックス内のイメージのライン
# イメージを拡大縮小し、縦横の歪みを調整する。
# イメージサイズの歪みの後、イメージのサイズよりも大きくなる可能性があるが、グレーのバーの追加に修正される
new_ar = w/h * rand(1-jitter, 1+jitter)/rand(1-jitter, 1+jitter) # 元イメージの幅と高さの歪み率の表。jitter=0,そうすると、元のイメージの幅と高さの比率は変わらないが、そうでなければ、イメージの幅と高さがある程度歪む。
scale = rand(.25, 2) # scale元イメージのズーム比をコントロールする。rand(.25, 2) 0.25の間でズームすると、イメージは拡大されるかもしれないし、縮小されるかもしれない。rand(.25, 1)元のイメージは縮小され、グレーのバーでイメージの端は、小さなターゲットの検出にネットワークを訓練することができる。
if new_ar < 1:
nh = int(scale * h)
nw = int(nh * new_ar)
else:
nw = int(scale * w)
nh = int(nw / new_ar)
image = image.resize((nw, nh), Image.BICUBIC)
# print(nw,nh) # イメージの幅と高さの歪みの後
# イメージの余分な部分にグレーのバーが表示されているが、このバーが表示されるイメージの大きさを確認してほしい。w,h =
dx = int(rand(0, w - nw))
dy = int(rand(0, h - nh))
new_image = Image.new('RGB', (w, h), (, 128)) # (, 128)灰色を代表して
new_image.paste(image, (dx, dy))
image = new_image
# イメージを反転させるかどうか
flip = rand() < .5 # 50%反転の可能性
if flip: image = image.transpose(Image.FLIP_LEFT_RIGHT) # 左右反転
# 色域の歪み
# このhsvの色域は、色相H、彩度S、明度Vの3つのコントロールで、この3つの値を調整して色域の歪みの比率を調整する。
hue = rand(-hue, hue)
sat = rand(1, sat) if rand()<.5 else 1/rand(1, sat)
val = rand(1, val) if rand()<.5 else 1/rand(1, val)
x = rgb_to_hsv(np.array(image) / 255.) # RGBイメージからhsv色域に調整し、その色域を歪める。
x[..., 0] += hue
x[..., 0][x[..., 0] > 1] -= 1
x[..., 0][x[..., 0] < 0] += 1
x[..., 1] *= sat
x[..., 2] *= val
x[x > 1] = 1
x[x < 0] = 0
image_data = hsv_to_rgb(x) # numpy array, 0 to 1
# ボックスが調整される
# 元のイメージは、歪み後の項目にだけでなく、ボックスの元のイメージにもそれに応じて調整する必要がある!
box_data = np.zeros((max_boxes, 5))
if len(box) > 0:
np.random.shuffle(box)
# 歪みの調整
box[:, [0, 2]] = box[:, [0, 2]] * nw / iw + dx
box[:, [1, 3]] = box[:, [1, 3]] * nh / ih + dy
# 調整を回転させる
if flip: box[:, [0, 2]] = w - box[:, [2, 0]]
# ターゲットボックスの調整のイメージでは、もはや調整は調整されていないためである。
box[:, 0:2][box[:, 0:2] < 0] = 0
box[:, 2][box[:, 2] > w] = w
box[:, 3][box[:, 3] > h] = h
box_w = box[:, 2] - box[:, 0]
box_h = box[:, 3] - box[:, 1]
box = box[np.logical_and(box_w > 1, box_h > 1)] # discard invalid box
if len(box) > max_boxes: box = box[:max_boxes]
box_data[:len(box)] = box
return image_data, box_data
# 元イメージの描画
def normal_(annotation_line, input_shape):
"""
random preprocessing for real-time data augmentation
:param annotation_line: イメージに対応するデータセットa行を選択し、データ強調を行う。
:param input_shape: 入力のサイズ
:return:
"""
line = annotation_line.split() # 空間によるセグメンテーション
# イメージに対応する行を取得する
image = Image.open(line[0])
# 各ターゲットボックスのイメージを取得する
box = np.array([np.array(list(map(int, box.split(',')))) for box in line[1:]])
return image, box
if __name__ == "__main__":
with open("2007_train.txt") as f:
lines = f.readlines()
a = np.random.randint(0, len(lines))
line = lines[a] # イメージに対応するデータセットa行を選択し、データ強調を行う。
image_data, box_data = normal_(line, [])
img = image_data
# 元イメージの描画
#イメージ1行目のデータセット
for j in range(len(box_data)):
thickness = 3
left, top, right, bottom = box_data[j][0:4]
draw = ImageDraw.Draw(img)
for i in range(thickness):
draw.rectangle([left + i, top + i, right - i, bottom - i], outline=(, 255))
img.show()
#イメージのデータ強調の後
image_data, box_data = get_random_data(line, [])
print(box_data)
img = Image.fromarray((image_data * 255).astype(np.uint8))
for j in range(len(box_data)):
thickness = 3
left, top, right, bottom = box_data[j][0:4]
#描画オブジェクトを作成する
draw = ImageDraw.Draw(img)
for i in range(thickness):
draw.rectangle([left + i, top + i, right - i, bottom - i], outline=(, 255))
img.show()
コードからわかる主な手順は、データセットイメージを読み込む→データエンハンスメントを行うためにイメージにデータを与える→イメージ内のターゲットボックスを調整する、です。