やること
これを
こう
環境
MacOS Catalina 10.15.4
Python 3.7.6
face_recognitionとは?
学習済みモデルをつかい、顔検出などいくつかの画像処理を行えるライブラリ。
dlibが使われているとのこと。
https://github.com/ageitgey/
リポジトリ
face_recognitionをつかったコードです。
https://github.com/komiyakomiyakomiya/face_trim
terminal
$ git https://github.com/komiyakomiyakomiya/face_trim.git
ライブラリ
opencv-python==4.2.0.34
face-recognition==1.3.0
インストール
terminal
$ pip install opencv-python==4.2.0.34 face-recognition==1.3.0
コード
face_trim.py
import os
from pathlib import Path
import subprocess
import sys
import cv2
import face_recognition
from IPython.display import display
from IPython.display import Image
cwd = Path().resolve()
def exec_cmd(cmd):
""" コマンド実行 """
# cmd文字列の前後にスペースが入っていたら削除 -> スペースで分割しlist化
cmd_split = cmd.strip().split()
# stdoutの設定で標準出力を取得
cp = subprocess.run(cmd_split, stdout=subprocess.PIPE)
# cp = subprocess.check_output(cmd_split)
if cp.returncode != 0:
print(f'{cmd_split[0]} faild.', file=sys.stderr)
sys.exit(1)
# 標準出力があれば返す
if cp.stdout is not None:
# bytes -> strへデコード
return cp.stdout.decode('utf-8')
def get_face_location(img_path):
""" 顔の座標を取得 """
img = face_recognition.load_image_file(img_path)
# location = face_recognition.face_locations(img, model='cnn')
location = face_recognition.face_locations(img, model='hog')
print(location)
# [(82, 175, 180, 76)]
top = location[0][0]
right = location[0][1]
bottom = location[0][2]
left = location[0][3]
return top, right, bottom, left
def get_face_location_cli(img_path):
""" CLIツールのface_detectionを実行し顔の座標を取得
load_image_file()メソッドがバグで使えない場合こっちを利用 """
# 顔を検出し、Top, Right, Bottom, Leftの座標を標準出力するコマンド
cmd_face_detection = f'face_detection {img_path}'
# cmd_face_detection = f'face_detection --model cnn {img_path}'
# 標準出力を受け取る
stdout = exec_cmd(cmd_face_detection)
print(stdout)
# /Users/USER_NAME/path/to/dir/input/Zinedine_Zidane_0001.jpg,89,181,192,77
# カンマ区切りでリスト化
stdout_list = stdout.strip().split(',')
top = int(stdout_list[1])
right = int(stdout_list[2])
bottom = int(stdout_list[3])
left = int(stdout_list[4])
return top, right, bottom, left
def display_image(img_path):
""" 画像を表示 """
# 画像の読み込み
img = cv2.imread(img_path)
# 拡張子を取得
format = os.path.splitext(img_path)[1]
# 渡した拡張子(format)の形式にエンコード
decoded_bytes = cv2.imencode(format, img)[1].tobytes()
print(cv2.imencode(format, img)[1])
# [[255]
# [216]
# [255]
# ...
# [103]
# [255]
# [217]]
# print(decoded_bytes)
# b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x0......
display(Image(data=decoded_bytes))
if __name__ == '__main__':
# お好きな画像に置き換えて下さい
file_name = f'Zinedine_Zidane_0001.jpg'
# 元画像の置き場所
input_path = f'{cwd}/../input'
# トリミング画像の出力先
output_path = f'{cwd}/../output'
# 出力先ディレクトリがなければ作成
os.makedirs(output_path, exist_ok=True)
# 顔座標を取得
top, right, bottom, left = get_face_location(f'{input_path}/{file_name}')
# 元ファイルの読み込み
img = cv2.imread(f'{input_path}/{file_name}')
# 表示
display_image(f'{input_path}/{file_name}')
# トリミング
img_face = img[top:bottom, left:right]
# outputディレクトリに保存
cv2.imwrite(f'{output_path}/{file_name}', img_face)
# 表示
display_image(f'{output_path}/{file_name}')
ディレクトリ内の画像まとめてトリミング
if __name__ == '__main__':
# 元画像の置き場所
input_path = f'{cwd}/../input'
# トリミング画像の出力先
output_path = f'{cwd}/../output'
# 出力先ディレクトリがなければ作成
os.makedirs(output_path, exist_ok=True)
# パスオブジェクトを生成
path_obj = Path(input_path)
# globでパターンマッチング
files_path = path_obj.glob('*')
# posix変換
files_path_posix = [file_path.as_posix() for file_path in files_path]
print(files_path_posix)
for file_path in files_path_posix:
# ファイル名取得
file_name = file_path.split('/')[-1]
# 顔座標を取得
top, right, bottom, left = get_face_location(file_path)
# 元ファイルの読み込み
img = cv2.imread(file_path)
# 表示
display_image(file_path)
# トリミング
img_face = img[top:bottom, left:right]
# outputディレクトリに保存
cv2.imwrite(f'{output_path}/{file_name}', img_face)
# 表示
display_image(f'{output_path}/{file_name}')
エラー
こんなエラーが出ることがありました。
AttributeError: module 'face_recognition' has no attribute 'load_image_file'
イシューも立っていたのですが、ここで書かれていることを試しても解決せず。
https://github.com/ageitgey/face_recognition/issues/318
あきらめてCLIツールの標準出力から顔座標を取得するという強引なやり方を試していたら、いつの間にかなおってました...。
トリミング画像をクラスタリング
こちらに記事を書きました。
もしよろしければ
おしまい
最後まで読んでいただきありがとうございました!
ジダンに意味はありません。
たまたま、そばにいたので。