使用python,dlib,OpenCV提取眼睛,鼻子,嘴唇及下颌
-
- 1. 效果圖
- 2. 原理
- 3. 源碼
- 參考
上一篇部落格中,我們了解了什麼是面部标志,以及如何使用dlib,OpenCV和Python檢測它們。利用dlib的HOG SVM的形狀預測器獲得面部ROI中面部區域的68個點(x,y)坐标。
這一篇部落格中,将示範如何使用NumPy數組切片魔術來分别通路每個面部部分并提取眼睛,眉毛,鼻子,嘴巴和下巴的特征。
1. 效果圖
先上一張檢測完的圖:
也可以每一部分先辨別出來:
2. 原理
面部标志主要是: 口 右眉 左眉 右眼 左眼 鼻子 下颚線
這一節即提取這些部分;
從圖中可以看到假設是以0為下标的數組:
嘴唇可以認為是: points [48, 68]. 内嘴唇:[60,68]
右眉毛 points [17, 22].
左眉毛 points [22, 27].
右眼 [36, 42].
左眼 [42, 48].
鼻子 [27, 35].
下颌 [0, 17].
已經知道下标,數組切片,并用不同的顔色來辨別各個部位,imutils包,可以幫助我們更優雅的寫代碼的包;已經有封裝好方法face_utils 。
嘴唇等是閉合區域,用閉合的凸包表示,下颌用線勾勒;
面部标志檢測傳回結果是:68個(x,y)坐标:
(1)先轉為适合OpenCV處理的 Numpy array,
(2)數組切片,用不同的顔色辨別不同的面部結構部分;
3. 源碼
# 安裝了dlib
# imutils 是最新的版本
# python detect_face_parts.py --shape-predictor shape_predictor_68_face_landmarks.dat --image images/girl.jpg
from imutils import face_utils
import numpy as np
import argparse
import imutils
import dlib
import cv2
import shutil
import os
# 建構指令行參數
# --shape-predictor 必須 形狀檢測器位置
# --image 必須 待檢測的圖檔
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())
temp_dir = "temp"
shutil.rmtree(temp_dir, ignore_errors=True)
os.makedirs(temp_dir)
# 初始化dlib中基于HOG的面部檢測器,及形狀預測器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(args["shape_predictor"])
# 加載待檢測的圖檔,resize,并且裝換為灰階圖
image = cv2.imread(args["image"])
image = imutils.resize(image, width=500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 在灰階圖中檢測面部
rects = detector(gray, 1)
# 循環檢測到的面部
num = 0
for (i, rect) in enumerate(rects):
# 确定面部區域進行面部标志檢測,并将其檢測到的68個點轉換為友善python處理的Numpy array
shape = predictor(gray, rect)
shape = face_utils.shape_to_np(shape)
# 循環周遊面部标志獨立的每一部分
for (name, (i, j)) in face_utils.FACIAL_LANDMARKS_IDXS.items():
# 複制一張原始圖的拷貝,以便于繪制面部區域,及其名稱
clone = image.copy()
cv2.putText(clone, name, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
0.7, (0, 0, 255), 2)
# 周遊獨立的面部标志的每一部分包含的點,并畫在圖中
for (x, y) in shape[i:j]:
cv2.circle(clone, (x, y), 1, (0, 0, 255), -1)
# 要實際提取每個面部區域,我們隻需要計算與特定區域關聯的(x,y)坐标的邊界框,并使用NumPy數組切片來提取它:
(x, y, w, h) = cv2.boundingRect(np.array([shape[i:j]]))
roi = image[y:y + h, x:x + w]
# resize ROI區域為 寬度250,以便于更好的可視化
roi = imutils.resize(roi, width=250, inter=cv2.INTER_CUBIC)
# 展示獨立的面部标志
cv2.imshow("ROI", roi)
cv2.imshow("Image", clone)
cv2.waitKey(0)
num = num + 1
p = os.path.sep.join([temp_dir, "{}.jpg".format(
str(num).zfill(8))])
print('p: ', p)
cv2.imwrite(p, output)
# 應用visualize_facial_landmarks 功能為每個面部部位建立透明的覆寫層。(transparent overlay)
output = face_utils.visualize_facial_landmarks(image, shape)
cv2.imshow("Image", output)
cv2.waitKey(0)
參考
- https://www.pyimagesearch.com/2017/04/10/detect-eyes-nose-lips-jaw-dlib-opencv-python/