深層学習でラブライブサンシャインのキャラクター顔認識をしてみた part1(学習データの作成)
はじめに
私は研究で深層学習を使った画像認識の研究をしているのですが,ふとこの技術を使えばアニメキャラクターの顔認識をできるのでは!?と思いはじめました.今回は私の好きなラブライブサンシャインのキャラクターの顔認識を深層学習を使って実現に挑戦してみます.
開発環境
開発環境は以下のようになっています.●使用言語等
●その他構成
- OS : Windows10 (64bit)
- CPU : Intel Core i5 7400
- Memory : 16GB
- GPU : NIVIDIA GeForce GTX 1060 6GB
今回深層学習のフレームワークとしてPyTorchを使っていますが,理由は自分の研究で使っているから…っていう単純な理由です.一応まったく同じ動作をするものをKerasでも書いているので,機会があれば載せていきたいと思ってます.
ソフトウェアのインストール方法とかは割愛します.(いつか書くかも…)
学習データの収集
深層学習では大量のデータを必要とします.今はインターネットが普及しているのでグーグルでキャラクターの名前を検索すれば無限に画像が出てくるので,それらを学習データにします.適当にとってきた画像を以下のようなディレクトリ構造の中に保存しました.ディレクトリの最初に000~008の値を設定しているのはos.listdirで読み込んだ後にsortしたときにわかりやすくなるからです.
例えば千歌ちゃんのフォルダの中には…
見てるだけで幸せになれるネ!
今回1人あたり100枚の学習画像を用意しました(少ないかもしれないから本来であれば画像処理をして学習画像を増やすのが望ましいけど,とりあえず動かしてみたいから今回はこのままで).今回作成したソースコードはファイル名や画像形式を問わず読み込めるようにしているのでそろっていなくてもOKです.
しかし画像検索で出てきたキャラクターの画像をそのまま入力画像とすると他の情報(服装等)が多く含まれているため,認識精度があまり上がらないといった問題があります.今回は顔の部分だけを抜き出すことで,それ以外の余計な情報を学習せずに済み精度向上が見込めます.手動で取り出すのは面倒なので顔だけを抜き出す作業は以下のURLから頂いたlbpcascade_animeface.xmlというカスケード分類器を使います.これがすごく便利!
github.com
学習データの作成
それでは学習データを作成していきます.プログラムを載せる前に手順を紹介します.- ①各ディレクトリから画像を読み込む
- ②カスケード分類器で画像中の顔の位置を切り出す
- ③64×64のサイズにリサイズする
- ④画像のチャンネルの位置を変更 ※(height, width, channels)→(channels, height, width)に変更する(PyTorchの読み込みの形)
- ⑤入力画像用のリストに保存
- ⑥その画像の正解を正解用のリストに保存
プログラムの作成にあたっては以下のサイトを参考にしました.
qiita.com
ソースコード
作成したソースコードは以下になります.・make_dataset.py
# -*- coding: utf-8 -*- import os import numpy as np import cv2 from tqdm import tqdm #アニメキャラクターの顔位置抽出用に使うカスケード分類機の定義 cascade = cv2.CascadeClassifier('lbpcascade_animeface.xml') #学習用キャラクター画像が入っているディレクトリパスの定義 data_dir_path = "LoveLiveSunshine/" file_list = os.listdir(data_dir_path) dir_list = sorted([x for x in file_list if os.path.isdir(data_dir_path+x)]) input_image=[] anime_class=[] for count, dir_name in enumerate(tqdm(file_list)): file_list = os.listdir(data_dir_path+dir_name) for file_name in file_list: #1:画像を読み込む image_path = str(data_dir_path)+str(dir_name)+'/'+str(file_name) image = cv2.imread(image_path) height, width = image.shape[:2] #2:カスケード分類器でキャラクターの顔位置抽出を行う faces = cascade.detectMultiScale(image, scaleFactor = 1.1, minNeighbors = 4, minSize= (24, 24)) if len(faces) > 0: #もし顔が見つかったら (x,y,w,h) = faces[0] #最も確率の高かった顔位置情報を抽出 if(x<0 or y+h>height or x<0 or x+w>width): #範囲外処理 image = image #元画像を使用 else: image = image[y:y+h,x:x+w] #顔位置のみを切り出す else: image = image #元画像を使用 #3:画像サイズを64x64にリサイズ image = cv2.resize(image, (64, 64)) #4:画像のチャンネルの位置を変更 image = image.transpose(2,0,1) #5,6:入力画像と正解をそれぞれ保存する input_image.append(image) anime_class.append(count) #キャラクター名と正解をcsvファイルに書き出す(後で使う) with open('file.csv', mode='w') as f: for n in dir_list: number, name = n.split('_',1) f.write(str(number)+','+str(name)+'\n') #学習画像とキャラクターの番号(正解)を書き出す np.save('anime_face_class.npy',np.array(anime_class)) np.save('anime_face_image.npy',np.array(input_image))
補足
tqdmとかいうプログレスバーを表示するものを使っていますが,なくてもOKです.なんとなく可視化するのが好きなので入れただけです.ね?オシャレでしょ?(威圧)
またcsvで正解を書き出していますが,以下のようなfile.csvができていればOKです.
これは今回のネットワーク構成では出力値が0~9であるため,例えば曜ちゃんの画像を入力させたときに1だよ!って言われても誰やねんってなるので,1→曜ちゃんと対応付けができるように作ったものです.