視線の検出をするには画像の中から目の位置を判定する必要があります. dlibを使って顔や顔器官の検出をすることができます. 今回はdlibのインストール,静止画の顔・顔器官検出,リアルタイムな顔・顔器官検出の方法について紹介します.
dlibのインストール方法に関してですが,少し複雑です. Git, CMake, Build Tools for Visual Studio 2022が必要になります. また,NVIDIAのGPUを使用したい場合は,NVIDIA ドライバ,NVIDIA CUDA ツールキット,NVIDIA cuDNNが追加で必要になります.(GPUが無くても動きます) 金子邦彦研究室のDlib,face_recognition のインストールと動作確認(顔検出,顔識別)(Python を使用)(Windows 上)で非常に分かりやすく解説されていますので詳しいインストール方法はこちらをご覧ください. 手元のWindows10, Python 3.9.7, Build Tools for Visual Studio 2022, NVIDIA CUDA ツールキット 11.8,NVIDIA cuDNN v8.6, NVIDIA GeForce RTX 2080で動作を確認しています. インストールの手順と参考になる金子邦彦研究室のリンクを載せておきます. 上から順に済ませていくと右往左往せずに済むと思います.
インストールが正常に終了したらコマンドプロンプトで下記のコードを走らせることで,ページ冒頭のような画像が表示されると思います.
cd C:\dlib
cd python_examples
python cnn_face_detector.py mmod_human_face_detector.dat ..\examples\faces\2007_007763.jpg
静止画についての dlib/python_exampleに入っている cnn_face_detector.py や face_detector.pyで行うことができます.
具体的には下記のようなコードです.
画像はフリー素材を使っています.
使用した画像はこちら.
frontal_face_detectorでは検出漏れがありますが,5人は検出できています.
import sys
import dlib
# detectorオブジェクトの作成
detector = dlib.get_frontal_face_detector()
# 表示用のウィンドウ
win = dlib.image_window()
# 画像の読み込み
filepath = "23337291_s.jpg"
img = dlib.load_rgb_image(filepath)
# 画像を検出器(detector)にかけて顔を検出します
dets = detector(img, 1)
print("Number of faces detected: {}".format(len(dets)))
for i, d in enumerate(dets):
print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
i, d.left(), d.top(), d.right(), d.bottom()))
# 画像に検出した顔の位置を重ね合わせて表示する
win.clear_overlay()
win.set_image(img)
win.add_overlay(dets)
また,predictorを使うことで顔器官を検出することができます.
顔の輪郭,鼻,口,目の位置を推測することができます.
推測した顔器官の位置に赤い点を打ち込んでいます.
import sys
import dlib
# detectorオブジェクトの作成
detector = dlib.get_frontal_face_detector()
# predictorオブジェクトの作成
PREDICTOR_PATH = r"C:\dlib\python_examples\shape_predictor_68_face_landmarks.dat"
predictor = dlib.shape_predictor(PREDICTOR_PATH)
# 表示用のウィンドウ
win = dlib.image_window()
# 画像の読み込み
filepath = "23337291_s.jpg"
img = dlib.load_rgb_image(filepath)
# 画像を検出器(detector)にかけて顔を検出します
dets = detector(img, 1)
print("Number of faces detected: {}".format(len(dets)))
for i, d in enumerate(dets):
print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
i, d.left(), d.top(), d.right(), d.bottom()))
# 画像に検出した顔の位置を重ね合わせて表示する
win.clear_overlay()
win.set_image(img)
win.add_overlay(dets)
for i in range(len(dets)):
parts = predictor(img, dets[i]).parts()
for point in parts:
win.add_overlay_circle(point, 1)
静止画について顔の検出および顔器官の検出をすることができたので,これをウェブカメラで撮影されたリアルタイムな映像に対しても行ってみます. 静止画に対して行った処理を1フレームごとに行っています. show_image(frame*0, parts)で背景を黒く塗りつぶしていますが,show_image(frame, parts)に変えることでカメラから受け取った映像の上に点をプロットできます.
import dlib
import cv2
import numpy as np
detector = dlib.get_frontal_face_detector()
PREDICTOR_PATH = r"C:\dlib\python_examples\shape_predictor_68_face_landmarks.dat"
predictor = dlib.shape_predictor(PREDICTOR_PATH)
def show_image(img, parts):
for i in parts:
cv2.circle(img, (i.x, i.y), 3, (255, 0, 0), -1)
cv2.imshow("dlib realtime", img)
cap = cv2.VideoCapture(0)
while True:
# カメラ映像の受け取り
ret, frame = cap.read()
# detetorによる顔の位置の推測
dets = detector(frame[:, :, ::-1])
if len(dets) > 0:
# predictorによる顔のパーツの推測
parts = predictor(frame, dets[0]).parts()
# 映像の描画
show_image(frame*0, parts) # *0 を取り除くことでそのままの映像が表示されます
# エスケープキーを押して終了します
if cv2.waitKey(1) == 27:
break
cap.release()
cv2.destroyAllWindows()
リアルタイム映像から顔器官の位置を推測することができました. 次回はリアルタイム映像から視線の向きを検出します.