Python实现将LabelMe生成的JSON格式转换成YOLOv8支持的TXT格式

      标注工具 LabelMe 生成的标注文件为JSON格式,而YOLOv8中支持的为TXT文件格式。以下Python代码实现3个功能

     1.将JSON格式转换成TXT格式;

     2.将数据集进行随机拆分,生成YOLOv8支持的目录结构;

     3.生成YOLOv8支持的YAML文件。

     代码test_labelme2yolov8.py如下:

import os
import json
import argparse
import colorama
import random
import shutildef parse_args():parser = argparse.ArgumentParser(description="json(LabelMe) to txt(YOLOv8)")parser.add_argument("--dir", required=True, type=str, help="images, json files, and generated txt files, all in the same directory")parser.add_argument("--labels", required=True, type=str, help="txt file that hold indexes and labels, one label per line, for example: face 0")parser.add_argument("--val_size", default=0.2, type=float, help="the proportion of the validation set to the overall dataset:[0., 0.5]")parser.add_argument("--name", required=True, type=str, help="the name of the dataset")args = parser.parse_args()return argsdef get_labels_index(name):labels = {} # key,valuewith open(name, "r") as file:for line in file:# print("line:", line)key_value = []for v in line.split(" "):# print("v:", v)key_value.append(v.replace("\n", "")) # remove line breaks(\n) at the end of the lineif len(key_value) != 2:print(colorama.Fore.RED + "Error: each line should have only two values(key value):", len(key_value))continuelabels[key_value[0]] = key_value[1]with open(name, "r") as file:line_num = len(file.readlines())if line_num != len(labels):print(colorama.Fore.RED + "Error: there may be duplicate lables:", line_num, len(labels))return labelsdef get_json_files(dir):jsons = []for x in os.listdir(dir):if x.endswith(".json"):jsons.append(x)return jsonsdef parse_json(name):with open(name, "r") as file:data = json.load(file)width = data["imageWidth"]height = data["imageHeight"]# print(f"width: {width}; height: {height}")objects=[]for shape in data["shapes"]:if shape["shape_type"] != "rectangle":print(colorama.Fore.YELLOW + "Warning: only the rectangle type is supported:", shape["shape_type"])continueobject = []object.append(shape["label"])object.append(shape["points"])objects.append(object)return width, height, objectsdef get_box_width_height(box):dist = lambda val: max(val) - min(val)x = [pt[0] for pt in box]y = [pt[1] for pt in box]return min(x), min(y), dist(x), dist(y)def bounding_box_normalization(width, height, objects, labels):boxes = []for object in objects:box = [] # class x_center y_center width heightbox.append(labels[object[0]])# print("point:", object[1])x_min, y_min, box_w, box_h = get_box_width_height(object[1])box.append(round((float(x_min + box_w / 2.0) / width), 6))box.append(round((float(y_min + box_h / 2.0) / height), 6))box.append(round(float(box_w / width), 6))box.append(round(float(box_h / height), 6))boxes.append(box)return boxes	def write_to_txt(dir, json, width, height, objects, labels):boxes = bounding_box_normalization(width, height, objects, labels)# print("boxes:", boxes)name = json[:-len(".json")] + ".txt"# print("name:", name)with open(dir + "/" + name, "w") as file:for item in boxes:# print("item:", item)if len(item) != 5:print(colorama.Fore.RED + "Error: the length must be 5:", len(item))continuestring = item[0] + " " + str(item[1]) + " " + str(item[2]) + " " + str(item[3]) + " " + str(item[4]) + "\r"file.write(string)def json_to_txt(dir, jsons, labels):for json in jsons:name = dir + "/" + json# print("name:", name)width, height, objects = parse_json(name)# print(f"width: {width}; height: {height}; objects: {objects}")write_to_txt(dir, json, width, height, objects, labels)def is_in_range(value, a, b):return a <= value <= bdef get_random_sequence(length, val_size):numbers = list(range(0, length))val_sequence = random.sample(numbers, int(length*val_size))# print("val_sequence:", val_sequence)train_sequence = [x for x in numbers if x not in val_sequence]# print("train_sequence:", train_sequence)return train_sequence, val_sequencedef get_files_number(dir):count = 0for file in os.listdir(dir):if os.path.isfile(os.path.join(dir, file)):count += 1return countdef split_train_val(dir, jsons, name, val_size):if is_in_range(val_size, 0., 0.5) is False:print(colorama.Fore.RED + "Error: the interval for val_size should be:[0., 0.5]:", val_size)raisedst_dir_images_train = "datasets/" + name + "/images/train"dst_dir_images_val = "datasets/" + name + "/images/val"dst_dir_labels_train = "datasets/" + name + "/labels/train"dst_dir_labels_val = "datasets/" + name + "/labels/val"try:os.makedirs(dst_dir_images_train) #, exist_ok=Trueos.makedirs(dst_dir_images_val)os.makedirs(dst_dir_labels_train)os.makedirs(dst_dir_labels_val)except OSError as e:print(colorama.Fore.RED + "Error: cannot create directory:", e.strerror)raise# supported image formatsimg_formats = (".bmp", ".jpeg", ".jpg", ".png", ".webp")# print("jsons:", jsons)train_sequence, val_sequence = get_random_sequence(len(jsons), val_size)for index in train_sequence:for format in img_formats:file = dir + "/" + jsons[index][:-len(".json")] + format# print("file:", file)if os.path.isfile(file):shutil.copy(file, dst_dir_images_train)breakfile = dir + "/" + jsons[index][:-len(".json")] + ".txt"if os.path.isfile(file):shutil.copy(file, dst_dir_labels_train)for index in val_sequence:for format in img_formats:file = dir + "/" + jsons[index][:-len(".json")] + formatif os.path.isfile(file):shutil.copy(file, dst_dir_images_val)breakfile = dir + "/" + jsons[index][:-len(".json")] + ".txt"if os.path.isfile(file):shutil.copy(file, dst_dir_labels_val)num_images_train = get_files_number(dst_dir_images_train)num_images_val = get_files_number(dst_dir_images_val)num_labels_train = get_files_number(dst_dir_labels_train)num_labels_val = get_files_number(dst_dir_labels_val)if  num_images_train + num_images_val != len(jsons) or num_labels_train + num_labels_val != len(jsons):print(colorama.Fore.RED + "Error: the number of files is inconsistent:", num_images_train, num_images_val, num_labels_train, num_labels_val, len(jsons))raisedef generate_yaml_file(labels, name):path = os.path.join("datasets", name, name+".yaml")# print("path:", path)with open(path, "w") as file:file.write("path: ../datasets/%s # dataset root dir\n" % name)file.write("train: images/train # train images (relative to 'path')\n")file.write("val: images/val  # val images (relative to 'path')\n")file.write("test: # test images (optional)\n\n")file.write("# Classes\n")file.write("names:\n")for key, value in labels.items():# print(f"key: {key}; value: {value}")file.write("  %d: %s\n" % (int(value), key))if __name__ == "__main__":colorama.init()args = parse_args()# 1. parse JSON file and write it to a TXT filelabels = get_labels_index(args.labels)# print("labels:", labels)jsons = get_json_files(args.dir)# print("jsons:", jsons)json_to_txt(args.dir, jsons, labels)# 2. split the datasetsplit_train_val(args.dir, jsons, args.name, args.val_size)# 3. generate a YAML filegenerate_yaml_file(labels, args.name)print(colorama.Fore.GREEN + "====== execution completed ======")

      代码有些多,主要函数说明如下:

     1.函数parse_args:解析输入参数;

     2.函数get_labels_index:解析labels文件,数据集中的所有类别及对应的索引,格式labels.txt如下所示:生成YOLOv8的YAML文件时也需要此文件

