实现VOC数据集与COCO数据集格式转换

news2024/11/25 12:32:37

实现VOC数据集与COCO数据集格式转换

  • 2、将voc数据集的xml转化为coco数据集的json格式
  • 2、COCO格式的json文件转化为VOC格式的xml文件
  • 3、将 txt 文件转换为 Pascal VOC 的 XML 格式

在这里插入图片描述

<annotation>
    <folder>文件夹目录</folder>
    <filename>图片名.jpg</filename>
    <path>path_to\at002eg001.jpg</path>
    <source>
        <database>Unknown</database>
    </source>
    <size>
        <width>550</width>
        <height>518</height>
        <depth>3</depth>
    </size>
    <segmented>0</segmented>
    <object>
        <name>Apple</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <bndbox>
            <xmin>292</xmin>
            <ymin>218</ymin>
            <xmax>410</xmax>
            <ymax>331</ymax>
        </bndbox>
    </object>
    <object>
        ...
    </object>
</annotation>

在这里插入图片描述

coco
|______annotations # 存放标注信息
|        |__train.json
|        |__val.json
|        |__test.json
|______trainset # 存放训练集图像
|______valset   # 存放验证集图像
|______testset  # 存放测试集图像

一个标准的json文件包含如下信息:

{ 
    "info" : info,
    "licenses" : [license],
    "images" : [image],
    "annotations" : [annataton],
    "categories" : [category]
}

在这里插入图片描述

1)images字段列表元素的长度 = 划入训练集(或者测试集)的图片的数量;
(2)annotations字段列表元素的数量 = 训练集(或者测试集)中bounding box的数量;
(3)categories字段列表元素的数量 = 类别的数量

接下来我们看每个key对应的内容:
(1)info

info{
"year" : int,                # 年份
"version" : str,             # 版本
"description" : str,         # 详细描述信息
"contributor" : str,         # 作者
"url" : str,                 # 协议链接
"date_created" : datetime,   # 生成日期
}

(2)images

"images": [                                            
{"id": 0,                                                # int 图像id,可从0开始
 "file_name": "0.jpg",                                   # str 文件名
 "width": 512,                                           # int 图像的宽
 "height": 512,                                          # int 图像的高
 "date_captured": "2020-04-14 01:45:07.508146",          # datatime 获取日期
 "license": 1,                                           # int 遵循哪个协议
 "coco_url": "",                                         # str coco图片链接url
 "flickr_url": ""                                        # str flick图片链接url
}]

(3)licenses

 "licenses": [
{
 "id": 1,                                            # int 协议id号      在images中遵循的license即1
 "name": null,                                       # str 协议名        
 "url": null                                         # str 协议链接      
}]

(4)annotations

"annotations": [ 
{
 "id": 0,                                   # int 图片中每个被标记物体的id编号
 "image_id": 0,                             # int 该物体所在图片的编号
 "category_id": 2,                          # int 被标记物体的类别id编号
 "iscrowd": 0,                              # 0 or 1 目标是否被遮盖,默认为0
 "area": 4095.9999999999986,                # float 被检测物体的面积(64 * 64 = 4096)
 "bbox": [200.0, 416.0, 64.0, 64.0],        # [x, y, width, height] 目标检测框的坐标信息
 "segmentation": [[200.0, 416.0, 264.0, 416.0, 264.0, 480.0, 200.0, 480.0]]  
}]

在这里插入图片描述
(5)categories

"categories":[
{
 "id": 1,                                 # int 类别id编号
 "name": "rectangle",                     # str 类别名字
 "supercategory": "None"                  # str 类别所属的大类,如卡车和轿车都属于机动车这个class
}, 
{
 "id": 2,
 "name": "circle", 
 "supercategory": "None"
 }
]

2、将voc数据集的xml转化为coco数据集的json格式

在这里插入图片描述

# create_xml_list.py
import os
xml_list = os.listdir('C:/Users/user/Desktop/train')
with open('C:/Users/user/Desktop/xml_list.txt','a') as f:
    for i in xml_list:
        if i[-3:]=='xml':
            f.write(str(i)+'\n')

在这里插入图片描述

# voc2coco.py

