Message in a bottle

海に流すボトルメッセージのような、脈絡もないことを書き連ねていくブログです

ご注文はKerasですか?

あぁ^〜 心がぴょんぴょんするんじゃあ^〜

人生疲れたときにごちうさ見ると心が癒されますよね。

 

って思いながらネットサーフィンしてたらこのような記事に出会いました。

kivantium.hateblo.jp

 

Deep Learningを使ってごちうさのキャラの画像認識を行うというものでした。

 

・・・Kerasでもやってみたい!!!

 

ていうことでぴょんぴょんしていきましょう。

 

 

ラッキーアイテムはOpenCvと識別器とNicoVideo

 

顔認識はOpencvを使ってあげます。

http://anime.udp.jp/data/lbpcascade_animeface.xml

から識別器を入手。

nicovideo-dlを入手し、(自分は以下のリンクから直接入手しました)

https://osdn.net/projects/nicovideo-dl/

  www.nicovideo.jp

 

をダウンロードしましょう。

ダウンロードした後にこのファイルを実行して画像を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()

f:id:umi-0315:20191022000837p:plain f:id:umi-0315:20191022000833p:plain f:id:umi-0315:20191022000837p:plain

大体はうまくいってるのですが、まだ少し誤認識があるので手作業で、ディレクトリを移動します。

長くなってきたので、続きは次回へ!