Haar特徵描述算子--人臉檢測
學習目標:
- 理解Haar-like特徵
- 理解積分圖的計算方法
- 理解使用積分圖來計算Haar特徵值算法
- 理解Haar特徵歸一化算法
- 學會使用OpenCV自帶的Haar分類器進行人臉檢測
1 算法理論介紹
1.1 Haar-like 特徵
haar特徵分爲三類:邊緣特徵、線性特徵、中心特徵和對角線特徵,組合成特徵模板。特徵模板內有白色和黑色兩種矩形,並定義該模板的特徵值爲白色矩形像素和減去黑色矩形像素和。Haar特徵值反映了圖像的灰度變化情況。
Eg:臉部的一些特徵能由矩形特徵簡單的描述:眼睛要比臉頰顏色要深,鼻樑兩側要比鼻樑顏色要深。但矩形特徵只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述特定走向(水平、垂直、對角)的結構。
對於圖中的A,B和D類這類特徵,特徵數值計算公式爲:v=Σ白-Σ黑,而對於C來說,計算公式如下:v=Σ白-2*Σ黑;之所以將黑色區域像素和乘以2,是爲了使兩種矩形區域中像素數目一致。我們希望當把矩形放到人臉區域計算出來的特徵值和放到非人臉區域計算出來的特徵值差別越大越好,這樣就可以用來區分人臉和非人臉。
通過改變特徵模板的大小和位置,可在圖像子窗口中窮舉出大量的特徵。上圖的特徵模板稱爲“特徵原型”;特徵原型在圖像子窗口中擴展(平移伸縮)得到的特徵稱爲“矩形特徵”;矩形特徵的值稱爲“特徵值”。
**解釋:**兩個矩形特徵,表示出人臉的某些特徵。比如中間一幅表示眼睛區域的顏色比臉頰區域的顏色深,右邊一幅表示鼻樑兩側比鼻樑的顏色要深。
矩形特徵值是矩形模版類別、矩形位置和矩形大小這三個因素的函數。因此類別、大小和位置的變化,使得很小的檢測窗口含有非常多的矩形特徵。例如:在24*24像素大小的檢測窗口內矩形特徵數量可以達到16萬個。
這樣就有兩個問題需要解決:
- 如何快速計算那麼多特徵?—積分圖大顯神通
- 那些矩形特徵纔是對分類器分來是最有效的?----通過AdaBoost算法來訓練。
1.2 Haar-like特徵的計算–積分圖
積分圖就是隻遍歷一次圖像就可以求出圖像中所有區域像素和的快速算法,大大的提高了圖像特徵值計算的效率。
1.2.1 積分圖主要思想
是將圖像從起點開始到各個點所形成的矩形區域像素之和作爲一個數組的元素保存在內存中,當要計算某個區域的像素和時可以直接索引數組的元素,不用重新計算這個區域的像素和,從而加快了計算(這有個相應的稱呼,叫做動態規劃算法)。
1.2.2 積分圖構造算法
積分圖是一種能夠描述全局信息的矩陣表示方法。積分圖的構造方式是:位置(i,j)處的值ii(i,j)是原圖像(i,j)左上角方向所有像素f(k,l)的和: ,其中i(x,y)表示像素點(x,y)的積分圖,i(x,y)表示原始圖像。
構建算法步驟:
1.3 案列—計算Haar特徵值
一個區域的像素值的和,可以由該區域的端點的積分圖來計算。
由前面特徵模板的特徵值的定義可以推出,矩形特徵的特徵值可以由特徵端點的積分圖計算出來。以A矩形特徵爲例,如下圖,使用積分圖計算其特徵值:
該矩形特徵的特徵值,由定義可知爲區域A的像素值減去區域B的像素值。
區域A的像素值:ii(5)-ii(2)-ii(4)+ii(1),就是相當於多減去ii(1)一次
區域B的像素值:ii(6))-ii(5)-ii(3)+ii(2,相當於多減去ii(2)一次
1.4 特徵值歸一化
發現僅僅一個128大小的Haar特徵計算出的特徵值變化範圍從-2000~+6000,跨度非常大。這種跨度大的特性不利於量化評定特徵值,所以需要進行“歸一化”,壓縮特徵值範圍。
歸一化方法:
- 計算檢測窗口中圖像的灰度值和灰度值平方和:
- 計算平均值:
- 計算歸一化因子:
- 歸一化特徵值:
1.5 Adaboost級聯分類器
2 python代碼實現
導入這裏XML文件,就是OpenCV自帶的檢測器。
import cv2
import numpy as np
haar_front_face_xml = './data/haarcascade_frontalface_default.xml'
haar_eye_xml = './data/haarcascade_eye.xml'
2.1 靜態圖像中的人臉檢測
# 1.靜態圖像中的人臉檢測
def StaticDetect(filename):
# 創建一個級聯分類器 加載一個 .xml 分類器文件. 它既可以是Haar特徵也可以是LBP特徵的分類器.
face_cascade = cv2.CascadeClassifier(haar_front_face_xml)
# 加載圖像
img = cv2.imread(filename)
# 轉換爲灰度圖
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 進行人臉檢測,傳入scaleFactor:1.3,minNegihbors:5,分別表示人臉檢測過程中每次迭代時圖像的壓縮率以及
每個人臉矩形保留近似數目的最小值,返回人臉矩陣數組
faces = face_cascade.detectMultiScale(gray_img, 1.3, 5)
for (x, y, w, h) in faces:
# 在原圖像上繪製矩形
img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.namedWindow('Face Detected!')
cv2.imshow('Face Detected!', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
##2.2 視頻中的人臉檢測
在視頻幀上重複進行這個過程就能完成視頻中的人臉檢測。DynamicDetect函數主要包括:打開攝像頭、讀取幀、檢測人臉、掃描檢測到的人臉中的眼睛,並使用不同顏色繪製出矩形框。
def DynamicDetect():
'''
打開攝像頭,讀取幀,檢測幀中的人臉,掃描檢測到的人臉中的眼睛,對人臉繪製藍色的矩形框,對人眼繪製綠色的矩形框
'''
# 創建一個級聯分類器 加載一個 .xml 分類器文件. 它既可以是Haar特徵也可以是LBP特徵的分類器.
face_cascade = cv2.CascadeClassifier(haar_front_face_xml)
eye_cascade = cv2.CascadeClassifier(haar_eye_xml)
# 打開攝像頭
camera = cv2.VideoCapture(0)
cv2.namedWindow('Dynamic')
while True:
# 讀取一幀圖像
ret, frame = camera.read()
# 判斷圖片讀取成功?
if ret:
gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 人臉檢測
faces = face_cascade.detectMultiScale(gray_img, 1.3, 5)
for (x, y, w, h) in faces:
# 在原圖像上繪製矩形
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
roi_gray = gray_img[y:y + h, x:x + w]
# 眼睛檢測
eyes = eye_cascade.detectMultiScale(roi_gray, 1.03, 5, 0, (40, 40))
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(frame, (ex + x, ey + y), (x + ex + ew, y + ey + eh), (0, 255, 0), 2)
cv2.imshow('Dynamic', frame)
# 如果按下q鍵則退出
if cv2.waitKey(100) & 0xff == ord('q'):
break
camera.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
filename = 'test1.jpg'
StaticDetect(filename)
# DynamicDetect()
總結一下detectMultiScale函數:
detectMultiScale(image[,scaleFactor[,minNeighbors[,flags[,minSize[,maxSize]]]]])
- image:表示的是要檢測的輸入圖像
- scaleFactor:爲每一個圖像尺度中的尺度參數,默認值爲1.1。scaleFactor參數可以決定兩個不同大小的窗口掃描之間有多大的跳躍,這個參數設置的大,則意味着計算會變快,但如果窗口錯過了某個大小的人臉,則可能丟失物體。
- minNeighbors:參數爲每一個級聯矩形應該保留的鄰近個數,默認爲3。minNeighbors控制着誤檢測,默認值爲3表明至少有3次重疊檢測,我們才認爲人臉確實存。
- flags:對於新的分類器沒有用(但目前的haar分類器都是舊版的,CV_HAAR_DO_CANNY_PRUNING,這個值告訴分類器跳過平滑(無邊緣區域)。利用Canny邊緣檢測器來排除一些邊緣很少或者很多的圖像區域;* CV_HAAR_SCALE_IMAGE,這個值告訴分類器不要縮放分類器。而是縮放圖像(處理好內存和緩存的使用問題,這可以提高性能。)就是按比例正常檢測;CV_HAAR_FIND_BIGGEST_OBJECTS,告訴分類器只返回最大的目標(這樣返回的物體個數只可能是0或1)只檢測最大的物,CV_HAAR_DO_ROUGH_SEARCH,他只可與CV_HAAR_FIND_BIGGEST_OBJECTS一起使用,這個標誌告訴分類器在任何窗口,只要第一個候選者被發現則結束尋找(當然需要足夠的相鄰的區域來說明真正找到了。),只做初略檢測.
- minSize:爲目標的最小尺寸
- maxSize:爲目標的最大尺寸