【人臉識別(五)】:基於Haar+Adaboost的人臉檢測算法,及實例教程

人臉識別(一):Ubuntu Python安裝dlib C++ library

人臉識別(二):如何使用 dlib 實現簡單的人臉識別功能

人臉識別(三):使用face_recognition庫實現人臉識別,python實現

人臉識別(四):人臉識別理論、原理、分類、概括,請針對性學習所需算法,不要全學。

 

目錄

1. adaboost由來

2. Haar特徵

2.1 矩形特徵個數

2.2 積分圖

3. Adaboost算法流程

3.1 弱分類器訓練

3.2. 強分類器訓練

4. 使用Opencv實現人臉檢測


看了很多的文章,認爲liulina603nk_wavelet對adaboost算法講解的比較詳細,查閱相關資料後,本文將介紹haar+adaboost算法理論和具體實現,多處參考以上兩位博主。

1. adaboost由來

adaboost方法是Boosting方法的提升版,Boosting方法又起源於PCA學習模型。1984年Valiant提出PCA模型,1990年,SChapire就首先構造出一種多項式級的算法,將弱學習算法提升爲強學習算法,就是最初的Boosting算法。1993年,Drucker和Schapire首次以神經網絡作爲弱學習器,利用Boosting算法解決實際問題。1994年,Kearns和Valiant證明,在Valiant的PAC(Probably ApproximatelyCorrect)模型中,只要數據足夠多,就可以將弱學習算法通過集成的方式提高到任意精度。1995年,Freund在Kearns和Valiant證明的基礎上提出了一種效率更高的Boosting算法,即現在的Adaboost模型,對Boosting算法有巨大提升。

PCA(Probably Approximately Correct)模型是計算學習理論中常用的模型,PAC學習的實質就是在樣本訓練的基礎上,使算法的輸出以概率接近未知的目標概念。PAC學習模型是考慮樣本複雜度(指學習器收斂到成功假設時至少所需的訓練樣本數)及計算複雜度(指學習器收斂到成功假設時所需的計算量)的一個基本框架,成功的學習被定義爲形式化的概率理論。

Boosting 原意爲提升、加強,現在一般指的是將弱學習算法提升爲強學習算法的一類算法。boosting模型就是學習一系列的分類器,每個分類器對其前一個分類器產生的錯誤給予更大的重視,並增加導致錯誤分類的樣本權值,重新對該樣本訓練分類器後,再學習下一個分類器。該訓練過程重複到設定的次數後停止,最終分類器從這一系列的分類器中得出。Boosting是一種把若干個若分類器結合到一個強分類器中,從而大大提高檢測性能的方法。強分類器對數據進行分類,是通過弱分類器的多數投票機制進行的。

Adaboost(Adaptive Boosting)是Boosting家族的代表算法之一,不需要任何關於弱學習器性能的先驗知識,而且和Boosting算法具有同樣的效率,所以在提出之後得到了廣泛的應用。

Adaboost算法已被證明是一種有效而實用的Boosting算法,其算法原理是通過調整樣本權重和弱分類器權值,從訓練出的弱分類器中篩選出權值係數最小的弱分類器組合成一個最終強分類器。基於訓練集訓練弱分類器,每次下一個弱分類器都是在樣本的不同權值集上訓練獲得的。每個樣本被分類的難易度決定權重,而分類的難易度是經過前面步驟中的分類器的輸出估計得到的。

Adaboost算法在樣本訓練集使用過程中,對其中的關鍵分類特徵集進行多次挑選,逐步訓練分量弱分類器,用適當的閾值選擇最佳弱分類器,最後將每次迭代訓練選出的最佳弱分類器構建爲強分類器。其中,級聯分類器的設計模式爲在儘量保證感興趣圖像輸出率的同時,減少非感興趣圖像的輸出率,隨着迭代次數不斷增加,所有的非感興趣圖像樣本都不能通過,而感興趣樣本始終保持儘可能通過爲止。

首先需要了解若分類器、強分類器和級聯分類器。弱分類器:沒有專門的定義,可以理解爲對分類的效果較弱,正確率較低。強分類器:即分類學習正確率較高,有顯著的分類分類效果。級聯分類器:將多個分類器連在一起組成一個強分類器,再由多個強分類器級聯在一起組成一個標準分類器。

Adaboost是一種基於級聯分類模型的分類器,級聯分類模型可以用下圖表示:

所有樣本進入第一個強分類器,若爲正例則進入下一個強分類器,否則,直接作爲負例輸出,以此類推,直到最後的強分類器輸出正例,作爲最終的輸出結果。

