文章目录
- 一、项目简介
- 二、环境配置
- 2.1、dlib人脸检测器:dlib.get_frontal_face_detector()
- 2.2、dlib关键点定位工具:shape_predictor_68_face_landmarks.dat
- 三、项目实战
一、项目简介
该项目基于dlib模块
提供的人脸检测器
以及关键点定位工具
完成。首先通过检测器在图像中定位人脸的位置,然后通过关键点定位工具提取脸部关键点坐标,最后绘制脸部特征点。
二、环境配置
- dlib是一个c++库,其包含了很多有用的预训练工具。
dlib工具的python API
下载地址:http://dlib.net/python/- dlib库包的介绍与使用:opencv+dlib人脸检测 + 人脸68关键点检测 + 人脸识别 + 人脸特征聚类 + 目标跟踪
2.1、dlib人脸检测器:dlib.get_frontal_face_detector()
dlib官方详细说明:dlib.get_frontal_face_detector()
2.2、dlib关键点定位工具:shape_predictor_68_face_landmarks.dat
dlib官方预训练工具的下载地址:http://dlib.net/files/
(1)5个关键点检测:shape_predictor_5_face_landmarks.dat
。五个点分别为:左右眼 + 鼻子 + 左右嘴角
(2)68个关键点检测:shape_predictor_68_face_landmarks.dat
脸部关键点注释详细请看:https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/
三、项目实战
- 【参数配置】方式一:Pycharm + Terminal + 输入指令自动检测:
python detect_face_parts.py --shape-predictor shape_predictor_68_face_landmarks.dat --image images/1.jpg
- 【参数配置】方式二:Pycharm + 点击Edit Configuration,输入配置参数
--shape-predictor shape_predictor_68_face_landmarks.dat --image images/1.jpg
,点击Run开始检测。
from collections import OrderedDict
import numpy as np
import argparse
import dlib
import cv2
#https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/
#http://dlib.net/files/
def shape_to_np(shape, dtype="int"):
"""获取68个关键点的坐标,并转换为ndarray格式"""
# (1)创建68*2模板。68个关键点坐标(x,y)
coords = np.zeros((shape.num_parts, 2), dtype=dtype)
# (2)遍历每一个关键点, 得到坐标(x,y)
for i in range(0, shape.num_parts):
coords[i] = (shape.part(i).x, shape.part(i).y)
return coords
def visualize_facial_landmarks(image, shape, colors=None, alpha=0.75):
"""可视化脸部位置"""
overlay = image.copy() # 绘制图像
output = image.copy() # 输出图像
# (1)设置七个颜色,分别对应脸部的七个位置
if colors is None:
colors = [(19, 199, 109), (79, 76, 240), (230, 159, 23), (168, 100, 168), (158, 163, 32), (163, 38, 32), (180, 42, 220)]
# (2)遍历每一个区域(七个脸部位置)
for (i, name) in enumerate(FACIAL_LANDMARKS_68_IDXS.keys()):
# 获取当前区域68个关键点的坐标
(j, k) = FACIAL_LANDMARKS_68_IDXS[name]
pts = shape[j:k]
# 检查脸部位置
if name == "jaw": # 下巴使用线条绘制
for l in range(1, len(pts)):
ptA = tuple(pts[l - 1])
ptB = tuple(pts[l])
cv2.line(overlay, ptA, ptB, colors[i], 2) # 绘制线条
else: # 其余位置使用凸包绘制
hull = cv2.convexHull(pts) # 计算凸包
cv2.drawContours(overlay, [hull], -1, colors[i], -1) # 绘制凸包
# (3)图像融合
cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0, output)
return output
if __name__ == '__main__':
###################################################################################################################
# (1)参数配置
ap = argparse.ArgumentParser()
# 【参数1】面部地标预测器路径: shape_predictor_68_face_landmarks.dat
ap.add_argument("-p", "--shape-predictor", required=True, help="path to facial landmark predictor")
# 【参数2】待检测图像的存放路径
ap.add_argument("-i", "--image", required=True, help="path to input image")
args = vars(ap.parse_args())
# (2)68个关键点与5个关键点(嘴 + 右眉毛 + 左眉毛 + 右眼 + 左眼 + 鼻子 + 下巴)
# from collections import OrderedDict 由于字典是无序的,故导入模块使得字典有序。因为需要按指定顺序提取,以识别当前数据。
FACIAL_LANDMARKS_68_IDXS = OrderedDict([("mouth", (48, 68)),
("right_eyebrow", (17, 22)),
("left_eyebrow", (22, 27)),
("right_eye", (36, 42)),
("left_eye", (42, 48)),
("nose", (27, 36)),
("jaw", (0, 17))])
FACIAL_LANDMARKS_5_IDXS = OrderedDict([("right_eye", (2, 3)), ("left_eye", (0, 1)), ("nose", 4)])
###################################################################################################################
# (1)先检测人脸,然后定位脸部的关键点。优点: 与直接在图像中定位关键点相比,准确度更高。
detector = dlib.get_frontal_face_detector() # 1.1、基于dlib的人脸检测器
predictor = dlib.shape_predictor(args["shape_predictor"]) # 1.2、基于dlib的关键点定位(68个关键点)
# (2)图像预处理
image = cv2.imread(args["image"]) # 2.1、读取图像
(h, w) = image.shape[:2] # 获取图像的宽和高
width = 500 # 指定宽度
r = width / float(w) # 计算比例
dim = (width, int(h * r)) # 按比例缩放高度: (宽, 高)
image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA) # 2.2、图像缩放
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 2.3、灰度图
# (3)人脸检测
rects = detector(gray, 1) # 若有多个目标,则返回多个人脸框
# (4)遍历检测得到的【人脸框 + 关键点】
for (i, rect) in enumerate(rects): # rect: 人脸框
shape = predictor(gray, rect) # 4.1、定位脸部的关键点(返回的是一个结构体信息,需要遍历提取坐标)
shape = shape_to_np(shape) # 4.2、遍历shape提取坐标并进行格式转换: ndarray
# 4.3、遍历当前框的所有关键点(name: 脸部位置。i,j表示脸部的坐标。)
for (name, (i, j)) in FACIAL_LANDMARKS_68_IDXS.items():
clone = image.copy()
cv2.putText(clone, name, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) # 在图像的指定位置显示当前脸部位置的名称
# 4.4、根据脸部位置画点(每个脸部由多个关键点组成)
for (x, y) in shape[i:j]:
cv2.circle(clone, (x, y), 3, (0, 0, 255), -1)
# 4.5、提取ROI区域(即截取脸部位置)
(x, y, w, h) = cv2.boundingRect(np.array([shape[i:j]])) # 矩形框得到坐标
roi = image[y:y + h, x:x + w] # 获取ROI区域
(h, w) = roi.shape[:2] # 获取ROI宽和高
width = 250 # 指定宽度
r = width / float(w) # 计算比例
dim = (width, int(h * r)) # 按比例缩放高度: (宽, 高)
roi = cv2.resize(roi, dim, interpolation=cv2.INTER_AREA) # 图像缩放
# 4.6、显示图像
cv2.imshow("ROI", roi) # 将当前脸部位置截取出来
cv2.imshow("Image", clone) # 显示带有关键点特征的图像
cv2.waitKey(0)
# 可视化脸部位置
output = visualize_facial_landmarks(image, shape)
cv2.imshow("Image", output)
cv2.waitKey(0)