Python 学習済みCNN画像分類器を用いて、画像を分類する雛形コード「TensorFlow2」

 本記事では、作成した学習器(CNN:畳み込みニューラルネットワーク)を用いて、画像を分類する雛形コードを載せました。

 自前の画像ファイル(jpg, png)で分類学習器を作成する雛形コードは、次のリンク先です。hk29.hatenablog.jp

本記事のプログラムを実行すると下図のように画像の判定確率を取得できます。そして、例えば判定確率90%以上を正解として分類することが出来ます。

f:id:HK29:20210322144832p:plain

下図は、0~9の手書き数字を分類した結果です。label_nullと記載したフォルダには、0~9のいずれの判定確率も90%未満であったものを分類しています。

f:id:HK29:20210328181532p:plain

■本プログラム

# -*- coding: utf-8 -*-
import os, glob, re
import json, pprint
import shutil
import numpy as np
import pandas as pd
import tensorflow as tf
#print("Num GPUs:", len(tf.config.list_physical_devices('GPU')))
from tensorflow import keras
from tensorflow.keras.models import model_from_json
from tensorflow.keras.preprocessing.image import array_to_img, img_to_array, load_img


# CNN分類学習器を読み込んで実行する関数
def load_cnn_func(modelFile, model_weight):
    model = model_from_json(open(modelFile).read())
    model.load_weights(os.path.join(os.path.dirname(modelFile), model_weight))

    img_data_list = []
    for file_path in file_list:
        img = img_to_array(load_img(file_path, target_size=(img_width, img_height, img_ch)))
        img_data_list.append(img)

    # numpyアレイ型へ変換
    img_data_np = np.asarray(img_data_list)
    img_data_np = img_data_np.astype('float32')
    img_data_np = img_data_np / 255.0

    # 予測結果を返す
    return model.predict(img_data_np)


# メイン関数
def main():
    # CNN実行して予測結果を取得
    predict_y = load_cnn_func(modelFile, model_weight)
    print(predict_y)
    
    # 予測結果をひとつのcsvファイルに保存する
    df = pd.DataFrame(predict_y, columns = label_name_list)
    df.insert(0, 'file_name', file_list)
    print(df)
    df.to_csv('predict_y.csv', sep=',', header=True, index=False)

    # 画像を分類する。
    if os.path.isdir('class_picture'):
        shutil.rmtree('class_picture')
    os.makedirs('class_picture', exist_ok=False)
    
    for i in range(df.shape[1]-1):
        label_name = 'label_' + str(i) # ラベル名
        df_buf = df[df[label_name] >= target_value] # 指定条件の値のある行を抽出
        df_buf.to_csv('class_picture/predict_y_label_' + str(i) + '.csv') # csvに保存
        os.mkdir('class_picture/' + label_name) # ラベル名のフォルダを作成
        for file_path in df_buf['file_name']:
            new_file_path = '/'.join(['class_picture', label_name, os.path.basename(file_path)])
            shutil.copy2(file_path, new_file_path)
    
    # 指定した判定確率未満の画像をnullとして分類する
    index_list = []
    for file_path in glob.glob('class_picture/*.csv'):
        df_buf = pd.read_csv(file_path, index_col=0)
        index_list.extend(df_buf.index.values.tolist())
    df_drop = df.drop(index=index_list)
    df_drop.to_csv('class_picture/predict_y_label_null.csv') # csvに保存
    
    os.mkdir('class_picture/label_null') # ラベル名のフォルダを作成
    for file_path in df_drop['file_name']:
        new_file_path = '/'.join(['class_picture/label_null', os.path.basename(file_path)])
        shutil.copy2(file_path, new_file_path)


if __name__ == '__main__':
    print(tf.__version__)
    
    file_list = glob.glob('testSet/*.jpg')
    file_list = sorted(file_list, key=lambda x:int((re.search(r"[0-9]+", x)).group(0)))
    
    modelFile = 'model.json'
    model_weight = 'model_weight.hdf5'

    # 判定確率90%以上を正解として分類する
    target_value = 0.90
    
    # 分類クラス数をモデルから取得する
    json_open = open(modelFile, 'r')
    json_load = json.load(json_open)
    pprint.pprint(json_load)
    myclasses = json_load['config']['layers'][-1]['config']['units']
    print('myclasses -> ', myclasses)

    label_name_list = []
    for i in range(myclasses):
        label_name_list.append('label_' + str(i))
    print(label_name_list)
    
    # 画像の読み込み設定
    img_width = 28 # 横
    img_height = 28 # 縦
    img_ch = 3 # 3ch(RGB)
    
    main()

以上

<広告>