OpenCVを使って、画像から顔を認識してみます。
環境設定
グラフィックスを扱えるPython環境が必要なので Jupyter Notebook を使います。Tensorflow用の環境を作る方法について解説した別記事がありますので参照してください。どちらの説明にもTensorflowをインストールする手順が含まれていますが、この記事ではOpenCVを主に使いますのでTensorflowは不要です。ただし、実験用の仮想環境を作って(名前は何でも良い)opencv と、よく使う PIL、matplotlib、pandas、numpy ぐらいはインストールしておきましょう。
作った仮想環境で Jupyter Notebook を動作させる方法は Tensorflowで機械学習 の記事に書いてありますので参照してください。
準備
まず、テストに使う画像データを準備してください。顔の大きさや背景、写り具合などが認識に影響しますので最初ははっきりした画像が良いです。
OpenCVにはカスケード分類器というものが標準添付されているのですが、仮想環境にOpenCVをインストールした場合にはそのファイルがパソコンのどこにあるのかわかりにくいと思います。GitHubにファイルがありますので改めてダウンロードしてわかりやすいところに置いておきましょう。
https://github.com/opencv/opencv
→ data
→ haarcascades
ここに haarcascade_〜.xml というファイルがあり、これが判別する対象物の画像の特徴を学習した「カスケード分類器」です。例えば haarcascade_frontalface_default.xml は正面の顔の画像を学習したものです。同じ顔でも条件によっていくつかファイルがあります。猫の顔etc.もあります。
別のGitHubリポジトリで公開されているカスケード分類器もあります。標準では提供されていない、鼻や口を検出したければそちらからファイルをダウンロードしてください。
https://github.com/opencv/opencv_contrib
→ cascades
実装
Jupyter Notebookを起動します。ブラウザが開きますので適当な作業フォルダに移動します。
右上の「新規」または「New」のプルダウンリストから「Python3 (ipykernel)」または「Python3」を選択すると Jupyter Notebook の編集画面になるので次のソースコードを入力してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import cv2 from PIL import Image import matplotlib.pyplot as plt import numpy as np cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml") # 顔の検出器 #cascade = cv2.CascadeClassifier("haarcascade_mcs_mouth.xml") # 口の検出器 img = cv2.imread("test.jpg") # 画像データファイル gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケールに変換 rects = cascade.detectMultiScale(gray, 1.3, 5) # 検出の実行 for (x,y,w,h) in rects: print(x,y,w,h) img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),5) # 青色で枠を描く cv2.imwrite("result.jpg", img) # 画像の保存 # 画像の表示 img = Image.open("result.jpg") a = np.array(img) plt.imshow(a) |
変数 cascade の初期化時にカスケード分類機のファイル名を指定しています。エラーが起きるようならパスも含めてファイル名を書いてください。その下のデータファイル名も同様です。実行結果はresult.jpgというファイルに保存されます。
口のカスケード分類器 haarcascade_mcs_mouth.xml を使ってみました。
木村拓哉さんと鈴木京香さんはこうなります。女性の方がよく認識できるのは口元がはっきりしているせいか、それともお化粧のせいでしょうか? detectMultiScale() にはいくつかオプションがあり、対象物の大きさ minSize 等を設定することで精度を上げることができます。あるいは、まず顔を認識してから、その範囲で口や鼻を認識すればより正確な認識ができる可能性があります。
動画・カメラから顔認識
カメラからの動画に対して同じ処理を実行してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import cv2 from PIL import Image import matplotlib.pyplot as plt import numpy as np # VideoCapture オブジェクトを取得 capture = cv2.VideoCapture(0) cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml") # 顔の検出器 while(True): # 'q' が押されたら終了 if cv2.waitKey(1) & 0xFF == ord('q'): break # 1フレームを読み込む ret, img = capture.read() gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケールに変換 rects = cascade.detectMultiScale(gray, 1.3, 5) # 検出の実行 for (x,y,w,h) in rects: print(x,y,w,h) img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),5) # 青色で枠を描く # 画像の表示 cv2.imshow('frame',img) capture.release() cv2.destroyAllWindows() |
cv2.VideoCapture() の引数に mp4 等の動画ファイル名を渡してやると動画から認識してくれます。
コメント