# pip install lxml

import sys
import os
import json
import xml.etree.ElementTree as ET

START_BOUNDING_BOX_ID = 1
PRE_DEFINE_CATEGORIES = {}
# If necessary, pre-define category and its id
#  PRE_DEFINE_CATEGORIES = {"aeroplane": 1, "bicycle": 2, "bird": 3, "boat": 4,
                         #  "bottle":5, "bus": 6, "car": 7, "cat": 8, "chair": 9,
                         #  "cow": 10, "diningtable": 11, "dog": 12, "horse": 13,
                         #  "motorbike": 14, "person": 15, "pottedplant": 16,
                         #  "sheep": 17, "sofa": 18, "train": 19, "tvmonitor": 20}


def get(root, name):
    vars = root.findall(name)
    return vars


def get_and_check(root, name, length):
    vars = root.findall(name)
    if len(vars) == 0:
        raise NotImplementedError('Can not find %s in %s.'%(name, root.tag))
    if length > 0 and len(vars) != length:
        raise NotImplementedError('The size of %s is supposed to be %d, but is %d.'%(name, length, len(vars)))
    if length == 1:
        vars = vars[0]
    return vars


def get_filename_as_int(filename):
    try:
        filename = os.path.splitext(filename)[0]
        return int(filename)
    except:
        raise NotImplementedError('Filename %s is supposed to be an integer.'%(filename))


def convert(xml_list, xml_dir, json_file):
    list_fp = open(xml_list, 'r')
    json_dict = {"images":[], "type": "instances", "annotations": [],
                 "categories": []}
    categories = PRE_DEFINE_CATEGORIES
    bnd_id = START_BOUNDING_BOX_ID
    for line in list_fp:
        line = line.strip()
        print("Processing %s"%(line))
        xml_f = os.path.join(xml_dir, line)
        tree = ET.parse(xml_f)
        root = tree.getroot()
        path = get(root, 'path')
        if len(path) == 1:
            filename = os.path.basename(path[0].text)
        elif len(path) == 0:
            filename = get_and_check(root, 'filename', 1).text
        else:
            raise NotImplementedError('%d paths found in %s'%(len(path), line))
        ## The filename must be a number
        image_id = get_filename_as_int(filename)
        size = get_and_check(root, 'size', 1)
        width = int(get_and_check(size, 'width', 1).text)
        height = int(get_and_check(size, 'height', 1).text)
        image = {'file_name': filename, 'height': height, 'width': width,
                 'id':image_id}
        json_dict['images'].append(image)
        ## Cruuently we do not support segmentation
        #  segmented = get_and_check(root, 'segmented', 1).text
        #  assert segmented == '0'
        for obj in get(root, 'object'):
            category = get_and_check(obj, 'name', 1).text
            if category not in categories:
                new_id = len(categories)
                categories[category] = new_id
            category_id = categories[category]
            bndbox = get_and_check(obj, 'bndbox', 1)
            xmin = int(get_and_check(bndbox, 'xmin', 1).text) - 1
            ymin = int(get_and_check(bndbox, 'ymin', 1).text) - 1
            xmax = int(get_and_check(bndbox, 'xmax', 1).text)
            ymax = int(get_and_check(bndbox, 'ymax', 1).text)
            assert(xmax > xmin)
            assert(ymax > ymin)
            o_width = abs(xmax - xmin)
            o_height = abs(ymax - ymin)
            ann = {'area': o_width*o_height, 'iscrowd': 0, 'image_id':
                   image_id, 'bbox':[xmin, ymin, o_width, o_height],
                   'category_id': category_id, 'id': bnd_id, 'ignore': 0,
                   'segmentation': []}
            json_dict['annotations'].append(ann)
            bnd_id = bnd_id + 1

    for cate, cid in categories.items():
        cat = {'supercategory': 'none', 'id': cid, 'name': cate}
        json_dict['categories'].append(cat)
    json_fp = open(json_file, 'w')
    json_str = json.dumps(json_dict)
    json_fp.write(json_str)
    json_fp.close()
    list_fp.close()


