OpenCV实现人脸关键点检测

目录

实现过程

1,代码解读

[1.1 导入工具包](#1.1 导入工具包)

1.2导入所需图像,以及训练好的人脸预测模型

[1.3 将 dlib 的关键点对象转换为 NumPy 数组,以便后续处理](#1.3 将 dlib 的关键点对象转换为 NumPy 数组,以便后续处理)

1.4图像上可视化面部关键点

[1.5# 读取输入数据,预处理](# 读取输入数据,预处理)

1.6进行人脸检测

1.7遍历检测到的框

1.8遍历每个面部

2,所有代码

3,结果展示


实现过程

  1. 导入工具包:首先导入所需的Python库,包括dlib用于人脸检测和关键点定位,以及OpenCV用于图像处理。

  2. 参数解析:使用argparse库解析命令行参数,以指定面部关键点预测器的路径和输入图像的路径。

  3. 定义关键点范围:定义了两个字典(FACIAL_LANDMARKS_68_IDXS和FACIAL_LANDMARKS_5_IDXS),它们包含了不同面部部位的关键点索引范围,用于标识人脸的不同部分。

  4. 图像预处理:加载输入图像,将其缩放为指定宽度(500像素),并将其转换为灰度图像。这些预处理步骤有助于提高人脸检测的性能和稳定性。

  5. 人脸检测:使用dlib库的人脸检测器检测灰度图像中的人脸。检测结果是一个包含人脸边界框的列表。

  6. 遍历检测到的人脸:对于每个检测到的人脸,使用面部关键点定位器获取关键点的坐标。然后,对不同的面部部位进行循环处理。

  7. 绘制关键点:为了可视化,代码使用OpenCV在图像上绘制关键点。每个关键点以红色圆圈的形式标记在图像上,并标注了各个部位的名称。

  8. 提取ROI区域:在每个部位上,代码还提取了一个感兴趣区域(ROI),这是通过计算关键点的包围矩形来实现的。ROI区域随后可以用于进一步的分析或显示。

  9. 调整ROI尺寸:最后,代码调整了ROI区域的尺寸,以确保它们具有一致的宽度(250像素),同时保持高宽比例不变。

1,代码解读

1.1 导入工具包

  • collections.OrderedDict: 用于创建有序的字典。
  • numpy: 用于处理数值计算。
  • argparse: 用于处理命令行参数。
  • dlib: 一个图像处理库,用于人脸检测和关键点定位。
  • cv2 (OpenCV): 用于图像处理。

1.2导入所需图像,以及训练好的人脸预测模型

参数

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")

1.3 将 dlib 的关键点对象转换为 NumPy 数组,以便后续处理

'''这个函数用于将 dlib 的关键点对象转换为 NumPy 数组,以便后续处理。

它遍历关键点对象中的每个点,提取其 x 和 y 坐标,然后将坐标保存在 NumPy 数组中。'''

def shape_to_np(shape, dtype="int"):

创建68*2

coords = np.zeros((shape.num_parts, 2), dtype=dtype)

遍历每一个关键点

得到坐标

for i in range(0, shape.num_parts):

coords[i] = (shape.part(i).x, shape.part(i).y)

return coords

1.4图像上可视化面部关键点

这个函数用于在图像上可视化面部关键点。

它接受输入图像、关键点坐标、可选颜色和透明度参数。

在输入图像上绘制关键点,可以为不同面部部位指定不同的颜色。

最后,将可视化的图像与原图像混合以得到输出图像。'''

def visualize_facial_landmarks(image, shape, colors=None, alpha=0.75):

创建两个copy

overlay and one for the final output image

overlay = image.copy()

output = image.copy()

设置一些颜色区域

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)]

遍历每一个区域

for (i, name) in enumerate(FACIAL_LANDMARKS_68_IDXS.keys()):

得到每一个点的坐标

(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)

叠加在原图上,可以指定比例

cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0, output)

return output

1.5# 读取输入数据,预处理

image = cv2.imread(args["image"])

(h, w) = image.shape[:2]

width=500#这一行定义了一个新的宽度,即将图像调整为的目标宽度。

r = width / float(w)

'''这一行创建一个新的图像维度 dim,它是一个元组,包含了目标宽度 width 和一个计算出的新高度。

新高度是原始高度 h 乘以比例 r 并取整数部分'''

dim = (width, int(h * r))

'''最后一行使用OpenCV的 cv2.resize 函数,

将原始图像 image 调整为新的维度 dim,以实现目标宽度为500像素,同时保持高宽比例不变。

interpolation 参数指定了插值方法,这里使用了 cv2.INTER_AREA,它适合缩小图像。'''

image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

1.6进行人脸检测

'''1 是一个可选参数,它控制人脸检测的程度。

通常,值为 1 表示对图像进行一次粗略的检测。

你也可以尝试使用不同的值,以获得更灵敏或更宽松的人脸检测结果'''

rects = detector(gray, 1)

1.7遍历检测到的框

for (i, rect) in enumerate(rects):

对人脸框进行关键点定位

转换成ndarray

shape = predictor(gray, rect)

shape = shape_to_np(shape)

1.8遍历每个面部

遍历每一个部分

#这段代码针对每个面部部位执行一系列操作

for (name, (i, j)) in FACIAL_LANDMARKS_68_IDXS.items():

clone = image.copy() #这一行创建了图像的一个副本 clone,以便在副本上绘制标记,以保持原始图像不受影响。

cv2.putText(clone, name, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,

0.7, (0, 0, 255), 2)

'''

这一行在图像上标记面部部位的名称,使用 OpenCV 的 cv2.putText 函数。

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), 3, (0, 0, 255), -1)

''' 这个循环遍历给定部位的关键点坐标 (x, y),并在 clone 图像上绘制红色的小圆圈,以标记关键点的位置。

(x, y) 是关键点的坐标。

3 是圆圈的半径。

(0, 0, 255) 是红色的颜色。'''

提取ROI区域

(x, y, w, h) = cv2.boundingRect(np.array([shape[i:j]]))

2,所有代码

#导入工具包
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/

# 参数
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())
'''这两个字典包含了不同面部部位的关键点索引范围,用于标识人脸的不同部分,例如嘴巴、眼睛、鼻子等。'''
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))
])
'''这个函数用于将 dlib 的关键点对象转换为 NumPy 数组,以便后续处理。
它遍历关键点对象中的每个点,提取其 x 和 y 坐标,然后将坐标保存在 NumPy 数组中。'''
def shape_to_np(shape, dtype="int"):
	# 创建68*2
	coords = np.zeros((shape.num_parts, 2), dtype=dtype)
	# 遍历每一个关键点
	# 得到坐标
	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):
	# 创建两个copy
	# overlay and one for the final output image
	overlay = image.copy()
	output = image.copy()
	# 设置一些颜色区域
	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)]
	# 遍历每一个区域
	for (i, name) in enumerate(FACIAL_LANDMARKS_68_IDXS.keys()):
		# 得到每一个点的坐标
		(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)
	# 叠加在原图上,可以指定比例
	cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0, output)
	return output

