从零开始使用YOLOv11——Yolo检测detect数据集自建格式转换为模型训练格式:20w+图片1w+类别代码测试成功
在之前的文章中记录了YOLO环境的配置安装和基本命令的一些使用,上一篇博文的地址快速链接:从零开始使用YOLOv8——环境配置与极简指令(CLI)操作:1篇文章解决—直接使用:模型部署 and 自建数据集:训练微调-CSDN博客
使用YOLO作为目标检测任务的平台一个好处是,其搭建了非常简洁明了的训练命令行模式,可以便捷的对自建数据集进行微调。
在对自己数据集进行模型训练前,非常重要费时的就是对数据的预处理,包括数据清洗、统计信息分析、数据格式转换。本文专注于将自己数据 json 格式转为YOLO训练支持的 txt 数据格式,并给出可以复用的数据集构建代码,代码已上传至Gitee平台。
Gitee链接:https://gitee.com/machine-bai-xue/yolo-source-code-analysis
如果链接失效,访问404拒绝,可以直接在Gitee码云主页搜索——“机器白学”,所有项目中的YOLO源码实验就是本系列所有实验代码。

目录
一、初始自建数据集Json格式
1.文件存放格式
2.标签JSON格式
二、YOLO训练数据集创建类
1.直接使用
2.可视化检查
3.完整代码与扩展
一、初始自建数据集Json格式
1.文件存放格式
首先约定一下数据的初始格式,本文选择最简单的 JSON 列表数据集格式作标签保存。所有图片在一个文件夹(img)下,所有便签在另一个文件夹(json)下。

2.标签JSON格式
对标签数据具体来说,坐标数据(下图红框)和类别数据(下图蓝框)存放在同一个列表里,前四个为左上右下两点的xy绝对坐标值,类别字符信息放在后面。
(如果还有除了类别外的其余信息可以直接在列表后添加,最后构建数据集只需取出对应索引即可。例如,对于同一批图片数据和坐标数据可能存在多种分类任务,就官方coco例子来说,其给的类别是详细分类后的物体名称——长颈鹿、花瓶、杯子......如果想构建一个大致分类的检测模型,如将细化类改为抽象类名称——动物、装饰品、日用品......只需在列表后面继续添加即可,如下第一个图第一个框可以改为——【385, 60, 600, 357, “giraffe”, “动物”】)


二、YOLO训练数据集创建类
将任意训练数据集搭建成初始的Json格式并存放按文件夹存放后,即可使用下面的数据转换类生成多个符合训练标准的数据集格式——包括训练集train和验证集val、yaml配置文件、txt标签文件等部分。
1.直接使用
首先总览整个类的使用。首先确保 opencv-python(cv2)和 pillow(PIL)库正确安装在环境里了。

导入定义的转化类(可在文章最后直接复制,或者在Gitee地址下载对应py文件),实例初始化。初始化中三个关于文件地址的基本参数是必须存在的。
初始化基本参数按输入顺序含义归纳在下面表格。
| img_path | 所有图片存放文件地址(str) |
| label_path | 所有Json格式标签数据文件地址(str) |
| save_path | Yolo数据集结果保存地址(str) |

另外初始化中还有几个可以调整的附加参数。其影响数据集搭建的某些细节部分。
| train_ratio | 训练集占总数据量的比重,小数数据格式(float) |
| cls_id | 训练数据集中类别标签在原始数据中的索引位置(int,>=4) |
| seed | 设置打乱数据集文件名的随机种子——随机分配训练和验证数据(int) |
配置完参数后,直接使用类下的 dataset_main() 方法就可以自动生成训练验证数据集和yaml配置文件了。

所有数据按照设定的划分比例随机采样分开。

其中 cls_freq.json 是统计所有类别出现的频率字典,字典键对应类别名,值对应出现的次数。可以根据其频率查看哪些类训练样本偏少,决定是否要进行数据增强操作。

.yaml 文件是YOLO训练的配置文件。其中names是按出现频率排序的类别和标签索引对。