face 0
hand 1
eye 2
mouth 3
horse 4
tree 5
bridge 6
house 7

     3.函数get_json_files:获取指定目录下的所有json文件;

     4.函数parse_json:解析json文件,将txt文件中需要的数据提取出来;

     5.函数bounding_box_normalization:将bounding box值归一化到(0,1)区间;

     6.函数write_to_txt:将最终结果写入txt文件;

     7.函数split_train_val:将数据集随机拆分为训练集和验证集,并按YOLOv8支持的目录结构存放,根目录为datasets,接着是指定的数据集名,例如为fake,与YOLOv8中数据集coco8目录结构完全一致

     8.函数generate_yaml_file:生成YOLOv8支持的yaml文件,存放在datasets/数据集名下,例如为fake.yaml

      接收4个参数:参数dir为存放数据集的目录;参数labels指定labels文件;参数val_size指定验证集所占的比例;参数name指定新生成的YOLOv8数据集的名字

      这里从网上随机下载了10幅图像,使用LabelMe进行了标注,执行结果如下图所示:

     生成的fake.yaml文件如下图所示:

path: ../datasets/fake # dataset root dir
train: images/train # train images (relative to 'path')
val: images/val  # val images (relative to 'path')
test: # test images (optional)# Classes
names:0: face1: hand2: eye3: mouth4: horse5: tree6: bridge7: house

      将生成的fake数据集进行训练,测试代码test_yolov8_detect.py如下:

