YOLOv8训练自己的数据集,通过LabelImg

news2024/11/18 14:39:10

记录下labelImg标注数据到YOLOv8训练的过程,其中容易遇到labelImg的坑

数据集处理

首先在mydata下创建4个文件夹

在这里插入图片描述
images文件夹下存放着所有的图片,包括训练集和测试集等。后续会根据代码进行划分。
json文件夹里存放的是labelImg标注的所有数据。需要注意的是,json文件的命名应与images文件夹中的图片一一对应。labels文件夹是空的,后续会根据代码将json转化为YOLOv8支持的训练数据集。接下来需要创建一个 split_train_val.py 文件,放在mydata目录下,用于将images文件夹中的图片划分为训练集和测试集。代码如下:

import os
import json
import random
import argparse

class DatasetSplitter:
    def __init__(self, json_path, txt_path):
        self.json_path = json_path
        self.txt_path = txt_path
        self.trainval_percent = 1.0
        self.train_percent = 0.9

        self.total_json = os.listdir(json_path)
        self.num = len(self.total_json)
        self.list_index = list(range(self.num))

        if not os.path.exists(txt_path):
            os.makedirs(txt_path)

    def split_dataset(self):
        tv = int(self.num * self.trainval_percent)
        tr = int(tv * self.train_percent)
        trainval = random.sample(self.list_index, tv)
        train = random.sample(trainval, tr)

        file_trainval = open(os.path.join(self.txt_path, 'trainval.txt'), 'w')
        file_test = open(os.path.join(self.txt_path, 'test.txt'), 'w')
        file_train = open(os.path.join(self.txt_path, 'train.txt'), 'w')
        file_val = open(os.path.join(self.txt_path, 'val.txt'), 'w')

        for i in self.list_index:
            name = self.total_json[i][:-5] + '\n'  # Assuming filenames end with '.json'
            if i in trainval:
                file_trainval.write(name)
                if i in train:
                    file_train.write(name)
                else:
                    file_val.write(name)
            else:
                file_test.write(name)

        file_trainval.close()
        file_train.close()
        file_val.close()
        file_test.close()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--json_path', default='json', type=str, help='input json label path')
    parser.add_argument('--txt_path', default='dataSet', type=str, help='output txt label path')
    opt = parser.parse_args()

    dataset_splitter = DatasetSplitter(opt.json_path, opt.txt_path)
    dataset_splitter.split_dataset()

运行后会在dataSet生成四个文件.
如图所示
然后前往mydata目录的上一级目录,例如我这里是test目录下,创建voc_label.py文件.用于将labelImg标注的json数据转化为txt文本数据.

请注意,YULO的标注框中的x和y表示矩形框的左上角,而labelImg中的(x,y,w,h)可能表示矩形框的中心点坐标。在使用时需要确认,以免训练出来的YOLO存在偏差。
可以通过以下代码draw_picture_by_json.py进行绘图测试,以下我是默认labelImg的格式是(x_center,y_center,w,h)的格式进行绘制.

from typing import Dict
from PIL import Image, ImageDraw
import json

def draw_pic_by_raw_data(image_path:str, output_path:str, json_data: Dict):
    data = json_data
    img = Image.open(image_path)
    draw = ImageDraw.Draw(img)
    # Load JSON file with bounding box information
    # Iterate through bounding boxes and draw them on the image
    annotations = data[0]["annotations"]
    for bbox in annotations:
        label = bbox["label"]
        x_center, y_center, width, height = (
            bbox["coordinates"]["x"],
            bbox["coordinates"]["y"],
            bbox["coordinates"]["width"],
            bbox["coordinates"]["height"]
        )
        #FIXME TODO 从中心坐标x,y LabelImg 计算左上角坐标
        x, y = x_center - width / 2, y_center - height / 2

        # Draw bounding box
        draw.rectangle([x, y, x+width, y+height], outline="red", width=2)


        # Draw label
        draw.text((x, y-15), label, fill="red")

    # Save the result
    img.save(output_path)
    img.show()

if __name__ == "__main__":
    test_img_path = "3157.jpg"
    test_json_path = "3157.json"
    output_path = "out.jpg"

    with open(test_json_path, 'r') as f:
        data = json.load(f)

    draw_pic_by_raw_data(test_img_path, output_path, data)

通过以上代码,如果矩形框正确,则验证了labelImg的x、y、w和h坐标应该是x_center、y_center、w和h的情况。需要在将json转换为txt文本时进行处理。这里给出voc_label.py的代码如下:请注意修改classes中的类别,修改为和mydata.yaml的顺序一致,否则会导致标签错误。

代码运行前请在mydata目录的上一级,也就是我这里的test目录下创建一个paper_data文件夹,用于等会在mydata.yaml中指定路径.

import os
import json
from os import getcwd

sets = ['train', 'val', 'test']
classes = ["A", "B", "C", "D", "E"]  # 请根据您的实际类别进行修改 对齐yaml文件中的names
abs_path = os.getcwd()
print(abs_path)


def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0 - 1
    y = (box[2] + box[3]) / 2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return x, y, w, h


