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()
画像のノイズを除去、画像の水増しテクニックで精度をあげる