一、Haar特徵原理綜述
Haar特徵是一種反映影像的灰度變化的,畫素分模組求差值的一種特徵。它分為三類:邊緣特徵、線性特徵、中心特徵和對角線特徵。用黑白兩種矩形框組合成特徵模板,在特徵模板內用 黑色矩形畫素和 減去 白色矩形畫素和來表示這個模版的特徵值。例如:臉部的一些特徵能由矩形模組差值特徵簡單的描述,如:眼睛要比臉頰顏色要深,鼻樑兩側比鼻樑顏色要深,嘴巴比周圍顏色要深等。但矩形特徵只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述在特定方向(水平、垂直、對角)上有明顯畫素模組梯度變化的影像結構。
如上圖A、B、D模組的影像Haar特徵為:v=Sum白-Sum黑
C 模組的影像Haar特徵為:v=Sum白(左)+Sum白(右)-2*Sum黑
這裡要保證白色矩形模組中的畫素與黑色矩形的模組的畫素數相同,所以乘2
對於一幅影像來說,可以通過通過改變特徵模板的大小和位置,可窮舉出大量的特徵來表示一幅影像。上圖的特徵模板稱為“特徵原型”;特徵原型在影像子視窗中擴充套件(平移伸縮)得到的特徵稱為“矩形特徵”;矩形特徵的值稱為“特徵值”。例如在24*24大小的影像中可以以座標(0,0)開始寬為20高為20矩形模版計算上圖A特徵,也可以以座標(0,2)開始寬為20高為20矩形模版計算上圖A特徵,也可以以座標(0,0)開始寬為22高為22矩形模版計算上圖A特徵,這樣矩形特徵值隨著類別、大小和位置的變化,使得很小的一幅很小的影像含有非常多的矩形特徵。矩形特徵值是矩形模版類別、矩形位置和矩形大小這三個因素的函式。
二、AdaBoost分類器
AdaBoost是典型的Boosting演算法,屬於Boosting家族的一員。在說AdaBoost之前,先說說Boosting提升演算法。
Boosting演算法是將“弱學習演算法“提升為“強學習演算法”的過程,主要思想是“三個臭皮匠頂個諸葛亮”。一般來說,找到弱學習演算法要相對容易一些,然後通過反覆學習得到一系列弱分類器,組合這些弱分類器得到一個強分類器。Boosting演算法要涉及到兩個部分,加法模型和前向分步演算法。加法模型就是說強分類器由一系列弱分類器線性相加而成。一般組合形式如下:
其中,h(x;am) 就是一個個的弱分類器,am是弱分類器學習到的最優引數,βm就是弱學習在強分類器中所佔比重,P是所有am和βm的組合。這些弱分類器線性相加組成強分類器。
前向分步就是說在訓練過程中,下一輪迭代產生的分類器是在上一輪的基礎上訓練得來的。也就是可以寫成這樣的形式:
由於採用的損失函式不同,Boosting演算法也因此有了不同的型別,AdaBoost就是損失函式為指數損失的Boosting演算法。
AdaBoost
原理理解
基於Boosting的理解,對於AdaBoost,我們要搞清楚兩點:
每一次迭代的弱學習h(x;am)有何不一樣,如何學習?
弱分類器權值βm如何確定?
對於第一個問題,AdaBoost改變了訓練資料的權值,也就是樣本的概率分佈,其思想是將關注點放在被錯誤分類的樣本上,減小上一輪被正確分類的樣本權值,提高那些被錯誤分類的樣本權值。然後,再根據所採用的一些基本機器學習演算法進行學習,比如邏輯迴歸。
對於第二個問題,AdaBoost採用加權多數表決的方法,加大分類誤差率小的弱分類器的權重,減小分類誤差率大的弱分類器的權重。這個很好理解,正確率高分得好的弱分類器在強分類器中當然應該有較大的發言權。
例項解釋
為了加深理解,我們來舉一個例子。
有如下的訓練樣本,我們需要構建強分類器對其進行分類。x是特徵,y是標籤。
序號 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
y | 1 | 1 | 1 | -1 | -1 | -1 | 1 | 1 | 1 | -1 |
令權值分佈D1=(w1,1,w1,2,…,w1,10)
並假設一開始的權值分佈是均勻分佈:w1,i=0.1,i=1,2,…,10
現在開始訓練第一個弱分類器。我們發現閾值取2.5時分類誤差率最低,得到弱分類器為:
當然,也可以用別的弱分類器,只要誤差率最低即可。這裡為了方便,用了分段函式。得到了分類誤差率e1=0.3。
第二步計算(G1(x)在強分類器中的係數
這個公式先放在這裡,下面再做推導。
第三步更新樣本的權值分佈,用於下一輪迭代訓練。由公式:
得到新的權值分佈,從各0.1變成了:
D2=(0.0715,0.0715,0.0715,0.0715,0.0715,0.0715,0.1666,0.1666,0.1666,0.0715)
可以看出,被分類正確的樣本權值減小了,被錯誤分類的樣本權值提高了。
第四步得到第一輪迭代的強分類器:
以此類推,經過第二輪……第N輪,迭代多次直至得到最終的強分類器。迭代範圍可以自己定義,比如限定收斂閾值,分類誤差率小於某一個值就停止迭代,比如限定迭代次數,迭代1000次停止。這裡資料簡單,在第3輪迭代時,得到強分類器:
的分類誤差率為0,結束迭代。
F(x)=sign(F3(x))就是最終的強分類器。
演算法流程
總結一下,得到AdaBoost的演算法流程:
輸入:訓練資料集
其中,
迭代次數M
1. 初始化訓練樣本的權值分佈:
2.對於m=1,2,…,M
(a)使用具有權值分佈Dm的訓練資料集進行學習,得到弱分類器Gm(x)
(b)計算Gm(x)在訓練資料集上的分類誤差率:
(c)計算Gm(x)在強分類器中所佔的權重:
(d)更新訓練資料集的權值分佈(這裡,zm是歸一化因子,為了使樣本的概率分佈和為1):
3.得到最終分類器:
公式推導
現在我們來搞清楚上述公式是怎麼來的。
假設已經經過m−1輪迭代,得到Fm−1(x),根據前向分步,我們可以得到:
我們已經知道AdaBoost是採用指數損失,由此可以得到損失函式:
這時候,Fm−1(x)是已知的,可以作為常量移到前面去:
其中,
敲黑板!這個就是每輪迭代的樣本權重!依賴於前一輪的迭代重分配。
是不是覺得還不夠像?那就再化簡一下:
現在夠像了吧?ok,我們繼續化簡Loss:
公式變形之後,炒雞激動!
這個不就是分類誤差率em嗎???!重寫一下,
Ok,這樣我們就得到了化簡之後的損失函式。接下來就是求導了。
對αm求偏導,令
得到:
AdaBoost分析原文連結:https://www.cnblogs.com/ScorpioLu/p/8295990.html
三、例項
detectMultiScale()
引數
- InputArray image,待檢測圖片,一般為灰度影像加快檢測速度;
- std::vector< Rect > & objects,被檢測物體的矩形框向量組;為輸出量,如人臉檢測矩陣Mat
- double scaleFactor,表示在前後兩次相繼的掃描中,搜尋視窗的比例係數。預設為1.1即每次搜尋視窗依次擴大10%;一般設定為1.1
- int minNeighbors,表示構成檢測目標的相鄰矩形的最小個數(預設為3個)。 如果組成檢測目標的小矩形的個數和小於 min_neighbors – 1 都會被排除。
如果min_neighbors 為 0, 則函式不做任何操作就返回所有的被檢候選矩形框,
這種設定值一般用在使用者自定義對檢測結果的組合程式上;- int flags,要麼使用預設值,要麼使用CV_HAAR_DO_CANNY_PRUNING,如果設定為CV_HAAR_DO_CANNY_PRUNING,那麼函式將會使用Canny邊緣檢測來排除邊緣過多或過少的區域,因此這些區域通常不會是人臉所在區域;
- Size minSize,最小尺寸,用來限制得到的目標區域的範圍。
- Size maxSize,最大尺寸,用來限制得到的目標區域的範圍。
import cv2
import numpy as np
face_xml = cv2.CascadeClassifier(`haarcascade_frontalface_default.xml`)
eye_xml = cv2.CascadeClassifier(`haarcascade_eye.xml`)
# 載入檔案
# 檔案來源:https://juejin.im/post/5afd25b66fb9a07aa34a775f
img = cv2.imread(`timg.jpg`)
# 載入圖片
cv2.imshow(`src`,img)
# 列印圖片
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 進行灰色處理
faces = face_xml.detectMultiScale(gray,1.3,5)
# 檢測出圖片的人臉
print(`face=`,len(faces))
# 列印檢測出了多少個人臉
for (x,y,w,h) in faces:
# 繪製每一個人臉
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
# 給人臉繪製矩形
roi_face = gray[y:y+h,x:x+w]
roi_color = img[y:y+h,x:x+w]
# 識別人臉
eyes = eye_xml.detectMultiScale(roi_face)
# 識別眼睛
print(`eye=`,len(eyes))
# 列印檢測出了多少個眼睛
for (e_x,e_y,e_w,e_h) in eyes:
cv2.rectangle(roi_color,(e_x,e_y),(e_x+e_w,e_y+e_h),(0,255,0),2)
# 給眼睛繪製矩形
cv2.imshow(`dst`,img)
# 列印繪製後圖片
cv2.waitKey(0)
複製程式碼
原圖:
結果:
face= 4
eye= 2
eye= 2
eye= 1
eye= 2
複製程式碼