在上個教程中,使用 Adaboost 學習分類函數過程非常有效,但仍存在一個重大問題。在圖像中,大部分圖像為非面部區域。對圖像的每個區域給予等同的注意力是沒有意義的,因為我們應該主要關注最有可能包含人臉的區域。Viola 和 Jone 使用級聯分類器在減少了計算時間的同時,實作了更高的檢測率。
關鍵思想是在識别人臉區域時排除不含人臉的子視窗。由于任務是正确識别人臉,我們希望假陰率最小,即包含人臉卻未被識别的子視窗最少。
每個子視窗都使用一系列分類器。這些分類器是簡單的決策樹:
·如果第一個分類器檢測為正樣本,繼續用第二個
·如果第二個分類器檢測是正樣本,繼續用第三個
·以此類推
雖然有時可能包含人臉的圖被認成負樣本被子視窗漏檢。但初級分類器以較低的計算成本篩除了大多數負樣本,下圖的分類器可額外消除更多的負樣本,但需要更多的計算量。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNCM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR50djpnT6lEROBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwUTN2QDMwATM4ETMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
使用 Adaboost 訓練分類器,并調整門檻值使錯誤率降到最低。在訓練該模型時,變量如下:
· 每個階段分類器數量
· 每個階段的特征數量
· 每個階段的門檻值
友善的是,在 OpenCV 中,整個模型已經經過預訓練,可直接用于人臉檢測。
如果想了解有關 Boosting 技術的更多資訊,歡迎檢視作者關于 Adaboost 的文章:
https://maelfabien.github.io/machinelearning/adaboost
實戰
下一步是找到預訓練的權重。我們将使用預設的預訓練模型來檢測人臉、眼睛和嘴巴。
關于OpenCV中的已經訓練好的XML檔案,這個需要自行去官網下載下傳,這邊就不再贅述。
确定路徑後,以此方式聲明級聯分類器:
view plaincopy to clipboardprint?
cascPath = "haarcascade_frontalface_default.xml"
eyePath = "haarcascade_eye.xml"
smilePath = "haarcascade_smile.xml"
faceCascade = cv2.CascadeClassifier(cascPath)
eyeCascade = cv2.CascadeClassifier(eyePath)
smileCascade = cv2.CascadeClassifier(smilePath)
檢測圖像中的人臉
在實作實時人臉檢測算法之前,讓我們先嘗試在圖像上簡單檢測一下。從加載測試圖像開始:
view plaincopy to clipboardprint?
gray = cv2.imread('min.jpg',0)
plt.figure(figsize=(12,8))
plt.imshow(gray, cmap='gray')
plt.show()
然後開始檢測人臉,并将檢測到的人臉框起來。
view plaincopy to clipboardprint?
# Detect faces
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
flags=cv2.CASCADE_SCALE_IMAGE
)
# For each face
for (x, y, w, h) in faces:
# Draw rectangle around the face
cv2.rectangle(gray, (x, y), (x+w, y+h), (255, 255, 255), 3)
以下是 detectMultiScale 函數常見的參數清單:
·scaleFactor:确定每個圖像縮放比例大小。
·minNeighbors:确定每個候選矩形應保留多少個相鄰框。
·minSize:最小目标的大小。小于該值的目标将被忽略。
·maxSize:最大目标的大小。大于該值的目标将被忽略。
最後,顯示結果:
view plaincopy to clipboardprint?
plt.figure(figsize=(12,8))
plt.imshow(gray, cmap='gray')
plt.show()
在測試圖像上成功檢測到人臉。現在開始實時檢測!
實時人臉檢測
下面繼續進行實時人臉檢測的 Python 實作。第一步是啟動攝像頭,并拍攝視訊。然後,将圖像轉換為灰階圖。這用于減小輸入圖像的維數。實際上,我們應用了一個簡單的線性變換,而不是每個像素用三個點來描述紅、綠、藍。
這在 OpenCV 中是預設實作的。
view plaincopy to clipboardprint?
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
現在我們使用上述定義的 faceCascade 變量,它包含一個預訓練算法,現在将其用于灰階圖。
view plaincopy to clipboardprint?
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE
)
對于檢測到的每個人臉,都加上一個矩形框:
view plaincopy to clipboardprint?
for (x, y, w, h) in faces:
if w > 250 :
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3)
roi_gray = gray[y:y+h, x:x+w]
roi_color = frame[y:y+h, x:x+w]
對于檢測到的每張嘴,都加上一個矩形框:
view plaincopy to clipboardprint?
smile = smileCascade.detectMultiScale(
roi_gray,
scaleFactor= 1.16,
minNeighbors=35,
minSize=(25, 25),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (sx, sy, sw, sh) in smile:
cv2.rectangle(roi_color, (sh, sy), (sx+sw, sy+sh), (255, 0, 0), 2)
cv2.putText(frame,'Smile',(x + sx,y + sy), 1, 1, (0, 255, 0), 1)
對于檢測到的每雙眼睛,都加上一個矩形框:
view plaincopy to clipboardprint?
eyes = eyeCascade.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
cv2.putText(frame,'Eye',(x + ex,y + ey), 1, 1, (0, 255, 0), 1)
然後計算人臉總數,顯示整體圖像:
view plaincopy to clipboardprint?
cv2.putText(frame,'Number of Faces : ' + str(len(faces)),(40, 40), font, 1,(255,0,0),2)
# Display the resulting frame
cv2.imshow('Video', frame)
當按下 q 鍵時,執行退出選項。
view plaincopy to clipboardprint?
if cv2.waitKey(1) & 0xFF == ord('q'):
break
最後當所有操作完成後,關閉所有視窗。
view plaincopy to clipboardprint?
video_capture.release()
cv2.destroyAllWindows()
封裝代碼:
view plaincopy to clipboardprint?
import cv2
import matplotlib.pyplot as plt
cascPath = "haarcascade_frontalface_default.xml"
eyePath = "haarcascade_eye.xml"
smilePath = "haarcascade_smile.xml"
faceCascade = cv2.CascadeClassifier(cascPath)
eyeCascade = cv2.CascadeClassifier(eyePath)
smileCascade = cv2.CascadeClassifier(smilePath)
font = cv2.FONT_HERSHEY_SIMPLEX
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(200, 200),
flags=cv2.CASCADE_SCALE_IMAGE
)
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 3)
roi_gray = gray[y:y + h, x:x + w]
roi_color = frame[y:y + h, x:x + w]
cv2.putText(frame, 'Face', (x, y), font, 2, (255, 0, 0), 5)
smile = smileCascade.detectMultiScale(
roi_gray,
scaleFactor=1.16,
minNeighbors=35,
minSize=(25, 25),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (sx, sy, sw, sh) in smile:
cv2.rectangle(roi_color, (sh, sy), (sx + sw, sy + sh), (255, 0, 0), 2)
cv2.putText(frame, 'Smile', (x + sx, y + sy), 1, 1, (0, 255, 0), 1)
eyes = eyeCascade.detectMultiScale(roi_gray)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
cv2.putText(frame, 'Eye', (x + ex, y + ey), 1, 1, (0, 255, 0), 1)
cv2.putText(frame, 'Number of Faces : ' + str(len(faces)), (40, 40), font, 1, (255, 0, 0), 2)
# Display the resulting frame
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything is done, release the capture
video_capture.release()
cv2.destroyAllWindows()
至于結果大家自行實驗。用自己的攝像頭就可以。
檢視文章彙總頁https://blog.csdn.net/weixin_44237705/article/details/107864965
更多openvino技術資訊可以入群交流~
申請備注:CSDN