基于 YOLO V8 Pose Fine-Tuning 训练 15 点人脸关键点检测模型

一、YOLO V8 Pose

YOLO V8 在上篇文章中进了简单的介绍,并基于YOLO V8 Fine-Tuning 训练了自定义的目标检测模型,而YOLO V8 Pose 是建立在YOLO V8基础上的关键点检测模型,本文基于 yolov8n-pose 模型实验 Fine-Tuning 训练15 点人脸关键点检测模型,并配合上篇文章训练的人脸检测模型一起使用。

上篇文章地址:

基于 YOLO V8 Fine-Tuning 训练自定义的目标检测模型

YOLO V8 的细节可以参考下面官方的介绍:

https://docs.ultralytics.com/zh/models/yolov8/#citations-and-acknowledgements

本文依旧使用 ultralytics 框架进行训练和测试,其中 ultralyticspytorch 的版本如下:

torch==1.13.1+cu116
ultralytics==8.1.37

YOLO V8 Pose 调用示例如下:

测试图像:
在这里插入图片描述

这里使用 yolov8n-pose 模型,如果模型不存在会自动下载:

from ultralytics import YOLO
# Load a model
model = YOLO('yolov8n-pose.pt')  # pretrained YOLOv8n modelresults = model.predict('./img/1.png')
# Show results
results[0].show()

在这里插入图片描述

二、人脸关键点检测数据集

在计算机视觉人脸计算领域,人脸关键点检测是一个十分重要的区域,可以实现例如一些人脸矫正、表情分析、姿态分析、人脸识别、人脸美颜等方向。

人脸关键点数据集通常有 5点、15点、68点、96点、98点、106点、186点 等,例如通用 Dlib 中的 68 点检测,它将人脸关键点分为脸部关键点和轮廓关键点,脸部关键点包含眉毛、眼睛、鼻子、嘴巴共计51个关键点,轮廓关键点包含17个关键点。

在这里插入图片描述

本文基于 kaggleFacial Keypoints Detection 中的数据集进行实践,该数据集包含包括7,049幅训练图像,图像是 96 x 96像素的灰度图像,其中关键点有 15个点,注意数据集有的字段缺失,如果去除字段缺失的数据,实际训练数据只有 2,140 幅训练图像,还包括1,783张测试图片,数据集的效果如下所示:

在这里插入图片描述
可以看出,关键点包括眉毛的两端、眼睛的中心和两端、鼻子尖、嘴巴两端和上下嘴唇的中间。

下载数据集

数据集在 kaggle 的官方网址上:

https://www.kaggle.com/c/facial-keypoints-detection

下载前需要进行登录,如果没有 kaggle 账号可以注册一个。

在这里插入图片描述

下载解压后,可以看到 training.ziptest.zip 两个文件,分别对应训练集和测试集,解压后数据是以 CSV 的格式进行存放的:

在这里插入图片描述
其中 training.csv 中的字段分别表示:

序号字段含义
0left_eye_center_x左眼中心 x 点
1left_eye_center_y左眼中心 y 点
2right_eye_center_x右眼中心 x 点
3right_eye_center_y右眼中心 y 点
4left_eye_inner_corner_x左眼内端 x 点
5left_eye_inner_corner_y左眼内端 y 点
6left_eye_outer_corner_x左眼外端 x 点
7left_eye_outer_corner_y左眼外端 y 点
8right_eye_inner_corner_x右眼内端 x 点
9right_eye_inner_corner_y右眼内端 y 点
10right_eye_outer_corner_x右眼外端 x 点
11right_eye_outer_corner_y右眼外端 y 点
12left_eyebrow_inner_end_x左眉毛内端 x 点
13left_eyebrow_inner_end_y左眉毛内端 y 点
14left_eyebrow_outer_end_x左眉毛外端 x 点
15left_eyebrow_outer_end_y左眉毛外端 y 点
16right_eyebrow_inner_end_x右眉毛内端 x 点
17right_eyebrow_inner_end_y右眉毛内端 y 点
18right_eyebrow_outer_end_x右眉毛外端 x 点
19right_eyebrow_outer_end_y右眉毛外端 y 点
20nose_tip_x鼻尖中心 x 点
21nose_tip_y鼻尖中心 y 点
22mouth_left_corner_x嘴巴左端 x 点
23mouth_left_corner_y嘴巴左端 y 点
24mouth_right_corner_x嘴巴右端 x 点
25mouth_right_corner_y嘴巴右端 y 点
26mouth_center_top_lip_x上嘴唇中心 x 点
27mouth_center_top_lip_y上嘴唇中心 y 点
28mouth_center_bottom_lip_x下嘴唇中心 x 点
29mouth_center_bottom_lip_y下嘴唇中心 y 点
30Image图形像素

