基于 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 model

results = 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 plt

def 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))
    # 去除最后一列的 Image
    cols = train_df.columns[:-1]
    y_train = train_df[cols].values

    print('训练集 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 img


def 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.size
        yolo_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.size
        yolo_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 YOLO

def toRgbImg(img):
    img = np.fromstring(img, sep=' ').astype(np.uint8)
    img = Image.fromarray(img).convert('RGB')
    return img

def 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.xy
            for 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 plt


def 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.xyxy
    print(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.xy
        for 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()

测试效果:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

04_Git开发流程

文章目录 Git开发创建阶段开发阶段合并阶段常用指令 Git开发 创建阶段 共建Git仓库&#xff0c;首次使用请使用git clone指令 git clone xxx.git在master/main主干上搭建起基本的项目结构和公共内容&#xff0c;将这些内容push到远程仓库 在Github上创建分支dev&#xff08;de…

浅谈高阶智能驾驶-NOA领航辅助的技术与发展

浅谈高阶智能驾驶-NOA领航辅助的技术与发展 附赠自动驾驶学习资料和量产经验&#xff1a;链接 2019年在国内首次试驾特斯拉NOA领航辅助驾驶的时候&#xff0c;当时兴奋的觉得未来已来;2020年在试驾蔚来NOP领航辅助驾驶的时候&#xff0c;顿时不敢小看国内新势力了;现在如果哪家…

houdini 对lsystem类carve效果

1.for 对每个prim执行carve 2.delete 3.

吴恩达:现在做GPT-4智能体,或将提前达到GPT-5效果|钛媒体AGI

斯坦福大学客座教授吴恩达&#xff08;Andrew Ng&#xff09;© 林志佳 美国斯坦福大学教授吴恩达&#xff08;Andrew Ng&#xff09; 人工智能智能体&#xff08;AI Agents&#xff09;似乎将引领 AI 行业新的发展趋势。 近日红杉资本&#xff08;Sequoia&#xff09;在…

使用 MergeKit 创建专家组合---将多个模型合并到同个 MoE 中

原文地址&#xff1a;create-mixtures-of-experts-with-mergekit 2024 年 3 月 27 日 由于 Mixtral 的发布&#xff0c;Mixture of Experts&#xff08;MoE&#xff09;架构近几个月开始流行。这种架构提供了一个有趣的权衡&#xff1a;以增加 VRAM 使用为代价获得更高的性能…

【C语言】联合体、枚举: 联合体与结构体区别,枚举的优点

目录 1、联合体 1.1、什么是联合体 1.2、联合体的声明 1.3、联合体的特点 1.4、联合体与结构体区别 1.5、联合体的大小 2、枚举 2.1、枚举类型的声明 2.2、枚举类型的优点 3、三种自定义类型&#xff1a;结构体、联合体、枚举 正文 1、联合体 1.1、什么是联合体 联…

脑部肿瘤检测YOLOV8

脑部肿瘤检测&#xff0c;采用YOLOV8训练得到PT模型&#xff0c;然后转换成ONNX&#xff0c;OPENCV调用&#xff0c;支持C/PYTHON/ANDORID开发脑部肿瘤检测YOLOV8

台球王子,Android小游戏开发

使用 Android Studio 开发了一款休闲游戏 —— 《台球王子》 关键词&#xff1a;台球 A. 项目描述 台球作为一项优雅、策略性强的运动&#xff0c;在众多游戏类型中却相对较少。因此&#xff0c;开发《台球王子》小游戏&#xff0c;可以让更多玩家能够轻松享受到台球的乐趣。…

Mysql数据库故障排查与优化

目录 前言 一、Mysql数据库的单实例故障 1.故障一——拒绝连接数据库 1.1故障内容 1.2问题分析 1.3解决方法 2.故障二——密码错误 2.1故障内容 2.2问题分析 2.3解决方法 3.故障三——数据库处理较慢 3.1故障内容 3.2问题分析 3.3解决方法 4.故障四——数据库表…

学习【Redis原理篇】这一篇就够了

目录 1. 数据结构1-1. 动态字符串&#xff08;SDS&#xff09;1-2. intset1-3. Dict 2. 网络模型3. 通信协议4. 内存策略 1. 数据结构 1-1. 动态字符串&#xff08;SDS&#xff09; 我们都知道Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字…

gdb调试运行中的多线程

步骤如下&#xff1a; 一、查看线程状态和打印变量值 1、gdb -p 进程号 2、thread apply all bt &#xff08;查看所有线程都运行到了哪里&#xff0c;是否 有hang住的地方&#xff0c;以及确定要打印的变量属于哪个thread下、属于哪个堆栈帧&#xff09; 3、thread $THRE…

KUKA机器人调整示教器灵敏度(校屏)

KUKA机器人KRC4的示教器升级后&#xff0c;示教器屏幕由之前的电阻屏改为电容屏&#xff0c;不仅在外观上有所变化&#xff0c;屏幕校准的方法也有所不同。通过以下方法分别对新旧两款示教器进行屏幕校正&#xff0c;调整示教器屏幕灵敏度。 对新款示教器而言&#xff1a; 一…

Electron + Vue3 + TS + Vite 搭建桌面应用

参考&#xff1a;https://blog.csdn.net/mo911108/article/details/131456698 npm -v 10.2.4npm create vitelatest gcto-electron-app --template vue-ts运行项目 npm run dev切换镜像源并安装electron&#xff0c;需要设置ELECTRON_MIRROR才行&#xff0c;win10操作如下&am…

波奇学Linux:TCP协议

TCP协议传输层有发送缓冲区和接收缓冲区 read&#xff0c;recv&#xff0c;send的函数调用发送缓冲区&#xff0c;本质并不是数据发送到网络当中&#xff0c;数据什么时候发送&#xff0c;发送多少&#xff0c;出错了怎么办&#xff0c;由TCP协议自主决定 发送到对方缓冲区本…

Elasticsearch是什么及作用

初识Elasticsearch 一、Elasticsearch是什么&#xff1f; es是款强大的开源搜索技术&#xff0c;具备非常多强大的功能&#xff0c;能够帮助我们开发人员从海量数据中快速找到需要的内容。例如在GitHub上搜索代码&#xff0c;在jd、tb网站中搜索商品、在baidu中搜索答案。 二、…

智慧停车系统运行原理和影响评估

一&#xff1a;智慧停车系统概述 智慧停车系统运用信息通信技术&#xff0c;整合传感器、摄像头、车牌识别设备&#xff0c;实时监控停车场情况&#xff0c;为车主提供便捷快速的停车体验。主要功能包括车位查询、预约停车、自动计费、无感支付等。车主可通过手机APP或自助终端…

Autodesk Maya 2025 mac玛雅三维动画特效软件

Autodesk Maya 2025 for Mac是一款功能强大、操作简便的三维动画软件&#xff0c;适用于电影、电视、游戏、建筑、工业设计、虚拟现实和动画等领域。无论是专业设计师还是初学者&#xff0c;都可以通过Maya 2025实现自己的创意和想法&#xff0c;创作出高质量的三维作品。 软件…

NEO 学习之 MLE(最大似然估计)

文章目录 简单题目MLE 在不同的分布的运用正态分布指数分布均匀分布泊松分布 如何理解 最大似然估计&#xff1f; 就是我们先取出一堆样本&#xff0c;得到一个L( θ \theta θ) 函数&#xff0c;然后的话&#xff0c;这个是关于 θ \theta θ 的一个函数&#xff0c;那么由于存…

C++学习笔记(入门)

c学习笔记&#xff08;入门&#xff09; 文章目录 c学习笔记&#xff08;入门&#xff09;前言精华一、&#xff08;1&#xff09;c语言结构基础1.头文件2.指明空间&#xff1a;using namespace std3.输入输出&#xff1a;cin >>&#xff0c;cout << ... << …

3.29 文章翻译RO——Robust scheduling of building energy system under uncertainty

highlight 我们建立了一个带有冷却器和冰热能储存的建筑能源系统模型。 提出了一种两阶段鲁棒策略来调度系统运行。 具有适当参数的鲁棒策略优于确定性方法。 鲁棒策略和MPC方法的性能相似。 本文提出了一种鲁棒调度策略&#xff0c;用于在预测不确定的情况下管理具有太阳能发电…