(101) OpenCV #6 : 写真から顔を自動検出

投稿者: | 2018年9月18日

6,115 views

この記事は最終更新から 1646日 が経過しています。

1. やりたいこと

Pythonで OpenCVの第 6回目、今回は OpenCVの Haar Cascades を使って写真から顔検出して遊んでみる。

敢えて「遊んでみる」と書いたのは、原理的な所を学習せずに顔検出機能を使ってみるだけだから…

2. 前準備

(1) 顔の写った写真を用意する。

顔検出に使った写真をこのブログに掲載するので、以下の条件を満たしている必要がある。
・自分や知り合いの顔が写っている写真はダメだ。
・ライセンス上の問題が発生する写真はダメだ。

ということで CC0ライセンス画像を使うことにする。
pixabay

(2) OpenCVで使用する学習済みデータを入手する。

こちらから入手する。
https://github.com/opencv/opencv

この中から以下の2ファイルを使用する。
・opencv/data/haarcascades/haarcascade_eye.xml
・opencv/data/haarcascades/haarcascade_frontalface_default.xml

3. やってみる

基本的にはこちらのチュートリアルのまんま書いて遊んでみる。
Face Detection using Haar Cascades

(1) まずは顔だけを抽出してみる。

import numpy as np
import cv2 as cv

# 顔検出対象の画像をロードし、白黒画像にしておく。
imgS = cv.imread('face.png')
imgG = cv.cvtColor(imgS, cv.COLOR_BGR2GRAY)

# 学習済みデータをロード
face_cascade = cv.CascadeClassifier('haarcascade_frontalface_default.xml')

# 顔検出を実行
faces = face_cascade.detectMultiScale(imgG, 1.3, 5)

# 顔検出箇所を矩形で囲む。
for (x,y,w,h) in faces:
    cv.rectangle(imgS,(x,y),(x+w,y+h),(0,255,255),2)

# 表示
cv.imshow('image',imgS)
cv.waitKey(0)

# 表示消去
cv.destroyAllWindows()

斜め後ろから見ている人を除き 5人を検出できた。

(2) 次に顔の中から目を検出してみる。

import numpy as np
import cv2 as cv

# 顔検出対象の画像をロードし、白黒画像にしておく。
imgS = cv.imread('face.png')
imgG = cv.cvtColor(imgS, cv.COLOR_BGR2GRAY)

# 学習済みデータをロード
face_cascade = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade  = cv.CascadeClassifier('haarcascade_eye.xml')

# 顔検出を実行
faces = face_cascade.detectMultiScale(imgG, 1.3, 5)

# 顔検出箇所を矩形で囲む。
for (x,y,w,h) in faces:
    cv.rectangle(imgS,(x,y),(x+w,y+h),(0,255,255),4)
    # 目を検出
    imgG_face = imgG[y:y+h, x:x+w]
    imgC_face = imgS[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(imgG_face)
    for (ex,ey,ew,eh) in eyes:
        cv.rectangle(imgC_face,(ex,ey),(ex+ew,ey+eh),(0,128,255),4)

# 表示
cv.imshow('image',imgS)
cv.waitKey(0)

# 表示消去
cv.destroyAllWindows()

口を誤検出しているが概ね良好な結果かも。

4. おまけ

(1) 検出パラメーターを変更してみる。

(scaleFactor, minNeighbors) = (1.1, 3)

(scaleFactor, minNeighbors) = (1.1, 5)

(scaleFactor, minNeighbors) = (1.3, 3)

(scaleFactor, minNeighbors) = (1.3, 5)

(scaleFactor, minNeighbors) = (2.0, 3)

(scaleFactor, minNeighbors) = (2.0, 5)

(2) 検出した顔をファイル保存する。

検出した顔をくり抜いて PNGファイルに保存してみる。

import numpy as np
import cv2 as cv
import os, shutil

imgS = cv.imread('face2.jpg')
imgG = cv.cvtColor(imgS, cv.COLOR_BGR2GRAY)

face_cascade = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(imgG, 1.1, 3)

img_out_path = './out'
if os.path.exists(img_out_path):
    shutil.rmtree(img_out_path)
os.mkdir(img_out_path)

i = 1
for (x,y,w,h) in faces:
    cv.rectangle(imgS,(x,y),(x+w,y+h),(0,255,255),4)
    imgC_face = imgS[y:y+h, x:x+w]
    fpath = img_out_path + '/face_%05d.png' % i
    cv.imwrite(fpath, imgC_face)
    i = i + 1

こんな感じで切り抜けた。
当然だが誤検出した物も PNGファイル出力されている。

人間であれば「これ顔じゃないだろ」ってすぐに判別できる物でも、機械は顔と認識してしまう。
スピードと精度のトレードオフだ。
商用の顔認識モジュールの精度がどれほどのものなのか気になるなぁ…

5. 所感

いつかちゃんとアルゴリズムを学習しよう。
特徴点を抽出し、マッチングし、なのだとは思うが。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です