2.可视化检查
转换类中还定义了一些可视化函数,可以检查数据是否正确。其中对于初始数据只需直接使用visual_json_main() 方法即可。

还可以直接使用类中的可视化函数,进行自定义的检查。

3.完整代码与扩展
下面将完整类代码放在下面,可以对其中相应函数方法进行修改实现扩展任务。欢迎批评指正。
import os
import json
import random
import cv2
import yaml
import numpy as np
from PIL import Image, ImageDraw, ImageFontclass YOLO_Dataset_Creator:def __init__(self, img_path, label_path, save_path, train_ratio=0.85, cls_id=4, seed=42):self.img_path, self.labels, self.data = img_path, label_path, save_pathself.train = train_ratioself.cls = Noneself.cls_id = cls_idself.seed = seeddef dataset_main(self):# 读取图片信息划分train和val集self.tr_name, self.val_name = self.divide_dataset(self.labels)# 根据json中类别信息生成配置yaml文件self.cls = self.generate_yaml(self.labels)# 生成yolo的txt训练数据集self.dataset_create(self.data)def divide_dataset(self, json_path):# 根据图片获取所有文件名信息total_file_list = []for file in os.listdir(json_path):if file.lower().split('.')[-1] in ['json']:base = file.split('.')[0]total_file_list.append(base)# 随机打乱后按比例生成训练train和验证valrandom.seed(self.seed)random.shuffle(total_file_list)length = len(total_file_list)tr_file_list = [tr for tr in total_file_list[:int(self.train * length)]]val_file_list = [te for te in total_file_list[int(self.train * length):]]return tr_file_list, val_file_listdef statis_info(self, json_path):cls_dict = dict()for file in os.listdir(json_path):if file.lower().split('.')[-1] in ['json']:jsondir = os.path.join(json_path, file)with open(jsondir, 'r', encoding='utf-8') as f:box_cls_list = json.load(f)for box_cls in box_cls_list:cls = box_cls[self.cls_id]if str(cls) not in cls_dict.keys():cls_dict[str(cls)] = 1else:cls_dict[str(cls)] +=1cls_dictdir = os.path.join(self.data, 'cls_freq.json')with open(cls_dictdir, 'w') as f:json.dump(cls_dict, f)return cls_dictdef generate_yaml(self, json_path):# 获得类别频率字典cls_dict = self.statis_info(json_path)# 生成yaml配置文件sorted_cls = sorted(cls_dict, key=cls_dict.get, reverse=True)names_dict = {}clses_dict = {}for id, c in enumerate(sorted_cls):names_dict[id] = cclses_dict[c] = idyaml_dict = {"path":self.data,"train":"images/train","val":"images/val","names":names_dict}yaml_savedir = os.path.join(self.data, 'HP_Data.yaml')with open(yaml_savedir, "w") as f:yaml.dump(yaml_dict,f)print('yaml success')return clses_dictdef dataset_create(self,data_path):# 必要子文件生成tr_img = os.path.join(data_path, 'images/train')va_img = os.path.join(data_path, 'images/val')tr_lab = os.path.join(data_path, 'labels/train')va_lab = os.path.join(data_path, 'labels/val')# 创建文件夹for file in [tr_img, va_img, tr_lab, va_lab]:os.makedirs(file, exist_ok=True)# train和valself._train(tr_img, tr_lab)self._val(va_img, va_lab)def _train(self, tr_img, tr_lab):# 生产训练集trainfor name in self.tr_name:print(name, 'start')# 图片复制保存移动imgsave = os.path.join(tr_img, name+'.jpg')jpgdir = os.path.join(self.img_path, name+'.jpg')# 标签txtsave = os.path.join(tr_lab, name+'.txt')jsondir = os.path.join(self.labels, name+'.json')self.label_create(jsondir, txtsave, name, jpgdir, imgsave)def _val(self, va_img, va_lab):# 生产验证集valfor name in self.val_name:# 图片复制保存移动imgsave = os.path.join(va_img, name + '.jpg')jpgdir = os.path.join(self.img_path, name + '.jpg')# 标签txtsave = os.path.join(va_lab, name + '.txt')jsondir = os.path.join(self.labels, name + '.json')self.label_create(jsondir, txtsave, name, jpgdir, imgsave)def label_create(self, jsondir, txtsave, name, jpgdir, imgsave):# 图片信息img = cv2.imread(jpgdir)if img is None:return print(name, 'jpg is empty')height, width, _ = img.shape# 框信息with open(jsondir, 'r', encoding='utf-8') as f:box_list = json.load(f)box_str_list = []for box_cls in box_list:box = box_cls[:4]conv_box = self.normalize((width, height), box)text = box_cls[self.cls_id]cls = self.cls[str(text)]conv_box.insert(0, int(cls))box_str = " ".join(str(item) for item in conv_box)+'\n'box_str_list.append(box_str)if box_str_list!=[]:with open(txtsave, "w", encoding="utf-8") as f:f.writelines(box_str_list)if os.path.exists(txtsave):cv2.imwrite(imgsave, img)def normalize(self, size, box): # size:(原图w,原图h) , box:(xmin,xmax,ymin,ymax)# 锚框归一化dw = 1. / size[0] # 1/wdh = 1. / size[1] # 1/hx = (box[0] + box[2]) / 2.0 # 物体在图中的中心点x坐标y = (box[1] + box[3]) / 2.0 # 物体在图中的中心点y坐标w = box[2] - box[0] # 物体实际像素宽度h = box[3] - box[1] # 物体实际像素高度x = x * dw # 物体中心点x的坐标比(相当于 x/原图w)w = w * dw # 物体宽度的宽度比(相当于 w/原图w)y = y * dh # 物体中心点y的坐标比(相当于 y/原图h)h = h * dh # 物体宽度的宽度比(相当于 h/原图h)return [x, y, w, h] # 返回 相对于原图的物体中心点的x坐标比,y坐标比,宽度比,高度比,取值范围[0-1]def denormalize(self, size, normalized_box): # size: (原图w, 原图h), normalized_box: [x, y, w, h]# 提取原图的宽度和高度w, h = size# 将中心点坐标和宽高还原为原图的像素坐标x_center = normalized_box[0] * wy_center = normalized_box[1] * hbox_width = normalized_box[2] * wbox_height = normalized_box[3] * h# 计算还原后的边界框坐标xmin = x_center - box_width / 2.0xmax = x_center + box_width / 2.0ymin = y_center - box_height / 2.0ymax = y_center + box_height / 2.0return [int(xmin), int(ymin), int(xmax), int(ymax)] # 返回还原后的边界框坐标def visual_json_main(self, visfile):for file in os.listdir(self.img_path):base = file.split('.')[0]jpgdir = os.path.join(self.img_path, file)img = cv2.imread(jpgdir)if img is None:return print('img is empty')jsondir = os.path.join(self.labels, base+'.json')with open(jsondir, 'r', encoding='utf-8') as f:boxes_list = json.load(f)box_list = []for box_ in boxes_list:box = box_[:4]text = box_[self.cls_id]box.append(text)box_list.append(box)visdir = os.path.join(visfile, file)vis = self.visual_word(box_list, img ,(0,255,0))cv2.imwrite(visdir, vis)print(file,' success')def visual_box(self, box_list, img, color):for idx, box in enumerate(box_list):if len(box) == 4:l, t, r, b = box# 图片画框cv2.rectangle(img, (int(l), int(t)), (int(r), int(b)), color, thickness=2, lineType=cv2.LINE_AA)elif len(box) == 8:pts = np.array(box, np.int32)pts = pts.reshape((-1, 1, 2))cv2.polylines(img, [pts], isClosed=True, color=color, thickness=2)return imgdef visual_word(self, word_list, img, color):font_path = "C:\Windows\Fonts\SimHei.ttf"font_size = 45for idx, box in enumerate(word_list):l, t, r, b, word = box# 图片画框cv2.rectangle(img, (l, t), (r, b), color, thickness=2, lineType=cv2.LINE_AA)caption = f"{word}"pil_img = Image.new('RGB', (0, 0))draw = ImageDraw.Draw(pil_img)text_size = draw.textbbox((0, 0), caption, font=ImageFont.truetype(font_path, font_size))text_width = text_size[2] - text_size[0]text_height = text_size[3] - text_size[1]# 使用 OpenCV 画文本背景框cv2.rectangle(img, (r, t), (r + text_width, t + text_height), color, -1)# 使用 PIL 绘制中文标签img = self.put_chinese_text(img, caption, (r, t), font_size, font_path, (0, 0, 0))return imgdef put_chinese_text(self, img, text, position, font_size, font_path, text_color):# 创建一个 PIL 图像pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(pil_img)# 加载字体font = ImageFont.truetype(font_path, font_size)# 绘制文本draw.text(position, text, font=font, fill=text_color)# 将 PIL 图像转换回 OpenCV 格式img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)return img相关文章:
从零开始使用YOLOv11——Yolo检测detect数据集自建格式转换为模型训练格式:20w+图片1w+类别代码测试成功
在之前的文章中记录了YOLO环境的配置安装和基本命令的一些使用,上一篇博文的地址快速链接:从零开始使用YOLOv8——环境配置与极简指令(CLI)操作:1篇文章解决—直接使用:模型部署 and 自建数据集:…...
自动化新时代:机器取代工作,我们该如何重塑自我?
内容概要 在自动化时代的浪潮中,技术的飞速发展对传统工作模式产生了深远影响。我们眼前浮现的是一个充满机遇与挑战的新世界。许多岗位面临被机器取代的威胁,然而,这一变化并不仅仅是消极的。在这个背景下,个体不仅需要重新审视…...
GEE 土地分类——利用Sentinel-2数据进行土地分类
目录 简介 函数 ee.Classifier.smileRandomForest(numberOfTrees, variablesPerSplit, minLeafPopulation, bagFraction, maxNodes, seed) Arguments: Returns: Classifier 代码 结果 简介 利用Sentinel-2数据进行土地分类的流程大致可分为以下几个步骤: 1. 数据获取…...
《C++ 游戏开发》
一、引言 在当今的数字娱乐时代,游戏开发已经成为一个充满活力和创新的领域。C 作为一种强大的编程语言,在游戏开发中占据着重要的地位。它具有高效的性能、丰富的功能和广泛的适用性,能够满足游戏开发中对性能和灵活性的高要求。本文将深入探…...
2024年11月10日系统架构设计师考试题目回顾
案例分析 试题一:质量属性 基于描述填空是什么质量属性,常规题。(性能,功能,安全,可用等等)可用性而言,王工建议采用 ping/echo 机制检测,不过从资源使用角度ÿ…...
测试实项中的偶必现难测bug--苹果支付丢单问题
问题描述: app支付后,由于某种原因(可能是网络、流量不稳定、或者用户快速频繁操作。。。)会造成一定概率性的回调苹果支付结果失败的情况出现,表现的直观现象就是客户反馈已经支付了,包括苹果支付也是有记录,但是我们的后台显示的是已取消状态的订单 验证难点:测试和…...
Elasticsearch的数据类型
Elasticsearch(简称 ES)支持多种数据类型,主要分为以下几类: 1. 基本数据类型 Text:用于全文搜索的文本字段。ES 会对其内容进行分词处理。Keyword:适用于精确匹配的字段,例如名称、标签等。ES 不会对其内容分词处理。Integer:整数类型,包括 byte、short、integer 和…...
SSL 证书申请以及配置流程
SSL 证书申请以及配置流程 手动申请免费 SSL 证书的简明指南 如果你希望手动为你的网站申请免费的 SSL 证书,Let’s Encrypt 提供了一个很棒的免费服务。而 Certbot 则是官方推荐的工具,可以帮助你完成证书的申请和配置。以下是如何一步步完成的详细说…...
[Docker#4] 镜像仓库 | 部分常用命令
目录 什么是 Docker Registry 镜像仓库生活案例 镜像仓库分类 镜像仓库工作机制 常用的镜像仓库 私有仓库 镜像仓库命令 镜像命令[部分] 容器命令[部分] 什么是 Docker Registry 定义:Docker Registry 负责存储、管理和分发镜像,并提供了登录认…...
工业通信协议对比:OPC-UA、Modbus、MQTT、HTTP
综合对比表 对比项OPC-UAModbusMQTTHTTP通信效率低,带宽消耗高高高,开销低,效率高低,带宽消耗大实时性一般,延迟较高高,延迟低高,低延迟低,延迟高性能消耗高,需要高性能…...
docker 常用方法
目录 docker参数解释 基础信息和环境变量设置 容器运行和管理相关参数 数据卷挂载 GPU 相关参数 镜像相关参数 查看现有的镜像 docker images 查看正在运行的docker docker ps 1、docker启动停止及查看状态 启动docker: systemctl start docker 停止docker…...
区块链技术入门:以太坊智能合约详解
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 区块链技术入门:以太坊智能合约详解 区块链技术入门:以太坊智能合约详解 区块链技术入门:以太…...
特定数据库的备份脚本
该脚本 mysql_backup.sh 是一个 MySQL 数据库的备份脚本,以下是它的工作原理和需要注意的细节: 脚本内容分析 1.设置时间变量 TIME : TIMEdate %F_%H-%M-%S该变量 TIME 存储当前日期和时间,格式为 YYYY-MM-DD_HH-MM-SS,用于生…...
uni-app打包后报错云服务空间未关联
使用uni-app打包到h5 项目里面用到了uni-app的云端一体城市选择组件,这个组件数据用到了uniCloud云服务空间,在本地运行没问题,打包之后测试环境报错: 一顿查,查到了官网是这样说的: cli publish --platfo…...
FPGA学习(10)-数码管
前3节视频目的是实现显示0~F的数码管仿真,后3节是用驱动芯片驱动数码管。 目录 1.数码管显示原理 2.代码过程 2.1仿真结果 3.串行移位寄存器原理 3.1原理 编辑 3.2 数据手册 3.3 先行设计思路 4.程序 4.1确定SRCLK的频率 4.2序列计数器 4.3 不同coun…...
C++(继承)
继承的语法 继承的好处:减少重复代码 语法: class 子类 : 继承方法 父类 子类 也称为 派生类 父类 也成为 基类 继承方式 公共继承 保护继承 私有继承 结论:父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后…...
华为OD机试 - RSA加密算法(Java 2024 E卷 100分)
long n (long) Math.sqrt(num); 与long n (long) Math.floor(Math.sqrt(num)); 这两行代码的目的都是计算 num 的平方根,并将结果转换为 long 类型的整数。然而,它们在处理方式上有一些微小的差别。 long n (long) Math.sqrt(num);long n (long) M…...
分组校验在Spring中的应用详解
目录 前言1. 什么是分组校验2. 分组校验的基本原理3. 分组校验的实现步骤3.1 定义分组接口3.2 在校验项中指定分组3.3 校验时指定要校验的分组3.4 默认分组和分组的继承 4. 分组校验的优势和适用场景4.1 优势4.2 适用场景 5. 常见问题与解决方案5.1 校验未生效5.2 无法识别默认…...
torch.nn.**和torch.nn.functional.**的区别
torch.nn.** torch.nn.**是一个继承了torch.nn.Module的类,使用前必须先构造对象,然后再调用。如果直接使用则会报错 例如 a torch.randn(3,4) print(a) sigmoid torch.nn.Sigmoid() a sigmoid(a) print(a) a torch.nn.Sigmoid(a)tensor([[ 0.2462…...
Air780E基于LuatOS编程开发
Air780E基于LuatOS编程开发 Air780E开发板下载固件版本开发板刷机开发调试源码编译下载源码编译工具编译工具链 Air780E开发板 合宙通信推出的 LTE Cat.1 bis通信模块,采用移芯EC618平台,支持4G全网通, 包括的模组有: Air780E – 4G Cat.1Air780EG – …...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献
Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译: ### 胃肠道癌症的发病率呈上升趋势,且有年轻化倾向(Bray等人,2018&#x…...