有些強分類器可能包含10個弱分類器,有些則包含20個弱分類器,一般情況下一個級聯用的強分類器包含20個左右的弱分類器,然後在將10個強分類器級聯起來,就構成了一個級聯強分類器,這個級聯強分類器中總共包括200弱分類器。因爲每一個強分類器對負樣本的判別準確度非常高,所以一旦發現檢測到的目標位負樣本,就不在繼續調用下面的強分類器,減少了很多的檢測時間。因爲一幅圖像中待檢測的區域很多都是負樣本,這樣由級聯分類器在分類器的初期就拋棄了很多負樣本的複雜檢測,所以級聯分類器的速度是非常快的;只有正樣本纔會送到下一個強分類器進行再次檢驗,這樣就保證了最後輸出的正樣本的僞正(false positive)的可能性非常低。

級聯結構分類器由多個弱分類器組成,每一級都比前一級複雜。每個分類器可以讓幾乎所有的正例通過,同時濾除大部分負例。這樣每一級的待檢測正例就比前一級少,排除了大量的非檢測目標,可大大提高檢測速度。

其次,Adaboost是一種迭代算法。初始時,所有訓練樣本的權重都被設爲$1/N$,在此樣本分佈下訓練出一個弱分類器。在第($n=1,2,3,....,T$,T爲迭代次數)次迭代中,樣本的權重由第n-1次迭代的結果而定。在每次迭代的最後,都有一個調整權重的過程,被分類錯誤的樣本將得到更高的權重。這樣分錯的樣本就被突出出來,得到一個新的樣本分佈。在新的樣本分佈下,再次對弱分類器進行訓練,得到下一個新的弱分類器。經過T次循環,得到T個弱分類器,把這T個弱分類器按照一定的權重疊加起來,就得到最終的強分類器。

Aadboost 算法系統具有較高的檢測速率,且不易出現過適應現象。但是該算法在實現過程中爲取得更高的檢測精度則需要較大的訓練樣本集,在每次迭代過程中,訓練一個弱分類器則對應該樣本集中的每一個樣本,每個樣本具有很多特徵,因此從龐大的特徵中訓練得到最優弱分類器的計算量增大。

2. Haar特徵

Harr-like特徵是Viola等提出的一種簡單矩形特徵,因其類似於Harr小波而得名,它反映了圖像局部的灰度化。影響AdaBoost檢測訓練算法速度很重要的兩方面是特徵的選取和特徵值的計算。臉部的一些特徵可以由矩形特徵(特徵模板)簡單地描繪。如下圖示範:

上圖中兩個矩形特徵,表示出人臉的某些特徵。比如中間一幅表示眼睛區域的顏色比臉頰區域的顏色深,右邊一幅表示鼻樑兩側比鼻樑的顏色要深。同樣,其他目標,如眼睛等,也可以用一些矩形特徵來表示。在給定有限的數據情況下,基於特徵的檢測能夠編碼特定區域的狀態,而且基於特徵的系統比基於像素的系統要快得多。矩形特徵對一些簡單的圖形結構,比如邊緣、線段,比較敏感,但是其只能描述特定走向(水平、垂直、對角)的結構,因此比較粗略。如上圖,臉部一些特徵能夠由矩形特徵簡單地描繪,例如,通常眼睛要比臉頰顏色更深;鼻樑兩側要比鼻樑顏色要深;嘴巴要比周圍顏色更深。

對於一個 24×24 檢測器,其內的矩形模板決定的矩形特徵數量超過160,000個,必須通過特定算法甄選合適的矩形特徵,並將其組合成強分類器才能檢測人臉。

常用的矩形特徵有三種:兩矩形特徵、三矩形特徵、四矩形特徵,如圖:

由圖表可以看出,兩矩形特徵反映的是邊緣特徵,三矩形特徵反映的是線性特徵、四矩形特徵反映的是特定方向特徵。LienhartR.等對Haar-like矩形特徵庫作了進一步擴展,加入了旋轉$45^o$角的矩形特徵。擴展後的特徵大致分爲4種類型:邊緣特徵、線特徵環、中心環繞特徵和對角線特徵:如下圖

特徵模板的特徵值定義爲:模板內白色矩形像素和減去黑色矩形像素和$(S_w_h_i_t_e-S_b_l_a_c_k)$

接下來就需要求解特徵個數特徵值

2.1 矩形特徵個數

如圖所示的一個m*m大小的子窗口,可以計算在這麼大的子窗口內存在多少個矩形特徵。特徵模板可以在子窗口內以“任意”尺寸“任意”放置,每一種形態稱爲一個特徵。找出子窗口所有特徵,是進行弱分類訓練的基礎。

