作者|OpenCV-Python Tutorials
編譯|Vincent
來源|OpenCV-Python Tutorials
目標
在本教程中,
- 我們將學習Haar級聯對象檢測的工作原理。
- 我們將使用基於Haar Feature的Cascade分類器了解人臉檢測和眼睛檢測的基礎知識。
- 我們將使用cv::CascadeClassifier類來檢測視頻流中的對象。特別是,我們將使用以下函數:
- cv::CascadeClassifier::load來加載.xml分類器文件。它可以是Haar或LBP分類器
- cv::CascadeClassifier::detectMultiScale來執行檢測。
理論
使用基於Haar特征的級聯分類器的對象檢測是Paul Viola和Michael Jones在其論文“使用簡單特征的增強級聯進行快速對象檢測”中於2001年提出的一種有效的對象檢測方法。這是一種基於機器學習的方法,其中從許多正負圖像中訓練級聯函數。然后用於檢測其他圖像中的對象。
在這里,我們將進行人臉檢測。最初,該算法需要大量正圖像(面部圖像)和負圖像(無面部圖像)來訓練分類器。 然后,我們需要從中提取特征。為此,使用下圖所示的Haar功能。 它們就像我們的卷積核一樣。 每個特征都是通過從黑色矩形下的像素總和中減去白色矩形下的像素總和而獲得的單個值。
現在,每個內核的所有可能大小和位置都用於計算許多功能。(試想一下它產生多少計算?即使是一個24x24的窗口也會產生超過160000個特征)。對於每個特征計算,我們需要找到白色和黑色矩形下的像素總和。為了解決這個問題,他們引入了整體圖像。無論你的圖像有多大,它都會將給定像素的計算減少到僅涉及四個像素的操作。很好,不是嗎?它使事情變得更快。
但是在我們計算的所有這些特征中,大多數都不相關。例如,考慮下圖。第一行顯示了兩個良好的特征。選擇的第一個特征似乎着眼於眼睛區域通常比鼻子和臉頰區域更暗的性質。選擇的第二個特征依賴於眼睛比鼻梁更黑的屬性。但是,將相同的窗口應用於臉頰或其他任何地方都是無關緊要的。那么,我們如何從16萬多個功能中選擇最佳特征?它是由Adaboost實現的。
為此,我們將所有特征應用於所有訓練圖像。對於每個特征,它會找到最佳的閾值,該閾值會將人臉分為正面和負面。顯然,會出現錯誤或分類錯誤。我們選擇錯誤率最低的特征,這意味着它們是對人臉和非人臉圖像進行最准確分類的特征。 (此過程並非如此簡單。在開始時,每個圖像的權重均相等。在每次分類后,錯誤分類的圖像的權重都會增加。然后執行相同的過程。將計算新的錯誤率。還要計算新的權重。繼續進行此過程,直到達到所需的精度或錯誤率或找到所需的功能數量為止。
最終分類器是這些弱分類器的加權和。之所以稱為弱分類,是因為僅憑它不能對圖像進行分類,而是與其他分類一起形成強分類器。該論文說,甚至200個功能都可以提供95%的准確度檢測。他們的最終設置具有大約6000個功能。 (想象一下,從160000多個功能減少到6000個功能。這是很大的收獲)。
因此,現在你拍攝一張照片。取每個24x24窗口。向其應用6000個功能。檢查是否有臉。哇..這不是效率低下又費時嗎?是的。作者對此有一個很好的解決方案。
在圖像中,大多數圖像是非面部區域。因此,最好有一種簡單的方法來檢查窗口是否不是面部區域。如果不是,請一次性丟棄它,不要再次對其進行處理。相反,應將重點放在可能有臉的區域。這樣,我們將花費更多時間檢查可能的面部區域。
為此,他們引入了級聯分類器的概念。不是將所有6000個功能部件應用到一個窗口中,而是將這些功能部件分組到不同的分類器階段,並一一應用。 (通常前幾個階段將包含很少的功能)。如果窗口在第一階段失敗,則將其丟棄。我們不考慮它的其余功能。如果通過,則應用功能的第二階段並繼續該過程。經過所有階段的窗口是一個面部區域。這個計划怎么樣!
作者的檢測器具有6000多個特征,具有38個階段,在前五個階段具有1、10、25、25和50個特征。 (上圖中的兩個功能實際上是從Adaboost獲得的最佳兩個功能)。根據作者的說法,每個子窗口平均評估了6000多個特征中的10個特征。
因此,這是Viola-Jones人臉檢測工作原理的簡單直觀說明。閱讀本文以獲取更多詳細信息,或查看其他資源部分中的參考資料。
OpenCV中的Haar-級聯檢測器
OpenCV提供了一種訓練方法(請參閱Cascade分類器訓練)或預先訓練的模型,可以使用cv::CascadeClassifier::load方法讀取。預訓練的模型位於OpenCV安裝的data文件夾中,或在此處找到。
以下代碼示例將使用預訓練的Haar級聯模型來檢測圖像中的面部和眼睛。首先,創建一個cv::CascadeClassifier並使用cv::CascadeClassifier::load方法加載必要的XML文件。然后,使用cv::CascadeClassifier::detectMultiScale方法完成檢測,該方法返回檢測到的臉部或眼睛的邊界矩形。
本教程的代碼如下所示。你也可以從這里下載
from __future__ import print_function
import cv2 as cv
import argparse
def detectAndDisplay(frame):
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
frame_gray = cv.equalizeHist(frame_gray)
#-- 檢測面部
faces = face_cascade.detectMultiScale(frame_gray)
for (x,y,w,h) in faces:
center = (x + w//2, y + h//2)
frame = cv.ellipse(frame, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4)
faceROI = frame_gray[y:y+h,x:x+w]
#-- 在每張面部上檢測眼睛
eyes = eyes_cascade.detectMultiScale(faceROI)
for (x2,y2,w2,h2) in eyes:
eye_center = (x + x2 + w2//2, y + y2 + h2//2)
radius = int(round((w2 + h2)*0.25))
frame = cv.circle(frame, eye_center, radius, (255, 0, 0 ), 4)
cv.imshow('Capture - Face detection', frame)
parser = argparse.ArgumentParser(description='Code for Cascade Classifier tutorial.')
parser.add_argument('--face_cascade', help='Path to face cascade.', default='data/haarcascades/haarcascade_frontalface_alt.xml')
parser.add_argument('--eyes_cascade', help='Path to eyes cascade.', default='data/haarcascades/haarcascade_eye_tree_eyeglasses.xml')
parser.add_argument('--camera', help='Camera divide number.', type=int, default=0)
args = parser.parse_args()
face_cascade_name = args.face_cascade
eyes_cascade_name = args.eyes_cascade
face_cascade = cv.CascadeClassifier()
eyes_cascade = cv.CascadeClassifier()
#-- 1. 加載級聯
if not face_cascade.load(cv.samples.findFile(face_cascade_name)):
print('--(!)Error loading face cascade')
exit(0)
if not eyes_cascade.load(cv.samples.findFile(eyes_cascade_name)):
print('--(!)Error loading eyes cascade')
exit(0)
camera_device = args.camera
#-- 2. 讀取視頻流
cap = cv.VideoCapture(camera_device)
if not cap.isOpened:
print('--(!)Error opening video capture')
exit(0)
while True:
ret, frame = cap.read()
if frame is None:
print('--(!) No captured frame -- Break!')
break
detectAndDisplay(frame)
if cv.waitKey(10) == 27:
break
結果
- 這是運行上面的代碼並將內置攝像頭的視頻流用作輸入的結果:
請確保程序會找到文件haarcascade_frontalface_alt.xml和haarcascade_eye_tree_eyeglasses.xml的路徑。它們位於opencv/data/ haarcascades中
- 這是使用文件lbpcascade_frontalface.xml(經過LBP訓練)進行人臉檢測的結果。對於眼睛,我們繼續使用本教程中使用的文件。
附加資源
- Paul Viola and Michael J. Jones. Robust real-time face detection. International Journal of Computer Vision, 57(2):137–154, 2004. [228]
- Rainer Lienhart and Jochen Maydt. An extended set of haar-like features for rapid object detection. In Image Processing. 2002. Proceedings. 2002 International Conference on, volume 1, pages I–900. IEEE, 2002. [129]
- Video Lecture on Face Detection and Tracking
- An interesting interview regarding Face Detection by Adam Harvey
- OpenCV Face Detection: Visualized on Vimeo by Adam Harvey