OpenCV实现人脸关键点检测

目录

实现过程

1,代码解读

1.1 导入工具包

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

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*2coords = 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 imageoverlay = 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):# 对人脸框进行关键点定位# 转换成ndarrayshape = 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=250r = 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,结果展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/105044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决Win10电脑无线网卡的移动热点无法开启问题

一、目的 利用无线网卡连接网络,然后又用无线网卡通过移动热点分享该网络。 移动热点,简单地说,就是将台式机或笔记本的 Internet 连接转化成 WIFI 信号以供移动设备无线上网的功能,硬件前提是电脑须安装有无线网卡。 二、问题 …

torch.hub.load报错urllib.error.HTTPError: HTTP Error 403: rate limit exceeded

在运行DINOv2的示例代码时,需要载入预训练的模型,比如: backbone_model torch.hub.load(repo_or_dir"facebookresearch/dinov2", modelbackbone_name) torch.hub.load报错“urllib.error.HTTPError: HTTP Error 403: rate limit…

重拾技术写作,勿忘初心

说说这一年的学习经历 关于我 我来自湖南省的一所专科院校,非科班;当前已经是大二了。后年就要专升本了,不由的感叹,这时间为什么会这么快? 其实我早在大一上下学期就学完了以下知识点:C语言 、基础数据结…

Linux- 自定义一个ARP请求

自定义一个ARP请求或响应&#xff0c;并使用AF_PACKET套接字发送&#xff0c;需要手动创建整个以太网帧。 下面是一个简单的C代码示例&#xff0c;用于发送一个ARP请求&#xff0c;查询给定IP地址的MAC地址&#xff1a; #include <stdio.h> #include <stdlib.h> …

530. 二叉搜索树的最小绝对差

给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 题解&#xff1a;使用中序遍历来实现 代码如下&#xff1a; public int getMinimumDifference(TreeNode root) {int pre …

利用Python提取将Excel/PDF文件数据

使用Python来创建一个接口&#xff0c;用于接收Excel文件资源链接&#xff0c;下载文件并执行指定的操作&#xff0c;然后返回处理后的数据。以下是一个基本的示例&#xff0c;展示如何使用Flask来创建这样的接口。请注意&#xff0c;这是一个简化的示例&#xff0c;您可能需要…

JVM第三讲:JVM 基础-字节码的增强技术详解

JVM 基础-字节码的增强技术详解 本文是JVM第三讲&#xff0c;JVM 基础-字节码的增强技术。在上文中&#xff0c;着重介绍了字节码的结构&#xff0c;这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术…

人大金仓分析型数据库COPY装载数据

目录 文件装载 STDIN装载 \copy装载数据 输入格式 错误隔离 优化性能 COPY FROM将文件或标准输入中的数据复制到表中&#xff0c;并将数据附加到表内容中。 COPY是非并行的&#xff1a;使用master实例在单个进程中加载数据。建议仅对非常小的数据文件使用COPY。主机上的后…

Stable Diffusion 动画animatediff-cli-prompt-travel

基于 sd-webui-animatediff 生成动画或者动态图的基础功能,animatediff-cli-prompt-travel突破了部分限制,能让视频生成的时间更长,并且能加入controlnet和提示词信息控制每个片段,并不像之前 sd-webui-animatediff 的一套关键词控制全部画面。 动图太大传不上来,凑合看每…

python 并发请求,转发

python 并发请求&#xff0c;转发 http://t.csdnimg.cn/snSm5 另外&#xff1a;如果想要随机入参&#xff0c;可以参考加入随机数 #codingutf-8 import requests import json import threading import time import uuid import random class postrequests(): def init(self):…

css 块元素、行内元素、行内块元素相互转换

在HTML和CSS中&#xff0c;元素可以分为三类&#xff1a;块级元素&#xff08;Block-level Elements&#xff09;、内联元素&#xff08;Inline Elements&#xff09;和内联块级元素&#xff08;Inline-block Elements&#xff09;。 块级元素&#xff08;Block-level Elements…

10月14日,每日信息差

今天是2023年10月14日&#xff0c;以下是为您准备的8条信息差 第一、中国石油摘得日本碳信用实货交易首单。据了解&#xff0c;日本交易所集团旗下的东京证券交易所11日宣布&#xff0c;交易二氧化碳排放量的“碳信用市场”正式开始运营 第二、前三季度全国铁路投产新线1402公…

【C++】哈希对unordered_map和unodered_set的封装

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; C学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最大…

Paddle build_cinn_pass_test源码阅读(fluid目录下)

代码位置在 paddle\fluid\framework\paddle2cinn\build_cinn_pass_test.cc &#xff0c;因为paddle CINN和PIR部分依旧在高频更新&#xff0c;所以各位看到的可能和我的不一样 inline bool CheckNodeExisted(const std::unordered_set<Node*>& nodes,const std::str…

Godot 单元测试

前言 单元测试是我们常用的功能&#xff0c;Godot作为一个游戏&#xff0c;单元测试和热重载是我们常用的功能。这里我们讲解最简单的单元测试的情况。 Godot 配置 我们添加一个最简单的节点&#xff0c;挂载一个最简单的脚本。 添加测试方法&#xff08;只能是静态方法&…

【Python】Python语言基础(中)

第十章 Python的数据类型 基本数据类型 数字 整数 整数就是整数 浮点数 在编程中&#xff0c;小数都称之为浮点数 浮点数的精度问题 print(0.1 0.2) --------------- 0.30000000000000004 ​​1.可以通过round()函数来控制小数点后位数 round(a b)&#xff0c;则表示…

Linux该如何学习,给你支招

如果你已经确定对 Linux 产生了兴趣&#xff0c;那么接下来我们介绍一下学习 Linux 的方法。这只是自己关于学习Linux的建议。 一、如何去学习 学习大多类似庖丁解牛&#xff0c;对事物的认识一般都是由浅入深、由表及里的过程&#xff0c;循序才能渐进。学习 Linux 同样要有一…

关于RNNoise、webrtc_ns、三角带通滤波器、对数能量

语音特征参数MFCC提取过程详解 其中讲解了&#xff1a;三角带通滤波器 、计算每个滤波器组输出的对数能量、对数能量、经离散余弦变换&#xff08;DCT&#xff09;得到MFCC系数 推荐阅读某乎这位大佬的全部文章&#xff1a; 下面是几篇出自这位大佬的很好的文章&#xff1a; …

SSH 基础学习使用

什么是SSH 1.SSH SSH&#xff08;Secure Shell&#xff09; 是较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议&#xff0c;利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。 实际应用中&#xff0c;主要用于保证远程登录和远程通信的安全&#…

微信小程序入门讲解【超详细】

一. 微信小程序简介 1.1 什么是小程序 2017年度百度百科十大热词之一 微信小程序&#xff08;wei xin xiao cheng xu&#xff09;&#xff0c;简称小程序&#xff0c;英文名Mini Program&#xff0c;是一种不需要下载安装即可使用的应用( 张小龙对其的定义是无需安装&#xf…