import argparse
import colorama
from ultralytics import YOLOdef parse_args():parser = argparse.ArgumentParser(description="YOLOv8 object detect")parser.add_argument("--yaml", required=True, type=str, help="yaml file")parser.add_argument("--epochs", required=True, type=int, help="number of training")args = parser.parse_args()return argsdef train(yaml, epochs):model = YOLO("yolov8n.pt") # load a pretrained modelresults = model.train(data=yaml, epochs=epochs, imgsz=640) # train the modelmetrics = model.val() # It'll automatically evaluate the data you trained, no arguments needed, dataset and settings rememberedmodel.export(format="onnx", dynamic=True) # export the modelif __name__ == "__main__":colorama.init()args = parse_args()train(args.yaml, args.epochs)print(colorama.Fore.GREEN + "====== execution completed ======")

      执行结果如下图所示:目前此测试代码接收2个参数:参数yaml指定yaml文件;参数epochs指定训练次数;由以下结果可知,生成的新数据集无需做任何改动即可进行训练

      GitHub:https://github.com/fengbingchun/NN_Test

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

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

相关文章

基于EBAZ4205矿板的图像处理:07sobel边缘检测算法

基于EBAZ4205矿板的图像处理&#xff1a;07sobel边缘检测算法 项目文件 随后会上传项目全部文件&#xff0c;和之前一样免费下载 先看效果 如上所见&#xff0c;能够提取图像的边缘&#xff0c;这个sobel边缘检测算法的阈值&#xff08;认定是否为边缘的阈值&#xff09;一样…

C++入门 基于ros的话题通信

一、 开发环境 ubuntu20.04 ros版本noetic 参考视频 https://www.bilibili.com/video/BV1Ci4y1L7ZZ/?p52&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source4cd1b6f268e2a29a11bea5d2568836ee 二、 创建两个功能包 //创建工作空间 工作空…

英伟达:AI之火还在燃烧!

昨晚&#xff0c;全球市场屏息以待的一家公司财报终于发布了&#xff0c;没有超出大家预期的是&#xff0c;他还是超预期了。 大家当然都知道我们要说的是——英伟达&#xff01; 如今&#xff0c;全球大模型之Z激Z正酣&#xff0c;AI芯片装备竞赛需求猛烈&#xff0c;作为AI…

浅析智能体开发(第二部分):智能体设计模式和软件架构

大语言模型&#xff08;LLM&#xff09;驱动的智能体&#xff08;AI Agent&#xff09;展现出许多传统软件所不具备的特征。不仅与传统软件的设计理念、方法、工具和技术栈有显著的差异&#xff0c;AI原生&#xff08;AI Native&#xff09;的智能体还融入了多种新概念和技术。…

外汇天眼:塞舌尔券商JustMarkets被控为诈骗平台,众多交易纠纷背后的真相究竟为何?

近年来外汇市场因为具有高流动性、交易时间长、不容易被操控等特色&#xff0c;受到愈来愈多投资人重视&#xff0c;相关交易愈来愈火热。外汇天眼身为全球最权威的经纪商查询平台&#xff0c;不仅致力于收录交易商信息&#xff0c;也经常发布券商解析与测评文章。最近我们发现…

IDEA 自定义注解(类注释、方法注释)

一、生成类注释 1、打开设置位置 打开File —> Settings —> Editor —> File and Code Templates —> Files —> Class 2、将自定义的类注解规则&#xff0c;复制到Class中。 /** * * 功能: * * 作者: 暗自着迷 * * 日期: ${YEAR}-${MONTH}-${DAY} ${HOU…

3D 高斯泼溅(Gaussian Splatting)-3D重建的3DGS时代

3D重建自从NeRfs出现之后又热闹了一次&#xff0c;3D GS技术一时间燃变了整个三维重建和Slam领域&#xff0c;几个月不见&#xff0c;沧海桑田。 NeRF貌似已成为过去式&#xff0c;三维重建进入了3DGS时代&#xff0c;且3DGS在各方面比NeRF落地更快。3D 高斯泼溅&#xff08;S…

Docker-数据卷的挂载

文章目录 数据卷概念数据卷实现机制数据卷特性数据卷操作数据卷挂载通用命令匿名挂载具名挂载数据卷继承容器数据卷只读容器数据卷读写-默认 总结 数据卷概念 为了很好的实现数据保存和数据共享&#xff0c;Docker提出了Volume这个概念&#xff0c;简单的说就是绕过默认的联合文…

Java(十)---抽象类和接口

文章目录 前言知识回顾1.抽象类1.1.抽象类语法1.2 抽象类特性 2.接口2.1.接口的概念2.2 语法规则2.3 接口使用2.4 接口特性2.5 实现多个接口 3.Object类3.1 获取对象信息3.2.对象比较equals方法 4.接口使用实例4.1.Comparable4.2.Comparator4.3.Cloneable深拷贝和浅拷贝 前言 …

