Opencv project combat: face key point detection based on dlib

1. Project introduction

This project is based on dlib模块supplied 人脸检测器as well as 关键点定位工具completed. First, locate the position of the face in the image through the detector, then extract the coordinates of the key points of the face through the key point positioning tool, and finally draw the facial feature points.

2. Environment configuration

2.1, dlib face detector: dlib.get_frontal_face_detector()

dlib official detailed description: dlib.get_frontal_face_detector()

2.2. dlib key point positioning tool: shape_predictor_68_face_landmarks.dat

Download address of dlib official pre-training tool: http://dlib.net/files/
(1) 5 key point detection: shape_predictor_5_face_landmarks.dat. The five points are: left and right eyes + nose + left and right mouth corners
(2) 68 key points detection:shape_predictor_68_face_landmarks.dat

Annotation of facial key pointsFor details, please see: https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/
insert image description here

3. Project actual combat

  • [Parameter configuration] Method 1: Pycharm + Terminal + input command automatic detection:python detect_face_parts.py --shape-predictor shape_predictor_68_face_landmarks.dat --image images/1.jpg
  • [Parameter Configuration] Method 2: Pycharm + click Edit Configuration, enter configuration parameters --shape-predictor shape_predictor_68_face_landmarks.dat --image images/1.jpg, and click Run to start detection.

insert image description here

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)

Guess you like

Origin blog.csdn.net/shinuone/article/details/130958271