超詳細註釋之OpenCV Haar級聯檢測器進行面部檢測

這篇博客將介紹如何使用預訓練好的OpenCV Haar級聯人臉、眼睛、嘴部檢測器,並將它們應用於圖片及實時視頻流的檢測。

人臉檢測結果是最穩定和準確的。不幸的是,在許多情況下,眼睛檢測和嘴巴檢測結果是不可用的——對於面部特征/部分提取,強烈建議使用python,dlib,OpenCV提取眼睛,鼻子,嘴唇及下頜,dlib的檢測要比眼睛Haar級聯,嘴巴Haar級聯本身更穩定,甚至更快。

Haar級聯算法是OpenCV最流行的目標檢測算法,主要優點是速度太快瞭,盡管許多算法(如HOG+線性SVM、SSDs、更快的R-CNN、YOLO等等)比Haar級聯算法更精確。但如果需要純粹的速度,就是無法打敗OpenCV的Haar cascades。

Haar Cascades尤其是在資源受限的設備中工作時,當無法使用更昂貴的計算對象檢測器時,效果顯著。Haar級聯的缺點是容易出現假陽性檢測,應用於推理/檢測時需要進行參數調整。

1. 效果圖

Haar級聯檢測的效果如下:

可以看到圖中有固定大小的面在移動,就可以“訓練”分類器來識別圖像的給定區域是否包含人臉。

在這裡插入圖片描述

面部、眼睛、嘴部檢測效果圖如下:

在這裡插入圖片描述

有時候會有假陽性結果,如下圖:
可以看到檢測並不是最準確的,臉部是準確的,但嘴和眼睛級聯發生好幾個假陽性。當眨眼時,有兩種情況發生:(1)眼睛區域不再被檢測到,或者(2)它被錯誤地標記為嘴巴,在許多幀中往往有多個嘴巴檢測結果。

在這裡插入圖片描述

2. 原理

2.1 Haar級聯是什麼?

Haar級聯檢測5個特征:邊緣特征、線特征、四角-矩形的特征,計算特征需要從黑色區域下的像素總和中減去白色區域下的像素總和。有趣的是,這些特征在人臉檢測中具有實際的重要性:

  • 眼睛區域往往比臉頰區域暗。
  • 鼻子區域比眼睛區域亮。

給定這五個矩形區域及其相應的和差,就可以形成能夠對人臉的各個部分進行分類的特征。

Haar級聯的一些好處是,由於使用瞭積分圖像(也稱為求和面積表),它們在計算類似Haar的特征時非常快。通過使用AdaBoost算法,它們對特征選擇也非常有效。最重要的是,它們可以檢測圖像中的人臉,而不考慮人臉的位置或比例。

2.2 Haar級聯的問題與局限性

Haar級聯檢測器的問題與局限主要有3點:

  1. 需要最有效的正面圖像的臉;
  2. 容易出現誤報——Viola-Jones算法可以在沒有人臉的情況下輕松報告圖像中的人臉;
  3. 調優OpenCV檢測參數會非常乏味。有時可以檢測出圖像中的所有人臉,有時會(1)圖像的區域被錯誤地分類為面部;(2)面部被完全遺漏時。

2.3 Haar級聯預訓練的模型

OpenCV庫維護一個預先訓練好的Haar級聯庫。包括:

  • haarcascade_frontalface_default.xml:檢測面部
  • haarcascade_eye.xml:檢測左眼和右眼
  • haarcascade_smile.xml:檢測面部是否存在嘴部
  • haarcascade_eye_tree_eyeglasses.xml:檢測是否帶墨鏡🕶
  • haarcascade_frontalcatface.xml:檢測貓臉
  • haarcascade_frontalcatface_extended.xml:檢測貓臉延伸
  • haarcascade_frontalface_alt.xml:檢測貓臉屬性
  • haarcascade_frontalface_alt_tree.xml
  • haarcascade_frontalface_alt2.xml
  • haarcascade_fullbody.xml:檢測全身
  • haarcascade_lefteye_2splits.xml:檢測左眼
  • haarcascade_licence_plate_rus_16stages.xml:檢測證件
  • haarcascade_lowerbody.xml:檢測下半身
  • haarcascade_profileface.xml
  • haarcascade_righteye_2splits.xml:檢測右眼
  • haarcascade_russian_plate_number.xml:檢測俄羅斯字母車牌號
  • haarcascade_upperbody.xml:檢測上半身

