OpenCV-Python實戰(15)——面部特征點檢測詳解(僅需5行代碼學會3種面部特征點檢測方法)
- 0. 前言
- 1. 面部特征點簡介
- 2. 使用 OpenCV 檢測面部特征點
- 3. 用 dlib 檢測面部特征點
- 4. 使用 face_recognition 檢測面部特征點
- 小結
- 系列鏈接
0. 前言
人臉處理是人工智能中的一個熱門話題,人臉處理可以使用計算機視覺演算法從人臉中自動提取大量資訊,例如身份、意圖和情感,在計算機視覺中,面部關鍵點(也稱為面部特征點)的定位通常是許多面部分析方法和演算法中的關鍵步驟,例如,面部表情識別、頭部姿態估計和疲倦檢測系統都依賴于面部特征點檢測提供的面部資訊,在本文中,我們將使用 OpenCV、dlib 以及 face_recognition 檢測面部特征點,
1. 面部特征點簡介
面部特征點檢測演算法的目標是自動識別影像或視頻中面部特征點的位置,更具體地說,這些關鍵點是描述面部組件位置(例如,嘴角或眼角)的主要點,或者是連接面部組件和面部輪廓主要點及其插值點,形式上,給定表示為 I 的面部影像,特征點檢測演算法檢測 D 個特征點的位置
x
=
x
1
,
y
1
,
x
2
,
y
2
,
.
.
.
,
x
D
,
y
D
x = {x_1, y_1, x_2, y_2, ..., x_D, y_D}
x=x1?,y1?,x2?,y2?,...,xD?,yD?,其中 x 和 y 表示影像的面部特征點的坐標,
2. 使用 OpenCV 檢測面部特征點
OpenCV 人臉特征點 API 稱為 Facemark,它包括特征點檢測的三種不同實作:
- FacemarkLBF
- FacemarkKamezi
- FacemarkAAM
以下示例展示了如何使用這些演算法檢測面部特征點:
import cv2
import numpy as np
# 加載圖片
image = cv2.imread("example",0)
# 檢測人臉
cas = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
faces = cas.detectMultiScale(image , 1.5, 5)
print("faces", faces)
# 創建特征點檢測器并對其進行測驗
print("testing LBF")
# 第一種面部特征點檢測方法,第一行代碼
# 創建特征點檢測器
facemark = cv2.face.createFacemarkLBF()
# 第一種面部特征點檢測方法,第二行代碼
# 加載檢測器模型
facemark.loadModel("lbfmodel.yaml")
# 第一種面部特征點檢測方法,第三行代碼
# 檢測面部特征點
ok, landmarks = facemark.fit(image , faces)
print ("landmarks LBF", ok, landmarks)
# 測驗其他特征點檢測演算法
print("testing AAM")
facemark = cv2.face.createFacemarkAAM()
facemark .loadModel("aam.xml")
ok, landmarks = facemark.fit(image , faces)
print ("landmarks AAM", ok, landmarks)
print("testing Kazemi")
facemark = cv2.face.createFacemarkKazemi()
facemark .loadModel("face_landmark_model.dat")
ok, landmarks = facemark.fit(image , faces)
print ("landmarks Kazemi", ok, landmarks)
上述示例使用 OpenCV 提供的三種不同演算法來檢測面部特征點,
3. 用 dlib 檢測面部特征點
我們也可以使用 dlib 庫來檢測面部特征點,接下來,我們加載測驗影像,然后使用 dlib 執行人臉檢測,最后使用人臉特征檢測器獲取檢測面部特征點,想要運行以下代碼,首先需要下載檢測面部特征點檢測器檔案 shape_predictor_68_face_landmarks.dat,
# 加載影像并轉換為灰度影像
test_face = cv2.imread("example.png")
gray = cv2.cvtColor(test_face, cv2.COLOR_BGR2GRAY)
# 人臉檢測
detector = dlib.get_frontal_face_detector()
rects = detector(gray, 0)
# 檢測面部特征點
p = "shape_predictor_68_face_landmarks.dat"
# 第二種面部特征點檢測方法,第一行代碼
predictor = dlib.shape_predictor(p)
# 第二種面部特征點檢測方法,第二行代碼
shape = predictor(gray, rect)
shape 是一個 dlib full_object_detection 物件,用于表示影像中物件的位置,接下來需要將其轉換為 numpy 陣列,撰寫 shape_to_np() 函式執行此轉換:
def shape_to_np(dlib_shape, dtype="int"):
# 初始化 (x, y) 坐標串列
coordinates = np.zeros((dlib_shape.num_parts, 2), dtype=dtype)
# 回圈所有面部特征點,并將其轉換為 (x, y) 坐標的元組
for i in range(0, dlib_shape.num_parts):
coordinates[i] = (dlib_shape.part(i).x, dlib_shape.part(i).y)
# 回傳 (x,y) 坐標的串列
return coordinates
最后,在影像中繪制了 68 個面部特征點,我們可以使用靈活的方式以所需的格式在影像中繪制特征點,接下來,介紹集中常用的繪制檢測到的面部特征點的不同方法:
(1) 使用線潭訓制面部特征點形狀,以連接繪制臉部的不同部分的輪廓(例如鼻子、眼睛等):
# 定義不同特征點取值切片
JAWLINE_POINTS = list(range(0, 17))
RIGHT_EYEBROW_POINTS = list(range(17, 22))
LEFT_EYEBROW_POINTS = list(range(22, 27))
NOSE_BRIDGE_POINTS = list(range(27, 31))
LOWER_NOSE_POINTS = list(range(31, 36))
RIGHT_EYE_POINTS = list(range(36, 42))
LEFT_EYE_POINTS = list(range(42, 48))
MOUTH_OUTLINE_POINTS = list(range(48, 61))
MOUTH_INNER_POINTS = list(range(61, 68))
ALL_POINTS = list(range(0, 68))
# 使用線潭訓制面部特征點
def draw_shape_lines_all(np_shape, image):
draw_shape_lines_range(np_shape, image, JAWLINE_POINTS)
draw_shape_lines_range(np_shape, image, RIGHT_EYEBROW_POINTS)
draw_shape_lines_range(np_shape, image, LEFT_EYEBROW_POINTS)
draw_shape_lines_range(np_shape, image, NOSE_BRIDGE_POINTS)
draw_shape_lines_range(np_shape, image, LOWER_NOSE_POINTS)
draw_shape_lines_range(np_shape, image, RIGHT_EYE_POINTS, True)
draw_shape_lines_range(np_shape, image, LEFT_EYE_POINTS, True)
draw_shape_lines_range(np_shape, image, MOUTH_OUTLINE_POINTS, True)
draw_shape_lines_range(np_shape, image, MOUTH_INNER_POINTS, True)
# 連接不同的點來繪制曲線形狀
def draw_shape_lines_range(np_shape, image, range_points, is_closed=False):
np_shape_display = np_shape[range_points]
points = np.array(np_shape_display, dtype=np.int32)
cv2.polylines(image, [points], is_closed, (255, 255, 0), thickness=2, lineType=cv2.LINE_8)
# 函式呼叫
draw_shape_lines_all(shape, test_face)
cv2.imshow("Landmarks detection using dlib", test_face)
cv2.waitKey(0)