對於 mm×mm 子窗口,我們只需要確定了矩形左上頂點 $A(x_1,y_2)$ 和右下頂點$B(x_2,y_2)$,即可以確定一個矩形。如果這個矩形還必須滿足下面兩個條件(稱爲$(s,t)$條件,滿足$(s,t)$條件的矩形稱爲條件矩形,即在x方向和y方向可以被s和t整除。這樣就可以矩形模板的在不同的尺寸,都可以將圖片完整劃分成多個矩形。

如下圖特徵模板和對應的(s,t)條件:

模板1對應的是(1,2)條件,所以,x方向可以被1整除,y方向可以被2整除就可以,這樣就把(50x100)圖片劃分成多個50*50個小格;再將模板按照倍數放大(橫縱倍數可以不同)=====》(1,4),這樣又可以把這個(50x100)的圖片劃分成50*25個小格,以此類推,直到不能再放大模板位置。這樣得到的每個矩形小格都代表每種特徵,此時所有小格的個數就是矩形特徵的個數。

下面以24×24子窗口和一下五種模板爲例,具體計算其特徵總數量:

下面列出了,在不同子窗口大小內,特徵的總數量:

2.2 積分圖

在獲取了矩形特徵後,要計算矩形特徵的特徵值。Viola等人提出了利用積分圖求特徵值的方法。積分圖的概念可用下圖表示:

在上圖中,$SAT(x,y)$表示點A(x,y)的積分圖,指的是從(1,1)到A(x,y)的圖像像素之和。

如上圖,SAT(1)表示A區域的像素之和,SAT(2)表示A+B區域的像素之和,SAT(3)表示A+C區域的像素之和,SAT(4)表示A+B+C+D區域的像素之和。

所以D區域的像素之和 $= SAT(4)+SAT(1)-SAT(2)-SAT(3)$。所以,一個區域的像素值,可以由區域的積分圖計算。使用模板將圖像劃分網格後,就可以利用積分圖計算每個區域的像素值,這中方法比計算像素值要快很多。

如下圖,使用模板中的2號模板(s,t)爲(2,1)將圖像劃分網格:

A和B區域代表着舉行模板,所以A的像素值使用積分圖計算:$SAT(5)+SAT(1)-SAT(2)-SAT(4)$;B區域的像素值爲:$SAT(6)+SAT(2)-SAT(5)-SAT(3)$。那麼AB區域的特徵模板的特徵值爲A區域像素值減去B區域像素值:$SAT5+SAT1-SAT2-SAT4-[SAT6+SAT2-SAT5-SAT3] = SAT5-SAT4+ SAT3-SAT2-[SAT2-SAT1]-[SAT6-SAT5]$

所以,矩形特徵的特徵值,至於矩形端點的積分圖有關,與座標無關。計算端點的積分圖,再加減運算,就可以得到特徵值,運算速度大大提高,檢測速增加。

 

3. Adaboost算法流程

如上述,adaboost採用迭代的方法,用不同訓練集訓練同一個弱分類器,然後再把不同訓練集得到的弱分類器集合在一起,構成一個強分類器,組後再把幾組強分類器聯在一起構成一個分類器。

3.1 弱分類器訓練

弱分類器數學結構如下:

其中f爲特徵,θ爲閾值,p指示不等號的方向,x該表一個檢測子窗口。對每個特徵f,訓練一個弱分類器h(x,f,p,θ),就是確定f的最優閾值,使得這個弱分類器 h(x,f,p,θ)對所有訓練樣本的分類誤差最小。

弱分類器訓練的過程大致分爲如下幾步:
  1)對每個特徵f,計算所有訓練樣本的特徵值;
  2)將特徵值排序;
  3)對排好序的每個元素計算:
    3.1)全部正例的權重和T+;
    3.2)全部負例的權重和T−;
    3.3)該元素前正例的權重和S+;
    3.4)該元素前負例的權重和S−.
       4)選取當前元素的特徵值$F_k_j$和它前面的一個特徵值$F_k_j_-_1$之間的作爲閾值,所得到的弱分類器就在當前元素處把樣本分開 —— 也就是說這個閾值對應的弱分類器將當前元素前的所有元素分爲人臉(或非人臉),而把當前元素後(含)的所有元素分爲非人臉(或人臉)。該閾值的分類誤差爲:

於是,通過把這個排序表從頭到尾掃描一遍就可以爲弱分類器選擇使分類誤差最小的閾值(最優閾值),也就是選取了一個最佳弱分類器。

3.2. 強分類器訓練

