はじめに
SENSY株式会社に入社して2年が経ちました!
もうすぐ2019年も終わりですね🎄早い💦
前から、好きなアニメキャラの画像+機械学習を使って何かできることはないかなと考えていたのですが、去年は画像が全然集まらず断念しました💔
今年こそは!と思い、まずはキャラクターの画像集めから始めようと思います。
今回は、動画から画像を保存して、画像からキャラクターの顔を検出したので、記事にしてみました。
opencvとは
opencv(Computer Vision Library)は、オープンソースのコンピュータビジョン向けの、画像処理・画像解析および機械学習等の機能を持つC/C++、Java、Python、MATLAB用ライブラリ。
今回はpythonでopencvを用いて画像処理を行いました。
インストール
mainモジュールを使用するので、下のコマンドでpipインストールしました。
$ pip install opencv-python
動画から画像を保存
早速opencvを利用して、動画から任意の範囲のフレーム画像を保存しました。
import cv2
import os
def movie_to_image(video_path, output_dir_path, num_cut=1, start_frame=0):
# 動画ファイルから画像データを取得
capture = cv2.VideoCapture(video_path)
# 静止画像を保存するフォルダを作成
os.makedirs(output_dir_path, exist_ok=True)
# 動画の総フレーム数
digit = capture.get(cv2.CAP_PROP_FRAME_COUNT)
image_cnt = 0
for n in range(start_frame, int(digit), num_cut):
# 動画の現在位置(フレーム)をnに指定
capture.set(cv2.CAP_PROP_POS_FRAMES, n)
ret, frame = capture.read()
if ret:
# 静止画像を指定したjpg画像として保存
cv2.imwrite('{}/image_{}.jpg'.format(output_dir_path, image_cnt), frame)
image_cnt += 1
else:
return
# 動画を閉じる
capture.release()
MOVIE_PATH = 'free_1.mov'
OUTPUT_FOLDER = 'data/free_image'
movie_to_image(MOVIE_PATH, OUTPUT_FOLDER, 10, 0)
video_path:動画の保存先のpath(ファイル名を含む)
output_dir_path:静止画像の保存先(フォルダ名)
num_cut:任意のフレーム数ごとに画像を保存
start_frame:画像保存を始める最初のフレーム数を指定する
os.makedirs()は、output_dir_pathの中間のディレクトリ(今回のdata/
)が存在しなかった場合でも、エラーなくディレクトリを作成してくれます。また、exist_ok=True
とすることで、すでにディレクトリが存在していた場合でもエラーが出ないようになります。
フレームレートとは1秒間に何コマあるかという数字で、1秒間に24コマだと24fps、30コマあれば30fpsとなります。一般的にアニメや映画は24fps、テレビは30fpsで作成されているようなので、24fpsだといろんな表情の画像が保存できるはずです!
今回は、秒数指定ではなく、何フレーム飛ばすかというパラメータを用いたため、10フレームごとに画像を保存しました。
動画ファイル自体は総フレーム数54,270だったので、5,427枚の静止画像が保存できました。
MacBook ProのlocalのJupiter notebook上で実行し、約45分で完了しました。
画像から顔の検出
opencvの「カスケード分類器」という仕組みがあったので、これを用いてキャラクターの顔を検出し、枠で囲いました。
アニメ画像の顔検出をするための特徴量ファイルはこちらのlbpcascade_animeface.xml
を利用しています。
他にもたくさん特徴量ファイルの種類があるようなので、気になる方はこちらを参考にしてください。
import cv2
import os
def face_cascade(img_path, save_cascade_image_dir, name):
# 画像を読み込む
img = cv2.imread(img_path)
# カスケード分類器を生成 -> 今回はアニメ画像の正面の顔を検出
cascade = cv2.CascadeClassifier('lbpcascade_animeface.xml')
# 保存先ディレクトリ作成
os.makedirs(save_cascade_image_dir, exist_ok=True)
# 顔を検出する
facerect = cascade.detectMultiScale(img)
# 検出した顔を四角い枠線で囲む(検出した顔の数だけ繰り返す)
for rect in facerect:
cv2.rectangle(img, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), (255, 255, 255), thickness=2)
# 画像を保存する
cv2.imwrite('{}/cascade_image_{}.jpg'.format(save_cascade_image_dir, name), img)
SAVE_CASCADE_FOLDER = 'free_2/facecascade'
for i in range(5427):
face_cascade('free_2/image_{}.jpg'.format(i), SAVE_CASCADE_FOLDER, str(i))
img_path:読み込む画像のpath(ファイル名を含む)
save_cascade_image_dir:顔を枠で囲った画像の保存先ディレクトリ
name:画像の保存ファイル名
facerectは検出された顔の位置座標と大きさを表しています。
[x座標, y座標, width, hight]
実行結果
print(facerect)
>> [[ 502 243 519 519]
[1522 377 519 519]]
print(facerect)
>> [[ 926 237 277 277]
[1250 244 442 442]
[ 486 306 215 215]
[1815 499 314 314]]
正面を向いているはっきりした画像だと、大人数でも顔が検出できました🎉
画像から顔の切り抜き
最後に、検出された顔を切り抜いて画像として保存します。
def face_cut(img_path, save_cut_image_dir, name):
# 画像を読み込む
img = cv2.imread(img_path)
# カスケード分類器を生成 -> 今回はアニメ画像の正面の顔を検出
cascade = cv2.CascadeClassifier('lbpcascade_animeface.xml')
# 保存先ディレクトリ作成
os.makedirs(save_cut_image_dir, exist_ok=True)
# 顔を検出する
facerect = cascade.detectMultiScale(img)
for i, (x,y,w,h) in enumerate(facerect):
# 一人ずつ顔を切り抜く(縦横10pxずつ大きめにカット)
face_image = img[y-10:y+h+10, x-10:x+w+10]
# サイズを(128×128)に統一 -> 機械学習で使いやすいように!
face_image = cv2.resize(face_image, (128, 128))
cv2.imwrite('{}/cut_image_{}.jpg'.format(save_cut_image_dir, name + '_' + str(i)),face_image)
SAVE_CASCADE_CUT_FOLDER = 'free_2/face_cut_image'
for i in range(5427):
face_cut('free_2/image_{}.jpg'.format(i), SAVE_CASCADE_FOLDER,SAVE_CASCADE_CUT_FOLDER, str(i))
img_path:読み込む画像のpath(ファイル名を含む)
save_cascade_image_dir:カットされた画像の保存先ディレクトリ
name:保存する画像名
良い感じに切り取れました♡
おわりに
今回は動画から画像を保存し、画像からキャラの顔を検出して画像として保存しました。
15分の動画から2,853枚の画像が取得できました✨(約1%は誤認識)
動画から切り抜くことで、キャラクターのいろいろな表情を集めることができて、とても楽しかったです😎
次は集めた画像でganや機械学習を使って、遊んでみようと思います。
参考文献
https://note.nkmk.me/python-opencv-video-to-still-image/
https://oku.edu.mie-u.ac.jp/~okumura/python/opencv.html
https://opencv.org/
https://weblabo.oscasierra.net/python/opencv-object-detection-tutorial-1.html
https://qiita.com/mczkzk/items/fda37ac4f9ddab2d7f45