【YoucansのOpenCV学習講座】 23. 顔検出:Haarカスケード検出器

コラムアドレス:「youcans 画像処理学習講座」
記事ディレクトリ:「youcans 画像処理学習講座 総合カタログ」



4.ハールカスケード分類器

Haar 特徴に基づくカスケード分類器は、Paul Viola が論文「Rapid Object Detection using a Boosted Cascade of Simple Features」で提案したオブジェクト検出方法です。

Haar カスケード分類器は、AdaBoost アルゴリズムを使用して、ノードの各レベルで検出率が高く、拒否率が低い多層分類器を学習します。その特徴は次のとおりです。

  1. Haar のような入力特徴を使用して、四角形のイメージ領域の合計または差をしきい値処理します。

  2. 積分画像を使用して 45° 回転した領域のピクセル合計を計算し、Haar のような入力特徴の計算を高速化します。

  3. 統計ブースティングを使用して、バイナリ (顔/非顔) 分類子ノード (高い合格率、低い拒否率) を作成します。

  4. 弱分類器を並列に組み合わせて、スクリーニング カスケード分類器を形成します。

ここに画像の説明を挿入

すべてのレベルで分類器をブーストすると、人間の顔の検出ウィンドウを通過させると同時に、顔以外の検出ウィンドウのごく一部を拒否し、次の分類器に渡す検出ウィンドウを渡すことができます。類推すると、最後の分類器は顔以外の検出ウィンドウをほとんどすべて拒否し、人間の顔検出ウィンドウのみを残します。したがって、検出ウィンドウ領域がすべてのレベルの Boosting 分類器を通過する限り、検出ウィンドウに人間の顔があると見なされます。

実際のアプリケーションでは、入力画像のサイズが大きく、複数領域および複数スケールの検出が必要です。マルチリージョンは、画像のさまざまな位置を横断することであり、マルチスケールは、画像内のさまざまなサイズの顔を検出することです。

Haar カスケード分類顔検出器では、顔の構造的特徴が主に使用されます。

  • 目は頬より暗い
  • 目と比べて鼻筋が明るい
  • 目、口、鼻の位置が比較的固定されている

この 5 つの長方形の領域の明暗の関係によって、顔の各部分の識別特徴を形成することができます。たとえば、下の画像では、最初の特徴は目と頬上部の間の強度の違いを検出し、2 番目の特徴は目の間の距離を検出します。

ここに画像の説明を挿入

Haar は顔検出について高度なトレーニングを受けていますが、横顔ではうまく機能しません。


5. ハール顔/アイディテクター

5.1 OpenCV のカスケード分類子

カスケード分類子クラス cv::CascadeClassifier は OpenCV で定義されています。Python 言語では、インターフェース関数cv.CascadeClassifier()を使用して、ファイルから分類器を作成します。

cv.CascadeClassifier(filename)
cv.CascadeClassifier.load(filename[, ]) → retval
cv.CascadeClassifier.read(node[, ]) → retval
cv.CascadeClassifier.empty([, ]) → retval

cv.CascadeClassifier.convert(oldcascade, newcascade[, ]) → retval
cv.CascadeClassifier.detectMultiScale(image[, scaleFactor=1.1, minNeighbors=3, flags=0, minSize=Size(), maxSize=Size()]) → objects

メンバー関数 cv.CascadeClassifier.load() はファイルからカスケード分類器モデルをロードし、メンバー関数 cv.CascadeClassifier.read() は FileStorage ノードから分類器を読み取り、メンバー関数 cv.CascadeClassifier.empty() は分類子が正常にロードされました。

メンバー関数 cv.CascadeClassifier.detectMultiScale() は画像のターゲット検出を実行するために使用され、メンバー関数 cv.CascadeClassifier.convert() は


パラメータの説明:

  • filename: 読み込まれた分類子モデルのファイル パスと名前、文字列。
  • image: 検出される入力画像 (CV_8U 形式)。
  • scaleFactor: 検索ウィンドウの倍率。デフォルト値は 1.1 です。
  • minNeighbors: 検出対象を構成する隣接する長方形の最小数を示し、デフォルト値は 3 です。
  • flags: バージョン互換性フラグ。デフォルト値は 0 です。
  • minSize: 検出対象のタプル (h, w) の最小サイズ。
  • maxSize: 検出対象のタプル (h, w) の最大サイズ。
  • objects: 検出されたターゲットの長方形の境界ボックスである戻り値は、(N,4) のような形状の Numpy 配列です。

パラメータの説明:

(1) 戻り値オブジェクトは (N, 4) の形式の Numpy 配列で、各行には左上の頂点座標 (x, y) と幅、高さを表す 4 つの要素 (x、y、幅、高さ) があります。長方形のボックスの高さ。

(2) 読み込まれたカスケード分類モデル ファイルの拡張子は .xml です。


5.2 Haar カスケード検出器の学習済みモデル

OpenCV は、カスケード分類器のトレーニング メソッドを提供します。または、事前トレーニング済みのモデルを直接ダウンロードし、load() メソッドを使用してモデルをロードすることもできます。

