HAAR與DLib的實時人臉檢測之實現與對比

人臉檢測方法有許多,好比opencv自帶的人臉Haar特徵分類器和dlib人臉檢測方法等。python

對於opencv的人臉檢測方法,優勢是簡單,快速;存在的問題是人臉檢測效果很差。正面/垂直/光線較好的人臉,該方法能夠檢測出來,而側面/歪斜/光線很差的人臉,沒法檢測。所以,該方法不適合現場應用。而對於dlib人臉檢測方法採用64個特徵點檢測,效果會好於opencv的方法識別率會更高,本文會分別採用這幾種方法來實現人臉識別。那個算法更好,跑跑代碼就知道。git

實時圖像捕獲

首先在進行人臉識別以前須要先來學點OpenCV的基礎,起碼知道如何從攝像頭獲取當前拍到的圖像吧。OpenCV其實很簡單,接下來的代碼就是最基本的起步點。算法

第一步:打開本機上的攝像頭,實例化VideoCaptureapi

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而後在命令行直接運行查看效果:app

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方程,而後將其應用於其餘圖片。ide

在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。

參考閱讀

  • HAAR分類器 - 這篇知乎上的文章對HAAR分類器的原理分析得很詳盡,有興趣能夠讀一讀
  • 本文代碼可到個人碼雲上下載
相關文章
相關標籤/搜索