目标识别数据集互相转换——xml、txt、json数据格式互转

2023-11-02

VOC数据格式与YOLO数据格式互转

1.VOC数据格式

VOC(Visual Object Classes)是一个常用的计算机视觉数据集,它主要用于对象检测、分类和分割任务。VOC的标注格式,也被许多其他的数据集采用,因此理解这个数据格式是很重要的。下面是一个详细的介绍:

一个典型的VOC数据集主要包括以下两个主要组成部分:

  1. JPEGImages:这个文件夹包含所有的图片文件,通常都是jpg格式。
  2. Annotations:这个文件夹包含每张图片对应的标注文件。每个标注文件都是xml格式的,其中包含了图片中每个对象的信息,如类别、位置等。

格式如下:

<annotation>
    <folder>图像文件所在文件夹名称</folder>
    <filename>图像文件名</filename>
    <source>...省略...</source>
    <size>
        <width>图像宽度</width>
        <height>图像高度</height>
        <depth>图像深度,例如RGB图像深度为3</depth>
    </size>
    <segmented>省略...</segmented>
    <object>
        <name>物体类别名称</name>
        <pose>省略...</pose>
        <truncated>是否被截断(0表示未被截断,1表示被截断)</truncated>
        <difficult>是否难以识别(0表示容易识别,1表示难以识别)</difficult>
        <bndbox>
            <xmin>物体边界框左上角的x坐标</xmin>
            <ymin>物体边界框左上角的y坐标</ymin>
            <xmax>物体边界框右下角的x坐标</xmax>
            <ymax>物体边界框右下角的y坐标</ymax>
        </bndbox>
    </object>
    ...其他物体的标注信息...
</annotation>

在标注文件中,可以包含多个<object>标签,每个标签都表示图片中的一个物体。每个物体的类别名称和位置信息都包含在这个标签中。位置信息通过一个矩形边界框来表示,该框由左上角和右下角的坐标确定。

2.YOLO数据格式

数据格式:label_index,cx, cy,w,h
label_index :为标签名称在标签数组中的索引,下标从 0 开始。
cx:标记框中心点的 x 坐标,数值是原始中心点 x 坐标除以 图宽 后的结果。
cy:标记框中心点的 y 坐标,数值是原始中心点 y 坐标除以 图高 后的结果。
w:标记框的 宽,数值为 原始标记框的 宽 除以 图宽 后的结果。
h:标记框的 高,数值为 原始标记框的 高 除以 图高 后的结果。

xml转txt

import os
import glob
import argparse
import random
import xml.etree.ElementTree as ET
from PIL import Image
from tqdm import tqdm

def get_all_classes(xml_path):
    xml_fns = glob.glob(os.path.join(xml_path, '*.xml'))
    class_names = []
    for xml_fn in xml_fns:
        tree = ET.parse(xml_fn)
        root = tree.getroot()
        for obj in root.iter('object'):
            cls = obj.find('name').text
            class_names.append(cls)
    return sorted(list(set(class_names)))

