はじめに
第4回の投稿となる今回は、特徴点抽出機能を作っていきたいと思います。なお、この記事は第3回:顔認証システムの実装①(顔検出機能)の続きとなっているので、そちらをまず見ることを推奨します。
今回のゴール
前回と同様に今回もゴールを決めていきたいと思います。今回は特徴点というものを理解するために、画像上の特徴点を出力するプログラムを作って実行することをゴールにしていきたいと思います。
特徴点について
特徴点とは
第一回で少し触れましたが、ここでは特徴点についてより深く解説していきたいと思います。
↓↓この画像を見てください。
まず我々人間の場合で考えてみます。 早速ですが、これは画像には何が写っていますか?当然可愛い猫ちゃんが写っていますね!! それではなぜこの画像に猫が写っているということがわかるのでしょうか?おそらくその手がかりはたくさんあると思いますが、
- 猫っぽい目
- 猫っぽい鼻
- 猫っぽい口
- 猫っぽい輪郭 だいたいここら辺でしょう。人間はこれらの要素を画像の中から入力として受け取り、結果的にこれが猫であるということを判断しています。ここで猫っぽいという言葉をあえて強調したのは、人間の場合、この画像に写っているのが猫であることを画像からのみではなく経験も踏まえて判断することができるからです。
続いてコンピュータの場合を考えていきます。当然ですがコンピュータは画像をデータとしてしか見ることはできません。例えば1280x960の大きさの画像があったなら、コンピュータはそれを1280x960の大きさの配列としてしか見ることはできません。
また、コンピュータは経験から予測することができません。当然画像の中に猫っぽい目や鼻や口や輪郭があってもそれを見つけることはできませんし、ましてや猫っぽさなどは理解不能です。ですのでコンピュータには指標となる手がかりが必要になります。そしてそれがコンピュータにおける特徴点となります。
特徴点を表示してみる
とりあえず「百聞は一見に如かず」なので、画像から特徴点抽出し表示する、というプログラムを組んでいきたいと思います。まず、前回と同様にFaceRecognitionプロジェクトの下にpythonのファイルを作りましょう!名前は何でも良いですが、ここでは分かりやすくkePoint.pyという名前にしておきます。
実装
import cv2 <200b> # 画像ファイルの読み込み img = cv2.imread("sample.jpg") <200b> # AKAZE特徴量を使った特徴点検出の準備 akaze = cv2.AKAZE_create() # 特徴検出 keypoints = akaze.detect(img) <200b> # 画像への特徴点の書き込み out = cv2.drawKeypoints(img, keypoints, None) # 書き込み cv2.imwrite('keypoints.png', out)
実装の解説
それでは実装の解説をしていきます。
import cv2 <200b> # 画像ファイルの読み込み img = cv2.imread("sample.jpg")
import cv2については前回でも紹介したので飛ばします。
img = cv2.imread(“sample.jpg”)ではcv2.imread()を使用して引数のパスから画像を読み込み、それをimgにら次元配列として入れています。今はsample.jpgを読み込んでいますが、ここのパスは適宜変えてください。
# AKAZE特徴量を使った特徴点検出の準備 akaze = cv2.AKAZE_create() # 特徴検出 keypoints = akaze.detect(img)
out = cv2.drawKeypoints(img, keypoints, None)では、keypointsで取得した特徴点の座標に強度ごとの色を加えてimgに合成し、その画像をoutに入れます。
cv2.imwrite(‘keypoints.png’, out)では、imwrite()によってoutに入っている画像を書き込みます。実行後、今いる作業ディレクトリの中にkeypoints.pngという画像ファイルが生成されているはずです!
実行結果
顔領域のみに絞った特徴点の出力
上記で画像全体の特徴点を出力しました! しかし、顔照合を行う際に必要なのは顔の特徴点ですので、ここから少し変更を加えて顔領域のみの特徴点を出力することにします。 画像から顔領域のみを抽出するプログラムは前回やったので、しっかり覚えていますよね??
実装
import cv2 <200b> # カスケード機生成 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') # 画像ファイルの読み込み img = cv2.imread("sample.jpg") <200b> # グレースケール変換 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 顔領域取得 faces = face_cascade.detectMultiScale(img_gray, minSize=(100, 100)) <200b> # AKAZE特徴量を使った特徴点検出の準備 akaze = cv2.AKAZE_create() # 特徴検出 keypoints = akaze.detect(img) <200b> # 顔領域の特徴点 face_keypoints = [] # 全ての特徴点から顔領域にある特徴点を抽出 for keypoint in keypoints: for x, y, w, h in faces: if x <= keypoint.pt[0] and keypoint.pt[0] <= (x + w) and y <= keypoint.pt[1] and keypoint.pt[1] <= (y + h): face_keypoints.append(keypoint) <200b> # 画像への特徴点の書き込み out = cv2.drawKeypoints(img, face_keypoints, None) # 表示 cv2.imwrite('keypoints.png', out)
実装の解説
それでは解説していきます。なお前章と被っている部分は省きます。
# カスケード機生成 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
- face_cascade = cv2.CascadeClassifi(‘haarcascade_frontalface_default.xml’)では前回と同様にカスケード機を生成しています。ここの詳しい説明は前回やったので、忘れてしまった方は前回のブログへゴー!
# グレースケール変換 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 顔領域取得 faces = face_cascade.detectMultiScale(img_gray, minSize=(100, 100))
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)では、imgをグレースケールへ変換しています。顔領域はグレースケールされた画像から行うので変換しているわけです。
faces = face_cascade.detectMultiScale(img_gray, minSize=(100, 100))では、グレースケールした画像から顔領域を取得しています。
# 顔領域の特徴点 face_keypoints = [] # 全ての特徴点から顔領域にある特徴点を抽出 for keypoint in keypoints: for x, y, w, h in faces: if x <= keypoint.pt[0] and keypoint.pt[0] <= (x + w) and y <= keypoint.pt[1] and keypoint.pt[1] <= (y + h): face_keypoints.append(keypoint)
face_keypoints = []では、顔領域のみの特徴点を入れておくための配列をあらかじめ作っときます。
そして26行目の多重ループの中で、全ての特徴点から顔領域のみに絞った特徴点を絞ります。1つ目のfor分の最初でkeypoints配列の中から1つずつ特徴点の座標を取ってきているのですが、その座標が顔領域の中にあるかどうかを判定し、中にあればface_keypoints配列の中に入れていくといった感じです。
実行結果
それでは実行していきましょう!
概ねしっかり取れていますね! 前回の実装からもわかる通り顔領域は四角い領域で表されるので、少しはみ出ている部分に関しては、その性質上顔領域として認識されてしまっているのが原因です。 ですのでそこはご愛嬌ということで、、、
最後に
お疲れ様でした!今回も最後までみてくれてありがとうございます!! 今回は特徴点について詳しくやってきましたが理解することはできたでしょうか?最終回となる次回では今回扱った特徴点を元に人の顔を比較し、個人を判別するプログラムを作っていくのでお楽しみに!