关键点检测--使用YOLOv8对Leeds Sports Pose(LSP)关键点检测

news2025/7/19 7:48:04

目录

  • 1. Leeds Sports Pose数据集下载
  • 2. 数据集处理
    • 2.1 获取标签
    • 2.2 将图像文件和标签文件处理成YOLO能使用的格式
  • 3. 用YOLOv8进行训练
    • 3.1 训练
    • 3.2 预测


1. Leeds Sports Pose数据集下载

从kaggle官网下载这个数据集,地址为link,下载好的数据集文件如下:
| |——archive
|——images 这个文件夹中放了2000张运动图像
|——visualized 这个文件夹放的是带关键点的图像
|——joints.mat 存放的是关键点标签
|——README.txt 存放对数据集的介绍

2. 数据集处理

2.1 获取标签

原图像的关键点标签以joints.mat格式存放,用python脚本对其进行解析,这里注意每张图像的大小不同,因此不同图像的宽高不同要注意。 解析代码如下,注意更换里面的图像路径。

import os
import cv2
import numpy as np
import scipy.io as sio

# 加载 joints.mat 文件
mat_path = "joints.mat"
data = sio.loadmat(mat_path)

# 查看所有键
print(data.keys())

# 获取 joints 数据 (假设其结构为 (3, num_keypoints, num_samples))
joints = data['joints']

# 路径配置
output_dir = r"LSP\labels"
image_dir = r"LSP\images"  # 图像目录路径
os.makedirs(output_dir, exist_ok=True)

# 解析 joints 数据
num_samples = joints.shape[2]

for idx in range(num_samples):
    # 构建图像路径
    image_path = os.path.join(image_dir, f"im{idx + 1:04d}.jpg")

    # 检查图像是否存在
    if not os.path.exists(image_path):
        print(f"图像 {image_path} 不存在,跳过该样本。")
        continue

    # 获取当前样本的关键点数据
    keypoints = joints[:, :, idx]
    x_coords = keypoints[0, :]
    y_coords = keypoints[1, :]
    visibility = keypoints[2, :]

    # 读取图像获取实际尺寸
    img = cv2.imread(image_path)
    if img is None:
        print(f"无法读取图像 {image_path},跳过该样本。")
        continue

    img_height, img_width = img.shape[:2]

    # 归一化关键点坐标
    x_coords /= img_width
    y_coords /= img_height

    # 计算边界框
    x_min, x_max = np.min(x_coords), np.max(x_coords)
    y_min, y_max = np.min(y_coords), np.max(y_coords)
    bbox_width = x_max - x_min
    bbox_height = y_max - y_min
    x_center = x_min + bbox_width / 2
    y_center = y_min + bbox_height / 2

    # 构建标签行:class_id x_center y_center width height x1 y1 x2 y2 ...
    label = f"0 {x_center:.6f} {y_center:.6f} {bbox_width:.6f} {bbox_height:.6f} "
    label += " ".join([f"{x:.6f} {y:.6f}" for x, y in zip(x_coords, y_coords)])
    label += "\n"

    # 保存标签文件
    label_path = os.path.join(output_dir, f"im{idx + 1:04d}.txt")
    with open(label_path, "w") as f:
        f.write(label)

print(f"所有关键点数据已转换为 YOLOv8 格式,保存至 {output_dir}")

获取的关键点标签如下图:
在这里插入图片描述
对应的图像如下图:
在这里插入图片描述

2.2 将图像文件和标签文件处理成YOLO能使用的格式

我是按照8比2将数据集分成训练集和测试集,划分代码如下:

import os
import random
import shutil

# 数据集路径

images_path = r"LSP\images"
labels_path = r"LSP\labels"

# 输出路径
train_img_dir = os.path.join(images_path, "train")
val_img_dir = os.path.join(images_path, "val")
train_lbl_dir = os.path.join(labels_path, "train")
val_lbl_dir = os.path.join(labels_path, "val")

# 创建输出文件夹
os.makedirs(train_img_dir, exist_ok=True)
os.makedirs(val_img_dir, exist_ok=True)
os.makedirs(train_lbl_dir, exist_ok=True)
os.makedirs(val_lbl_dir, exist_ok=True)

# 获取所有图像文件名(不带扩展名)
image_files = sorted([f.split('.')[0] for f in os.listdir(images_path) if f.endswith('.jpg')])

# 设置划分比例
train_ratio = 0.8
val_ratio = 0.2

# 随机打乱文件列表
random.shuffle(image_files)

# 划分数据集
train_count = int(len(image_files) * train_ratio)
train_files = image_files[:train_count]
val_files = image_files[train_count:]

