ご注文はKerasですか?
あぁ^〜 心がぴょんぴょんするんじゃあ^〜
人生疲れたときにごちうさ見ると心が癒されますよね。
って思いながらネットサーフィンしてたらこのような記事に出会いました。
Deep Learningを使ってごちうさのキャラの画像認識を行うというものでした。
・・・Kerasでもやってみたい!!!
ていうことでぴょんぴょんしていきましょう。
ラッキーアイテムはOpenCvと識別器とNicoVideo
顔認識はOpencvを使ってあげます。
http://anime.udp.jp/data/lbpcascade_animeface.xml
から識別器を入手。
nicovideo-dlを入手し、(自分は以下のリンクから直接入手しました)
https://osdn.net/projects/nicovideo-dl/
をダウンロードしましょう。
ダウンロードした後にこのファイルを実行して画像を200枚ほどとります。
本家と同じようにC++ではなくpythonです。 どっちもぴょんぴょんするからいいよね!!
import cv2 import time import sys import os def main(): # ディレクトリの作成 output_dir = "image_outputs" if not os.path.exists(output_dir): os.mkdir(output_dir) # 動画を読み込む video = cv2.VideoCapture("1397552685.mp4") # 識別器を読み込む cascade = cv2.CascadeClassifier("lbpcascade_animeface.xml") # 読み込めなかった場合、強制終了する if not video.isOpened(): print("failed") sys.exit() framecount = -1 imagecount = 0 while True: framecount += 1 ret, frame = video.read() if framecount % 10 != 0: continue # 処理を高速化するためにグレースケールにする gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 顔の検出 返される形は[[x,y,w,h],[x,y,w,h]..] face = cascade.detectMultiScale( gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(100, 100)) # 顔が存在した場合に保存を行う if len(face) != 0: for i, (x, y, w, h) in enumerate(face): face_image = frame[y:y + h, x:x + w] imagename = "image" + str(imagecount) + ".png" imagepath = os.path.join(output_dir, imagename) cv2.imwrite(imagepath, face_image) imagecount += 1 if imagecount > 200: break video.release() if __name__ == "__main__": main()
Keras襲来
ここでKerasを使って大規模学習用のデータ学習器を作ります。
認識するのは
主要キャラクター5人とその他、計6クラスです。
画像による色の違いがあまりないように、画像の正規化を行なってあげましょう。
ネットワークの構築は適当です。
多分ここら辺をもう少し頑張ってあげると精度が向上すると思います。
from keras import models from keras import layers from keras import regularizers import glob import sys import cv2 import matplotlib.pyplot as plt import numpy as np class Processing_Image: # 画像の読み込みを行い、リストに保存する def loadimage(self): image_list = [] list_trainlabel = [] for i in range(6): trainlabel = [0 for i in range(6)] trainlabel[i] = 1 file_t = glob.glob("images_train_gen_" + str(i) + "/image*") for u in range(len(file_t)): image = cv2.imread("images_train_gen_" + str(i) + "/image_" + str(i) + "_" + str(u) + ".png") height, width, ch = image.shape # 画像の大きさが一律でないため、大きさを揃える if height >= 100 or width >= 100: image = cv2.resize(image, dsize=(100, 100), interpolation=cv2.INTER_AREA) else: image = cv2.resize(image, dsize=(100, 100), interpolation=cv2.INTER_LINEAR) height, width, ch = image.shape norm = np.zeros((height, width)) # 画像の正規化 image = cv2.normalize( image, norm, 0, 1, norm_type=cv2.NORM_MINMAX) image_list.append(np.array(image)) list_trainlabel.append(trainlabel) return image_list, np.array(list_trainlabel) class Neural_NetWork: def constract_network(self): model = models.Sequential() model.add(layers.Conv2D(32, (3, 3), activation="relu", input_shape=(100, 100, 3))) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation="relu")) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(128, (3, 3), activation="relu")) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(128, (3, 3), activation="relu")) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Flatten()) model.add(layers.Dropout(0.5)) model.add(layers.Dense( 512, kernel_regularizer=regularizers.l2(0.001), activation="relu")) model.add(layers.Dense(6, activation="sigmoid")) # Adadeltaいいっぽい model.compile(optimizer="Adadelta", loss="binary_crossentropy", metrics=["accuracy"]) return model def calculate_network(self, model, x_train, y_train, x_test, y_test): history = model.fit(x_train, y_train, epochs=20, batch_size=256, validation_data=(x_test, y_test)) model.save("bigdata_gotiusa_256_e20.h5") return history def plot_histrory(self, history): acc = history.history["acc"] val_acc = history.history["val_acc"] epochs = range(1, len(acc)+1) plt.plot(epochs, acc, "bo", label="Training acc") plt.plot(epochs, val_acc, "b", label="Validation acc") plt.title("Training and Validation acciracy") plt.xlabel("Epochs") plt.ylabel("Accuracy") plt.legend() plt.show() def plot_loss(self, history): loss = history.history['loss'] val_loss = history.history['loss'] epochs = range(1, len(loss) + 1) plt.plot(epochs, loss, 'bo', label='Training loss') plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.show() def main(): Process = Processing_Image() image_list, trainlabel = Process.loadimage() x_train, x_test, y_train, y_test = [], [], [], [] for i in range(min(len(image_list), len(trainlabel))): if i % 50 == 0: x_test.append(image_list[i]) y_test.append(trainlabel[i]) else: x_train.append(image_list[i]) y_train.append(trainlabel[i]) Neural_NetWorks = Neural_NetWork() model = Neural_NetWorks.constract_network() history = Neural_NetWorks.calculate_network( model, np.array(x_train), np.array(y_train), np.array(x_test), np.array(y_test)) Neural_NetWorks.plot_loss(history) Neural_NetWorks.plot_histrory(history) if __name__ == "__main__": main()
Keras Horizon
前のやつで学習したものを用い、大規模データを生成します。
他のごちうさのデータをとってきてあげたりして、15000枚前後集めました。
(gotiusa_kerasは前のpythonファイルの名前です)
from gotiusa_keras import Neural_NetWork, Processing_Image import os import cv2 import sys def make_direktory(): for i in range(6): name_dir = "images_" + str(i) if not os.path.exists(name_dir): os.mkdir(name_dir) def main(): make_direktory() network = Neural_NetWork() process = Processing_Image() model = network.constract_network() model.load_weights("mindata_gotiusa.h5") # 動画を読み込む video = cv2.VideoCapture("gotiusa_movie.mp4") # 識別器を読み込む cascade = cv2.CascadeClassifier("lbpcascade_animeface.xml") # 読み込めなかった場合、強制終了する if not video.isOpened(): print("failed") sys.exit() framecount = -1 imagecount = 0 list_numofimage = [0 for i in range(6)] while True: framecount += 1 ret, frame = video.read() if framecount % 3 != 0: continue # 処理を高速化するためにグレースケールにする gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 顔の検出 返される形は[[x,y,w,h],[x,y,w,h]..] face = cascade.detectMultiScale( gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(100, 100)) # 顔が存在した場合に保存を行う if len(face) != 0: for i, (x, y, w, h) in enumerate(face): face_image = frame[y:y + h, x:x + w] image = face_image height, width, ch = image.shape # 画像の大きさが一律でないため、大きさを揃える if height >= 100 or width >= 100: image = cv2.resize(image, dsize=(100, 100), interpolation=cv2.INTER_AREA) else: image = cv2.resize(image, dsize=(100, 100), interpolation=cv2.INTER_LINEAR) height, width, ch = image.shape import numpy as np norm = np.zeros((height, width)) # 画像の正規化 images = cv2.normalize( image, norm, 0, 1, norm_type=cv2.NORM_MINMAX) prediction = model.predict(np.array([images])) prediction = prediction.tolist()[0] max_index = prediction.index(max(prediction)) imagename = "image" + str(list_numofimage[max_index]) + ".png" output_dir = "images_" + str(max_index) imagepath = os.path.join(output_dir, imagename) #cv2.imwrite(imagepath, face_image) list_numofimage[max_index] += 1 imagename = "image" + str(imagecount) + ".png" #imagepath = os.path.join(output_dir, imagename) cv2.imwrite(imagepath, face_image) imagecount += 1 if imagecount > 20000: print("sucess") break if __name__ == "__main__": main()
大体はうまくいってるのですが、まだ少し誤認識があるので手作業で、ディレクトリを移動します。
長くなってきたので、続きは次回へ!