# 加载人脸检测与关键点定位
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(args["shape_predictor"])

# 读取输入数据,预处理
image = cv2.imread(args["image"])
(h, w) = image.shape[:2]
width=500#这一行定义了一个新的宽度,即将图像调整为的目标宽度。
r = width / float(w)
'''这一行创建一个新的图像维度 dim,它是一个元组,包含了目标宽度 width 和一个计算出的新高度。
新高度是原始高度 h 乘以比例 r 并取整数部分'''
dim = (width, int(h * r))
'''最后一行使用OpenCV的 cv2.resize 函数,
将原始图像 image 调整为新的维度 dim,以实现目标宽度为500像素,同时保持高宽比例不变。
interpolation 参数指定了插值方法,这里使用了 cv2.INTER_AREA,它适合缩小图像。'''
image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 人脸检测
'''1 是一个可选参数,它控制人脸检测的程度。
通常,值为 1 表示对图像进行一次粗略的检测。
你也可以尝试使用不同的值,以获得更灵敏或更宽松的人脸检测结果'''
rects = detector(gray, 1)

# 遍历检测到的框
for (i, rect) in enumerate(rects):
	# 对人脸框进行关键点定位
	# 转换成ndarray
	shape = predictor(gray, rect)
	shape = shape_to_np(shape)

	# 遍历每一个部分
	#这段代码针对每个面部部位执行一系列操作
	for (name, (i, j)) in FACIAL_LANDMARKS_68_IDXS.items():
		clone = image.copy() #这一行创建了图像的一个副本 clone,以便在副本上绘制标记,以保持原始图像不受影响。
		cv2.putText(clone, name, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
			0.7, (0, 0, 255), 2)
		'''
		    这一行在图像上标记面部部位的名称,使用 OpenCV 的 cv2.putText 函数。
    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), 3, (0, 0, 255), -1)
			'''    这个循环遍历给定部位的关键点坐标 (x, y),并在 clone 图像上绘制红色的小圆圈,以标记关键点的位置。
    (x, y) 是关键点的坐标。
    3 是圆圈的半径。
    (0, 0, 255) 是红色的颜色。'''

		# 提取ROI区域
		(x, y, w, h) = cv2.boundingRect(np.array([shape[i:j]]))
		
		roi = image[y:y + h, x:x + w]
		(h, w) = roi.shape[:2]
		width=250
		r = width / float(w)
		dim = (width, int(h * r))
		roi = cv2.resize(roi, dim, interpolation=cv2.INTER_AREA)
		
		# 显示每一部分
		cv2.imshow("ROI", roi)
		cv2.imshow("Image", clone)
		cv2.waitKey(0)

	# 展示所有区域
	output = visualize_facial_landmarks(image, shape)
	cv2.imshow("Image", output)
	cv2.waitKey(0)

3,结果展示

相关推荐
panpantt3213 分钟前
【参会邀请】第二届大数据与数据挖掘国际会议(BDDM 2024)邀您相聚江城!
大数据·人工智能·数据挖掘
lindsayshuo12 分钟前
jetson orin系列开发版安装cuda的gpu版本的opencv
人工智能·opencv
向阳逐梦12 分钟前
ROS机器视觉入门:从基础到人脸识别与目标检测
人工智能·目标检测·计算机视觉
Mr.Q20 分钟前
OpenCV和Qt坐标系不一致问题
qt·opencv
陈鋆38 分钟前
智慧城市初探与解决方案
人工智能·智慧城市
qdprobot38 分钟前
ESP32桌面天气摆件加文心一言AI大模型对话Mixly图形化编程STEAM创客教育
网络·人工智能·百度·文心一言·arduino
QQ395753323739 分钟前
金融量化交易模型的突破与前景分析
人工智能·金融
QQ395753323739 分钟前
金融量化交易:技术突破与模型优化
人工智能·金融
The_Ticker1 小时前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Elastic 中国社区官方博客1 小时前
Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索