新定义RD8T36P48点亮LED--汇编

其实汇编和C语言差不多&#xff0c;简单的东西用汇编挺好&#xff0c;中等及以上复杂度的程序还是C语言更灵活 直接在keil新建好工程&#xff0c;选好芯片型号和下载方式&#xff0c;再创建一个.asm文件并添加到工程&#xff0c; 工程创建完如图 工程配置 代码 ORG 0000HL…

两数交换,数组查找奇数个数的数(位运算)

文章目录 一、异或运算&#xff1a;1.1 Demo1.2 面试题 一、异或运算&#xff1a; 1.1 Demo 0和N进行异或运算都等于N 任何一个数和自己异或运算都等于0 且异或运算满足交换率 a^b b^a eg&#xff1a; a 甲 &#xff0c; b 已 那么则有 a a^b ​ b a^b ​ a a^b 故有&am…

如何理解数字孪生?数字孪生三维可视化有什么关系?

随着科技的飞速发展和数字化转型的浪潮&#xff0c;数字孪生技术逐渐崭露头角&#xff0c;并在多个领域展现出巨大的潜力。而在这股技术革新的潮流中&#xff0c;数字孪生三维可视化以其直观、精确和动态的特点&#xff0c;成为了推动数字化转型的重要部分。 一、数字孪生的魅…

八国多语言微盘微交易所系统源码 单控点控 K线完好

安装环境linux NGMySQL5.6PHP7.2&#xff08;函数全删&#xff09;pm2管理器&#xff08;node版本选择v12.20.0&#xff09; config/ database.php 修改数据库链接 设置运行目录 public 伪静态thinkphp

css左右滚动互不影响

想实现左右都可以滚动&#xff0c;且互不影响。 只需要再左边的css里面 .threedlist {cursor: pointer;width: 280px;position: fixed;height: 100vh; /* 定义父容器高度 */overflow-y: auto; /* 只有在内容超过父容器高度时才出现滚动条 */} 如果想取消滚动条样式 .threedli…

【设计模式深度剖析】【4】【创建型】【建造者模式】| 类比选购汽车的过程,加深理解

&#x1f448;️上一篇:抽象工厂模式 | 下一篇:原型模式&#x1f449;️ 目录 建造者模式概览定义英文原话直译如何理解呢&#xff1f;建造者模式将对象的建造过程给抽象出来了类比选购汽车 4个角色UML类图1. 抽象建造者&#xff08;Builder&#xff09;角色2. 具体建造者…

【Docker实操】启动redis服务

一、步骤 1、获取redis镜像 执行获取redis镜像命令&#xff1a;docker pull redis。打印镜像清单&#xff0c;可以看到新拉到的redis镜像。 2、创建redis.conf配置文件 linux主机 mkdir -p /root/www/redis/conf touch /root/www/redis/conf/redis.conf cat << EOF &…

三维焊接平台在新一代机器人生产中得到广泛应用-河北北重

随着智能制造行业的不断推进&#xff0c;三维焊接平台在工业机器人领域应用现象普遍。三维焊接平台、三维柔性焊接平台工装夹具也会在新一代机器人——智能机器人在工业生产中得到广泛应用。目前&#xff0c;三维焊接平台、焊接铸铁平台在工业机器人的主要作用是应用于弧焊、电…

内网穿透--Ngrok-入门-上线

免责声明:本文仅做技术交流与学习... 目录 Ngrok: 技术实现: 前提: 命令: 详细流程及图解: 平台Ngrok: Sunny-Ngrok内网转发内网穿透 - 国内内网映射服务器 支持的协议&#xff1a;tcp、http、https 支持的类型&#xff1a;正向代理、反向代理 --隧道开通免费的 --协议…

第三代“图即代码”低代码平台设计

低代码平台现在市面上的产品大致分为两类&#xff0c;一种是“ 搭积木”类型的 这种类型的主要是一些行业定制的saas产品&#xff0c;是在已经成型或者是平台提供的垄断性资源上来做二次“搭建”这种平台优势在于能快速上手&#xff0c;有难度的都进行了“简化”和“特定场景”…

经纬恒润第三代重载自动驾驶平板车

随着无人驾驶在封闭场地和干线道路场景的加速落地&#xff0c;港口作为无人化运营的先行者&#xff0c;其场景的复杂度、特殊性对无人化运营的技术提出了各种挑战。经纬恒润作为无人驾驶解决方案提供商&#xff0c;见证了港口在无人化运营方面的尝试及发展&#xff0c;并深度参…