由于数据是存放在CSV中,可以借助 pandas 工具对数据进行解析,如果没有安装 pandas 工具,可以通过下面指令安装:

pip3 install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple

下面程序通过 pandas 解析 CSV 文件,并将图片转为 numpy 数组,通过 matplotlib 可视化工具查看,其中具体的解释都写在了注释中:

import numpy as np
import pandas as pd
import matplotlib.pyplot as pltdef main():csv_path = './data/training.csv'# 读取 CSV 文件train_df = pd.read_csv(csv_path)# 查看数据框,并列出数据集的头部。train_df.info()# 丢弃有缺失数据的样本train_df = train_df.dropna()# 获取图片信息,并转为 numpy 结构x_train = train_df['Image'].apply(lambda img: np.fromstring(img, sep=' '))x_train = np.vstack(x_train)# 重新修改形状x_train = x_train.reshape((-1, 96, 96, 1))# 去除最后一列的 Imagecols = train_df.columns[:-1]y_train = train_df[cols].valuesprint('训练集 shape: ', x_train.shape)print('训练集label shape: ', y_train.shape)plt.figure(figsize=(10, 10))for p in range(2):data = x_train[(p * 9):(p * 9 + 9)]label = y_train[(p * 9):(p * 9 + 9)]plt.clf()for i in range(9):plt.subplot(3, 3, i + 1)img = data[i].reshape(96, 96, 1)plt.imshow(img, cmap='gray')# 画关键点l = label[i]# 从 1 开始,每次走 2 步,j-1,j 就是当前点的坐标for j in range(1, 31, 2):plt.plot(l[j - 1], l[j], 'ro', markersize=4)plt.show()if __name__ == '__main__':main()

运行之后,可以看到如下效果图:

在这里插入图片描述
下面我们基于该数据集进行建模,训练一个自己的关键点检测模型。

三、数据集拆分和转换

数据集格式需要转换成 Ultralytics 官方的 YOLO 格式,主要包括以下几点的注意:

  • 每幅图像一个文本文件:数据集中的每幅图像都有一个相应的文本文件,文件名与图像文件相同,扩展名为".txt"。
  • 每个对象一行:文本文件中的每一行对应图像中的一个对象实例。
  • 每行对象信息:每行包含对象实例的以下信息
    • 对象类别索引:代表对象类别的整数(如 0 代表人,1 代表汽车等)。
    • 对象中心坐标:对象中心的 xy 坐标,归一化后介于 01 之间。
    • 对象宽度和高度:对象的宽度和高度,标准化后介于 01 之间。
    • 对象关键点坐标:对象的关键点,归一化为 01

姿势估计任务的标签格式示例:

<class-index> <x> <y> <width> <height> <px1> <py1> <px2> <py2> ... <pxn> <pyn>

官方的介绍:

https://docs.ultralytics.com/zh/datasets/pose/#ultralytics-yolo-format

这里由于数据集中仅包含人脸信息,没有其他因素影响,因此,<class-index> <x> <y> <width> <height> 我们可以固定写死为:0 0.5 0.5 1 1 ,转换和拆分的逻辑如下:

