人臉檢測方法有許多,比如opencv自帶的人臉Haar特征分類器和dlib人臉檢測方法等。
對於opencv的人臉檢測方法,優點是簡單,快速;存在的問題是人臉檢測效果不好。正面/垂直/光線較好的人臉,該方法可以檢測出來,而側面/歪斜/光線不好的人臉,無法檢測。因此,該方法不適合現場應用。而對於dlib人臉檢測方法采用64個特征點檢測,效果會好於opencv的方法識別率會更高,本文會分別采用這幾種方法來實現人臉識別。那個算法更好,跑跑代碼就知道。
實時圖像捕獲
首先在進行人臉識別之前需要先來學點OpenCV的基礎,起碼知道如何從攝像頭獲取當前拍到的圖像吧。OpenCV其實很簡單,接下來的代碼就是最基本的起步點。
第一步:打開本機上的攝像頭,實例化VideoCapture
類
camera = cv2.VideoCapture(0)
開始第一幀圖像的捕獲,這個方法用來測試當前的攝像頭是否可用
success, frame = camera.read()
當success
返回真時表示開始捕捉圖像,反則表示攝像頭打開失敗,接下來就用最少的代碼來打開攝像頭並將當前的圖像直接顯示到一個窗口上,具體代碼結構如下:
# coding=utf-8
# ~/learn_face/cv_base.py
from __future__ import print_function
import cv2
cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()
while success and cv2.waitKey(1) == -1:
success, frame = cameraCapture.read()
#TODO:在此處可放置各種對當前每一幀圖像的處理
cv2.imshow("Camera", frame)
cameraCapture.release()
cv2.destroyAllWindows()
將上述代碼存為opencv_base.py
然后在命令行直接運行查看效果:
python opencv_base.py
效果如下:
HAAR 分類器
基於Haar特征的cascade分類器(classifiers) 是Paul Viola和 Michael Jone在2001年,論文”Rapid Object Detection using a Boosted Cascade of Simple Features”中提出的一種有效的物品檢測(object detect)方法。它是一種機器學習方法,通過許多正負樣例中訓練得到cascade方程,然后將其應用於其他圖片。
在OpenCV3的源碼的data
目錄中就可以找到已訓練好的HAAR算法模型,至HAAR算法的各種細節與理論有興趣的直接去Google或者百度吧,一搜一大堆。花時間看一堆理論不如直接上代碼,由代碼直接理解這些復雜理論的應用更適合開發人員,畢竟我們不是數學家。
使用HAAR模型識別圖像中的人臉其實只要三步走,即使你對深度網絡一點不懂也沒關系,再復雜的理論到最終不過是一個方法調用罷了,了解清楚其中的原理就好。
第一步:初始化分類器並載入已訓練好的HARR模型:
face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml')
第二步: 通過cv2.cvtColor
方法將當前的圖像進行灰度化處理,簡化圖像的信息:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
第三步:然后將灰度化后的圖像輸入到分類器進行預判:
faces = face_cascade.detectMultiScale(gray, 1.3, 5) #識別人臉
只要faces
數組的長度大於一就表示檢測到當前畫面中檢測到人臉,反之亦然。簡單來說其實人臉檢測已經完成,
最后,為了我們可以知道識別出來的結果,我們可以將臉用方框給圈出來,這里寫個方法來圈臉:
def mark_face(img,x,y,w,h):
return cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
以下為本例的全部代碼:
# coding=utf-8
# ~/learn_face/cv_haar.py
from __future__ import print_function
import cv2
def mark_face(img, x, y, w, h):
return cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()
face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml') # 1.載入模型
while success and cv2.waitKey(1) == -1:
success, frame = cameraCapture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 2.生成灰度圖
faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5
) # 3.進行識別
[mark_face(frame, *args) for args in faces] #畫出識別的結果
cv2.imshow("Camera", frame)
cameraCapture.release()
cv2.destroyAllWindows()
以下是運行效果:
運行起來就會覺得HAAR的識別效果不怎么樣,稍微動一下就很會識別不了。
Dlib
接下來我們試試用DLib這個老牌的專做人臉識別起家的C++庫來試試,Dlib是一個跨平台的C++公共庫,除了線程支持,網絡支持,提供測試以及大量工具等等優點,Dlib還是一個強大的機器學習的C++庫,包含了許多機器學習常用的算法。同時支持大量的數值算法如矩陣、大整數、隨機數運算等等。Dlib同時還包含了大量的圖形模型算法。最重要的是Dlib的文檔和例子都非常詳細。
與HAAR分類器的檢測方法相比dLib就簡單得多了,只需要用dlib自帶的人臉檢測器detector
就夠了,連模型都省了!之前的代碼兩步就能完成
第一步:實例化 detector
:
detector = dlib.get_frontal_face_detector()
第二步:進行人臉檢測
faces = detector(frame, 1)
That's all! 是不是很簡單?
以下是本例的全部代碼:
# coding=utf-8
# ~/learn_face/cv_dlib.py
from __future__ import print_function
import cv2
import dlib
cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()
detector = dlib.get_frontal_face_detector()
while success and cv2.waitKey(1) == -1:
success, frame = cameraCapture.read()
faces = detector(frame, 1)
for k, d in enumerate(faces):
frame = cv2.rectangle(frame, (d.left(), d.top()),
(d.right(), d.bottom()), (255, 0, 0), 2)
cv2.imshow("Camera", frame)
cameraCapture.release()
cv2.destroyAllWindows()
運行上述代碼后會發現dlib的效果真的比HAAR的檢測效果要好很多!不管頭怎么轉都能瞬間識別到,畫出來的矩形框都不帶閃的!
特征點檢測
接下來我們用DLib的特征點提取器detector
所識別出來的人臉輪廓點給標記出來。關鍵點(landmarks)提取需要一個特征提取器predictor
,為了構建特征提取器,預訓練模型必不可少。除了自行進行訓練外,可以使用官方提供的一個模型。該模型可從dlib sourceforge 庫下載,此模型是從人臉中提出64個特征點進行檢測,其准確度相當高。
具體實現思路如下:
- 第一步:生成灰度圖
- 第二步:生成直方圖
- 第三步:進行檢測
以下為全部代碼
# coding=utf-8
# ~/learn_face/landmark.py
import cv2
import dlib
cameraCapture = cv2.VideoCapture(0)
success, frame = cameraCapture.read()
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(
"shape_predictor_68_face_landmarks.dat")
while success and cv2.waitKey(1) == -1:
success, frame = cameraCapture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #生成灰度圖
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) #生成直方圖
clahe_image = clahe.apply(gray)
detections = detector(clahe_image, 1)
for k, d in enumerate(detections):
shape = predictor(clahe_image, d) # 獲取坐標
for i in range(1, 68): # 每張臉都有68個識別點
cv2.circle(frame, (shape.part(i).x, shape.part(i).y), 1, (0, 0, 255),
thickness=2)
cv2.imshow("Camera", frame)
cameraCapture.release()
cv2.destroyAllWindows()
運行效果:
小結
我在macBookPro上跑以上的代碼在速度是上沒有什么很大區別的,至少不會產生卡頓。但如果換將代碼植到樹莓3和樹莓Zero上區別就明顯了,HAAR分類器在樹梅Zero上的運行時間平均在1.2s左右,而dlib則需要8s。至於准確率Dlib又明顯會優於HAAR。