ディープラーニング カタカナ判定 CNNは画像に強い

ETL文字データベースは日本語の手書きデータを多く収録

ETL Character Database Download – etlcdb

データベースに画像を変換

#ETL1ファイルを読み込む
import struct
from PIL import Image, ImageEnhance
import glob, os

#出力ディレクトリ
outdir = "png-etl1/"
if not os.path.exists(outdir): os.mkdir(outdir)

#ETL1ディレクトリ配下のファイルを処理する
files = glob.glob("ETL1/*")
for fname in files:
    if fname == "ETL1/ETL1INFO": continue
    print(fname)
    #ETL1データフィあるを開く
    f = open(fname, 'rb')
    f.seek(0)
    while True:
        #メタデータ+画像データの組を1つずつ読む
        s = f.read(2052)
        if not s: break
        #バイナリデータなのでPythonが理解できるように抽出する
        r = struct.unpack('>H2sH6BI4H4B4x2016s4x', s)
        code_ascii = r[1]
        code_jis = r[3]
        #画像データとして取り出す
        iF = Image.frombytes('F', (64, 63), r[18], 'bit', 4)
        iP = iF.convert('L')
        #画像を鮮明にして保存する
        dir = outdir + "/" + str(code_jis)
        if not os.path.exists(dir): os.mkdir(dir)
        fn = "{0:02x}-{1:02x}{2:04x}.png".format(code_jis, r[0], r[2])
        fullpath = dir + "/" + fn
        if os.path.exists(fullpath): continue
        enhancer = ImageEnhance.Brightness(iP)
        iE  = enhancer.enhance(16)
        iE.save(fullpath, 'PNG')
print("ok")

画像のりサイズ

import glob
import numpy as np
import cv2
import matplotlib.pyplot as plt
import pickle

# 保存先や画像サイズの指定
out_dir = "./png-etl1"
im_size = 25
save_file = out_dir + "/katakana.pickle"
plt.figure(figsize=(9, 17))

# カタカナの画像が入っているディレクトリから画像を取得
kanadir = list(range(177, 220+1))
kanadir.append(166)
kanadir.append(221)
result = []
for i, code in enumerate(kanadir):
    img_dir = out_dir + "/" + str(code)
    fs = glob.glob(img_dir + "/*")
    print("dir=", img_dir)
    # 画像を読み込んでグレースケールに変換しリサイズする
    for j, f in enumerate(fs):
        img = cv2.imread(f)
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        img = cv2.resize(img_gray, (im_size, im_size))
        result.append([i, img])
        # Jupyter Notebookで画像を出力
        if j == 3:
            plt.subplot(11, 5, i + 1)
            plt.axis("off")
            plt.title(str(i))
            plt.imshow(img, cmap="gray")
# 画像のデータを保存する
pickle.dump(result, open(save_file, "wb"))
plt.show()
print("ok")

データを学習

import numpy as np
import cv2, pickle
from sklearn.model_selection import train_test_split
import keras

# データファイルと画像サイズの指定
data_file = "./png-etl1/katakana.pickle"
im_size = 25
in_size = im_size * im_size
out_size = 46

# 保存した画像データを読み込む
data = pickle.load(open(data_file, "rb"))

#画像データを0-1の範囲に直す
y = []
x = []
for d in data:
    (num, img) = d
    img = img.reshape(-1).astype('float') / 255
    y.append(keras.utils.to_categorical(num, out_size))
    x.append(img)
x = np.array(x)
y = np.array(y)

# 学習用とテスト用に分離する
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, train_size = 0.8, shuffle = True)

#モデル構造を定義
Dense = keras.layers.Dense
model = keras.models.Sequential()
model.add(Dense(512, activation="relu", input_shape=(in_size,)))
model.add(Dense(out_size, activation="softmax"))

#モデルを構築して学習を実行
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])  
model.fit(x_train, y_train, batch_size=20, epochs=50, verbose=1, validation_data=(x_test, y_test))

#モデルを評価
score = model.evaluate(x_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])

CNNで学習

import numpy as np
import cv2, pickle
from sklearn.model_selection import train_test_split
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D, Input
from keras.optimizers import RMSprop
from keras.datasets import mnist
import matplotlib.pyplot as plt

# データファイルと画像サイズの指定
data_file = "./png-etl1/katakana.pickle"
im_size = 25
out_size = 46
im_color = 1
in_shape = (im_size, im_size, im_color)

# カタカナ画像データセットを読み込む
data = pickle.load(open(data_file, "rb"))
# 画像データを0-1の範囲に正規化
y = []
x = []
for d in data:
    (num, img) = d
    img = img.astype('float').reshape(im_size, im_size, im_color) / 255
    y.append(keras.utils.to_categorical(num, out_size))
    x.append(img)
x = np.array(x)
y = np.array(y)

# 学習用とテスト用に分離
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, train_size=0.8, shuffle=True)

# CNNモデル構造を定義
model = Sequential()
model.add(Input(shape=in_shape))
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu'))
model.add(Conv2D(64, (3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(out_size, activation='softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(),
              metrics=['accuracy'])

# 学習を実行して評価
hist = model.fit(x_train, y_train, batch_size=128, epochs=12, verbose=1, validation_data=(x_test, y_test))

# モデルを評価
score = model.evaluate(x_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])

# 学習の様子をグラフへ描画
# 正解率の推移をプロット
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

# ロスの推移をプロット
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Loss')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

画像のノイズを除去、画像の水増しテクニックで精度をあげる

タイトルとURLをコピーしました