どこにでもいる30代SEの学習ブログ

主にプログラミング関連の学習内容。読んだ本の感想や株式投資についても書いてます。

【Python】dlibで顔検出(CNN版)

前回紹介した「dlib」の顔検出のうち、CNN版で顔検出を行いました。

前回、dlibで顔検出を行いOpenCVよりも精度は向上しました。しかしながら、横顔の検出などには課題が残りました。

https://predora005.hatenablog.com/entry/2021/08/30/190000predora005.hatenablog.com

CNN版を使用した結果を先に言うと、処理時間が長くなるものの精度は向上しました。

f:id:predora005:20210809085754j:plain

[1] 事前準備

[1-1] dlibのインストール

前回紹介した内容と同様です。

https://predora005.hatenablog.com/entry/2021/08/30/190000https://predora005.hatenablog.com/entry/2021/08/30/190000

[1-2] 顔検出器のダウンロード

学習済みのモデルをダウンロードし、解凍します。

curl -O http://dlib.net/files/mmod_human_face_detector.dat.bz2
bzip2 -d mmod_human_face_detector.dat.bz2

[2] ソースコード

公式のExampleを元に作成しています。

dlib/cnn_face_detector.py at master · davisking/dlib · GitHub

顔検出だけであれば「dlib」のみインポートで十分ですが、検出領域の表示等で「OpenCV」を使用しています。

mport os
import cv2
import dlib

# 顔検出器を取得
detector_file = 'mmod_human_face_detector.dat'
detector_path = os.path.join(os.path.expanduser('~'), detector_file)
cnn_face_detector = dlib.cnn_face_detection_model_v1(detector_path)

# 読み込むファイルのリスト
filelist = [ 'sample1.jpg',  'sample2.jpg', 'sample3.jpg']

for file in filelist:
    print("------------------------------")
    print("Processing file: {}".format(file))
    
    # 画像を読み込み
    imgdir = os.path.join(os.path.expanduser('~'), 'img')
    imgpath = os.path.join(imgdir, file)
    img = dlib.load_rgb_image(imgpath)
    
    # 顔検出を実行
    dets = cnn_face_detector(img, 1)
    
    # 検出した領域を出力
    print("Number of faces detected: {}".format(len(dets)))
    for i, d in enumerate(dets):
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {} Confidence: {}".format(
            i, d.rect.left(), d.rect.top(), d.rect.right(), d.rect.bottom(), d.confidence))

    # 保存用の画像データを準備
    save_img = cv2.imread(imgpath)
    
    # 検出した範囲を保存用画像に短形表示
    for d in dets:
        x1, y1, x2, y2 = d.rect.left(), d.rect.top(), d.rect.right(), d.rect.bottom()
        cv2.rectangle(save_img, (x1, y1), (x2, y2), color=(0,0,255), thickness=4)
    
    # 検出領域を示した画像を保存
    save_file = 'dlib_cnn_' + file
    save_imgpath = os.path.join(imgdir, save_file)
    cv2.imwrite(save_imgpath, save_img)

[3] 顔検出の結果

以前に紹介したOpenCVと同じ画像で、顔検出を行いました。

https://predora005.hatenablog.com/entry/2021/08/23/190000predora005.hatenablog.com

[3-1] OpenCVでも上手くいった例

f:id:predora005:20210809091043j:plain <ゆうせい モデルの紹介 - ぱくたそ>

OpenCVと同様に、上手く検出できています。

[3-2] OpenCVでは微妙だった例

f:id:predora005:20210809091058j:plain <Werner HeiberによるPixabayからの画像>

CNN版では6人中5人まで検出できています。OpenCVでは6人中3人の検出、dlibでは6人中4人の検出でした。

[3-3] OpenCV, dlibでは上手くいかなかった例

f:id:predora005:20210809085754j:plain <Sanu A SによるPixabayからの画像>

OpenCV, dlibともに1人しか検出できていませんでしたが、CNN版では4人まで検出できています。

[4] 補足とトラブルシューティング

[4-1] Memory Error

t3.medium(メモリ 4GiB)では足りませんでした。r5.large(メモリ 16GiB)では足りました。

MemoryError: std::bad_alloc

終わりに

CNN版を用いることで、精度が大きく向上しました。

一方、精度が向上したトレードオフとして、処理時間が長くなり、メモリ使用量が増大しました。

マシンスペックがそれなりに無いと動きません。小スペックの場合にはCNNではない、顔検出器を用いるのが良さそうです。

参考文献

画像の出典