def convert_annotation(img_path, xml_path, class_names, out_path):
    output = []
    im_fns = glob.glob(os.path.join(img_path, '*.jpg'))
    for im_fn in tqdm(im_fns):
        if os.path.getsize(im_fn) == 0:
            continue
        xml_fn = os.path.join(xml_path, os.path.splitext(os.path.basename(im_fn))[0] + '.xml')
        if not os.path.exists(xml_fn):
            continue
        img = Image.open(im_fn)
        height, width = img.height, img.width
        tree = ET.parse(xml_fn)
        root = tree.getroot()
        anno = []
        xml_height = int(root.find('size').find('height').text)
        xml_width = int(root.find('size').find('width').text)
        if height != xml_height or width != xml_width:
            print((height, width), (xml_height, xml_width), im_fn)
            continue
        for obj in root.iter('object'):
            cls = obj.find('name').text
            cls_id = class_names.index(cls)
            xmlbox = obj.find('bndbox')
            xmin = int(xmlbox.find('xmin').text)
            ymin = int(xmlbox.find('ymin').text)
            xmax = int(xmlbox.find('xmax').text)
            ymax = int(xmlbox.find('ymax').text)
            cx = (xmax + xmin) / 2.0 / width
            cy = (ymax + ymin) / 2.0 / height
            bw = (xmax - xmin) * 1.0 / width
            bh = (ymax - ymin) * 1.0 / height
            anno.append('{} {} {} {} {}'.format(cls_id, cx, cy, bw, bh))
        if len(anno) > 0:
            output.append(im_fn)
            with open(im_fn.replace('.jpg', '.txt'), 'w') as f:
                f.write('\n'.join(anno))
    random.shuffle(output)
    train_num = int(len(output) * 0.9)
    with open(os.path.join(out_path, 'train.txt'), 'w') as f:
        f.write('\n'.join(output[:train_num]))
    with open(os.path.join(out_path, 'val.txt'), 'w') as f:
        f.write('\n'.join(output[train_num:]))

def parse_args():
    parser = argparse.ArgumentParser('generate annotation')
    parser.add_argument('--img_path', type=str, help='input image directory',default= "data/jpg/")
    parser.add_argument('--xml_path', type=str, help='input xml directory',default= "data/xml/")
    parser.add_argument('--out_path', type=str, help='output directory',default= "data/dataset/")
    args = parser.parse_args()
    return args

if __name__ == '__main__':
    args = parse_args()
    class_names = get_all_classes(args.xml_path)
    print(class_names)
    convert_annotation(args.img_path, args.xml_path, class_names, args.out_path)

txt转xml

from xml.dom.minidom import Document
import os
import cv2
 
 
def makexml(picPath, txtPath, xmlPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
    dic = {'0': "ship",  # 创建字典用来对类型进行转换
           '1': "car_trucks",  # 此处的字典要与自己的classes.txt文件中的类对应,且顺序要一致
           '2' :'person',
           '3': 'stacking_area',
           '4': 'car_forklift',
           '5': 'unload_car',
           '6': 'load_car',
           '7': 'car_private',
           }

    files = os.listdir(txtPath)
    for i, name in enumerate(files):
        xmlBuilder = Document()
        annotation = xmlBuilder.createElement("annotation")  # 创建annotation标签
        xmlBuilder.appendChild(annotation)
        txtFile = open(txtPath + name)
        print(txtFile)
        txtList = txtFile.readlines()
        img = cv2.imread(picPath + name[0:-4] + ".png")
        Pheight, Pwidth, Pdepth = img.shape
 
        folder = xmlBuilder.createElement("folder")  # folder标签
        foldercontent = xmlBuilder.createTextNode("driving_annotation_dataset")
        folder.appendChild(foldercontent)
        annotation.appendChild(folder)  # folder标签结束
 
        filename = xmlBuilder.createElement("filename")  # filename标签
        filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".png")
        filename.appendChild(filenamecontent)
        annotation.appendChild(filename)  # filename标签结束

        size = xmlBuilder.createElement("size")  # size标签
        width = xmlBuilder.createElement("width")  # size子标签width
        widthcontent = xmlBuilder.createTextNode(str(Pwidth))
        width.appendChild(widthcontent)
        size.appendChild(width)  # size子标签width结束
 
        height = xmlBuilder.createElement("height")  # size子标签height
        heightcontent = xmlBuilder.createTextNode(str(Pheight))
        height.appendChild(heightcontent)
        size.appendChild(height)  # size子标签height结束
 
        depth = xmlBuilder.createElement("depth")  # size子标签depth
        depthcontent = xmlBuilder.createTextNode(str(Pdepth))
        depth.appendChild(depthcontent)
        size.appendChild(depth)  # size子标签depth结束
 
        annotation.appendChild(size)  # size标签结束
 
        for j in txtList:
            oneline = j.strip().split(" ")
            object = xmlBuilder.createElement("object")  # object 标签
            picname = xmlBuilder.createElement("name")  # name标签
            namecontent = xmlBuilder.createTextNode(dic[oneline[0]])
            picname.appendChild(namecontent)
            object.appendChild(picname)  # name标签结束
 
            pose = xmlBuilder.createElement("pose")  # pose标签
            posecontent = xmlBuilder.createTextNode("Unspecified")
            pose.appendChild(posecontent)
            object.appendChild(pose)  # pose标签结束
 
            truncated = xmlBuilder.createElement("truncated")  # truncated标签
            truncatedContent = xmlBuilder.createTextNode("0")
            truncated.appendChild(truncatedContent)
            object.appendChild(truncated)  # truncated标签结束
 
            difficult = xmlBuilder.createElement("difficult")  # difficult标签
            difficultcontent = xmlBuilder.createTextNode("0")
            difficult.appendChild(difficultcontent)
            object.appendChild(difficult)  # difficult标签结束
 
            bndbox = xmlBuilder.createElement("bndbox")  # bndbox标签
            xmin = xmlBuilder.createElement("xmin")  # xmin标签
            mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)
            xminContent = xmlBuilder.createTextNode(str(mathData))
            xmin.appendChild(xminContent)
            bndbox.appendChild(xmin)  # xmin标签结束
 
            ymin = xmlBuilder.createElement("ymin")  # ymin标签
            mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)
            yminContent = xmlBuilder.createTextNode(str(mathData))
            ymin.appendChild(yminContent)
            bndbox.appendChild(ymin)  # ymin标签结束
 
            xmax = xmlBuilder.createElement("xmax")  # xmax标签
            mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)
            xmaxContent = xmlBuilder.createTextNode(str(mathData))
            xmax.appendChild(xmaxContent)
            bndbox.appendChild(xmax)  # xmax标签结束
 
            ymax = xmlBuilder.createElement("ymax")  # ymax标签
            mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)
            ymaxContent = xmlBuilder.createTextNode(str(mathData))
            ymax.appendChild(ymaxContent)
            bndbox.appendChild(ymax)  # ymax标签结束
 
            object.appendChild(bndbox)  # bndbox标签结束
 
            annotation.appendChild(object)  # object标签结束
 
        f = open(xmlPath + name[0:-4] + ".xml", 'w')
        xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
        f.close()
 
 
