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

概要
OpenCV のカスケード分類器 CascadeClassifier を使用して、画像から顔や目を検出する方法について解説します。
カスケード分類器
カスケードは複数の分類器を繋げて行うアンサンブル学習の一種です。 画像が与えられたとき、まず特徴抽出器で画像から特徴量を抽出します。 その特徴量がカスケード分類器に与えられ、分類結果 (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
で正面の顔の検出を試してみます。
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)
cv2.imread()
で画像を読み込みます。
CascadeClassifier.detectMultiScale()
はグレースケール画像を要求するので、cv2.cvtColor()
でグレースケールに変換にします。
# 画像を読み込む。
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() で画像に描画します。
# 検出する。
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)
顔が検出できました。
!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
とそれより大きい値に設定しました。
# 目を検出するカスケード分類器を作成する。
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)

-
前の記事
OpenCV – 画像にモザイク処理を行う方法について 2020.04.07
-
次の記事
OpenCV – 背景差分で物体を検出する方法について 2020.05.20