import os
import shutil
from tqdm import tqdm
import numpy as np
import pandas as pd
from PIL import Image# training.csv 地址
csv_path = "./data/training.csv"
# 训练集的比例
training_ratio = 0.8
# 拆分后数据的位置
train_dir = "train_data"def toRgbImg(img):img = np.fromstring(img, sep=' ').astype(np.uint8).reshape(96, 96)img = Image.fromarray(img).convert('RGB')return imgdef split_data():# 训练集目录os.makedirs(os.path.join(train_dir, "images/train"), exist_ok=True)os.makedirs(os.path.join(train_dir, "labels/train"), exist_ok=True)# 验证集目录os.makedirs(os.path.join(train_dir, "images/val"), exist_ok=True)os.makedirs(os.path.join(train_dir, "labels/val"), exist_ok=True)# 读取数据train_df = pd.read_csv(csv_path)# 丢弃有缺失数据的样本train_df = train_df.dropna()# 获取图片信息,并转为 numpy 结构x_train = train_df['Image'].apply(toRgbImg)# 去除最后一列的 Image, 将y值缩放到[0,1]区间cols = train_df.columns[:-1]y_train = train_df[cols].values# 使用 80% 的数据训练,20% 的数据进行验证size = int(x_train.shape[0] * 0.8)x_val = x_train[size:]y_val = y_train[size:]x_train = x_train[:size]y_train = y_train[:size]trains = []vals = []# 生成训练数据for i, image in tqdm(enumerate(x_train), total=len(x_train)):label = y_train[i]image_file = os.path.join(train_dir, f"images/train/{i}.jpg")label_file = os.path.join(train_dir, f"labels/train/{i}.txt")image.save(image_file)trains.append(image_file)width, height = image.sizeyolo_label = ["0", "0.5", "0.5", "1", "1"]for i, v in enumerate(label):if i % 2 == 0:yolo_label.append(str(v / float(width)))else:yolo_label.append(str(v / float(height)))with open(label_file, "w", encoding="utf-8") as w:w.write(" ".join(yolo_label))# 生成验证数据for i, image in tqdm(enumerate(x_val), total=len(x_val)):label = y_val[i]image_file = os.path.join(train_dir, f"images/val/{i}.jpg")label_file = os.path.join(train_dir, f"labels/val/{i}.txt")image.save(image_file)vals.append(image_file)width, height = image.sizeyolo_label = ["0", "0.5", "0.5", "1", "1"]for i, v in enumerate(label):if i % 2 == 0:yolo_label.append(str(v / float(width)))else:yolo_label.append(str(v / float(height)))with open(label_file, "w", encoding="utf-8") as w:w.write(" ".join(yolo_label))with open(os.path.join(train_dir, "train.txt"), "w") as file:file.write("\n".join([image_file for image_file in trains]))print("save train.txt success!")with open(os.path.join(train_dir, "val.txt"), "w") as file:file.write("\n".join([image_file for image_file in vals]))print("save val.txt success!")if __name__ == '__main__':split_data()

运行后,可以在 train_data 下面看到拆分后的数据:
在这里插入图片描述

四、训练

使用 ultralytics 框架训练非常简单,仅需三行代码即可完成训练,不过在训练前需要编写 YAML 配置信息,主要标记数据集的位置。

创建 face.yaml 文件,写入下面内容:

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: D:/pyProject/yolov8/face/train_data  # dataset root dir
train: images/train  # train images (relative to 'path') 4 images
val: images/val  # val images (relative to 'path') 4 images
test:  # test images (optional)# Keypoints
kpt_shape: [15, 2]  # number of keypoints, number of dims (2 for x,y or 3 for x,y,visible)# Classes dictionary
names:0: person

开始训练:

