【TensorFlow】CNNで顔検出やってみた
目標
今回の目標は画像から顔を検出してバウンディングボックスを描画することです。 気軽にお試ししたいので今回は学習済みモデルを使用します。
実行環境
tensorflow==1.14.0
手順
リポジトリのclone
$ git clone https://github.com/davidsandberg/facenet
facenet/src/以下に以下の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()を修正する
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を動かして顔検出のお試ししてみました。
思ったより精度高そうでだいぶ使えそうです。
色々応用できそうですね!