本代码基于 Advance Computer Vision with Python 进行修改,更加适合中国宝宝体质
我的相关代码及数据集已经上传GitHub仓库,欢迎使用 Advance-Computer-Vision-with-Python
Basics.py
import cv2
import mediapipe as mp
import time
# 打开视频文件
cap = cv2.VideoCapture(
"E:\\Advance Computer Vision with Python\\main\\Chapter 3 Face Detection\\Videos\\3.mp4"
)
if not cap.isOpened():
print("Error: Could not open video.")
exit()
pTime = 0
# 初始化 MediaPipe 的绘图工具和面部网格模型
mpDraw = mp.solutions.drawing_utils # 导入 MediaPipe 的绘图工具模块
mpFaceMesh = mp.solutions.face_mesh # 导入 MediaPipe 的面部网格模块,用于检测和处理面部特征点
faceMesh = mpFaceMesh.FaceMesh(max_num_faces=2) # 初始化面部网格模型,设置最多检测两张人脸
drawSpec = mpDraw.DrawingSpec(thickness=1, circle_radius=2) # 创建一个绘图规格对象,用于定义标志点和连接线的绘制样式
# thickness 指定线的厚度,circle_radius 指定标志点的半径
while True:
print("Reading video frame...")
success, img = cap.read()
print("Read success:", success)
if not success:
print("Finished processing video or error occurred.")
break
# 将图像转换为 RGB
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 处理图像以检测面部网格
results = faceMesh.process(imgRGB)
if results.multi_face_landmarks:
for faceLms in results.multi_face_landmarks:
# 绘制面部网格
mpDraw.draw_landmarks(img, faceLms, mpFaceMesh.FACEMESH_TESSELATION, drawSpec, drawSpec)
# mpDraw.draw_landmarks 调用 MediaPipe 的绘图函数,用于在图像上绘制标志点和连接
# img: 要在其上绘制标志点的图像
# faceLms: 检测到的人脸标志点集合
# mpFaceMesh.FACEMESH_TESSELATION: 指定要绘制的连接类型,这里是面部网格的细分连接
# drawSpec: 定义标志点和连接线的绘制样式(如厚度和圆圈半径)
# 后面两个drawSpec,第一个用于定义标志点(关键点)的绘制样式,比如圆圈的半径和颜色,第二个用于定义连接线的绘制样式,比如线的厚度和颜色
# 可以选择分别定义:
# drawSpecPoints = mpDraw.DrawingSpec(color=(0, 255, 0), thickness=1, circle_radius=2) # 绿色
# drawSpecLines = mpDraw.DrawingSpec(color=(255, 0, 0), thickness=1) # 蓝色
# 其中对于drawSpecLines 中定义 circle_radius=2 是没有效果的,circle_radius 只影响标志点(关键点)的绘制,而不会影响连接线的绘制,因此,在 drawSpecLines 中设置 circle_radius 没有意义
for id, lm in enumerate(faceLms.landmark):
# 获取图像的尺寸
ih, iw, ic = img.shape
x, y = int(lm.x * iw), int(lm.y * ih)
# 打印每个标志点的 ID 和坐标
print(id, x, y)
# 计算并显示帧率
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(
img, f"FPS: {int(fps)}", (20, 70), cv2.FONT_HERSHEY_PLAIN, 5, (255, 0, 0), 5
)
cv2.namedWindow("Image", cv2.WINDOW_NORMAL) # 创建可调整大小的窗口
# 显示图像
cv2.imshow("Image", img)
cv2.waitKey(1)
cap.release()
cv2.destroyAllWindows()
FaceMeshModule.py
import cv2
import mediapipe as mp
import time
class FaceMeshDetector:
def __init__(
self, staticMode=False, maxFaces=2, minDetectionCon=0.5, minTrackCon=0.5
):
# 初始化参数
self.staticMode = staticMode # 是否使用静态模式
self.maxFaces = maxFaces # 最大检测人脸数量
self.minDetectionCon = minDetectionCon # 最小检测置信度
self.minTrackCon = minTrackCon # 最小跟踪置信度
# 初始化 MediaPipe 的绘图工具和面部网格模型
self.mpDraw = mp.solutions.drawing_utils # 绘图工具
self.mpFaceMesh = mp.solutions.face_mesh # 面部网格模块
# self.faceMesh = self.mpFaceMesh.FaceMesh(
# self.staticMode, self.maxFaces, self.minDetectionCon, self.minTrackCon
# )
self.faceMesh = self.mpFaceMesh.FaceMesh(
static_image_mode=self.staticMode,
max_num_faces=self.maxFaces,
min_detection_confidence=self.minDetectionCon,
min_tracking_confidence=self.minTrackCon,
)
self.drawSpec = self.mpDraw.DrawingSpec(
thickness=1, circle_radius=2
) # 绘图规格
def findFaceMesh(self, img, draw=True):
# 将图像转换为 RGB
self.imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 处理图像以检测面部网格
self.results = self.faceMesh.process(self.imgRGB)
faces = [] # 存储检测到的面部特征点
if self.results.multi_face_landmarks:
for faceLms in self.results.multi_face_landmarks:
if draw:
# 绘制面部网格
self.mpDraw.draw_landmarks(
img,
faceLms,
self.mpFaceMesh.FACEMESH_TESSELATION,
self.drawSpec,
self.drawSpec,
)
face = [] # 存储单个人脸的特征点
for id, lm in enumerate(faceLms.landmark):
ih, iw, ic = img.shape # 获取图像的高、宽、通道数
x, y = int(lm.x * iw), int(lm.y * ih) # 将归一化坐标转换为像素坐标
face.append([x, y]) # 添加特征点坐标
faces.append(face) # 添加到面部列表
return img, faces # 返回图像和面部特征点
def main():
# 打开视频文件
cap = cv2.VideoCapture(
"E:\\Advance Computer Vision with Python\\main\\Chapter 3 Face Detection\\Videos\\4.mp4"
)
pTime = 0 # 上一帧的时间
detector = FaceMeshDetector(maxFaces=2) # 初始化面部网格检测器
while True:
success, img = cap.read()
if not success:
break
img, faces = detector.findFaceMesh(img) # 检测面部网格
if len(faces) != 0:
print(faces[0]) # 打印第一个面部的特征点
cTime = time.time() # 当前时间
fps = 1 / (cTime - pTime) # 计算帧率
pTime = cTime # 更新上一帧的时间
cv2.putText(
img, f"FPS: {int(fps)}", (20, 70), cv2.FONT_HERSHEY_PLAIN, 3, (0, 255, 0), 3
) # 在图像上显示帧率
cv2.namedWindow("Image", cv2.WINDOW_NORMAL) # 创建可调整大小的窗口
cv2.imshow("Image", img) # 显示图像
cv2.waitKey(1) # 等待键盘输入
if __name__ == "__main__":
main()
mp.solutions.face_mesh
mpFaceMesh = mp.solutions.face_mesh
导入 MediaPipe 的面部网格模块,用于检测和处理面部特征点
faceMesh = mpFaceMesh.FaceMesh(max_num_faces=2)
初始化面部网格模型,设置最多检测两张人脸
results = faceMesh.process(imgRGB)
处理图像以检测面部网格
mpFaceMesh.FaceMesh()
类的参数有:self.staticMode, self.maxFaces, self.minDetectionCon, self.minTrackCon
- staticMode:是否将每帧图像作为静态图像处理。如果为 True,每帧都会进行人脸检测;如果为 False,在检测到人脸后进行跟踪,速度更快
- maxFaces:要检测的最大人脸数量
- minDetectionCon:检测的最小置信度阈值。低于此值的人脸将被忽略
- minTrackCon:跟踪的最小置信度阈值。低于此值的跟踪将被忽略
mp.solutions.drawing_utils
mpDraw = mp.solutions.drawing_utils
导入 MediaPipe 的绘图工具模块
drawSpec = mpDraw.DrawingSpec(thickness=1, circle_radius=2)
创建一个绘图规格对象,用于定义标志点和连接线的绘制样式,thickness 指定线的厚度,circle_radius 指定标志点的半径
mpDraw.draw_landmarks(img, faceLms, mpFaceMesh.FACEMESH_TESSELATION, drawSpec, drawSpec)
mpDraw.draw_landmarks 调用 MediaPipe 的绘图函数,用于在图像上绘制标志点和连接
- img: 要在其上绘制标志点的图像
- faceLms: 检测到的人脸标志点集合
- mpFaceMesh.FACEMESH_TESSELATION: 指定要绘制的连接类型,这里是面部网格的细分连接
- drawSpec: 定义标志点和连接线的绘制样式(如厚度和圆圈半径),后面两个drawSpec,第一个用于定义标志点(关键点)的绘制样式,比如圆圈的半径和颜色,第二个用于定义连接线的绘制样式,比如线的厚度和颜色
源代码的小问题
这些bug直接运行是不会报错的,只有调试的时候才会报错
1、有个参数在新版本换名字了
原来:
现在: