ImageDataGenerator로 이미지를 물 늘리는 방법

소개



DeepLearning을 활용함에 있어 ImageDataGenerator 클래스를 이용하여 이미지의 물을 늘리고 폴더별 라벨링에서 물을 늘리는 방법을 메모했습니다. 또한 이미지 데이터를 npz 파일에 바이너리 데이터로 저장하는 방법을 보여주었습니다.

파일 폴더의 위치 관계



이번에는, 넷으로부터 사과, 바나나, 포도의 이미지를 각각 3장 적당히 가져와, 그들을 폴더로 분류했습니다.
$ tree
.
|-- img_increase.ipynb
`-- img_original
    |-- apple
    |   |-- apple1.jpg
    |   |-- apple2.jpg
    |   `-- apple3.jpg
    |-- banana
    |   |-- banana1.jpg
    |   |-- banana2.jpg
    |   `-- banana3.jpg
    `-- grape
        |-- grape1.jpg
        |-- grape2.jpg
        `-- grape3.jpg

가져올 라이브러리


import numpy as np
import glob
import random
import cv2
import keras
import matplotlib.pyplot as plt
from keras.preprocessing.image import ImageDataGenerator
%matplotlib inline

이미지 로드



  이하에, 상기의 원화상을 읽어들여, 폴더 마다 라벨 붙이는 프로그램을 나타냈습니다. 이 프로그램을 실행하면 원화상 데이터 및 그에 대한 라벨 데이터가 npz 파일에 저장됩니다.
 # npzファイル:Numpy配列 ndarray を保存するバイナリファイル
outfile="fruits_org_data.npz"#保存ファイル名
max_photo=3 #各フォルダ内の枚数
photo_size=80 #画素数(80*80)
x=[]#画像データ
y=[]#ラベルデータ

#フォルダ名
categories = ["apple","banana","grape"]

#path以下の画像を読み込む
def glob_files(path,label):
    files=glob.glob(path+"/*.jpg") #フォルダ内の画像ファイル名をリストで返す
    random.shuffle(files) #フォルダごとに画像をシャッフル
    #各ファイルを処理
    num=0
    for f in files:
        if num >=max_photo:break #フォルダ内の写真を全て読み込んだら終了
        num+=1
        #画像ファイルを読む
        img=cv2.imread(f)
        img=cv2.resize(img, (photo_size,photo_size ))
        img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        img=np.asarray(img)
        x.append(img)
        y.append(label)

    print(num)

def main():
    for cat, label in zip(categories, range(len(categories))):
        #各画像のフォルダーを読む(./は現在のフォルダ)
        glob_files("./img_original/" + cat, label)

    #x(学習データ),y(ラベル)の対応は維持したまま全画像データをシャッフル
    for l in [x, y]:
        np.random.seed(1)
        np.random.shuffle(l) 

    #ファイルへ保存
    np.savez(outfile,x=x,y=y)#xとyがnumpyのリストとして与えられる
    print("保存しました:"+outfile,len(x))

main()

프로그램의 설명은 코멘트문으로 실시하고 있으므로, 세세한 것은 생략합니다만, 여기서는 13행째의 glob 함수에 대해서 설명합니다.

glob 함수의 실행 예
시도에 다음 프로그램을 실행하면
print(glob.glob("./img_original/apple/*.jpg"))

이러한 결과가 출력됩니다.
['./img_original/apple\\apple1.jpg', './img_original/apple\\apple2.jpg', './img_original/apple\\apple3.jpg']

따라서 glob 함수는 지정된 파일까지의 경로를 목록으로 반환하는 함수입니다.

ImageDataGenerator에 의한 이미지 물 증가



원화상을 읽을 수 있었으므로, 다음은 물 증가를 실시해 갑니다. 다음 코드를 실행하면 90장(=3×3×10)으로 늘어납니다.
# ImageDataGeneratorクラスのオブジェクト生成
datagen = ImageDataGenerator(
        rotation_range=45, #±45°でランダムに回転
        vertical_flip=True, #垂直方向にランダムで反転
        horizontal_flip=True) #水平方向にランダムで反転

def images_gen(x_list,y_list):
    x_list_add=[]
    y_list_add=[]
    for x ,y in zip(x_list,y_list):
        x = x.reshape((1,) + x.shape)

        batch_list=[]
        i = 0

        # flowメソッド:numpyデータとラベルの配列を受け取り、拡張/正規化したデータのバッチを生成
        for batch in datagen.flow(x, batch_size=1):
            batch=batch.astype(np.uint8)#データ型を揃える
            batch=batch.reshape((photo_size, photo_size, 3))
            x_list_add.append(batch)
            y_list_add.append(y)
            i += 1
            if i > 9:#1枚から10枚作る(計90=3*3*10)
                break             
    x_np_add=np.array(x_list_add)
    y_np_add=np.array(y_list_add)

    #x(学習データ),y(ラベル)の対応は維持したままシャッフル
    for l in [x_np_add, y_np_add]:
        np.random.seed(1)
        np.random.shuffle(l) 

    return x_np_add,y_np_add


#画像データを読み込み
images=np.load("./fruits_org_data.npz")
x=images["x"] #画像データ
y=images["y"] #ラベルデータ

#読み込んだデータを三次元配列に変換
x=x.reshape(-1,photo_size,photo_size,3) #(サンプル数、行数、列数、RGB)の形に

#水増し
x_add,y_add=images_gen(x,y)

ImageDataGenerator 클래스의 자세한 내용은, 이쪽에 실려 있습니다. ⇒ KerasDocumentation
상기의 프로그램의 3~5행째로, ±45°의 회전, 수직·수평 방향의 반전을 실시하는 것을 지정하고 있습니다. 그 외에도 이미지의 시프트, 줌, 명암을 변경하는 인수가 있습니다.

물이 증가했는지 확인
plt.imshow(x_add[60])
print("Label: {}".format(y_add[60]))

이것을 실행해 보면, 다음과 같이 제대로 표시된 것으로부터, 물 늘어나고 있는 것을 알 수 있군요.



마지막으로 주의



・화상의 물 증가는, 원화상을 train과 test 데이터로 나누고 나서 실시한다!
・위의 프로그램에서는 y의 Label 데이터는 0~2의 list가 되어 있으므로, one-hot
인코딩을 잊지 마세요!

끝에



이 방법으로 ImageDataGenerator 클래스를 사용하면 쉽게 물을 늘릴 수 있습니다. 또, ImageDataGenerator 클래스에 포함되어 있지 않은 노이즈등은, 클래스의 계승에 의해, 노이즈를 붙이는 함수를 더하는 것으로 해결할 수 있습니다.

참고문헌


  • Keras의 ImageDataGenerator를 사용하여 학습 이미지 늘리기
  • Keras Documentation
  • 라면을 진심으로 분류해 보았다
  • 좋은 웹페이지 즐겨찾기