OpenCV实现人脸关键点检测
该代码实现了基于dlib的面部关键点检测和可视化。以下是核心内容的摘要:
导入工具包:包括collections.OrderedDict、numpy、argparse、dlib和cv2用于处理数据、解析参数、图像处理和关键点检测。
参数解析:使用argparse解析命令行参数,包括面部关键点预测器的路径和输入图像路径。
预处理:读取输入图像并调整尺寸,保持高宽比例不变。将图像转换为灰度图像以便于后续处理。
人脸检测:使用dlib的getfrontalface_detector检测灰度图像中的脸部。
关键点定位:对检测到的每个脸部区域使用shape_predictor定位关键点,并将dlib的关键点对象转换为NumPy数组以便处理。
关键点可视化:在图像上绘制关键点,使用不同颜色标记不同面部部位,并提取并调整ROI区域。
结果展示:通过cv2.imshow显示关键点和ROI区域的可视化结果。
代码通过这些步骤实现了从输入图像到关键点检测和可视化的完整流程。
目录
实现过程
1,代码解读
1.1 导入工具包
1.2导入所需图像,以及训练好的人脸预测模型
1.3 将 dlib 的关键点对象转换为 NumPy 数组,以便后续处理
1.4图像上可视化面部关键点
1.5# 读取输入数据,预处理
1.6进行人脸检测
1.7遍历检测到的框
1.8遍历每个面部
2,所有代码
3,结果展示
实现过程
导入工具包**:首先导入必要的Python库,包括dlib库以实现人脸检测和关键点定位功能,同时导入OpenCV库以处理图像数据。
参数解析:通过argparse库解析命令行参数,用于指定面部关键点预测器的路径以及输入图像的路径。
明确关键点范围:明确了两个字典(FACIAL_LANDMARKS_68_IDXS和FACIAL_LANDMARKS_5_IDXS),它们涵盖了不同面部部位的关键点索引范围,用于标识人脸的不同部位。
图像预处理步骤包括:首先读取输入图像,随后调整其尺寸至指定宽度(500像素),并进行灰度化处理。这些预处理操作有助于提升性能和增强稳定性。
人脸检测方案:基于dlib库的 facial detection engine is employed to analyze grayscale images for face localization.该方案输出的检测结果为一组包含人脸边界框的坐标信息。
对所有检测到的人脸进行遍历处理:通过面部关键点定位器获取每个面部关键点的坐标,然后依次对各个面部区域进行处理。
标记关键点 :代码采用OpenCV技术,用于可视化显示。每个关键点以红色圆圈的形式绘制在图像上,同时标注了各个部位的名称,以清晰展示人体结构。
识别感兴趣区域:代码在每个部位上识别了一个感兴趣区域(ROI),这是基于计算关键点的包围矩形的。该区域随后可用于进一步的分析或显示。
调整ROI尺寸:代码对ROI区域的尺寸进行了优化设置,以确保其宽度统一为250像素,同时保持高宽比例不变。
1,代码解读
1.1 导入工具包
该库专为生成有序字典而设计。
该库主要用于进行数值运算。
该模块主要用于管理终端输入参数。
该库为图像处理提供工具,主要用于进行人脸检测和关键点定位。
该库为OpenCV的图像处理功能提供支持。
1.2导入和加载所需图像数据,同时导入并加载训练好的人脸识别模型模型
参数
ap.add_argument("-p", "--shape-predictor", required=True, help="该程序需要指定面部关键点预测器的路径")
ap.add_argument("-i", "--image", required=True, help="该程序需要指定输入图像的路径")
1.3 将 dlib 的关键点对象转换为 NumPy 数组,以便后续处理
该函数[()旨在将dlib的关键点对象转换为NumPy数组,以便后续处理。该函数通过遍历关键点对象中的每一个点,获取其x坐标和y坐标,并将这些坐标存储到NumPy数组中。具体而言,函数首先初始化一个形状为(68,2)的二维数组,其中68代表关键点对象的总数量。随后,函数遍历每一个关键点,使用循环结构获取每个关键点的x和y坐标,并将其赋值到数组的相应位置。最终,函数返回包含所有关键点坐标的NumPy数组。
代码实现如下:
def shape_to_np(shape, dtype="int"):
# 初始化一个形状为(68,2)的二维数组
coords = np.zeros((shape.num_parts, 2), dtype=dtype)
# 遍历每一个关键点
# 获取其x坐标和y坐标
for i in range(0, shape.num_parts):
coords[i] = (shape.part(i).x, shape.part(i).y)
# 返回所有坐标
return coords
1.4图像上可视化面部关键点
该函数用于展示面部关键点在图像中的位置。它接受输入图像、关键点坐标、可选颜色和透明度参数。首先,函数在输入图像上绘制关键点,可以为不同面部部位指定不同的颜色。接着,通过混合原图像和叠加图像,生成最终输出图像。代码实现中,函数首先创建两个图像副本,分别用于绘制关键点和生成最终输出。如果未提供颜色参数,则默认使用特定的颜色集合。然后,函数遍历每一个面部区域,根据预定义的索引列表获取关键点坐标。对于“脸部”区域,函数使用线条连接关键点;而对于其他区域,则计算凸包并填充颜色。最后,通过加权叠加原图和叠加图像,生成最终输出图像并返回。
1.5# 读取输入数据,预处理
image = cv2.imread(args["image"])
(h, w) = image.shape[:2]
指定目标宽度为500像素。
计算出新的缩放比例 r = width / float(w)
创建了一个新的图像维度 dim,该维度由目标宽度 width 和计算出的新高度组成。
新高度的计算公式为 h * r,并取整数部分。
使用OpenCV的 cv2.resize 函数,将原始图像调整为指定的维度 dim,采用 cv2.INTER_AREA 插值方法以实现图像缩小。
将原始图像调整为指定的尺寸后,执行颜色空间转换,将图像从BGR格式转换为灰度格式。
1.6进行人脸检测
1 是一个可选参数,用于调节的人脸检测强度。
当设置为 1 时,通常会对图像进行粗略的人脸检测。
通过调整该参数,您还可以获得更灵敏或更宽松的人脸检测效果。
rects = detector(gray, 1)
1.7遍历检测到的框
遍历每一张人脸框rect,通过关键点检测技术定位每一张人脸框的位置。随后,将灰度图像转换为NumPy数组,利用预训练的形状预测器predictor,根据当前灰度图像gray和单个人脸框rect生成形状描述符。接着,将预测得到的形状信息转换为可操作的NumPy数组表示。
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,结果展示