還提供瞭其他經過預訓練的Haar級聯,包括一個用於俄羅斯牌照,另一個用於貓臉檢測。

可以使用cv2.CascadeClassifer從磁盤加載預先訓練好的Haar級聯檢測器:

detector = cv2.CascadeClassifier(path)

可以使用detectMultiScale對其進行預測:

 results = detector.detectMultiScale(
		   gray, scaleFactor=1.05, minNeighbors=5,
		   minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE)

3. 源碼

3.1 圖像檢測

# USAGE
# python opencv_haar_cascades_images.py --cascades cascades --image ml.jpg

# 導入必要的包
import argparse
import os  # 不同系統路徑分隔符

import cv2  # opencv綁定
import imutils

# 構建命令行參數及解析
# --cascades 級聯檢測器的路徑
ap = argparse.ArgumentParser()
ap.add_argument("-c", "--cascades", type=str, default="cascades",
                help="path to input directory containing haar cascades")
ap.add_argument("-i", "--image", type=str, default="ml2.jpg",
                help="path to input image")
args = vars(ap.parse_args())

# 初始化字典,並保存Haar級聯檢測器名稱及文件路徑
detectorPaths = {
    "face": "haarcascade_frontalface_default.xml",
    "eyes": "haarcascade_eye.xml",
    "smile": "haarcascade_smile.xml",
}

# 初始化字典以保存多個Haar級聯檢測器
print("[INFO] loading haar cascades...")
detectors = {}

# 遍歷檢測器路徑
for (name, path) in detectorPaths.items():
    # 加載Haar級聯檢測器並保存到map
    path = os.path.sep.join([args["cascades"], path])
    detectors[name] = cv2.CascadeClassifier(path)

# 從磁盤讀取圖像,縮放,並轉換灰度圖
print(args['image'])
image = cv2.imread(args["image"])
image = imutils.resize(image, width=500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 使用合適的Haar檢測器執行面部檢測
faceRects = detectors["face"].detectMultiScale(
    gray, scaleFactor=1.05, minNeighbors=5, minSize=(30, 30),
    flags=cv2.CASCADE_SCALE_IMAGE)

# 遍歷檢測到的所有面部
for (fX, fY, fW, fH) in faceRects:
    # 提取面部ROI
    faceROI = gray[fY:fY + fH, fX:fX + fW]

    # 在面部ROI應用左右眼級聯檢測器
    eyeRects = detectors["eyes"].detectMultiScale(
        faceROI, scaleFactor=1.1, minNeighbors=10,
        minSize=(15, 15), flags=cv2.CASCADE_SCALE_IMAGE)

    # 在面部ROI應用嘴部檢測
    smileRects = detectors["smile"].detectMultiScale(
        faceROI, scaleFactor=1.1, minNeighbors=10,
        minSize=(15, 15), flags=cv2.CASCADE_SCALE_IMAGE)

    # 遍歷眼睛邊界框
    for (eX, eY, eW, eH) in eyeRects:
        # 繪制眼睛邊界框(紅色)
        ptA = (fX + eX, fY + eY)
        ptB = (fX + eX + eW, fY + eY + eH)
        cv2.rectangle(image, ptA, ptB, (0, 0, 255), 2)

    # 遍歷嘴部邊界框
    for (sX, sY, sW, sH) in smileRects:
        # 繪制嘴邊界框(藍色)
        ptA = (fX + sX, fY + sY)
        ptB = (fX + sX + sW, fY + sY + sH)
        cv2.rectangle(image, ptA, ptB, (255, 0, 0), 2)

    # 繪制面部邊界框(綠色)
    cv2.rectangle(image, (fX, fY), (fX + fW, fY + fH),
                  (0, 255, 0), 2)

# 展示輸出幀
cv2.imshow("image", image)
cv2.waitKey(0)
# 清理工作
cv2.destroyAllWindows()

3.2 實時視頻流檢測

# USAGE
# python opencv_haar_cascades.py --cascades cascades

# 導入必要的包
import argparse
import os  # 不同系統路徑分隔符
import time  # sleep 2秒

import cv2  # opencv綁定
import imutils
from imutils.video import VideoStream  # 訪問網絡攝像頭

# 構建命令行參數及解析
# --cascades 級聯檢測器的路徑
ap = argparse.ArgumentParser()
ap.add_argument("-c", "--cascades", type=str, default="cascades",
                help="path to input directory containing haar cascades")
args = vars(ap.parse_args())

# 初始化字典,並保存Haar級聯檢測器名稱及文件路徑
detectorPaths = {
    "face": "haarcascade_frontalface_default.xml",
    "eyes": "haarcascade_eye.xml",
    "smile": "haarcascade_smile.xml",
}

# 初始化字典以保存多個Haar級聯檢測器
print("[INFO] loading haar cascades...")
detectors = {}

# 遍歷檢測器路徑
for (name, path) in detectorPaths.items():
    # 加載Haar級聯檢測器並保存到map
    path = os.path.sep.join([args["cascades"], path])
    detectors[name] = cv2.CascadeClassifier(path)

# 初始化視頻流,允許攝像頭預熱2s
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)