from ultralytics import YOLO# 加载模型
model = YOLO('yolov8n-pose.pt')# 训练
model.train(data='face.yaml', # 训练配置文件epochs=50, # 训练的周期imgsz=640, # 图像的大小device=[0], # 设备,如果是 cpu 则是 device='cpu'workers=0,lr0=0.001, # 学习率batch=8, # 批次大小amp=False # 是否启用混合精度训练
)

运行后可以看到打印的网络结构:

在这里插入图片描述

训练中:

在这里插入图片描述
训练结束后可以在 runs 目录下面看到训练的结果:

在这里插入图片描述

看下训练时 loss 的变化图:

在这里插入图片描述

三、模型预测

首先使用测试集进行测试:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image
from ultralytics import YOLOdef toRgbImg(img):img = np.fromstring(img, sep=' ').astype(np.uint8)img = Image.fromarray(img).convert('RGB')return imgdef main():csv_path = 'data/test.csv'# 读取 CSV 文件test_df = pd.read_csv(csv_path)# 查看数据框,并列出数据集的头部。test_df.info()# 获取图片信息,并转为 numpy 结构test_df = test_df['Image'].apply(toRgbImg)test_df = np.vstack(test_df)# 重新修改形状test_df = test_df.reshape((-1, 96, 96, 3))# 加载模型model = YOLO('runs/pose/train/weights/best.pt')plt.figure(figsize=(10, 10))for p in range(5):data = test_df[(p * 9):(p * 9 + 9)]plt.clf()for i in range(9):plt.subplot(3, 3, i + 1)img = data[i]plt.imshow(img, cmap='gray')results = model.predict(img, device='cpu')# 画关键点keypoints = results[0].keypoints.xyfor keypoint in keypoints:for xy in keypoint:plt.plot(xy[0], xy[1], 'ro', markersize=4)plt.show()if __name__ == '__main__':main()

在这里插入图片描述

在这里插入图片描述

可以看到对于鼻子位置的关键点有些会出现偏差。

四、结合上篇的人脸检测模型

from ultralytics import YOLO
from PIL import Image
from matplotlib import pyplot as pltdef main():# 加载人脸检测模型detection_model = YOLO('yolov8_face_detection.pt')# 加载人脸关键点检测模型point_model = YOLO('runs/pose/train/weights/best.pt')image = plt.imread('./img/10.jpg')# 预测results = detection_model.predict(image, device='cpu')boxes = results[0].boxes.xyxyprint(boxes)ax = plt.gca()for boxe in boxes:x1, y1, x2, y2 = boxe[0], boxe[1], boxe[2], boxe[3]ax.add_patch(plt.Rectangle((x1, y1), (x2 - x1), (y2 - y1), fill=False, color='red'))# 截取图片crop = image[int(y1):int(y2), int(x1):int(x2)]results = point_model.predict(crop, device='cpu')keypoints = results[0].keypoints.xyfor keypoint in keypoints:for xy in keypoint:plt.plot(xy[0]+ x1, xy[1]+ y1, 'ro', markersize=2)plt.imshow(image)plt.show()if __name__ == '__main__':main()

测试效果:

在这里插入图片描述

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

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

相关文章

我的C++奇迹之旅:值和引用的本质效率与性能比较

文章目录 &#x1f4dd;引用&#x1f320;引用概念&#x1f309;引用特性 &#x1f320;使用场景&#x1f309;做参数&#xff08;传值与传地址&#xff09;&#x1f309;传值、传引用效率比较 &#x1f320;引用做返回值&#x1f309;引用和指针的区别 &#x1f320;常引用&am…

Visual Studio安装遇到的问题

因为在安装pytorch3d0.3.0时遇到问题&#xff0c;提示没有cl.exe&#xff0c;VS的C编译组件&#xff0c;查了下2019版比2022问题少&#xff0c;下载安装时遇到的问题记录&#xff1a; 查看搜素栏搜时间&#xff0c;查看系统日志&#xff0c;报错为&#xff1a; 创建 TLS 客户端…

