作爲計算機視覺工程師和研究人員,很久以前,我們就一直在努力理解人類的面孔,從很早的時候起。面部分析最明顯的應用是人臉識別。但是爲了能夠識別圖像中的一個人,我們首先需要找到圖像中臉所在的位置。因此,人臉檢測-在圖像中定位人臉並返回包含人臉的邊框矩形/正方形是一個熱門的研究領域。早在2001年,保羅·維奧拉和邁克爾·瓊斯的開創性論文題爲“使用簡單特徵的增強級聯快速目標檢測”,幾乎解決了這個問題。在OpenCV的早期,甚至在某種程度上,OpenCV的殺手應用就是Paul Viola和Michael Jones面部檢測器的一個很好的實現。 一旦你在圖像中確定了臉的包圍框,那麼顯而易見的研究問題就是看你是否能準確地找到不同面部特徵的位置(例如 眼角、眉毛、嘴、鼻尖等)。面部特徵檢測在文獻中也被稱爲“面部地標檢測”、“面部關鍵點檢測”和“面部對齊”,您可以在Google中使用這些關鍵字來尋找關於該主題的其他資料。
面部關鍵點檢測的應用
關鍵點檢測在人臉中有幾個有趣的應用。下面列出其中的幾項。
人臉特徵檢測增強人臉識別
面部地標可以用來將面部圖像對齊到一個平均的面部形狀,這樣對齊後,面部地標在所有圖像中的位置大致相同。直觀地說,用對齊圖像訓練的面部識別算法會表現得更好,這種直接的使用已經被許多研究論文所證實。
頭部姿態估計
一旦你知道了人臉的幾個關鍵點,你也可以估計頭部的姿勢。換句話說,你可以弄清楚頭部在空間中的朝向,或者這個人在看什麼地方。例如本文中描述的CLM-Framework也返回了頭部姿態。
面部調整
面部地標可以用來對齊面部,然後可以變形,將幾張不同的人臉圖像進行融合產生新的人臉圖像。
虛擬美顏
檢測到的地標被用來計算嘴、眼睛等的輪廓,進而渲染化妝。看下圖
面部替換
如果你在兩張臉上提取了面部特徵點,你可以將一張臉與另一張臉對齊,然後無縫地將一張臉克隆到另一張臉上。
人臉特徵檢測庫
因爲有一些高質量的開源軟件庫已經實現了人臉特徵檢測的算法,所以我們最好不要重複造輪子,當然對底層算法感興趣的朋友可以深挖這些開源代碼的實現並嘗試重寫。Dlib和CLM-framework 是最常用的2個人臉特徵檢測庫。
Dlib(C++/Python)
在機器學習、計算機視覺、圖像處理和線性代數中,Dlib包含這幾個領域的多種算法。同時具有c++和python接口。 相對其他任何面部特徵檢測庫我更喜歡Dlib,因爲其代碼非常簡潔,有很好的文檔說明,允許在商業應用程序中免費使用,他們實現的算法非常高效和準確,您可以通過包含頭文件輕鬆集成到C++項目中。
CLM-Framework(C++)
CLM-framework,也被稱爲Cambridge Face Tracker,是一個用於面部關鍵點檢測和頭部姿態估計的C++庫。有兩種重要的原因使Dlib優於CLM-Framework。第一,DLib比CLM-Framework高效得多。第二,Dlib的許可證允許您在商業應用程序中自由使用它。如果我必須選,我會用Dlib。有趣的是,CLM-Framework依賴於Dlib!
接下來,我來做一個具體的實驗來演示。
先看效果:
1個銀兒
2個銀兒
3個銀兒
我們將使用dlib和OpenCV來檢測圖像中的面部特徵點。 面部特徵點被用來定位和表示面部的突出區域,如: 眼睛 眉毛 鼻子 嘴巴 臉頰。
檢測人臉特徵點一般分兩步:
1、定位圖片中的人臉位置
2、檢測人臉的特徵點。
人臉檢測有很多方法可以實現,我們可以使用opencv內建的Haar級聯檢測器,也可以使用HOG + Linear SVM 目標檢測器,當然也可以使用深度學習模型進行人臉檢測。不管使用哪種方法檢測圖像中的人臉位置都無所謂。重要的是能獲取到人臉的包圍框就行。
有很多人臉特徵點檢測器,但所有方法都是用於定位和標記以下面部區域:嘴巴、左眼眉、右眼眉、左眼、右眼、鼻子、下巴。
dlib庫中的人臉特徵點檢測器基於One Millisecond Face Alignment with an Ensemble of Regression Trees(Kazemi and Sullivan (2014))實現的。
理解dlib的人臉特徵點檢測器
dlib庫自帶的預訓練的人臉特徵點檢測器用於獲取臉部的特定區域對應的68(x,y)個座標點。69個座標點的位置如下:
這個68點模型來自於dlib所使用的訓練數據集iBUG 300-W dataset,當然也有其他的訓練數據集,如HELEN dataset,可以在該數據集上訓練194點的人臉特徵點檢測器。
無論使用哪個數據集,都可以利用相同的dlib框架來訓練輸入訓練數據上的特徵檢測器-如果您想訓練面部地標檢測器或自己的自定義形狀預測器,這一點很重要。
接下來我會演示如何提取出人臉特徵點。
使用dlib、opencv、python提取人臉特徵點
看完整代碼:
# USAGE
# python facial_landmarks.py --shape-predictor shape_predictor_68_face_landmarks.dat --image images/example_01.jpg
# import the necessary packages
import numpy as np
import argparse
import imutils
import dlib
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--shape-predictor", required=True,
help="path to facial landmark predictor")
ap.add_argument("-i", "--image", required=True,
help="path to input image")
args = vars(ap.parse_args())
def rect_to_bb(rect):
# take a bounding predicted by dlib and convert it
# to the format (x, y, w, h) as we would normally do
# with OpenCV
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
# return a tuple of (x, y, w, h)
return (x, y, w, h)
def shape_to_np(shape, dtype="int"):
# initialize the list of (x, y)-coordinates
coords = np.zeros((68, 2), dtype=dtype)
# loop over the 68 facial landmarks and convert them
# to a 2-tuple of (x, y)-coordinates
for i in range(0, 68):
coords[i] = (shape.part(i).x, shape.part(i).y)
# return the list of (x, y)-coordinates
return coords
# initialize dlib's face detector (HOG-based) and then create
# the facial landmark predictor
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(args["shape_predictor"])
# load the input image, resize it, and convert it to grayscale
image = cv2.imread(args["image"])
image = imutils.resize(image, width=500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# detect faces in the grayscale image
rects = detector(gray, 1)
# loop over the face detections
for (i, rect) in enumerate(rects):
# determine the facial landmarks for the face region, then
# convert the facial landmark (x, y)-coordinates to a NumPy
# array
shape = predictor(gray, rect)
shape = face_utils.shape_to_np(shape)
# convert dlib's rectangle to a OpenCV-style bounding box
# [i.e., (x, y, w, h)], then draw the face bounding box
(x, y, w, h) = rect_to_bb(rect)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
# show the face number
cv2.putText(image, "Face #{}".format(i + 1), (x - 10, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# loop over the (x, y)-coordinates for the facial landmarks
# and draw them on the image
for (x, y) in shape:
cv2.circle(image, (x, y), 1, (0, 0, 255), -1)
# show the output image with the face detections + facial landmarks
cv2.imshow("Output", image)
cv2.waitKey(0)
先解釋兩個通用功能函數,rect_to_bb和shape_to_np。
rect_to_bb接收一個參數rect,rect是人臉檢測測返回的矩形包圍框,它包括包圍框的坐上角座標和右下角座標,但是opencv中的矩形框表示形式爲 “(x, y, width, height)”,所以該函數將rect轉變爲opencv的格式返回。
人臉特徵檢測器返回一個shape對象,該對象包括68個座標點,使用shape_to_np,我們可以將68個座標點組成一個numpy數組,便於python代碼處理。
接下來分析主流程:
1、導入主要的模塊
2、處理命令行參數:
-
--shape-predictor:這是dlib預訓練的人臉特徵檢測器的路徑。你可在這裏下載here
-
--image:要獲取人臉特徵點的圖像的路徑
3、初始化人臉檢測器和人臉特徵點檢測器。
4、讀取圖片,調整圖片大小,將RGB圖像轉爲灰度圖,檢測人臉。
5、對檢測到的每個人臉矩形框進行人臉特徵點提取。
6、將人臉矩形框畫在圖片上,將68個特徵點畫在圖片上。
你可以用如下命令運行代碼:
ython facial_landmarks.py --shape-predictor shape_predictor_68_face_landmarks.dat --image images/example_01.jp
結果:
參考鏈接:https://www.learnopencv.com/facial-landmark-detection/
參考鏈接:https://www.pyimagesearch.com/2017/04/03/facial-landmarks-dlib-opencv-python/
一個有趣的應用:https://www.auduno.com/clmtrackr/examples/facesubstitution.html