def convert_annotation(image_id):
    in_file = open('mydata/json/%s.json' % (image_id), 'r', encoding='UTF-8')
    out_file = open('mydata/labels/%s.txt' % (image_id), 'w')
    data = json.load(in_file)
    for obj in data[0]["annotations"]:
        w = obj["coordinates"]["width"]
        h = obj["coordinates"]["height"]
        difficult = 0  # JSON数据中没有difficult字段,设为0
        cls = obj["label"]
        if cls not in classes or difficult == 1:
            continue
        cls_id = classes.index(cls)
        ##注意:这里的box是左上角和右下角的坐标,而不是中心点坐标
        x_center = obj["coordinates"]["x"]
        y_center = obj["coordinates"]["y"]
        width = obj["coordinates"]["width"]
        height = obj["coordinates"]["height"]
        x, y = x_center - width / 2, y_center - height / 2
        b = x, x + width, y, y + height
        # b = obj["coordinates"]["x"], obj["coordinates"]["x"] + obj["coordinates"]["width"], \
        #     obj["coordinates"]["y"], obj["coordinates"]["y"] + obj["coordinates"]["height"]
        b1, b2, b3, b4 = b
        # 标注越界修正
        if b2 > w:
            b2 = w
        if b4 > h:
            b4 = h
        b = (b1, b2, b3, b4)
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')


wd = getcwd()
for image_set in sets:
    if not os.path.exists('mydata/labels/'):
        os.makedirs('mydata/labels/')
    image_ids = open('mydata/dataSet/%s.txt' % (image_set)).read().strip().split()
    list_file = open('paper_data/%s.txt' % (image_set), 'w')
    for image_id in image_ids:
        list_file.write(abs_path + '/mydata/images/%s.jpg\n' % (image_id))
        convert_annotation(image_id)
    list_file.close()

yaml文件配置

截止到这里数据preprocess处理完毕.接下来进行训练前的yaml文件配置.
修改为刚才创建的paper_data的绝对路径
如上配置

并进行names的配置,注意顺序和数量需要与voc_label.py里面的列表顺序一致.

最后修改yolov8.yaml文件配置

yolov8.yaml的路径一般在ultralytics/ultralytics/cfg/models/v8目录下
修改nc为names中的类别数量
在这里插入图片描述

训练模型

yolo task=detect mode=train model=yolov8s.yaml data=mydata.yaml epochs=25 batch=16

这些模型可以支持多种尺寸,包括小(n)、中(s)、中大(m)、大(l)和超大(x)。模型的尺寸参数越大,所需的显存和训练时间也越多。要切换模型尺寸,只需在"model=yolov8"后面加上相应的尺寸参数(n、s、m、l、x),然后再加上.yaml即可。另外,epochs设置为25,batch大小为16。epochs表示训练的轮数, batch为每个批次的样本数量为16.

推理

训练结束后可以通过以下代码进行测试.

yolo predict model=xxxx/weights/best.pt source=xxxx/mydata/testvedio.mp4 imgsz=1280

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

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

相关文章

qtcreator使用qwt库