蓝桥杯 - 正则问题

解题思路&#xff1a; dfs import java.util.Scanner;public class Main {static int pos -1; // 充当charAt下标static String s;// 字符串型的静态变量public static void main(String[] args) {Scanner scanner new Scanner(System.in);s scanner.nextLine();System.ou…

4款在线网页原型图设计软件推荐

与桌面端相比&#xff0c;在线网页原型设计软件的使用具有优势&#xff0c;因为在线网页原型设计软件在整个使用过程中不需要安装&#xff0c;在线网页原型设计软件在任何地方都没有限制。更重要的是&#xff0c;无论是现在使用的 Linux&#xff0c;在线网页原型设计软件在操作…

浅聊什么是Redis?

需求&#xff1a;MySQL面临大量的查询&#xff0c;即读写操作&#xff0c;因此类比CPU&#xff0c;给数据加缓存&#xff0c;Redis诞生。应用程序从MySQL查询的数据&#xff0c;在Redis设置缓存&#xff08;记录在内存中&#xff0c;无需IO操作&#xff09;&#xff0c;后再需要…

SpringBoot整合Netty整合WebSocket-带参认证

文章目录 一. VectorNettyApplication启动类配置二.WebSocketServerBoot初始化服务端Netty三. WebsocketServerChannelInitializer初始化服务端Netty读写处理器四.initParamHandler处理器-去参websocket识别五.MessageHandler核心业务处理类-采用工厂策略模式5.1 策略上下文 六…

服务器设置了端口映射之后外网还是访问不了服务器

目录 排查思路参考&#xff1a; 1、确认服务是否在运行 2、确认端口映射设置是否正确 3、使用防火墙测试到服务器的连通性 4、检查服务内部的配置 5、解决办法 6、学习小分享 我们在一个完整的网络数据存储服务系统设备中都会存有业务服务器、防火墙、交换机、路由器&a…

Allavsoft for Mac v3.27.0.8852注册激活版 优秀的视频下载工具

Allavsoft for Mac是一款功能强大的多媒体下载和转换工具&#xff0c;支持从各种在线视频网站和流媒体服务下载视频、音频和图片。它具备批量下载和转换功能&#xff0c;可将文件转换为多种格式&#xff0c;以适应不同设备的播放需求。此外&#xff0c;Allavsoft还提供视频编辑…

Java | Leetcode Java题解之第3题无重复字符的最长子串

题目&#xff1a; 题解&#xff1a; class Solution {public int lengthOfLongestSubstring(String s) {// 哈希集合&#xff0c;记录每个字符是否出现过Set<Character> occ new HashSet<Character>();int n s.length();// 右指针&#xff0c;初始值为 -1&#…

Linux环境基础和工具的使用

目录 1、Linux软件包管理器---yum 2、Linux开发工具 2.1、vim基本概念 2.2 vim基本操作 2.3 vim正常模式命令集 2.4 vim末行模式命令集 2.5 简单vim配置 2.5.1 配置文件的位置 3 Linux编译器--gcc/g的使用 3.1 背景知识 3.2 gcc完成 4 Linux调试器--gdb使用 4.1 背…

二叉树的深度和高度问题-算法通关村

二叉树的深度和高度问题-算法通关村 1 最大深度问题 LeetCode104: 给定一个二叉树&#xff0c;找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明&#xff1a;叶子节点是指没有子节点的节点。 对于node&#xff08;3&#xff09;&#xff0…

《吴恩达:AI 智能体工作流引领人工智能新趋势》

近期值得看的 AI 视频之一&#xff1a;《吴恩达&#xff1a;AI 智能体工作流引领人工智能新趋势》这是吴恩达老师分享的他在 AI 智能体方面的发现。如果说智人区分于其他物种的能力是我们善用工具&#xff0c;那么对于 AI 来说&#xff0c;智能体就是它的工具。根据吴老师分享的…