第10回:自作データで機械学習の予測モデル自作!! (4) データの水増し

データの水増しをします。
「水増し」っていうとすこし聞こえが悪いですが、データ拡張 (Data Augmentation) とも呼ばれる処理です。
用意した画像を使って、少しだけ拡大縮小・上下左右移動した画像も作成します。
たとえば・・・

データの水増しの例

目的は、学習画像の数を増やすことと、 過学習(※)を抑えることです。
これもPythonで行います。

※ “過学習”
例えば、画像のある部分の1ピクセルだけに注目して「赤」「青」だけで機械学習が画像を分類しちゃうとか、そんなことです。
でも、たまたま、集めた学習データがそんな画像だけだった、ということもありますよね?
そんな “過学習” が起きてしまうと、注目した1ピクセルにノイズが入ったら、すぐ予測ミスするといったトラブルに弱い予測モデルとなってしまいます。

コード

# -*- coding: utf-8 -*-
"""
Created on Fri Sep  8 08:15:59 2023

@author: Plant-smile
"""
# プライベートファイル""data-mizumashiV3p1.py"を修正
# TF2.16(TensorFlow>=2.3)対応。 (import時 keras -> tensorflow.keras)

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

# ImageDataGeneratorで画像を水増しする方法
# https://qiita.com/toshi_machine/items/742bff659d51aaace265
photo_size=64 #画素数(正方形)
x=[]#画像データ
y=[]#ラベルデータ

# 水増しの図形の変形の方法
# ImageDataGeneratorクラスのオブジェクト生成
datagen = ImageDataGenerator(
    height_shift_range=0.03,
    width_shift_range=0.03)
#    zoom_range=0.1)

def original_resize(img_loc, reduce_size_loc): 
    img_H, img_W, img_c = img_loc.shape
    # 画像imgの縮小比。 横幅をreduce_size_locピクセルに収める。
    W_ratio = reduce_size_loc/img_W
    # そのように縮小した際の高さ
    H_img2 =img_H*W_ratio
    # アフィン変換
    # https://imagingsolution.net/program/python/opencv-python/opencv_python_affine_transformation/#toc3
    affineMatrix = cv2.getRotationMatrix2D( (0,(reduce_size_loc-H_img2)/2),
                                           0, W_ratio)
    img2 = cv2.warpAffine(img_loc, affineMatrix, 
                          (reduce_size_loc,reduce_size_loc),
                          borderMode=cv2.BORDER_REPLICATE)
    plt.imshow(img2)
    return(img2)

#path以下の画像を読み込んで、リサイズして、リストx, yに放り込む
def glob_files(path,label):
    files=glob.glob(path+"/*.jpg")
    files2=glob.glob(path+"/*.png" )
    files=files+files2
    #フォルダ内の画像ファイル名をリストで返す
    random.shuffle(files) #フォルダごとに画像をシャッフル
    #各ファイルを処理
    for f in files:
        #画像ファイルを読む
        img=cv2.imread(f)
        print(f)
        resized_img = original_resize(img, photo_size)
        resized_img=cv2.cvtColor(resized_img,cv2.COLOR_BGR2RGB)
        resized_img=np.asarray(resized_img)
        x.append(resized_img)
        y.append(label)

def images_gen(x_list,y_list):
    x_list_add=[]
    y_list_add=[]
    for xloc ,yloc in zip(x_list,y_list):
        xloc = xloc.reshape((1,) + xloc.shape)
        i = 0
        #flowメソッド:numpyデータとラベルの配列を受け取り、拡張/正規化したデータのバッチを生成
        for batch in datagen.flow(xloc, 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(yloc)
            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

# メイン
if __name__ == '__main__':
    #ディレクトリ名 を読み込み
    read_directory = 'img_original'
    dirs = os.listdir(read_directory)

    print(read_directory,"の下のディレクトリ群から読み込みます")
    for label, cat in enumerate(dirs):
        # label: 1,2,3,4,..., cat: img_folder下のディレクトリ名1,ディレクトリ名2, ...
        #また、catはimg_original下のディレクトリ名なので、このfor分の中だけで処理を回した方がスマート
        #各画像のフォルダーを読む(./は現在のフォルダ)
        #path以下の画像を読み込んで、リサイズして、リストx, yに放り込む
        glob_files("./"+ read_directory + "/" + cat, label)

    x = np.array(x)
    y = np.array(y)
    print(x.shape)
    #水増し
    x_add,y_add=images_gen(x,y)

    write_directory = 'img_mizumashi'
    print(write_directory,"の下に水増しデータを書き込みます")
    input("Enterキーを押したら実行")
    print("実行中")

    i=0
    for x,y in zip(x_add, y_add):
         # ディレクトリの作成 (, exist_ok=True・・・ ディレクトリが存在するときは何もしない)
        new_dir_path =  write_directory+ '/' + dirs[y]
        os.makedirs(new_dir_path,exist_ok=True)
        # ファイルの書き込み
        x1= cv2.cvtColor(x, cv2.COLOR_BGR2RGB)
        f_name = new_dir_path + '/' + dirs[y] + "00" + str(i) + ".png"
        cv2.imwrite(f_name, x1)
        i=i+1
プロフィール
この記事を書いた人
しょくぶつ (^ ^)

機械系の技術者です。学会発表13、論文掲載6(和・英)。プログラミング歴40年(つまり8bit世代ですね)。ゲーム歴40年(ファミコン世代ですね)。
お問い合わせは下記のメールアドレスにお寄せください。
plantsmilehatena@gmail.com

しょくぶつ (^ ^)をフォローする
pythonスプラトゥーン3
しょくぶつ (^ ^)をフォローする
タイトルとURLをコピーしました