python实现VOC格式(xml)标签批量转换为yolo格式(txt)标签

在这里插入图片描述


前言

我们常见的目标检测算法使用的数据集对应标签格式多为四种,分别是voc格式、yolo格式、json格式、coco格式。本文将分享自己使用的voc转yolo格式的脚本文件,批量转换,非常高效,后续将继续分享yolo格式转voc格式脚本、voc转json格式脚本等,如果本文对你有帮助,谢谢阅览点赞收藏!


一、VOC格式标签

在转换voc格式标签之前,我们先了解下voc格式标签是什么样的,有哪些特点。典的开源数据集VOC2007、VOC2012、VOC2017这些数据集的标签格式为voc格式,即标签文件为xml文件,xml文件包含的主要信息如下图所示:
在这里插入图片描述

二、YOLO格式标签

上面我们了解了VOC格式标签的基本样子和主要包含的信息,下面介绍一下yolo格式标签,重点讲下txt文件中每行数字代表什么意思。如下图所示:
在这里插入图片描述

三、voc_to_yolo.py转换脚本

1.引入库

代码如下(示例):

import os
import cv2
import pickle
import xml.etree.ElementTree as ET
from os.path import join
from skimage import io
from os import listdir, getcwd
from PIL import Image

2.定义转换逻辑

代码如下(示例):

def convert(size, box):
    x_center = (box[0]+box[1])/2.0
    y_center = (box[2]+box[3])/2.0
    x = x_center / size[0]
    y = y_center / size[1]

    w = (box[1] - box[0]) / size[0]
    h = (box[3] - box[2]) / size[1]
    """
    if x >= 1:
        x = 0.999
    if y >= 1:
        y = 0.999
    if w >= 1:
        w = 0.999
        
    if h >= 1:
        h = 0.999
    """
    # print(x, y, w, h)
    return (x,y,w,h)

3.实现转换函数

def convert_annotation(xml_files_path, save_txt_files_path, classes):  
    line_data = []
    with open(xml_files_path,'r') as f:
        for line in f.readlines():
            line = line.strip()
            x = line.split(";",6)
            print(x)
            print(x[0])
            out_txt_path = os.path.join(save_txt_files_path, x[0].split('.')[0] + '.txt')
            if x[5] == 'warning':
                class_id = 0
            if x[5] == 'prohibitory':
                class_id = 1
            if x[5] == 'mandatory':
                class_id = 2
            b = (float(x[1]),float(x[3]),float(x[2]),float(x[4]))
            
            img = Image.open('F:/CCTSDB_one/GroundTruth/'+x[0])
            w, h = list(img.size)
            
            print(w,h,b)
            bb = convert((w,h), b)
            with open(out_txt_path, 'w') as f:
                f.write(str(class_id) + " " + " ".join([str(a) for a in bb]) + '\n')

4.实现入口主函数

if __name__ == "__main__":
#定义类别,先从voc格式标签中提取,搞清楚,一定要对应起来,不能多,也不能少,否则最后转换的txt文件容易出错。
    classes1 = ['warning','prohibitory','mandatory']
    # voc格式的xml标签文件路径
    GT_files1 = r'F:\CCTSDB_one\GroundTruth\GroundT'
    #转化为yolo格式的txt标签文件存储路径
    save_txt_files1 = r'F:\CCTSDB_one\GroundTruth\yolo_txt'

    convert_annotation(GT_files1, save_txt_files1, classes1)

四、完整代码如下

"""
voc格式xml转化为yolo中的txt
"""

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
from PIL import Image
import cv2
from skimage import io

def convert(size, box):
    # size=(width, height)  b=(xmin, xmax, ymin, ymax)
    # x_center = (xmax+xmin)/2        y_center = (ymax+ymin)/2
    # x = x_center / width            y = y_center / height
    # w = (xmax-xmin) / width         h = (ymax-ymin) / height

    x_center = (box[0]+box[1])/2.0
    y_center = (box[2]+box[3])/2.0
    x = x_center / size[0]
    y = y_center / size[1]

    w = (box[1] - box[0]) / size[0]
    h = (box[3] - box[2]) / size[1]
    """
    if x >= 1:
        x = 0.999
    if y >= 1:
        y = 0.999
    if w >= 1:
        w = 0.999
        
    if h >= 1:
        h = 0.999
    """
    # print(x, y, w, h)
    return (x,y,w,h)



def convert_annotation(xml_files_path, save_txt_files_path, classes):  
    #xml_files = open(xml_files_path,'r')
    #gt_files = open(xml_files_path,'r')
    #print(gt_files)
    line_data = []
    #root = r'F:\CCTSDB_one\GroundTruth\'
    with open(xml_files_path,'r') as f:
        for line in f.readlines():
            line = line.strip()
            x = line.split(";",6)
            print(x)
            print(x[0])
            out_txt_path = os.path.join(save_txt_files_path, x[0].split('.')[0] + '.txt')
            #out_txt_f = open(out_txt_path, 'w')
            if x[5] == 'warning':
                class_id = 0
            if x[5] == 'prohibitory':
                class_id = 1
            if x[5] == 'mandatory':
                class_id = 2
            b = (float(x[1]),float(x[3]),float(x[2]),float(x[4]))
            
            img = Image.open('F:/CCTSDB_one/GroundTruth/'+x[0])
            w, h = list(img.size)
            
            print(w,h,b)
            bb = convert((w,h), b)
            with open(out_txt_path, 'w') as f:
                f.write(str(class_id) + " " + " ".join([str(a) for a in bb]) + '\n')
            
            
    
"""       
    for xml_name in xml_files:
        print(xml_name)
        xml_file = os.path.join(xml_files_path, xml_name)
        out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')
        out_txt_f = open(out_txt_path, 'w')
        tree=ET.parse(xml_file)
        root = tree.getroot()
        size = root.find('size')
        w = int(size.find('width').text)
        h = int(size.find('height').text)

        for obj in root.iter('object'):
            difficult = obj.find('difficult').text
            cls = obj.find('name').text
            if cls not in classes or int(difficult) == 1:
                continue
            cls_id = classes.index(cls)
            xmlbox = obj.find('bndbox')
            b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
            # b=(xmin, xmax, ymin, ymax)
            print(w, h, b)
            bb = convert((w,h), b)
            out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
"""

if __name__ == "__main__":    #================================================================================================
    classes1 = ['warning','prohibitory','mandatory']
    # 2、voc格式的xml标签文件路径
    GT_files1 = r'F:\CCTSDB_one\GroundTruth\GroundT.txt'
    # 3、转化为yolo格式的txt标签文件存储路径
    save_txt_files1 = r'F:\CCTSDB_one\GroundTruth\yolo_txt'

    convert_annotation(GT_files1, save_txt_files1, classes1)

五、总结

本文见本使用起来方便快捷。学好python,大大提高工作效率!觉得还不错的,感谢关注收藏,后续还会继续分享好用的数据处理脚本。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客程序设计

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值