# 遍歷視頻流的每一幀
while True:
    # 獲取視頻流的每一幀,縮放,並轉換灰度圖
    frame = vs.read()
    frame = imutils.resize(frame, width=500)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 使用合適的Haar檢測器執行面部檢測
    faceRects = detectors["face"].detectMultiScale(
        gray, scaleFactor=1.05, minNeighbors=5, minSize=(30, 30),
        flags=cv2.CASCADE_SCALE_IMAGE)

    # 遍歷檢測到的所有面部
    for (fX, fY, fW, fH) in faceRects:
        # 提取面部ROI
        faceROI = gray[fY:fY + fH, fX:fX + fW]

        # 在面部ROI應用左右眼級聯檢測器
        eyeRects = detectors["eyes"].detectMultiScale(
            faceROI, scaleFactor=1.1, minNeighbors=10,
            minSize=(15, 15), flags=cv2.CASCADE_SCALE_IMAGE)

        # 在面部ROI應用嘴部檢測
        smileRects = detectors["smile"].detectMultiScale(
            faceROI, scaleFactor=1.1, minNeighbors=10,
            minSize=(15, 15), flags=cv2.CASCADE_SCALE_IMAGE)

        # 遍歷眼睛邊界框
        for (eX, eY, eW, eH) in eyeRects:
            # 繪制眼睛邊界框(紅色)
            ptA = (fX + eX, fY + eY)
            ptB = (fX + eX + eW, fY + eY + eH)
            cv2.rectangle(frame, ptA, ptB, (0, 0, 255), 2)

        # 遍歷嘴部邊界框
        for (sX, sY, sW, sH) in smileRects:
            # 繪制嘴邊界框(藍色)
            ptA = (fX + sX, fY + sY)
            ptB = (fX + sX + sW, fY + sY + sH)
            cv2.rectangle(frame, ptA, ptB, (255, 0, 0), 2)

        # 繪制面部邊界框(綠色)
        cv2.rectangle(frame, (fX, fY), (fX + fW, fY + fH),
                      (0, 255, 0), 2)

    # 展示輸出幀
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(1) & 0xFF
    # 按下‘q'鍵,退出循環
    if key == ord("q"):
        break

# 清理工作
cv2.destroyAllWindows()
vs.stop()

參考

 https://www.pyimagesearch.com/2021/04/12/opencv-haar-cascades/

到此這篇關於超詳細註釋之OpenCV Haar級聯檢測器進行面部檢測的文章就介紹到這瞭,更多相關OpenCV Haar內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: