python3+openCV實現圖片的人臉人眼檢測,原理+參數+源代碼


 

 

上學時候用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)

官方定義:

image.png

 
        

其中需要注意的幾個參數設置:

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. 應該算是檢測的一個入門方法,這條路上可優化的地方太多了……研究算法的都是人才啊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM