CVAT格式XML转YOLO格式报错求助及代码评估需求
CVAT XML转YOLO格式问题解决方案
问题描述
尝试将CVAT格式的XML标注文件转换为YOLO格式时,计算归一化坐标(yolo_x、yolo_y、yolo_w、yolo_h)时出现类型错误,用int()转换坐标后仍触发值错误。
XML示例
<image id="0" name="20230226_145238.jpg" width="510" height="680"> <box label="meter" source="manual" occluded="0" xtl="202.10" ytl="259.28" xbr="314.74" ybr="305.89" z_order="0"> </box> <box label="zero" source="manual" occluded="0" xtl="219.68" ytl="269.57" xbr="234.84" ybr="293.43" z_order="0"> </box> <box label="eight" source="manual" occluded="0" xtl="234.84" ytl="270.35" xbr="249.11" ybr="293.99" z_order="0"> </box> <box label="one" source="manual" occluded="0" xtl="249.78" ytl="271.69" xbr="263.38" ybr="293.88" z_order="0"> </box> <box label="one" source="manual" occluded="0" xtl="263.38" ytl="272.69" xbr="278.99" ybr="295.10" z_order="0"> </box> <box label="eight" source="manual" occluded="0" xtl="279.55" ytl="272.80" xbr="293.71" ybr="296.33" z_order="0"> </box> <box label="three" source="manual" occluded="0" xtl="295.38" ytl="272.58" xbr="308.68" ybr="297.33" z_order="0"> </box> <box label="dot" source="manual" occluded="0" xtl="289.47" ytl="292.43" xbr="293.93" ybr="296.55" z_order="0"> </box> </image>
原转换代码
import os import glob from xml.etree.ElementTree import parse xml_dir = "./data/" class Voc_to_yolo_convter(): def __init__(self, xml_path): self.xml_path_list = glob.glob(os.path.join(xml_path, "*.xml")) # print(self.xml_path_list) def get_voc_to_yolo(self): for xml_path in self.xml_path_list: tree = parse(xml_path) root = tree.getroot() # image_meta meta = root.findall("image") for image in meta: image_name = image.attrib["name"] image_width = image.attrib["width"] image_height = image.attrib["height"] # print(image_width, image_height) # object_meta object_metas = image.findall("box") for bbox in object_metas: label = bbox.attrib["label"] xtl = int(bbox.attrib["xtl"]) ytl = bbox.attrib["ytl"] xbr = bbox.attrib["xbr"] ybr = bbox.attrib["ybr"] # CVAT to yolo yolo_x = round(((xtl + xbr)/2)/image_width, 6) yolo_y = round(((ytl + ybr)/2)/image_height, 6) yolo_w = round((xbr - xtl)/image_width, 6) yolo_h = round((ybr - ytl)/image_height, 6) print(yolo_x, yolo_y, yolo_w, yolo_h) test= Voc_to_yolo_convter(xml_dir) test.get_voc_to_yolo()
问题原因
- 类型不匹配:XML中读取的坐标(如
xtl="202.10")是带小数的字符串,直接用int()转换会报错;同时图片宽高image_width/image_height也是字符串,参与除法运算时触发类型错误。 - 变量转换不全:原代码仅转换了
xtl为int,其余坐标和尺寸未做类型转换,导致字符串与数值混合计算,引发值错误。
解决方案
将所有从XML读取的数值型属性(坐标、图片尺寸)统一转换为float类型,确保所有参与计算的变量都是数值类型,避免类型不兼容问题。
优化后的转换代码
import os import glob from xml.etree.ElementTree import parse xml_dir = "./data/" # 自定义标签映射,根据你的数据集修改 LABEL_MAP = { "meter": 0, "zero": 1, "eight": 2, "one": 3, "three": 4, "dot": 5 } class CVATToYOLOConverter(): def __init__(self, xml_path): self.xml_path_list = glob.glob(os.path.join(xml_path, "*.xml")) # 创建labels目录(如果不存在) os.makedirs("./labels", exist_ok=True) def convert(self): for xml_path in self.xml_path_list: tree = parse(xml_path) root = tree.getroot() for image in root.findall("image"): image_name = image.attrib["name"] # 转换图片尺寸为float img_width = float(image.attrib["width"]) img_height = float(image.attrib["height"]) # 生成对应YOLO格式的txt文件路径 txt_path = os.path.join("./labels", os.path.splitext(image_name)[0] + ".txt") # 清空文件(避免重复写入) with open(txt_path, "w", encoding="utf-8") as f: pass for bbox in image.findall("box"): label = bbox.attrib["label"] # 转换所有坐标为float xtl = float(bbox.attrib["xtl"]) ytl = float(bbox.attrib["ytl"]) xbr = float(bbox.attrib["xbr"]) ybr = float(bbox.attrib["ybr"]) # 计算YOLO归一化坐标 yolo_x = round(((xtl + xbr) / 2) / img_width, 6) yolo_y = round(((ytl + ybr) / 2) / img_height, 6) yolo_w = round((xbr - xtl) / img_width, 6) yolo_h = round((ybr - ytl) / img_height, 6) # 写入txt文件(YOLO格式:标签ID 中心x 中心y 宽 高) with open(txt_path, "a", encoding="utf-8") as f: f.write(f"{LABEL_MAP[label]} {yolo_x} {yolo_y} {yolo_w} {yolo_h}\n") print(f"已处理: {image_name} -> {label} {yolo_x} {yolo_y} {yolo_w} {yolo_h}") # 执行转换 converter = CVATToYOLOConverter(xml_dir) converter.convert()
代码优化说明
- 命名规范:类名和方法名改为符合Python规范的命名方式,可读性更强。
- 标签映射:添加
LABEL_MAP字典,将文本标签转为YOLO要求的数字ID,符合格式标准。 - 文件保存:自动创建
labels目录,将转换结果保存为对应图片名称的txt文件,完整实现YOLO格式输出。 - 类型统一:所有数值型属性统一转换为float,保留坐标精度的同时避免类型错误。
- 健壮性提升:自动创建目录、清空重复文件,避免数据冗余。
内容的提问来源于stack exchange,提问作者박경덕
相关产品推荐
相关产品推荐