在訓練強分類器中,$T = (x_1,y_1), (x_2,y_2),...,(x_N,y_N)$,其中實例空間$x\in X$,而實例空間$X\in R^n, y_i\in Y$Y = \begin{cases} -1\\ +1 \end{cases}。AdaBoost算法的目的就是從訓練數據中學習一系列弱分類器,然後將這些弱分類器組合成一個強分類器。AdaBoost算法流程如下:

 

簡單來說,AdaBoost有很多優點:
  ● AdaBoost是一種有很高精度的分類器;
  ● 可以使用各種方法構建子分類器,AdaBoost算法提供的是框架;
  ● 當使用簡單分類器時,計算出的結果是可以理解的。而且弱分類器構造極其簡單;
  ● 簡單,不用做特徵篩選;
  ● 不用擔心過擬合。

 

4. 使用Opencv實現人臉檢測

OpenCV自帶的AdaBoost程序能夠根據用戶輸入的正樣本集與負樣本集訓練分類器,常用於人臉檢測,行人檢測等。它的默認特徵採用了Haar,不支持其它特徵。

這次實現的是人臉檢測,首先是需要安裝opencv庫,可以從此下載opencv官方,安裝。

找到opencv\sources\data\haarcascades中的haarcascade_frontalface_alt.xml文件,此文件是opencv中已經訓練好的人臉adaboost聯級分類器,只需要解析此文件即可對圖像進行檢測是否存在人臉,以及檢測框的位置。可以將此文件複製到項目路徑下。導入分類器的方法是使用CascaClassifter函數,即:

cv2.CascadeClassifier('./haarcascade_frontalface_alt.xml')

使用face_Cascade.detectMultiScale(image,scaleFactor,minNeighbors,flags,minSize,maxSize)進行識別,

例:faceRects = face_Cascade.detectMultiScale(image, 1.05, 2, cv2.CASCADE_SCALE_IMAGE, minSize_1)

image:是待檢測圖像

scaleFactor:前後兩次相繼的掃描中,搜索窗口的比例係數

minNeighbors:構成檢測目標的相鄰矩形的最小個數。

minSize:目標的最小尺寸

maxSize:目標的最大尺寸

下面是使用haar+adaboost實現的人臉識別案例:

先上效果:

再上代碼部分:

# coding:utf-8
import cv2
import numpy as np

[x, y, w, h] = [0, 0, 0, 0]

path = './face_images/2008_002506.jpg'

face_Cascade = cv2.CascadeClassifier("./haarcascades/haarcascade_frontalface_alt.xml")

frame = cv2.imread(path)

size = frame.shape[:2]
image = np.zeros(size, dtype=np.float32)
image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# 直方圖均衡
image = cv2.equalizeHist(image)
im_h, im_w = size
minSize_1 = (im_w // 10, im_h // 10)
faceRects = face_Cascade.detectMultiScale(image, 1.05, 2, cv2.CASCADE_SCALE_IMAGE, minSize_1)
if len(faceRects) > 0:
    for faceRect in faceRects:
        x, y, w, h = faceRect
        cv2.rectangle(frame, (x, y), (x + w, y + h), [255, 255, 0], 2)


cv2.imshow("detection", frame)
cv2.waitKey(0)
print('okay')


同時還可以改造成視頻內的人臉檢測,如下:

# coding:utf-8
import cv2
import numpy as np

[x, y, w, h] = [0, 0, 0, 0]

video_capture = cv2.VideoCapture("./video/hamilton_clip.mp4")
# video_capture = cv2.VideoCapture(0)

face_Cascade = cv2.CascadeClassifier("./haarcascades/haarcascade_frontalface_alt.xml")

cv2.namedWindow("Face Detection System")

while video_capture.isOpened():
    ret, frame = video_capture.read()

    if not ret:
        break

    size = frame.shape[:2]
    image = np.zeros(size, dtype=np.float32)
    image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 直方圖均衡
    image = cv2.equalizeHist(image)
    im_h, im_w = size
    minSize_1 = (im_w // 8, im_h // 8)
    faceRects = face_Cascade.detectMultiScale(image, 1.05, 2, cv2.CASCADE_SCALE_IMAGE, minSize_1)
    if len(faceRects) > 0:
        for faceRect in faceRects:
            x, y, w, h = faceRect
            cv2.rectangle(frame, (x, y), (x + w, y + h), [0, 255, 0], 2)

    cv2.imshow("Face Detection System", frame)
    key = cv2.waitKey(5)
    if key == int(30):
        break

video_capture.release()
cv2.destroyWindow("Face Detection System")




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章