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

该文详细介绍了如何利用dlib库在Python中实现人脸检测和68个关键点定位,包括从dlib官网获取预训练模型,通过get_frontal_face_detector()检测人脸,使用shape_predictor_68_face_landmarks.dat文件定位脸部关键点,以及在图像和摄像头视频流上进行实时演示的方法。
摘要由CSDN通过智能技术生成

一、项目简介

该项目基于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)

四、项目实战(摄像头获取帧图像)

  • 【参数配置】方式一:Pycharm + Terminal + 输入指令自动检测:python detect_face_parts.py --shape-predictor shape_predictor_68_face_landmarks.dat
  • 【参数配置】方式二:Pycharm + 点击Edit Configuration,输入配置参数--shape-predictor shape_predictor_68_face_landmarks.dat,点击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)参数配置
    # 		【参数1】面部地标预测器路径: shape_predictor_68_face_landmarks.dat
    shape_predictor_path = "shape_predictor_68_face_landmarks.dat"

    # (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))])
    ###################################################################################################################
    # (1)先检测人脸,然后定位脸部的关键点。优点: 与直接在图像中定位关键点相比,准确度更高。
    detector = dlib.get_frontal_face_detector()  # 1.1、基于dlib的人脸检测器
    predictor = dlib.shape_predictor(shape_predictor_path)  # 1.2、基于dlib的关键点定位(68个关键点)

    # (2)图像预处理
    cap = cv2.VideoCapture(0)  # 创建视频捕获对象,参数为摄像头索引号(一般为0)

    while True:
        ret, frame = cap.read()  # 读取摄像头的图像帧
        if not ret:
            break

        # 图像预处理
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 2.3、灰度图

        # 人脸检测
        rects = detector(gray, 1)  # 若有多个目标,则返回多个人脸框

        # 遍历检测得到的【人脸框 + 关键点】
        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 = frame.copy()
                cv2.putText(clone, name, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

                # 遍历当前脸部位置的所有关键点坐标(i-j)
                for (x, y) in shape[i:j]:
                    cv2.circle(clone, (x, y), 1, (0, 0, 255), -1)

                # 可视化脸部位置
                output = visualize_facial_landmarks(frame, shape)
                cv2.imshow("Output", output)
                cv2.imshow("Image", clone)

        # 按下Esc键退出
        if cv2.waitKey(1) == 27:
            break

    cap.release()  # 释放视频捕获对象
    cv2.destroyAllWindows()  # 关闭所有窗口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖墩会武术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值