if __name__ == '__main__':
    if len(sys.argv) <= 1:
        print('3 auguments are need.')
        print('Usage: %s XML_LIST.txt XML_DIR OUTPU_JSON.json'%(sys.argv[0]))
        exit(1)

    convert(sys.argv[1], sys.argv[2], sys.argv[3])

在这里插入图片描述

import os
img_dir='F:/Billboard/dataset/images/'
lab_dir='F:/Billboard/dataset/labels/'
name_list = os.listdir(img_dir)
for i,name in enumerate(name_list):
    os.rename(img_dir+name,img_dir+str(i)+'.jpg')
    os.rename(lab_dir+name[:-4]+'.txt',lab_dir+str(i)+'.txt')


在这里插入图片描述

xmin = int(float(get_and_check(bndbox, 'xmin', 1).text)) - 1
ymin = int(float(get_and_check(bndbox, 'ymin', 1).text)) - 1
xmax = int(float(get_and_check(bndbox, 'xmax', 1).text))
ymax = int(float(get_and_check(bndbox, 'ymax', 1).text))


2、COCO格式的json文件转化为VOC格式的xml文件

在这里插入图片描述

# coco2voc.py

# pip install pycocotools
import os
import time
import json
import pandas as pd
from tqdm import tqdm
from pycocotools.coco import COCO
 
#json文件路径和用于存放xml文件的路径
anno = 'C:/Users/user/Desktop/val/instances_val2017.json'
xml_dir = 'C:/Users/user/Desktop/val/xml/'

coco = COCO(anno)  # 读文件
cats = coco.loadCats(coco.getCatIds())  # 这里loadCats就是coco提供的接口,获取类别
    
# Create anno dir
dttm = time.strftime("%Y%m%d%H%M%S", time.localtime())

def trans_id(category_id):
    names = []
    namesid = []
    for i in range(0, len(cats)):
        names.append(cats[i]['name'])
        namesid.append(cats[i]['id'])
    index = namesid.index(category_id)
    return index
    

def convert(anno,xml_dir): 

    with open(anno, 'r') as load_f:
        f = json.load(load_f)
    
    imgs = f['images']  #json文件的img_id和图片对应关系 imgs列表表示多少张图
    
    cat = f['categories']
    df_cate = pd.DataFrame(f['categories'])                     # json中的类别
    df_cate_sort = df_cate.sort_values(["id"], ascending=True)  # 按照类别id排序
    categories = list(df_cate_sort['name'])                     # 获取所有类别名称
    print('categories = ', categories)
    df_anno = pd.DataFrame(f['annotations'])                    # json中的annotation
    
    for i in tqdm(range(len(imgs))):  # 大循环是images所有图片,Tqdm是可扩展的Python进度条,可以在长循环中添加一个进度提示信息
        xml_content = []
        file_name = imgs[i]['file_name']    # 通过img_id找到图片的信息
        height = imgs[i]['height']
        img_id = imgs[i]['id']
        width = imgs[i]['width']
        
        version =['"1.0"','"utf-8"'] 
    
        # xml文件添加属性
        xml_content.append("<?xml version=" + version[0] +" "+ "encoding="+ version[1] + "?>")
        xml_content.append("<annotation>")
        xml_content.append("    <filename>" + file_name + "</filename>")
        xml_content.append("    <size>")
        xml_content.append("        <width>" + str(width) + "</width>")
        xml_content.append("        <height>" + str(height) + "</height>")
        xml_content.append("        <depth>"+ "3" + "</depth>")
        xml_content.append("    </size>")
    
        # 通过img_id找到annotations
        annos = df_anno[df_anno["image_id"].isin([img_id])]  # (2,8)表示一张图有两个框
    
        for index, row in annos.iterrows():  # 一张图的所有annotation信息
            bbox = row["bbox"]
            category_id = row["category_id"]
            cate_name = categories[trans_id(category_id)]
    
            # add new object
            xml_content.append("    <object>")
            xml_content.append("        <name>" + cate_name + "</name>")
            xml_content.append("        <truncated>0</truncated>")
            xml_content.append("        <difficult>0</difficult>")
            xml_content.append("        <bndbox>")
            xml_content.append("            <xmin>" + str(int(bbox[0])) + "</xmin>")
            xml_content.append("            <ymin>" + str(int(bbox[1])) + "</ymin>")
            xml_content.append("            <xmax>" + str(int(bbox[0] + bbox[2])) + "</xmax>")
            xml_content.append("            <ymax>" + str(int(bbox[1] + bbox[3])) + "</ymax>")
            xml_content.append("        </bndbox>")
            xml_content.append("    </object>")
        xml_content.append("</annotation>")
    
        x = xml_content
        xml_content = [x[i] for i in range(0, len(x)) if x[i] != "\n"]
        ### list存入文件
        #xml_path = os.path.join(xml_dir, file_name.replace('.xml', '.jpg'))
        xml_path = os.path.join(xml_dir, file_name.split('j')[0]+'xml')
        print(xml_path)
        with open(xml_path, 'w+', encoding="utf8") as f:
            f.write('\n'.join(xml_content))
        xml_content[:] = []