OpenCV が提供する Haar カスケード検出器の事前トレーニング済みモデルは、OpenCV インストール パッケージの\data\haarcascadesフォルダー、 [GitHub] opencv/data at 4.xからダウンロードされます。

ここに画像の説明を挿入


OpenCV が提供する haar カスケード検出器の事前トレーニング済みモデルには、次のものがあります。

haarcascade_eye.xml, 眼睛
haarcascade_eye_tree_eyeglasses.xml, 戴眼镜的眼睛
haarcascade_frontalcatface.xml, 正面猫脸
haarcascade_frontalcatface_extended.xml, 正面猫脸
haarcascade_frontalface_alt.xml, 正面人脸
haarcascade_frontalface_alt2.xml, 正面人脸
haarcascade_frontalface_alt_tree.xml, 正面人脸
haarcascade_frontalface_default.xml, 正面人脸
haarcascade_fullbody.xml, 人体
haarcascade_lefteye_2splits.xml, 左眼
haarcascade_license_plate_rus_16stages.xml, 
haarcascade_lowerbody.xml, 
haarcascade_profileface.xml, 
haarcascade_righteye_2splits.xml, 右眼
haarcascade_russian_plate_number.xml, 
haarcascade_smile.xml, 笑脸
haarcascade_upperbody.xml, 上身

5.3 顔検出・瞳検出の実装手順

Haar カスケード検出器を使用して画像内の顔を検出する手順:

(1) CascadeClassifier カスケード分類子オブジェクトを作成し、load() メソッドを使用してカスケード分類子モデルを .xml ファイルから読み込みます。

(2) 検出する画像を読み取ります。

(3) detectMultiScale() メソッドを使用して画像を検出し、検出された顔または目の境界矩形を返します。

(4) 検出された外接矩形を検出画像上に描画します。


例 17_6: Haar カスケード検出器を使用して顔を検出する

Haar カスケード検出器を使用してイメージ内の顔を検出します。

import numpy as np
import cv2 as cv

if __name__ == '__main__':
    # (6) 使用 Haar 级联分类器 预训练模型 检测人脸
    # 读取待检测的图片
    img = cv.imread("../images/img_group_02.jpg", flags=1)
    print(img.shape)

    # 加载 Haar 级联分类器 预训练模型
    model_path = "../data/haarcascade_frontalface_alt2.xml"
    face_detector = cv.CascadeClassifier(model_path)  # <class 'cv2.CascadeClassifier'>
    # 使用级联分类器检测人脸
    faces = face_detector.detectMultiScale(img, scaleFactor=1.1, minNeighbors=1,
                                           minSize=(30, 30), maxSize=(300, 300))
    print(faces.shape)  # (17, 4)
    print(faces[0])  # (x, y, width, height)

    # 绘制人脸检测框
    for x, y, width, height in faces:
        cv.rectangle(img, (x, y), (x + width, y + height), (0, 0, 255), 2, cv.LINE_8, 0)
    # 显示图片
    cv.imshow("faces", img)
    cv.waitKey(0)
    cv.destroyAllWindows()

ここに画像の説明を挿入

Haar カスケード検出器は、より高い率で顔を検出できますが、特定の誤検出率があります。つまり、一部の検出結果は顔ではありません。


例 17_7: Haar Cascade Detector を使用して人間の目を検出する

人間の目の検出方法は、haarcascade_eye.xml などの別の事前トレーニング済みモデルが使用されることを除いて、顔検出の方法と同じです。

目は顔のサイズよりも小さいため、パラメーター minSize=(20, 20)、検出関数 detectMultiScale() の maxSize が減少します。

import numpy as np
import cv2 as cv

if __name__ == '__main__':
    # (7) 使用 Haar 级联分类器 预训练模型 检测人眼
    # 读取待检测的图片
    img = cv.imread("../images/img_group_01.jpg", flags=1)
    print(img.shape)

    # 加载 Haar 级联分类器 预训练模型
    model_path = "../data/haarcascade_eye.xml"
    eye_detector = cv.CascadeClassifier(model_path)  # <class 'cv2.CascadeClassifier'>
    # 使用级联分类器检测人脸
    eyes = eye_detector.detectMultiScale(img, scaleFactor=1.1, minNeighbors=1,
                                           minSize=(20, 20), maxSize=(100, 100))
    print(eyes.shape)  # (51, 4)
    print(eyes[0])  # (x, y, width, height)

    # 绘制人脸检测框
    for x, y, width, height in eyes:
        cv.rectangle(img, (x, y), (x + width, y + height), (0, 0, 255), 2, cv.LINE_8, 0)
    # 显示图片
    cv.imshow("Haar_Cascade", img)
    # cv.imwrite("../images/imgSave3.png", img)
    cv.waitKey(0)
    cv.destroyAllWindows()

ここに画像の説明を挿入


例 17_8: Haar カスケード検出器を使用して人間の顔と目を検出する

