VOC数据集有中文标签,无法顺利转换为YOLO数据集

错误:

数据集转换是控制台显示乱码,无法正确识别中文标签。(如下报错)

原因:

出现乱码问题可能是因为标签名称的编码方式与代码中的编码方式不匹配导致的。你可以尝试指定正确的编码方式来解决这个问题。

解决方法:

假设乱码的标签名称使用的是GBK编码,你可以在代码中进行如下更改:

import os

# 原始编码方式
original_encoding = 'gbk'

# 新的编码方式
new_encoding = 'utf-8'

# 将原始编码的标签名称转换为新的编码方式
def convert_encoding(label):
    return label.encode(original_encoding).decode(new_encoding)

# 转换后的标签列表
new_class_id = [convert_encoding(label) for label in class_id]

# 输出转换后的标签列表
print(new_class_id)

在这段代码中,我们定义了一个convert_encoding函数,用于将原始编码的标签名称转换为新的编码方式。然后,我们使用列表推导式对class_id中的每个标签名称进行转换,并将转换后的结果存储在new_class_id列表中。

确保将original_encoding替换为乱码标签名称的正确编码方式,并将new_encoding替换为你希望转换的编码方式。运行代码后,应该能够得到一个转换后的标签列表new_class_id,其中的标签名称已经按照新的编码方式进行了转换。

然后,你可以使用new_class_id列表中的标签名称进行后续处理,例如在上述的XML转换代码中使用new_class_id来替换原始的class_id列表。这样可以确保标签名称的编码方式与代码中的编码方式一致,避免出现乱码问题。

如果出现下图错误:

如果在使用上述代码时出现UnicodeDecodeError,原因可能是在读取XML文件时使用了错误的编码方式。为了解决这个问题,你可以尝试指定正确的编码方式进行读取。

请尝试修改以下部分的代码:

# 打开当前转换的voc标注文件,指定正确的编码方式
in_file = open(os.path.join(voc_folder, xml_file), encoding='gbk')

# 将读取的内容进行解码,指定正确的编码方式
content = in_file.read().decode('utf-8')

# 解析XML内容
tree = ET.fromstring(content)

在上述代码中,我们在打开文件时使用了encoding='gbk'来指定正确的编码方式。然后,将读取的内容使用decode('utf-8')进行解码,指定正确的编码方式。

请确保将'gbk'替换为与你的XML文件使用的编码方式相对应的正确编码方式,如'utf-8''gb2312'等。

确定文件的编码方式时,可以尝试以下方法:

Python脚本:使用Python编程来确定文件的编码方式。以下是一个示例代码:

import chardet

def detect_encoding(file_path):
    with open(file_path, 'rb') as f:
        result = chardet.detect(f.read())
        encoding = result['encoding']
        return encoding

file_path = '文件路径'
encoding = detect_encoding(file_path)
print(encoding)

这段代码使用了chardet库来自动检测文件的编码方式。

如果出现以下错误:

根据报错信息,可以看出问题出现在解析XML文件时。在convert_annotation函数中,你使用了ET.parse方法来解析XML内容。然而,该方法要求传入一个文件对象作为参数,而不是直接传入XML内容。

为了解决这个问题,你可以按照以下步骤进行修改:

  1. content变量中的XML内容写入一个临时文件中,例如temp.xml
  2. 使用ET.parse方法解析临时文件。

以下是修改后的代码示例:

def convert_annotation(xml_file):
    file_name = xml_file.strip(".xml")
    in_file = open(os.path.join(voc_folder, xml_file), encoding='utf-8')
    content = in_file.read()

    # 写入临时文件
    temp_file = open("temp.xml", "w", encoding="utf-8")
    temp_file.write(content)
    temp_file.close()

    # 解析临时文件
    tree = ET.parse("temp.xml")
    root = tree.getroot()

    # ... 其他代码 ...

    # 删除临时文件
    os.remove("temp.xml")

完整代码:

import xml.etree.ElementTree as ET
import os

voc_folder = r"datasets/Annotations"  # 储存voc格式的标注文件的文件夹,相对路径
yolo_folder = r"yolo_datasets/Annotations"  # 转换后的yolo格式标注文件的储存文件夹,相对路径

class_id = ['0号猪', '1号猪', '2号猪', '4号猪', '5号猪','6号猪', 
             '9号猪', '12号猪', '13号猪', '16号猪','21号猪']

# 原始编码方式
original_encoding = 'utf-8'

# 新的编码方式
new_encoding = 'utf-8'

# 将原始编码的标签名称转换为新的编码方式
def convert_encoding(label):
    return label.encode(original_encoding, errors='ignore').decode(new_encoding)


# 转换后的标签列表
new_class_id = [convert_encoding(label) for label in class_id]

# voc标注的目标框坐标值转换到yolo标注的目标框坐标值的函数
def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    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)

# 对单个voc标注文件进行转换成其对应的yolo文件的函数
def convert_annotation(xml_file):
    file_name = xml_file.strip(".xml")  # 这一步将所有voc格式标注文件取出后缀名“.xml”,方便接下来作为yolo格式标注文件的名称
    # 打开当前转换的voc标注文件,指定正确的编码方式
    in_file = open(os.path.join(voc_folder, xml_file), encoding='utf-8')
    content = in_file.read()
    
    # 写入临时文件
    temp_file = open("temp.xml", "w", encoding="utf-8")
    temp_file.write(content)
    temp_file.close()

    # 解析临时文件
    tree = ET.parse("temp.xml")
    root = tree.getroot()
    in_file.close()

    out_file = open(os.path.join(yolo_folder, file_name + ".txt"), 'w')  # 创建并打开要转换成的yolo格式标注文件
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)
    for obj in root.iter('object'):
        cls = obj.find('name').text
        cls = convert_encoding(cls)  # 转换标签名称编码
        cls_id = new_class_id.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))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
    out_file.close()
    # 删除临时文件
    os.remove("temp.xml")


xml_fileList = os.listdir(voc_folder)  # 将所有voc格式的标注文件的名称取出存放到列表xml_fileList中
for xml_file in xml_fileList:  # 这里的for循环开始依次对所有voc格式标注文件生成其对应的yolo格式的标注文件
    convert_annotation(xml_file)

print("success!")

猜你喜欢

转载自blog.csdn.net/weixin_45819759/article/details/131560861