if __name__ == '__main__':
    convert(anno,xml_dir)

3、将 txt 文件转换为 Pascal VOC 的 XML 格式

比如从OpenImageV5下载下来的BIllboard数据集,目录如下:

Billboard
|______images # 存放训练集图像
|        |__train
		       |__train.jpg
|        |__val
               |__val.jpg
|______labels # 存放标注信息
|        |__train
		       |__train.txt
|        |__val
               |__val.txt

在这里插入图片描述
将 txt 文件转换为 Pascal VOC 的 XML 格式的代码如下:

#! /usr/bin/python
# -*- coding:UTF-8 -*-
import os, sys
import glob
from PIL import Image
 
# VEDAI 图像存储位置
src_img_dir = "F:/Billboard/dataset/images/val"
# VEDAI 图像的 ground truth 的 txt 文件存放位置
src_txt_dir = "F:/Billboard/dataset/labels/val"
src_xml_dir = "F:/Billboard/dataset/xml/val"
name=['billboard']
 
img_Lists = glob.glob(src_img_dir + '/*.jpg')
 
img_basenames = [] # e.g. 100.jpg
for item in img_Lists:
    img_basenames.append(os.path.basename(item))
 
img_names = [] # e.g. 100
for item in img_basenames:
    temp1, temp2 = os.path.splitext(item)
    img_names.append(temp1)
 
for img in img_names:
    im = Image.open((src_img_dir + '/' + img + '.jpg'))
    width, height = im.size
 
    # open the crospronding txt file
    gt = open(src_txt_dir + '/' + img + '.txt').read().splitlines()
    #gt = open(src_txt_dir + '/gt_' + img + '.txt').read().splitlines()
 
    # write in xml file
    #os.mknod(src_xml_dir + '/' + img + '.xml')
    xml_file = open((src_xml_dir + '/' + img + '.xml'), 'w')
    xml_file.write('<annotation>\n')
    xml_file.write('    <folder>VOC2007</folder>\n')
    xml_file.write('    <filename>' + str(img) + '.jpg' + '</filename>\n')
    xml_file.write('    <size>\n')
    xml_file.write('        <width>' + str(width) + '</width>\n')
    xml_file.write('        <height>' + str(height) + '</height>\n')
    xml_file.write('        <depth>3</depth>\n')
    xml_file.write('    </size>\n')
 
    # write the region of image on xml file
    for img_each_label in gt:
        spt = img_each_label.split(' ') #这里如果txt里面是以逗号‘,’隔开的,那么就改为spt = img_each_label.split(',')。
        xml_file.write('    <object>\n')
        xml_file.write('        <name>' + str(name[int(spt[0])]) + '</name>\n')
        xml_file.write('        <pose>Unspecified</pose>\n')
        xml_file.write('        <truncated>0</truncated>\n')
        xml_file.write('        <difficult>0</difficult>\n')
        xml_file.write('        <bndbox>\n')
        xml_file.write('            <xmin>' + str(float(spt[1])*width) + '</xmin>\n')
        xml_file.write('            <ymin>' + str(float(spt[3])*height) + '</ymin>\n')
        xml_file.write('            <xmax>' + str(float(spt[2])*width) + '</xmax>\n')
        xml_file.write('            <ymax>' + str(float(spt[4])*height) + '</ymax>\n')
        xml_file.write('        </bndbox>\n')
        xml_file.write('    </object>\n')
 
    xml_file.write('</annotation>')

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

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