def move_files(file_list, img_dir, lbl_dir):
    for filename in file_list:
        img_src = os.path.join(images_path, f"{filename}.jpg")
        lbl_src = os.path.join(labels_path, f"{filename}.txt")
        
        img_dst = os.path.join(img_dir, f"{filename}.jpg")
        lbl_dst = os.path.join(lbl_dir, f"{filename}.txt")
        
        if os.path.exists(img_src) and os.path.exists(lbl_src):
            shutil.move(img_src, img_dst)
            shutil.move(lbl_src, lbl_dst)

# 移动文件
move_files(train_files, train_img_dir, train_lbl_dir)
move_files(val_files, val_img_dir, val_lbl_dir)

print(f"数据集划分完成:\n  训练集:{len(train_files)} 张\n  验证集:{len(val_files)} 张")

划分后的文件格式图:
| | |——LSP 文件名
| |——images
|——train 训练数据
|——val 测试数据
| |——val
|——train 训练标签
|——val 测试标签
在这里插入图片描述
数据集的yaml格式如下:
在这里插入图片描述

3. 用YOLOv8进行训练

3.1 训练

下面是我进行训练的代码

# Ultralytics YOLO 🚀, AGPL-3.0 license

from copy import copy

from ultralytics.models import yolo
from ultralytics.nn.tasks import PoseModel
from ultralytics.utils import DEFAULT_CFG, LOGGER
from ultralytics.utils.plotting import plot_images, plot_results


class PoseTrainer(yolo.detect.DetectionTrainer):
    """
    A class extending the DetectionTrainer class for training based on a pose model.

    Example:
        ```python
        from ultralytics.models.yolo.pose import PoseTrainer

        args = dict(model='yolov8n-pose.pt', data='coco8-pose.yaml', epochs=3)
        trainer = PoseTrainer(overrides=args)
        trainer.train()
        ```
    """

    def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
        """Initialize a PoseTrainer object with specified configurations and overrides."""
        if overrides is None:
            overrides = {}
        overrides["task"] = "pose"
        super().__init__(cfg, overrides, _callbacks)

        if isinstance(self.args.device, str) and self.args.device.lower() == "mps":
            LOGGER.warning(
                "WARNING ⚠️ Apple MPS known Pose bug. Recommend 'device=cpu' for Pose models. "
                "See https://github.com/ultralytics/ultralytics/issues/4031."
            )

    def get_model(self, cfg=None, weights=None, verbose=True):
        """Get pose estimation model with specified configuration and weights."""
        model = PoseModel(cfg, ch=3, nc=self.data["nc"], data_kpt_shape=self.data["kpt_shape"], verbose=verbose)
        if weights:
            model.load(weights)

        return model

    def set_model_attributes(self):
        """Sets keypoints shape attribute of PoseModel."""
        super().set_model_attributes()
        self.model.kpt_shape = self.data["kpt_shape"]

    def get_validator(self):
        """Returns an instance of the PoseValidator class for validation."""
        self.loss_names = "box_loss", "pose_loss", "kobj_loss", "cls_loss", "dfl_loss"
        return yolo.pose.PoseValidator(
            self.test_loader, save_dir=self.save_dir, args=copy(self.args), _callbacks=self.callbacks
        )

    def plot_training_samples(self, batch, ni):
        """Plot a batch of training samples with annotated class labels, bounding boxes, and keypoints."""
        images = batch["img"]
        kpts = batch["keypoints"]
        cls = batch["cls"].squeeze(-1)
        bboxes = batch["bboxes"]
        paths = batch["im_file"]
        batch_idx = batch["batch_idx"]
        plot_images(
            images,
            batch_idx,
            cls,
            bboxes,
            kpts=kpts,
            paths=paths,
            fname=self.save_dir / f"train_batch{ni}.jpg",
            on_plot=self.on_plot,
        )

    def plot_metrics(self):
        """Plots training/val metrics."""
        plot_results(file=self.csv, pose=True, on_plot=self.on_plot)  # save results.png


if __name__ == "__main__":
    args = dict(model=r'E:\postgraduate\bolt_lossen_project\ultralytics-8.1.0\yolov8n-pose.pt', epochs= 100, mode='train')
    trains = PoseTrainer(overrides=args)
    trains.train()
    
    #predictor.predict_cli()

3.2 预测

预测代码:

# Ultralytics YOLO 🚀, AGPL-3.0 license

from ultralytics.engine.results import Results
from ultralytics.models.yolo.detect.predict import DetectionPredictor
from ultralytics.utils import DEFAULT_CFG, LOGGER, ops
import cv2


