Opencv项目实战:基于dlib的人脸关键点检测

一、项目简介

该项目基于dlib模块提供的人脸检测器以及关键点定位工具完成。首先通过检测器在图像中定位人脸的位置,然后通过关键点定位工具提取脸部关键点坐标,最后绘制脸部特征点。

二、环境配置

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)

猜你喜欢

转载自blog.csdn.net/shinuone/article/details/130958271