相关文章

2020蓝桥杯真题凯撒加密 C语言/C++

题目描述 给定一个单词&#xff0c;请使用凯撒密码将这个单词加密。 凯撒密码是一种替换加密的技术&#xff0c;单词中的所有字母都在字母表上向后偏移 3 位后被替换成密文。即 a 变为 d&#xff0c;b 变为 e&#xff0c;⋯&#xff0c;w 变为z&#xff0c;x 变为 a&#xff0…

【QT网络编程】实现UDP协议通信

文章目录概要&#xff1a;本期主要讲解QT中对UDP协议通信的实现。一、UDP协议通信二、Qt中UDP协议的处理1.QUdpSocket三、Qt实现UDP通信1.客户端2.服务器端结尾概要&#xff1a;本期主要讲解QT中对UDP协议通信的实现。 一、UDP协议通信 Internet 协议集支持一个无连接的传输协…

SprintBoot打包及profile文件配置

打成Jar包 需要添加打包组件将项目中的资源、配置、依赖包打到一个jar包中&#xff0c;可以使用maven的package&#xff1b;运行: java -jar xxx(jar包名) 操作步骤 第一步: 引入Spring Boot打包插件 <!--打包的插件--> <build><!--修改jar的名字--><fi…

认识vite_vue3 初始化项目到打包

从0到1创建vite_vue3的项目背景效果vite介绍&#xff08;对比和vuecli的区别&#xff09;使用npm创建vitevitevuie3创建安装antdesignvite自动按需引入&#xff08;vite亮点&#xff09;请求代理proxy打包背景 vue2在使用过程中对象的响应式不好用新增属性的使用$set才能实现效…

FPGA 20个例程篇:20.USB2.0/RS232/LAN控制并行DAC输出任意频率正弦波、梯形波、三角波、方波(二)

通过上面的介绍相信大家对数字变频已经有了一个较为整体性的认识&#xff0c;下面笔者来对照XILINX的DDS IP核对数字变频技术展开更进一步的说明&#xff0c;做到了理论和实践很好地结合&#xff0c;这样大家再带入Modelsim进行仿真测试就不仅掌握了数字变频的理论知识&#xf…

【Linux】网络原理

本篇博客让我们一起来了解一下网络的基本原理 1.网络发展背景 关于网络发展的历史背景这种东西就不多bb了&#xff0c;网上很容易就能找到参考资料&#xff0c;我的专业性欠缺&#xff0c;文章参考意义也不大。这里只做简单说明。 网络发展经过了如下几个模式 独立模式&…

创建线程的三种方法

文章目录1、创建一个类实现Runnable接口&#xff0c;并重写run方法。2、创建一个类继承Thread类&#xff0c;并重写run方法。3、实现Callable接口&#xff0c;重写call()方法&#xff0c;这种方式可以通过FutureTask获取任务执行的返回值。4、run()方法和start()方法有什么区别…

14 Day:同步锁与操作系统输入输出

前言&#xff1a;在上一期的线程章节中&#xff0c;我们的线程输出貌似有大问题&#xff0c;今天我们便要来学习同步锁来解决这个问题&#xff0c;同时再次基础上拿下键盘输入&#xff0c;实现操作系统的输入和输出。从今天开始我们的操作系统不在是一块“看板”了&#xff01;…

Python|数学|贪心|数组|动态规划|单选记录:实现保留3位有效数字(四舍六入五成双规则)|用Python来创造一个提示用户输入数字的乘法表|最小路径和

1、实现保留3位有效数字&#xff08;四舍六入五成双规则&#xff09;&#xff08;数学&#xff0c;算法&#xff09; 贡献者&#xff1a;weixin_45782673 输入&#xff1a;1234 输出&#xff1a;1234 12 12.0 4 4.00 0.2 0.200 0.32 0.320 1.3 1.30 1.235 1.24 1.245 1.24 1.…

Docker 入门建议收藏 第一部分

