Warning: Undefined variable $position in /home/pystyles/pystyle.info/public_html/wp/wp-content/themes/lionblog/functions.php on line 4897

OpenCV – カスケード分類器 CascadeClassifier で画像から顔や目を検出する方法について

OpenCV – カスケード分類器 CascadeClassifier  で画像から顔や目を検出する方法について

概要

OpenCV のカスケード分類器 CascadeClassifier を使用して、画像から顔や目を検出する方法について解説します。

Advertisement

カスケード分類器

カスケードは複数の分類器を繋げて行うアンサンブル学習の一種です。 画像が与えられたとき、まず特徴抽出器で画像から特徴量を抽出します。 その特徴量がカスケード分類器に与えられ、分類結果 (positive または negative) が出力されます。

カスケード検出器

カスケード分類器は複数の分類器で構成されており、各分類器で positive または negative のどちらであるか判定が行われます。ある分類器で negative と判定された場合はその時点で棄却され、positive と判定された場合は、分類器の出力結果を次の分類器に渡します。

CascadeClassifier クラス

OpenCV では CascadeClassifier クラスでカスケード分類器が提供されています。

cv2.CascadeClassifier(filename)
  • 引数
    • filename: カスケード分類器の設定ファイル

xml ファイルの一覧

CascadeClassifier は、特徴量の種類やカスケード分類器を構成している分類器の情報が記載された設定ファイルを読み込んで作成します。 OpenCV では、顔や目を検出するための設定ァイルが用意されています。 これらの設定ファイルは cv2.data.haarcascades ディレクトリ以下にあるので、以下のようにするとよいでしょう。

cascade_path = os.path.join(
    cv2.data.haarcascades, "<ファイル名>"
)
cascade = cv2.CascadeClassifier(cascade_path)
ファイル名 内容 特徴量
haarcascade_eye.xml Haar-like
haarcascade_eye_tree_eyeglasses.xml メガネ Haar-like
haarcascade_frontalcatface.xml 猫の顔 (正面) Haar-like
haarcascade_frontalcatface_extended.xml 猫の顔 (正面) Haar-like
haarcascade_frontalface_alt.xml 顔 (正面) Haar-like
haarcascade_frontalface_alt2.xml 顔 (正面) Haar-like
haarcascade_frontalface_alt_tree.xml 顔 (正面) Haar-like
haarcascade_frontalface_default.xml 顔 (正面) Haar-like
haarcascade_fullbody.xml 全身 Haar-like
haarcascade_lefteye_2splits.xml 左目 Haar-like
haarcascade_licence_plate_rus_16stages.xml ロシアのナンバープレート Haar-like
haarcascade_lowerbody.xml 下半身 Haar-like
haarcascade_profileface.xml 顔 (正面) Haar-like
haarcascade_righteye_2splits.xml 右目 Haar-like
haarcascade_russian_plate_number.xml ロシアのナンバープレート Haar-like
haarcascade_smile.xml 顔 (笑顔) Haar-like
haarcascade_upperbody.xml 上半身 Haar-like

顔を検出する

今回は、haarcascade_frontalface_default.xml で正面の顔の検出を試してみます。

In [1]:
import os

import cv2
from IPython.display import Image, display


def imshow(img):
    """ndarray 配列をインラインで Notebook 上に表示する。
    """
    ret, encoded = cv2.imencode(".jpg", img)
    display(Image(encoded))


# 正面の顔を検出するカスケード分類器を作成する。
cascade_path = os.path.join(
    cv2.data.haarcascades, "haarcascade_frontalface_default.xml"
)
face_cascade = cv2.CascadeClassifier(cascade_path)

sample.jpg

cv2.imread() で画像を読み込みます。
CascadeClassifier.detectMultiScale() はグレースケール画像を要求するので、cv2.cvtColor() でグレースケールに変換にします。

In [2]:
# 画像を読み込む。
img = cv2.imread("sample.jpg")

# グレースケールに変換する。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

CascadeClassifier.detectMultiScale() で画像から対象物の検出を行います。

objects = CascadeClassifier.detectMultiScale(image[, scaleFactor[, minNeighbors[, flags[, minSize[, maxSize]]]]])
  • 引数
    • image: グレースケール画像
    • scaleFactor: 検索窓の拡大率 (1.0 より大きい値で指定、デフォルトは 1.1)
    • minNeighbors: 近傍にこの値以上の検出矩形がない場合は、棄却する。値を大きくするほど、誤検出は減るが、未検出が増える可能性がある。(自然数で指定、デフォルトは3)
    • flags: 使用しない。
    • minSize: 検出矩形の最小サイズ
    • maxSize: 検出矩形の最大サイズ
  • 返り値
    • 検出矩形の一覧。各要素が (左上の x 座標、左上の y 座標、幅、高さ) のタプルで表されるリスト。

CascadeClassifier.detectMultiScale() で検出して、検出矩形の一覧を cv2.rectangle() で画像に描画します。

In [3]:
# 検出する。
faces = face_cascade.detectMultiScale(gray)

# 矩形を画像に描画する。
for x, y, w, h in faces:
    cv2.rectangle(img, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)
imshow(img)
errorTraceback (most recent call last) <ipython-input-4-ef93eed4807b> in <module> 1 # 検出する。 —-> 2 faces = face_cascade.detectMultiScale(gray) 3 4 # 矩形を画像に描画する。 5 for x, y, w, h in faces: error: OpenCV(4.2.0) /io/opencv/modules/objdetect/src/cascadedetect.cpp:1689: error: (-215:Assertion failed) !empty() in function ‘detectMultiScale’

顔が検出できました。

Advertisement

!empty() in function 'detectMultiScale というエラーが発生する場合

以下のエラーが発生した場合は cv2.CascadeClassifier() に指定した xml ファイルが間違っています。名前が合っているかどうか確認してください。

error: OpenCV(4.2.0) /io/opencv/modules/objdetect/src/cascadedetect.cpp:1689: error: (-215:Assertion failed) !empty() in function 'detectMultiScale'

目を検出する

haarcascade_eye.xml を使って、顔の領域にある目の検出も試してみます。 顔を検出するカスケード分類器で検出した各顔の領域を切り抜き、その領域に対して目の検出を行います。 デフォルトの minNeighbors=3 では誤検出が発生したので、minNeighbors=5 とそれより大きい値に設定しました。

In [4]:
# 目を検出するカスケード分類器を作成する。
cascade_path = os.path.join(cv2.data.haarcascades, "haarcascade_eye.xml")
eye_cascade = cv2.CascadeClassifier(cascade_path)

for x, y, w, h in faces:
    # 顔の領域を切り取る。
    roi = gray[y : y + h, x : x + w]

    # 目を検出する。
    eyes = eye_cascade.detectMultiScale(roi, minNeighbors=5)

    # 矩形を画像に描画する。
    for ex, ey, ew, eh in eyes:
        cv2.rectangle(
            img,
            (x + ex, y + ey),
            (x + ex + ew, y + ey + eh),
            color=(255, 0, 0),
            thickness=2,
        )


imshow(img)