if __name__ == "__main__":
    picPath = "data/images/"  # 图片所在文件夹路径,后面的/一定要带上
    txtPath = "data/labels/"  # txt所在文件夹路径,后面的/一定要带上
    xmlPath = "data/xml/"  # xml文件保存路径,后面的/一定要带上
    makexml(picPath, txtPath, xmlPath)
 

json转txt

import os
import numpy as np
import json
from glob import glob
import cv2
from sklearn.model_selection import train_test_split
from os import getcwd

classes = ["0","1","2"]
# 1.标签路径
labelme_path = r"dataset/"
isUseTest = False  # 是否创建test集
# 3.获取待处理文件
files = glob(labelme_path + "*.json")
files = [i.replace("\\", "/").split("/")[-1].split(".json")[0] for i in files]
# print(files)
if isUseTest:
    trainval_files, test_files = train_test_split(files, test_size=0.1, random_state=55)
else:
    trainval_files = files

train_files = files

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)

wd = getcwd()
# print(wd)

def ChangeToYolo5(files, txt_Name):
    if not os.path.exists('tmp/'):
        os.makedirs('tmp/')
    list_file = open('tmp/%s.txt' % (txt_Name), 'w')
    for json_file_ in files:
        print(json_file_)
        json_filename = labelme_path + json_file_ + ".json"
        imagePath = labelme_path + json_file_ + ".png"
        list_file.write('%s/%s\n' % (wd, imagePath))
        out_file = open('%s/%s.txt' % (labelme_path, json_file_), 'w')
        json_file = json.load(open(json_filename, "r", encoding="utf-8"))
        height, width, channels = cv2.imread(labelme_path + json_file_ + ".png").shape
        for multi in json_file["shapes"]:
            points = np.array(multi["points"])
            xmin = min(points[:, 0]) if min(points[:, 0]) > 0 else 0
            xmax = max(points[:, 0]) if max(points[:, 0]) > 0 else 0
            ymin = min(points[:, 1]) if min(points[:, 1]) > 0 else 0
            ymax = max(points[:, 1]) if max(points[:, 1]) > 0 else 0
            label = multi["label"]
            if xmax <= xmin:
                pass
            elif ymax <= ymin:
                pass
            else:
                cls_id = classes.index(label)
                b = (float(xmin), float(xmax), float(ymin), float(ymax))
                bb = convert((width, height), b)
                out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
                print(json_filename, xmin, ymin, xmax, ymax, cls_id)

