顔画像認識アプリを作成するにあたって、つまずいたところをメモとして書き留めます。
スクレイピングで集めてきた画像から顔だけ切り取りをしたいけど、OpenCVだと正常に切り取れない!(耳だけ切り取られた画像が出力されたなど)ということがあったので、face_recognitionライブラリを使って顔だけ切り取りを行いました。
その際にエラーが発生し原因が分からず、悩んでしまったのでメモします。
(著作権に引っ掛かってしまいそうなので、画像の添付は省略させていただきます)
使用環境
- google colaboratory
- face-recognition-1.3.0
顔の特徴量が見つけられない場合、発生するエラー
例えば横向きの画像を以下のコードで切り取りを行おうとすると
#face_recognitionはpip install する必要あり
#!pip install face_recognition
import face_recognition
import cv2
#jimin.jpgは横向きの画像
img_cv2 = cv2.imread('jimin.jpg')
image = face_recognition.load_image_file('jimin.jpg')
face_locations = face_recognition.face_locations(image, model='cnn', number_of_times_to_upsample=2)
print(face_locations)
#顔の切り出しを行うために各変数に値を保持する
top = face_locations[0][0]
right = face_locations[0][1]
bottom = face_locations[0][2]
left = face_locations[0][3]
print('top:',top, 'right:',right, 'bottom:',bottom, 'left:',left)
#顔のトリミング
img_face = img_cv2[top:bottom, left:right]
#トリミングした画像を保存
cv2.imwrite('jimin_change.jpg',img_face)
以下のエラーが発生しました(横向きの画像なので顔の切り取りができないのは承知です)。
(実際に使用したデータは顔の輪郭がぼけていたりしていました)
[]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-9-a65f96f2cfc8> in <module>()
10
11 #顔の切り出しを行うために各変数に値を保持する
---> 12 top = face_locations[0][0]
13 right = face_locations[0][1]
14 bottom = face_locations[0][2]
IndexError: list index out of range
変数face_locations が [] と出力されました。
face recognitionライブラリの公式のサイトhttps://face-recognition.readthedocs.io/en/latest/face_recognition.html#face_recognition.api.face_locations
を見てみると、返り値はA list of tuples of found face locations in css (top, right, bottom, left) order
と記載がありました。
確かに配列が出力されています。
私がやりたかったのは、指定したディレクトリ内の複数の画像から顔の切り出しを行うことだったので、顔が認識されずにエラーになってしまうのは不都合でした。
(for文でディレクトリ内のファイルを読み込んで顔の切り取りを行いたかったので、途中でエラーが発生するとなかなか作業が進まない、、、)
顔の特徴量が見つけられない場合は、その画像をそのまま出力させてしまおう
とにかくエラーを回避するために以下のようにコードを修正しました。
#face_recognitionはpip install する必要あり
#!pip install face_recognition
import face_recognition
import cv2
#画像読み込み
img_cv2 = cv2.imread('jimin.jpg')
#画像のサイズ取得
width = img_cv2.shape[0]
height = img_cv2.shape[1]
image = face_recognition.load_image_file('jimin.jpg')
face_locations = face_recognition.face_locations(image, model='cnn', number_of_times_to_upsample=2)
print(face_locations)
#face_recognition.face_locations()で顔が認識されない場合、[]が返るので最初に読み込んだ画像をそのまま返す
if face_locations == []:
face_locations = [(0,width,height,0)]
#顔の切り出しを行うために各変数に値を保持する
top = face_locations[0][0]
right = face_locations[0][1]
bottom = face_locations[0][2]
left = face_locations[0][3]
print('top:',top, 'right:',right, 'bottom:',bottom, 'left:',left)#出力>>>top: 156 right: 722 bottom: 461 left: 418
#顔のトリミング
img_face = img_cv2[top:bottom, left:right]
cv2.imwrite('jimin_not_change.jpg',img_face)
以下、出力内容です。jimin_not_change.jpgというファイルが生成されました。
[]
top: 0 right: 600 bottom: 488 left: 0
True
顔の特徴量が見つからない場合は元の画像を出力させて、指定したディレクトリ内の画像すべてを上記のコードで処理したあと、顔の切り取りができなかった画像は手動で削除する方針で解決しました。
うまく切り出せない画像はそんなに多くなかったので手動でいけました。
他に良い方法があれば教えていただけると幸いです。