検出効率を向上させるために、最初に人間の顔を検出し、次に人間の窓で人間の目を検出できます。これにより、検出効率が向上するだけでなく、検出精度も向上します。

import numpy as np
import cv2 as cv

if __name__ == '__main__':
    # (8) 使用 Haar 级联分类器 预训练模型 检测人脸和人眼
    # 读取待检测的图片
    img = cv.imread("../images/img_group_01.jpg", flags=1)
    print(img.shape)

    # 加载 Haar 级联分类器 预训练模型
    face_path = "../data/haarcascade_frontalface_alt2.xml"  # 人脸检测器
    face_detector = cv.CascadeClassifier(face_path)  # <class 'cv2.CascadeClassifier'>
    eye_path = "../data/haarcascade_eye.xml"  # 人眼检测器
    eye_detector = cv.CascadeClassifier(eye_path)  # <class 'cv2.CascadeClassifier'>
    # 使用级联分类器检测人脸
    faces = face_detector.detectMultiScale(img, scaleFactor=1.1, minNeighbors=2,
                                           minSize=(30, 30), maxSize=(300, 300))
    print(faces.shape)  # (15, 4)

    # 绘制人脸检测框
    for x, y, width, height in faces:
        cv.rectangle(img, (x, y), (x + width, y + height), (0, 0, 255), 2, cv.LINE_8, 0)
        # 在人脸区域内检测人眼
        roi = img[y:y + height, x:x + width]  # 提取人脸
        # 检测人眼
        eyes = eye_detector.detectMultiScale(roi, scaleFactor=1.1, minNeighbors=1,
                                             minSize=(20, 20), maxSize=(80, 80))
        # 绘制人眼
        for ex, ey, ew, eh in eyes:
            cv.rectangle(img, (x+ex, y+ey), (x+ex+ew, y+ey+eh), (255, 0, 0), 2)

    # 显示图片
    cv.imshow("Haar_Cascade", img)
    # cv.imwrite("../images/imgSave4.png", img)
    cv.waitKey(0)
    cv.destroyAllWindows()

ここに画像の説明を挿入


例 17_9: ビデオの顔検出に Haar カスケード分類器を使用する

最初にカメラを起動するか、ビデオ ファイルを読み取り、ビデオ フレームを読み取ります。次に、ビデオ フレームがグレースケール イメージに変換され、カスケード カスケード検出器を使用して顔が検出されます。検出された顔には、長方形の枠が追加されます。

import numpy as np
import cv2 as cv

if __name__ == '__main__':
    # (9) 使用 Haar 级联分类器检测视频流
    # 加载 Haar 级联分类器 预训练模型
    face_path = "../data/haarcascade_frontalface_default.xml"  # 人脸检测器
    face_detector = cv.CascadeClassifier(face_path)  # <class 'cv2.CascadeClassifier'>

    # 创建视频读取/捕获对象
    vedioRead = "../images/Megamind.avi"  # 读取视频文件的路径
    videoCap = cv.VideoCapture(vedioRead)  # 实例化 VideoCapture 类

    frameNum = 0  # 视频帧数初值
    # ret, frame = videoCap.read()  # 读取一帧图像
    # print("frame: ", frame.shape)  # (528, 720, 3)
    timef = 40  # 设置抽帧间隔
    plt.figure(figsize=(9, 5.6))
    while videoCap.isOpened():  # 检查视频捕获是否成功
        ret, frame = videoCap.read()  # 读取一帧图像, (528, 720, 3)
        if ret is True:
            frameNum += 1  # 读取视频的帧数
            gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)  # 灰度处理
            # 使用级联分类器检测人脸
            faces = face_detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2,
                                                   minSize=(50, 50), maxSize=(300, 300))
            # 绘制人脸检测框
            for x, y, width, height in faces:
                cv.rectangle(frame, (x, y), (x + width, y + height), (0, 0, 255), 2, cv.LINE_8, 0)
            cv.imshow('frame', frame)  # 目标识别视频
            if (frameNum%timef==0 and 1<=frameNum//timef<= 6):  # 判断抽帧条件
                plt.subplot(2, 3, frameNum//timef), plt.axis('off')
                plt.title("{}. Face detector (f={})".format(frameNum//timef, frameNum))
                plt.imshow(cv.cvtColor(frame, cv.COLOR_BGR2RGB))
            if cv.waitKey(10)&0xFF == 27:  # 按 'Esc' 退出
                break
        else:
            print("Can't receive frame at frameNum {}.".format(frameNum))
            break

    print("frameNum: ", frameNum)
    # 释放资源
    videoCap.release()  # 关闭读取视频文件
    cv.destroyAllWindows()  # 关闭显示窗口
    plt.tight_layout()
    plt.show()

ここに画像の説明を挿入



著作権表示:

Youcans@xupt 元の作品、転載は元のリンクでマークする必要があります: (https://blog.csdn.net/youcans/article/details/130423104)
Copyright 2022 youcans, XUPT 「Youcans OpenCV ラーニング コース」
に注目してください。シリーズ、続々更新中

おすすめ

転載: blog.csdn.net/youcans/article/details/130423104