(2) 呼叫 draw_shape_lines_range() 函式,可以僅繪制指定面部組件輪廓線,例如下顎線 JAWLINE_POINTS:
draw_shape_lines_range(shape, test_face, JAWLINE_POINTS)

(3) 繪制所有特征點及其位序:
# 繪制指定的特征點
def draw_shape_points_pos_range(np_shape, image, points):
np_shape_display = np_shape[points]
draw_shape_points_pos(np_shape_display, image)
# 使用每個特征點及其位序繪制形狀
def draw_shape_points_pos(np_shape, image):
for idx, (x, y) in enumerate(np_shape):
# 繪制每個檢測到的特征點的位序
cv2.putText(image, str(idx + 1), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255))
# 在每個特征點位置上繪制一個點
cv2.circle(image, (x, y), 2, (0, 255, 0), -1)
# 可以用兩種方法來繪制檢測到的所有特征點及其位序
# 方法1
draw_shape_points_pos(shape, test_face)
# 方法2
draw_shape_points_pos_range(shape, test_face, ALL_POINTS)

(4) 我們也可以僅繪制所有特征點:
# 繪制指定特征點
def draw_shape_points_range(np_shape, image, points):
np_shape_display = np_shape[points]
draw_shape_points(np_shape_display, image)
# 繪制所有特征點
def draw_shape_points(np_shape, image):
for (x, y) in np_shape:
cv2.circle(image, (x, y), 2, (0, 255, 0), -1)
# 可以用兩種方法繪制所有特征點
# 方法1
draw_shape_points(shape, test_face)
# 方法2
draw_shape_points_range(shape, test_face, ALL_POINTS)

(5) 利用上述函式,我們可以僅繪制指定特征點,例如僅繪制眼部和鼻子特征點:
draw_shape_points_pos_range(shape, test_face, LEFT_EYE_POINTS + RIGHT_EYE_POINTS + NOSE_BRIDGE_POINTS)