class PosePredictor(DetectionPredictor):
    """
    A class extending the DetectionPredictor class for prediction based on a pose model.

    Example:
        ```python
        from ultralytics.utils import ASSETS
        from ultralytics.models.yolo.pose import PosePredictor

        args = dict(model='yolov8n-pose.pt', source=ASSETS)
        predictor = PosePredictor(overrides=args)
        predictor.predict_cli()
        ```
    """

    def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
        """Initializes PosePredictor, sets task to 'pose' and logs a warning for using 'mps' as device."""
        super().__init__(cfg, overrides, _callbacks)
        self.args.task = "pose"
        if isinstance(self.args.device, str) and self.args.device.lower() == "mps":
            LOGGER.warning(
                "WARNING ⚠️ Apple MPS known Pose bug. Recommend 'device=cpu' for Pose models. "
                "See https://github.com/ultralytics/ultralytics/issues/4031."
            )

    def postprocess(self, preds, img, orig_imgs):
        """Return detection results for a given input image or list of images."""
        preds = ops.non_max_suppression(
            preds,
            self.args.conf,
            self.args.iou,
            agnostic=self.args.agnostic_nms,
            max_det=self.args.max_det,
            classes=self.args.classes,
            nc=len(self.model.names),
        )

        if not isinstance(orig_imgs, list):  # input images are a torch.Tensor, not a list
            orig_imgs = ops.convert_torch2numpy_batch(orig_imgs)

        results = []
        for i, pred in enumerate(preds):
            orig_img = orig_imgs[i]
            pred[:, :4] = ops.scale_boxes(img.shape[2:], pred[:, :4], orig_img.shape).round()
            pred_kpts = pred[:, 6:].view(len(pred), *self.model.kpt_shape) if len(pred) else pred[:, 6:]
            pred_kpts = ops.scale_coords(img.shape[2:], pred_kpts, orig_img.shape)
            img_path = self.batch[0][i]
            results.append(
                Results(orig_img, path=img_path, names=self.model.names, boxes=pred[:, :6], keypoints=pred_kpts)
            )
        return results

if __name__ == "__main__":
    img = r'E:\postgraduate\bolt_lossen_project\ultralytics-8.1.0\archive\LSP\images\train\im0089.jpg'
    args = dict(model=r'E:\postgraduate\bolt_lossen_project\ultralytics-8.1.0\runs\pose\train\weights\best.pt', source=img, task = 'pose')
    predictor = PosePredictor(overrides=args)
    predictor.predict_cli()

    

预测结果图:
在这里插入图片描述

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

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

相关文章

独立按键控制LED

目录 1.独立按键介绍 2.原理图 3.C51数据运输 解释&#xff1a;<< >> ​编辑 解释&#xff1a;& | 解释&#xff1a;^ ~ ​编辑 4.C51基本语句 5.按键的跳动 6.独立按键控制LED亮灭代码 第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1…

计算机科技笔记: 容错计算机设计03 系统可信性的度量 偶发故障期 浴盆曲线 韦布尔分布

可靠性 简化表达式 偶发故障期&#xff0c;系统发生故障概率趋近于一个常数 浴盆曲线 MTTF和计算 韦布尔分布 马尔可夫链 可靠度

爬虫准备前工作

1.Pycham的下载 网址&#xff1a;PyCharm: The only Python IDE you need 2.Python的下载 网址&#xff1a;python.org&#xff08;python3.9版本之后都可以&#xff09; 3.node.js的下载 网址&#xff1a;Node.js — 在任何地方运行 JavaScript&#xff08;版本使用18就可…

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】7.1 主流可视化工具对比(Tableau/Matplotlib/Python库)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 第七章 可视化工具集成&#xff1a;Tableau、Matplotlib与Python库深度对比7.1 主流可视化工具对比&#xff1a;技术选型的决策框架7.1.1 工具定位与核心能力矩阵7.1.2 数据…

操作系统实验习题解析 上篇

孤村落日残霞&#xff0c;轻烟老树寒鸦&#xff0c;一点飞鸿影下。 青山绿水&#xff0c;白草红叶黄花。 ————《天净沙秋》 白朴 【元】 目录 实验一&#xff1a; 代码&#xff1a; 解析&#xff1a; 运行结果&#xff1a; 实验二&#xff1a; 代码解析 1. 类设计 …

基于Arduino Nano的DIY示波器

基于Arduino Nano的DIY示波器&#xff1a;打造属于你的口袋实验室 前言 在电子爱好者的世界里&#xff0c;示波器是不可或缺的工具之一。它能够帮助我们观察和分析各种电子信号的波形&#xff0c;从而更好地理解和调试电路。然而&#xff0c;市面上的示波器价格往往较高&…

渠道销售简历模板范文

模板信息 简历范文名称&#xff1a;渠道销售简历模板范文&#xff0c;所属行业&#xff1a;其他 | 职位&#xff0c;模板编号&#xff1a;KRZ3J3 专业的个人简历模板&#xff0c;逻辑清晰&#xff0c;排版简洁美观&#xff0c;让你的个人简历显得更专业&#xff0c;找到好工作…

