🕌
CNNで顔検出やってみた
目標
今回の目標は画像から顔を検出してバウンディングボックスを描画することです。
気軽にお試ししたいので今回は学習済みモデルを使用します。
実行環境
tensorflow==1.14.0
手順
リポジトリのclone
$ git clone https://github.com/davidsandberg/facenet
facenet/src/以下に以下のface_detection.pyを配置する
face_detection.py
import align.detect_face
import tensorflow as tf
import numpy as np
import glob
import os
def face_detection(path, margin):
minsize = 20 # minimum size of face
threshold = [ 0.5, 0.6, 0.6 ] # three steps's threshold
factor = 0.709 # scale factor
gpu_memory_fraction = 1.0
print('Creating networks and loading parameters')
with tf.Graph().as_default():
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_memory_fraction)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))
with sess.as_default():
pnet, rnet, onet = align.detect_face.create_mtcnn(sess, None)
# read image
original_img = Image.open(path)
# image width & height
width, height = original_img.size
# pillow -> numpy
img = np.array(original_img, np.float32)
# inference
results, _ = align.detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor)
if len(results) < 1:
print("can't detect face")
else:
for result in results:
print(result)
x1, y1, x2, y2, score = result
x1 = np.maximum(x1-margin/2, 0)
y1 = np.maximum(y1-margin/2, 0)
x2 = np.minimum(x2+margin/2, width)
y2 = np.minimum(y2+margin/2, height)
# draw bounding box
img = ImageDraw.Draw(original_img)
img.rectangle((x1, y1, x2, y2), outline=(0,255,0), width=3)
return original_img
if __name__ == '__main__':
img_path = '../data/images/test.jpg'
output_path = './result.png'
margin = 0
detect_img = face_detection(
path=img_path,
margin=margin
)
detect_img.save(output_path)
face_detection.pyのimg_pathに入力画像のパス、output_pathに出力画像のパスを指定する
facenet/src/でface_detection.pyを実行する
$ python face_detection.py
入力画像
出力画像
つまずいたところ(エラー)
ValueError: Object arrays cannot be loaded when allow_pickle=False
numpy==1.16.3 より、numpy.load()関数の挙動が変更されたらしく、デフォルトでnumpy.load()の引数allow_pickleがFalseになっているのが原因らしい
解決法
facenet/src/align/detect_face.pyのload()関数内のnp.load()を修正する
detect_face.py
def load(self, data_path, session, ignore_missing=False):
"""Load network weights.
data_path: The path to the numpy-serialized network weights
session: The current TensorFlow session
ignore_missing: If true, serialized weights for missing layers are ignored.
"""
data_dict = np.load(data_path, encoding='latin1', allow_pickle=True).item() #ここを修正
for op_name in data_dict:
with tf.variable_scope(op_name, reuse=True):
for param_name, data in iteritems(data_dict[op_name]):
try:
var = tf.get_variable(param_name)
session.run(var.assign(data))
except ValueError:
if not ignore_missing:
raise
まとめ
学習済みのマルチタスクCNNを動かして顔検出のお試ししてみました。
思ったより精度高そうでだいぶ使えそうです。
色々応用できそうですね!
Discussion