dlib 還提供了檢測與雙眼和鼻尖位置相對應的 5 個面部特征點檢測器,如果想要使用此檢測器,需要首先下載 shape_predictor_5_face_landmarks.dat,然后加載它:
p = "shape_predictor_5_face_landmarks.dat"
4. 使用 face_recognition 檢測面部特征點
如果想要使用 face_recognition 包檢測和繪制面部特征點,需要呼叫 face_recognition.face_landmarks() 函式:
# 加載影像
image = cv2.imread("example.png")
image_68 = image.copy()
# 將影像從 BGR 顏色轉換為 RGB 顏色
rgb = image[:, :, ::-1]
# 檢測 68 個特征點
# 第三種面部特征點檢測方法,第一行代碼
face_landmarks_list_68 = face_recognition.face_landmarks(rgb)
此函式回傳影像中每張臉的面部特征點(例如,眼睛和鼻子)的字典,如果列印檢測到的特征點,則可以看到輸出如下:
[{'chin': [(113, 251), (111, 283), (115, 315), (122, 346), (136, 376), (154, 402), (177, 425), (203, 442), (231, 447), (260, 442), (285, 426), (306, 403), (323, 377), (334, 347), (340, 315), (343, 282), (343, 251)], 'left_eyebrow': [(123, 223), (140, 211), (163, 208), (185, 211), (206, 220)], 'right_eyebrow': [(240, 221), (263, 212), (288, 209), (312, 211), (332, 223)], 'nose_bridge': [(225, 249), (225, 272), (225, 295), (226, 319)], 'nose_tip': [(201, 337), (213, 340), (226, 343), (239, 339), (252, 336)], 'left_eye': [(144, 248), (158, 239), (175, 240), (188, 254), (173, 255), (156, 254)], 'right_eye': [(262, 254), (276, 240), (293, 239), (308, 248), (295, 254), (278, 255)], 'top_lip': [(185, 377), (200, 370), (216, 364), (226, 367), (238, 364), (255, 370), (274, 377), (267, 378), (238, 378), (227, 380), (215, 379), (192, 378)], 'bottom_lip': [(274, 377), (257, 391), (240, 399), (228, 400), (215, 398), (200, 391), (185, 377), (192, 378), (215, 381), (227, 382), (239, 380), (267, 378)]}]
最后繪制檢測到的特征點:
for face_landmarks in face_landmarks_list_68:
for facial_feature in face_landmarks.keys():
for p in face_landmarks[facial_feature]:
cv2.circle(image_68, p, 2, (255, 255, 0), -1)
face_recognition.face_landmarks() 函式的用法如下:
face_landmarks(face_image, face_locations=None, model="large")
默認情況下會檢測到 68 個特征點,如果 model="small",只會檢測 5 個特征點:
# 檢測 5 個特征點
face_landmarks_list_5 = face_recognition.face_landmarks(rgb, None, "small")
如果列印回傳的結果 face_landmarks_list_5,可以得到以下輸出:
[{'nose_tip': [(227, 343)], 'left_eye': [(145, 248), (191, 253)], 'right_eye': [(307, 248), (262, 252)]}]
在這種情況下,結果字典只包含雙眼和鼻尖的面部特征點位置,
接下來,同樣繪制檢測到的特征點:
for face_landmarks in face_landmarks_list_5:
for facial_feature in face_landmarks.keys():
for p in face_landmarks[facial_feature]:
cv2.circle(image_68, p, 2, (255, 255, 0), -1)
Facemark
在圖中,可以看到使用 face_recognition 包檢測到的 68 個和 5 個面部特征點,
小結
在本文中,介紹了如何使用 OpenCV 的 Facemark API、
dlib 的 shape_predictor() 函式以及 face_recognition 的 face_landmarks() 函式進行面部特征點檢測,
系列鏈接
OpenCV-Python實戰(1)——OpenCV簡介與影像處理基礎
OpenCV-Python實戰(2)——影像與視頻檔案的處理
OpenCV-Python實戰(3)——OpenCV中繪制圖形與文本
OpenCV-Python實戰(4)——OpenCV常見影像處理技術
OpenCV-Python實戰(5)——OpenCV影像運算
OpenCV-Python實戰(6)——OpenCV中的色彩空間和色彩映射
OpenCV-Python實戰(7)——直方圖詳解
OpenCV-Python實戰(8)——直方圖均衡化
OpenCV-Python實戰(9)——OpenCV用于影像分割的閾值技術
OpenCV-Python實戰(10)——OpenCV輪廓檢測
OpenCV-Python實戰(11)——OpenCV輪廓檢測相關應用
OpenCV-Python實戰(12)——一文詳解AR增強現實
OpenCV-Python實戰(13)——OpenCV與機器學習的碰撞
OpenCV-Python實戰(14)——人臉檢測詳解
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/345596.html
標籤:其他