JAVA练习题(1) 卖飞机票

import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner scnew Scanner(System.in);System.out.println("请输入飞机的票价&#xff1a;");int pricesc.nextInt();System.out.println("请输入月份&#xff1a;");…

杆件的拉伸与压缩变形

杆件的拉伸与压缩 第一题 Q u e s t i o n \mathcal{Question} Question 图示拉杆沿斜截面 m − m m-m m−m由两部分胶合而成。设在胶合面上许用拉应力 [ σ ] 100 MPa [\sigma]100\text{MPa} [σ]100MPa&#xff0c;许用切应力 [ τ ] 50 MPa [\tau]50\text{MPa} [τ]50MP…

企业开发平台大变革:AI 代理 + 平台工程重构数字化转型路径

在企业数字化转型的浪潮中&#xff0c;开发平台正经历着前所未有的技术革命。从 AST&#xff08;抽象语法树&#xff09;到 AI 驱动的智能开发&#xff0c;从微服务架构到信创适配&#xff0c;这场变革不仅重塑了软件开发的底层逻辑&#xff0c;更催生了全新的生产力范式。本文…

《汽车噪声控制》复习重点

题型 选择 填空 分析 计算 第一章 噪声定义 不需要的声音&#xff0c;妨碍正常工作、学习、生活&#xff0c;危害身体健康的声音&#xff0c;统称为噪声 噪声污染 与大气污染、水污染并称现代社会三大公害 声波基本概念 定义 媒质质点的机械振动由近及远传播&am…

Linux——MySQL约束与查询

表的约束 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合 法性&#xff0c;从业务逻辑角度保证数据的正确性。比如有一个字段是email&#xff0c;要求是唯一的。 表的约束是为了防止插入不合法的…

Asp.Net Core IIS发布后PUT、DELETE请求错误405

一、方案1 1、IIS管理器&#xff0c;处理程序映射。 2、找到aspNetCore&#xff0c;双击。点击请求限制...按钮&#xff0c;并在谓词选项卡上&#xff0c;添加两者DELETE和PUT. 二、方案2 打开web.config文件&#xff0c;添加<remove name"WebDAVModule" />&…

STL-to-ASCII-Generator 实用教程

参阅&#xff1a;STL-to-ASCII-Generator 使用教程 开源项目网址 下载 STL-to-ASCII-Generator-main.zip 解压到 D:\js\ index.html 如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta id"ascii&q…

巡检机器人数据处理技术的创新与实践

摘要 随着科技的飞速发展&#xff0c;巡检机器人在各行业中逐渐取代人工巡检&#xff0c;展现出高效、精准、安全等显著优势。当前&#xff0c;巡检机器人已从单纯的数据采集阶段迈向对采集数据进行深度分析的新阶段。本文探讨了巡检机器人替代人工巡检的现状及优势&#xff0c…

国产linux系统(银河麒麟,统信uos)使用 PageOffice 在线打开Word文件,并用前端对话框实现填空填表

不管是政府机关、公司企业&#xff0c;还是金融行业、教育行业等单位&#xff0c;在办公过程中都经常需要填写各种文书和表格&#xff0c;比如通知、报告、登记表、计划表、申请表等。这些文书和表格往往是用Word文件制作的模板&#xff0c;比方说一个通知模板中经常会有“关于…

RabbitMQ-高级特性1

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言消息确认机制介绍手动确认方法代码前言代码编写消息确认机制的演示自动确认automanual 持久化介绍交换机持久化队列持久化消息持久化 持久化代码持久化代码演示…

青藏高原东北部祁连山地区250m分辨率多年冻土空间分带指数图(2023)

时间分辨率&#xff1a;10年 < x < 100年空间分辨率&#xff1a;100m - 1km共享方式&#xff1a;开放获取数据大小&#xff1a;24.38 MB数据时间范围&#xff1a;近50年来元数据更新时间&#xff1a;2023-10-08 数据集摘要 多年冻土目前正在经历大规模的退化&#xff0c…

论文分享➲ arXiv2025 | TTRL: Test-Time Reinforcement Learning

TTRL: Test-Time Reinforcement Learning TTRL&#xff1a;测试时强化学习 https://github.com/PRIME-RL/TTRL &#x1f4d6;导读&#xff1a;本篇博客有&#x1f9a5;精读版、&#x1f407;速读版及&#x1f914;思考三部分&#xff1b;精读版是全文的翻译&#xff0c;篇幅较…

【计算机网络-传输层】传输层协议-TCP核心机制与可靠性保障

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;传输层协议-UDP 下篇文章&#xff1a; 网络层 我们的讲解顺序是&…