天天看點

【轉載】項目實戰—人臉檢測之級聯分類器實戰(二)

在上個教程中,使用 Adaboost 學習分類函數過程非常有效,但仍存在一個重大問題。在圖像中,大部分圖像為非面部區域。對圖像的每個區域給予等同的注意力是沒有意義的,因為我們應該主要關注最有可能包含人臉的區域。Viola 和 Jone 使用級聯分類器在減少了計算時間的同時,實作了更高的檢測率。

關鍵思想是在識别人臉區域時排除不含人臉的子視窗。由于任務是正确識别人臉,我們希望假陰率最小,即包含人臉卻未被識别的子視窗最少。

每個子視窗都使用一系列分類器。這些分類器是簡單的決策樹:

·如果第一個分類器檢測為正樣本,繼續用第二個

·如果第二個分類器檢測是正樣本,繼續用第三個

·以此類推

雖然有時可能包含人臉的圖被認成負樣本被子視窗漏檢。但初級分類器以較低的計算成本篩除了大多數負樣本,下圖的分類器可額外消除更多的負樣本,但需要更多的計算量。

【轉載】項目實戰—人臉檢測之級聯分類器實戰(二)

使用 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

【轉載】項目實戰—人臉檢測之級聯分類器實戰(二)

繼續閱讀