上學時候用matlab學過一些圖像處理的基礎知識,當時課程作業是用haar實現人臉檢測
but當時是心思根本不在圖像處理上,so找了個同學幫忙做的,自己沒上心
然鵝天道好輪回,現在撿起來了原來的算法一臉懵逼,自己挖的坑再深也得跳下去啊!

先上一張經典的lena圖鎮場子!
流程圖:
讀取一張圖片→轉灰度圖→人眼/人臉檢測→標識出來→顯示/保存結果
其中,重中之重就是怎樣進行檢測?下面主要講一下openCV中現成的一種算法——Haar
算法詳解請參考https://blog.csdn.net/playezio/article/details/80471000
如果看不懂很正常,這里用到了太多的數學、圖像處理的相關知識,要補的知識點實在是太多太多了!
簡單一句話來說:用一個“特征集”去“滑動”匹配待檢測的圖片,如果圖片中某個部分“符合”要求則會標記出來
特征集是個啥?
可以用openCV里封裝好的,比如人臉的特征集合(具體是什么我也沒有看懂內部算法……)、還有其他的比如eye、body、汽車等等,這些是openCV里已經寫好的,具有普適性可以供大家直接調用;
當然也可以自己建立,比如你想建立一個鼠標的特征集等等,難度較大
滑動?還摩擦摩擦呢……
如果特征集是個10*10的窗口,待檢測圖片是100*100的大小,那么這個小窗口會在圖片上從上到下,從左到右,步長為1(順序和步長不確定,只是推測是這么進行的)進行匹配,這稱為滑動窗口技術(sliding window)
在此條件下,遍歷一張圖片所需要的匹配次數是(100/10*1)*(100/10*1)=100次
“金字塔流程”——不是埃及辣個
如果有個10*10的眼睛的特征集,待檢測圖片是一張100*100的大頭照,一只眼睛的部分可能占了50*50(比例肯定不對,領會一下精神),那么用這個小窗口怎么匹配都匹配不到啊,怎么辦?
把圖片縮小到原來的五分之一或者把特征集擴大到5倍不就好了嘛!
在算法中是一點一點試驗這個縮放倍數的,就如同金字塔橫切面一樣。因此從默認的窗口遍歷一遍不夠,因此最終結果比100次要大的多,這個縮放倍數越小,計算量越大
符合要求?這里不展開講解了,太難!總之一旦符合,就會被標記出來,因此一幅圖中如果只有一張臉,但是周圍可能會有很多標記的方框(滑動窗口技術和金字塔流程共同導致的)以及可能看起來像人臉的部分,如下圖:
(測試結果不是我做的,網上找的)
但是我們想要的結果就是標記出來兩張臉就好了,該合並的就合並,該拋棄的就拋棄(所以說人還是要比機器智能一點的嘛)
首先,一個矩形在圖片中有四個參數(x,y,width,height),即(中心橫坐標、中心縱坐標、半寬、半長),判斷兩個矩形這四個參數的差值,在一定范圍內則可認為這些矩形是“同一個組織”

結果是一幅圖片中可能有不同的組織,每個組織的人數(也就是相似的矩形)不同,保留人數多的組織,拋棄人數少的組織(自定義閾值)。
其中,人數多的組織需要選定一個為代表(在算法里是取平均值),因此結果就是

到此為止,基本檢測的重點就說完了,下面講一下在Python3中怎么結合openCV實現
安裝環境什么的請自行百度吧,需要引用的是cv2模塊,這個模塊里的兩個方法比較重要
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
CascadeClassifier是一種級聯分類器,目前提供的分類器包括Haar分類器和LBP分類器,可選的特征池(xml文件)已經寫好,看名稱大體有:人臉、人眼、身體等等。
我這里存儲的目錄是:D:\Anaconda3\Library\etc,其中有兩個文件夾

本例中使用的是laarcascades下的這兩個xml文件:

選定好特征池后,下面是調用方法detecMultiScale()
faces = face_cascade.detectMultiScale(gray, 1.1, 5)
官方定義:

其中需要注意的幾個參數設置:
scaleFactor : 指定每個圖像縮放比例(也有文檔上說是滑動窗口擴大比例,理論上說后者的運算速度會快一丟丟),有些參考文獻上說是默認為1.1,但是我並沒有找到相關默認參數值。數值越小(但是也需要大於1),遍歷的次數越多,計算時間越長
minNeighbors:應該是“團伙中成員的個數”,(有些參考文獻上說默認是3,同樣我沒找到依據,表明至少有3次重疊檢測,程序才認為目標確實存在)。數值越大,檢測結果理論上會越少,但是過大或過小都會影響准確率,一般取值3~6
flags:對於新的分類器沒有用
minSize和maxSize用來限制得到的目標區域的范圍,后者一般不自行設定
源代碼:
1 import cv2 2 3 def pic_detect(filename): 4 """ 5 靜態圖片人臉、人眼檢測 6 :param filename: <str> 被檢測的圖片路徑 7 :return: None 8 """ 9 # cv2級聯分類器CascadeClassifier.xml文件為訓練數據 10 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#人臉 11 eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')#人眼 12 13 img = cv2.imread(filename) # 讀取圖片 14 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 轉灰度圖 15 faces = face_cascade.detectMultiScale(gray, 1.1, 5, minSize = (5,5))# 進行人臉檢測,調整參數 16 eyes = eye_cascade.detectMultiScale(gray,1.1,5) 17 print('發現了{0}個人的臉呦!'.format(len(faces))) 18 19 # 繪制人臉矩形框 20 for (x, y, w, h) in faces: 21 img = cv2.rectangle(img, (x, y), (x+w, y+h), (0, 250, 0), 1)#中心位置、長寬、畫筆顏色及大小 22 for (ex, ey, ew, eh) in eyes: 23 img = cv2.rectangle(img, (ex, ey), (ex + ew, ey + eh), (250, 0, 0), 1) 24 25 cv2.namedWindow('face_detect')# 命名顯示窗口 26 cv2.imshow('face_detect', img)# 顯示圖片 27 cv2.imwrite(filename+'_result.jpg', img)# 保存圖片 28 cv2.waitKey(0)# 設置顯示時間,0表示一直顯示 29 cv2.destroyAllWindows() 30 return None 31 32 filename = 'kkw.jpg' 33 pic_detect(filename)
結果:

檢測不了或者檢測失誤:
1. 側臉

2. 臉角度偏斜,比如將圖片旋轉90度以后……



3. 戴墨鏡的話可以檢測到人臉,但是眼睛就gg了

4. 不清楚的圖片或者有遮擋的


5. 莫名其妙的亂入……


總結:
1. 調整參數可能會得到不同的結果
2. 總體來說,此方法的對被檢測的圖片要求較高,檢測質量一般
3. 應該算是檢測的一個入門方法,這條路上可優化的地方太多了……研究算法的都是人才啊