ChangeToYolo5(train_files, "train")

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

目标识别数据集互相转换——xml、txt、json数据格式互转 的相关文章

  • npm run build:prod报错:events.js:291 throw er; // Unhandled ‘error‘ event处理办法

    解决办法 1 CTRL R输入cmd 2 在命令行输入 netstat ano findstr 8080 3 找到占用的PID号 进行查找 tasklist findstr 16504 4 CTRL SHIFT DELETE打开任务管理器
  • Qt: error: C2001: 常量中有换行符

    这里简单记录在使用Qt Creator时遇到的一个问题 如下一行代码 没有任何问题 但编译运行时会报错 label gt setText label 我是一个窗口 当使用中文时 可能会习惯性的使用QObject tr 函数 label gt
  • 文件查重FindDupFile

    finddupfile是网上用的比较多的一款绿色查重软件 具体步骤请参考以下 1 下载软件 可从网上下载该软件 或者从以下地址进行下载 本软件从网上可自行下载 下载链接 https pan baidu com s 1KDJ9U4U 8HQa

随机推荐

  • 数学分析闭区间套定理_什么是区间套定理?

    什么是闭区间 数轴上任意两点和这两点间所有点组成的线段为一个闭区间 闭区间套定理 有无穷个闭区间 第二个闭区间被包含在第一个区间内部 第三个被包含在第二个内部 以此类推 后一个线段会被包含在前一个线段里面 这些区间的长度组成一个无穷数列 如
  • FineReportV10.0入门

    第三章 报表属性设计基础 第三课层次坐标 常用公式
  • gitlab CI/CD自动化部署

    文章目录 1 gitlab Runner 1 1 安装gitlab Runner 1 2 注册runner 2 gitlab ci yml的书写 3 部署 3 1 docker方式部署 3 2 OSS部署 CI CD 是一种持续开发软件的方
  • 针对QT——“在程序文件中(*ui,*cpp,*h)更改之后编译运行的程序结果无法更新”——解决方案

    本篇文章主要介绍在QT中 对程序文件 ui cpp h 更改之后编译运行的程序结果却无法更新的解决方案 问题描述 在设计QT的GUI用户界面时 我们需要不断对程序文件进行修改以优化用户体验 因此需要更新程序的生成文件 实际经历 笔者最近在一
  • IntelliJ Spring Configuration Check

    用IntelliJ 导入现有工程时 如果原来的工程中有spring 每次打开工程就会提示 Spring Configuration Check 开始不知道怎么回事 但工程不影响 首先到工程设置界面 工程设置 Project Structur
  • 1-APP启动源码分析-1

    桌面app也就是我们认识的launcher app 点击app icon启动到app内部的过程分为2种情况 一种是冷启动 一种叫热启动 冷启动 系统没有创建过app的进程 也就是后台没有此app进程 所以冷启动系统会创建一个新的进程分配给a
  • 高效阅读嵌入式源码系列一:静态分析神器understand软件基本操作

    系列文章目录 高效阅读嵌入式源码系列一 静态分析神器understand软件基本操作 高效阅读嵌入式源码系列二 understand阅读linux uboot等源码 高效阅读嵌入式源码系列三 understand阅读经keil MDK编译的
  • Celery + custom backend

    custom backend 以redis为例 本质是用自定义的backend替换RedisBackend https docs celeryq dev en stable getting started backends and brok
  • 盘点 10大 数据库!

    大家好 我是小猿 DB Engines 最近发布了 2021 年 9 月份的数据库排名 该网站根据数据库管理系统的受欢迎程度对其进行排名 实时统计了 378 种数据库的排名指数 前 30 名的排行情况详见下图 前10大数据库 用线段做了分割
  • Docker安装clickhouse

    目录 1 创建相关配置目录 2 拉取镜像 3 查看 Network ports ClickHouse Docs 中端口号配置 暂时只需要映射8123 9000 两个端口 4 创建临时容器 用以生成配置文件 5 将配置文件复制到 data c
  • 达梦数据库教程:DM8查看试用版证书到期时间SQL

    达梦数据库试用期限为一年 不是以本地安装时间算起的 是安装包已经把开始时间和截止时间内置好了 官网定期更新安装包版本 如果想看你安装的达梦啥时候到期 执行以下语句即可 select from v license 查询出记录后 看EXPIRE
  • MySQL 留存率和复购率的场景分析

    实际工作中常见的业务场景是求次日留存率 还有一些会对次日留存率增加限制 例如求新用户的次日留存率或者求活跃用户留存率 另外 留存率和复购率看起来都是统计重复出现的概率 但实际求解方法是不一样的 场景 次日留存率 复购率 知识点 留存率的定义
  • gdb如何调试动态链接库

    gdb file
  • 桌面右键加入“用管理员权限运行命令行”DOS

    在桌面右键和文件夹空白处右键中加入 用管理员权限运行命令行 DOS Windows Registry Editor Version 5 00 HKEY CLASSES ROOT Directory Background shell runa
  • Django图书商城系统实战开发-总结经验之后端开发

    Django图书商城系统实战开发 总结经验之后端开发 简介 在这篇博客中 我将总结经验分享后端开发Django图书商城系统的过程 在开发过程中 我遇到了各种挑战和问题 并且通过实践获得了宝贵的经验和教训 通过本文 我希望能帮助读者更好地了解
  • 抖音卡片/快手/小红书/h5浏览器/微博跳转微信/qq/微信公众号/指定链接

    首先说明 本文内容及教程均转载自 抖音私信卡片系统源码搭建 图文教程 已经本人允许 功能说明 抖音卡片跳转 微信 抖音卡片跳转 qq 抖音卡片跳转 微信公众号 抖音卡片跳转 指定网页链接 快手跳转 微信 快手跳转 qq 快手跳转 微信公众号
  • Jmeter(二十四) - 从入门到精通 - JMeter函数 - 中篇(详解教程)

    1 简介 在性能测试中为了真实模拟用户请求 往往我们需要让提交的表单内容每次都发生变化 这个过程叫做参数化 JMeter配置元件与前置处理器都能帮助我们进行参数化 但是都有局限性 为了帮助我们能够更好地进行参数化 JMeter提供了一组函数
  • Android Handler消息机制原理最全解读(持续补充中)

    本文主要详细去解读Android开发中最常使用的Handler 以及使用过程中遇到的各种各样的疑问 Handler 在Android开发的过程中 我们常常会将耗时的一些操作放在子线程 work thread 中去执行 然后将执行的结果告诉U
  • 西瓜书复习:决策树

    一棵决策树包含一个根结点 若干个内部结点和若干个叶结点 叶结点对应于决策结果 其他每个结点则对应于一个属性测试 每个结点包含的样本集合根据属性测试的节点被划分到子结点中 根结点包含样本全集 从根结点到每个叶结点的路径对应了一个判定测试序列
  • 目标识别数据集互相转换——xml、txt、json数据格式互转

    VOC数据格式与YOLO数据格式互转 1 VOC数据格式 VOC Visual Object Classes 是一个常用的计算机视觉数据集 它主要用于对象检测 分类和分割任务 VOC的标注格式 也被许多其他的数据集采用 因此理解这个数据格式