先配置好.pro文件,再去ui界面拖拽控件 ui界面会更改配置,故顺序错一个,就凉了,重来吧 准备:库,库头文件 库文件:路径如下 头文件:路径如下 鼠标->右键 (有些不用勾…

读元宇宙改变一切笔记13_治理与管理

1. 元宇宙的经济价值 1.1. 元宇宙的价值最终将“超过”物理世界 1.2. 人们之所以对低延迟网络进行投资,是因为有一些体验需要元宇宙:同步实时渲染的虚拟世界、AR和云游戏流 1.3. 在大多数情况下,数字经济并不是什么新鲜事 1.3.1. 数字经济…

【算法】北极通讯网络(Kruskal)

题目 北极的某区域共有 n 座村庄,每座村庄的坐标用一对整数 (x,y) 表示。 为了加强联系,决定在村庄之间建立通讯网络,使每两座村庄之间都可以直接或间接通讯。 通讯工具可以是无线电收发机,也可以是卫星设备。 无线电收发机有…

【shell-10】shell实现的各种kafka脚本

kafka-shell工具 背景日志 log一.启动kafka->(start-kafka)二.停止kafka->(stop-kafka)三.创建topic->(create-topic)四.删除topic->(delete-topic)五.获取topic列表->(list-topic)六. 将文件数据 录入到kafka->(file-to-kafka)七.将kafka数据 下载到文件-&g…

Oracle RAC集群日志

文章目录 一、DB日志1、日志所在位置介绍2、知识介绍 二、ASM日志1、日志所在位置介绍2、知识介绍 三、CRS日志1、日志所在位置介绍2、知识介绍 四、RAC相关日志详细总结 一、DB日志 DB日志也就是数据库日志,全称Oracle Database Logs 1、日志所在位置介绍 日志位…

【计算机图形学】实验五 一个简单的交互式绘图系统(实验报告分析+截图+源码)

可以先看一看这篇呀~【计算机图形学】专栏前言-CSDN博客https://blog.csdn.net/m0_55931547/article/details/135863062 目录 一、实验目的 二、实验内容

Transformer and Pretrain Language Models3-6

Pretrain Language Models预训练语言模型 content: language modeling(语言模型知识) pre-trained langue models(PLMs)(预训练的模型整体的一个分类) fine-tuning approaches GPT and BERT(…

银行数据仓库体系实践(3)--数据架构

狭义的数据仓库数据架构用来特指数据分布,广义的数据仓库数据架构还包括数据模型、数据标准和数据治理。即包含相对静态部分如元数据、业务对象数据模型、主数据、共享数据,也包含相对动态部分如数据流转、ETL、整合、访问应用和数据全生命周期管控治理。…

Angular组件(一) 分割面板ShrinkSplitter

Angular组件(一) 分割面板ShrinkSplitter 前言 分割面板在日常开发中经常使用,可将一片区域,分割为可以拖拽整宽度或高度的两部分区域。模仿iview的分割面板组件,用angular实现该功能,支持拖拽和[(ngModel)]双向绑定的方式控制区…

为什么 FPGA 比 CPU 和 GPU 快?

FPGA、GPU 与 CPU——AI 应用的硬件选择 现场可编程门阵列 (FPGA) 为人工智能 (AI) 应用带来许多优势。图形处理单元 (GPU) 和传统中央处理单元 (CPU) 相比如何? 人工智能(AI)一词是指能够以类似于人类的方式做出决策的非人类机器智能。这包…

Excel 2019 for Mac/Win:商务数据分析与处理的终极工具

在当今快节奏的商业环境中,数据分析已经成为一项至关重要的技能。从市场趋势预测到财务报告,再到项目管理,数据无处不在。而作为数据分析的基石,Microsoft Excel 2019 for Mac/Win正是一个强大的工具,帮助用户高效地处…

77 C++对象模型探索。虚函数- 从静态联编,动态联编出发,分析 虚函数调用问题探究

什么叫做单纯的类: 比较简单的类,尤其不包括 虚函数 和虚基类。 什么叫不单纯的类: 从上一章的学习我们知道,在某些情况下,编译器会往类内部增加一些我们看不见但是真实存在的成员变量,例如vptr&#xff…

matlab appdesigner系列-图窗工具2-工具栏

工具栏,就是一般在任意软件界面上方的工具菜单栏 示例:工具菜单绘制正弦函数 操作步骤如下: 1)将坐标区和工具栏拖拽到画布上 2)点击工具栏的号,可以看到可以添加2种工具,按钮工具和切换工具&#xff0c…

【JavaScript权威指南第七版】读书笔记速度

JavaScript权威指南第七版 序正文前言:图中笔记重点知识第1章 JavaScript简介第一章总结 第2章 词法结构注释字面量标识符和保留字Unicode可选的分号第二章总结 第3章 类型、值和变量【重要】原始类型特殊类型第三章总结 第4章 表达式与操作符表达式操作符条件式调用…

【量化交易】股市舞者:小明的撮合交易之旅

马西森AES撮合交易系统 在繁华的都市中,小明,一个普通的青年,刚刚赚到了人生的第一桶金——20万。这笔意外的财富,点燃了他对股市的强烈兴趣。他开始如饥似渴地学习金融知识,钻研各种交易策略。 一天,小…

基于 java+springboot+mybatis电影售票网站管理系统前台+后台设计和实现

基于 javaspringbootmybatis电影售票网站管理系统前台后台设计和实现 🍅 作者主页 央顺技术团队 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 文末获取源码联系方式 📝 🍅 查看下方微信号获取联系方式 承…

微软 Power Apps Canvas App 画布应用将上传的附件转化为base64编码操作

微软 Power Apps Canvas App 画布应用将上传的附件结合Power Automate转化为base64编码操作 在使用canvas app的过程中,我们有时需要将上传的文件转换为base64存入数据库或者,调用外部接口传参,那么看下如何将文件转化为base64编码格式。 首先…

金智易表通构建学生缴费数据查询+帆软构建缴费大数据报表并整合到微服务

使用金智易表通挂接外部数据,快速建设查询类服务,本次构建学生欠费数据查询,共有3块设计,规划如下: 1、欠费明细查询:学校领导和财务处等部门可查询全校欠费学生明细数据;各二级学院教职工可查询本二级学院欠费学生明细数据。 2、大数据统计报表:从应收总额、欠费总额…

C语言编程中的陷阱与规避策略

一、引言 C语言作为一门历史悠久且广泛应用的编程语言,其强大的功能和灵活性深受开发者喜爱。然而,这种灵活性也带来了许多潜在的陷阱和难点,特别是对于新手来说,可能会在编程过程中遇到各种预料之外的问题。本文将深入探讨C语言…

自动验证码解析器:CapSolver的Chrome扩展程序自动解析器

自动验证码解析器:CapSolver的Chrome扩展程序自动解析器 验证码是网站实施的一种安全措施,通常对用户构成挑战。然而,随着技术的进步,验证码解析器已经出现,以简化这一过程。在本文中,我们将探讨专为Googl…