一、Docker 是什么&#xff1f; Docker&#xff0c;翻译过来就是码头工人 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可抑制的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器完全使用沙盒…

JVM概览:内存空间与数据存储

核心的五个部分虚拟机栈&#xff1a;局部变量中基础类型数据、对象的引用存储的位置&#xff0c;线程独立的。堆&#xff1a;大量运行时对象都在这个区域存储&#xff0c;线程共享的。方法区&#xff1a;存储运行时代码、类变量、常量池、构造器等信息&#xff0c;线程共享。程…

ClassMix: Segmentation-Based Data Augmentation for Semi-Supervised Learning学习笔记

ClassMix相关介绍主要思想方法Mean-Teacher损失函数交叉熵损失标签污染实验实验反思参考资料相关介绍 从DAFormer溯源到这篇文章&#xff0c;ClassMix主要是集合了伪标签和一致性正则化&#xff0c;思想来源于CutMix那条研究路线&#xff0c;但是优化了CutMix中的标签污染的情…

使用 HTML5 轻松验证表单插件

下载:https://download.csdn.net/download/mo3408/87559594 效果图: 当您通过表单从人们那里收集信息时,必须应用某种验证。如果不这样做,可能会导致客户流失、数据库中的垃圾数据甚至网站的安全漏洞。从历史上看,构建表单验证一直很痛苦。在服务器端,全栈框架会为您处理…

【AI绘图学习笔记】深度前馈网络(一)

有关深度前馈网络的部分知识&#xff0c;我们已经在吴恩达的机器学习课程中有过了解了&#xff0c;本章主要是对《深度学习》花书中第六章&#xff1a;深度前馈网络的总结笔记。我希望你在看到这一章的时候&#xff0c;能回忆起机器学习课程中的一些环节或者细节&#xff0c;这…

【现代机器人学】学习笔记十一:抓握与操作

本章是比较独特的一章&#xff0c;相对于前面的内容&#xff0c;内容较为独立&#xff0c;主要描述的是力学相关的一些理论。因此&#xff0c;读者也完全不必根据题目产生一些不必要的幻想&#xff0c;认为似乎看完这章我就可以学会机器人抓取。不过&#xff0c;我仍然认为这章…

新入职的项目经理,如何击破权力微薄的困境?

“从此找到了上班的意义”这个话题最近登上了热搜&#xff0c;在“铜三铁四”的招聘季&#xff0c;大家停止了内卷&#xff0c;给自己安排得明明白白&#xff0c;每天上班的动力就是&#xff1a;充电、蹭网、干饭、灌水、睡午觉、上厕所。但咱项目经理们却没办法Get这些动力&am…

【UEFI基础】HOB介绍

综述 HOB的全称是Hand-Off Block&#xff0c;从名字上也可以看出来&#xff0c;它表示的是一种用于交接的数据。按照HOB的使用情况&#xff0c;可以将BIOS的启动阶段分为两个部分&#xff1a; HOB生成阶段&#xff08;HOB producer phase&#xff09;&#xff0c;用来创建和修…

PMP项目管理项目质量管理

目录1 项目质量管理概述2 规划质量管理3 管理质量4 控制质量1 项目质量管理概述 项目质量管理包括把组织的质量政策应用于规则、管理、控制项目和产品质量要求&#xff0c;以满足相关方目标的各个过程。项目质量管理还将以组织的名义支持过程的持续改进活动。 核心概念 质量是…

Elasticsearch:集群管理

在今天的文章中&#xff0c;我们应该学习如何管理我们的集群。 备份和分片分配是我们应该能够执行的基本任务。 分片分配过滤 Elasticsearch 将索引配到一个或多个分片中&#xff0c;我们可以将这些分片保存在特定的集群节点中。 例如&#xff0c;假设你有多个数据集群节点&am…

感应电机数学模型(电机控制应用基础系列)

电机在工业控制中的地位不言而喻&#xff0c;所以对电机模型的了解是我们理解各种算法的基础。这篇博客帮大家整理总结。张力控制离不开电机控制&#xff0c;有关张力控制的详细内容请参看下面的文章链接&#xff1a; PLC张力控制&#xff08;开环闭环算法分析&#xff09;_张…