码农-小林 2025-09-09 10:00 采纳率: 54.8%
浏览 7
已结题

Yolov3:win10下训练自己的数据(整理图集遇到问题)

为什么运行voc_labels.py文件时候,存放YOLO文件夹的所有文件标注信息都被清空,且运行可以执行完毕就是在生成目录下main没有生成对应的2025_train.txt和 2025_val.txt.
这是文件目录Annotations是存xml文件,labels是存转换后的txt文件,:

img


这是目录下LimgeSets下main自定义train和val,其中train存了所有图片的文件名,val为空

img

这是labels下的

img


这是没有运行voc_labels.py文件时候labels中一个图片的YOLO信息

img


这是运行voc_labels.py文件时候labels中一个图片的YOLO信息都被清空了

img


这是voc_labels.py文件

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
 
sets = [('2025', 'train'), ('2025', 'val')]
classes = ["shu"]
 
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)
 
def convert_annotation(year, image_id):
    in_file = open(f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\Annotations\\{image_id}.xml')
    out_file = open(f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\labels\\{image_id}.txt', 'w')
    tree = ET.parse(in_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))
        bb = convert((w, h), b)
        out_file.write(f"{cls_id} {' '.join([str(a) for a in bb])}\n")
 
wd = getcwd()
 
for year, image_set in sets:
    label_dir = f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\labels\\'
    if not os.path.exists(label_dir):
        os.makedirs(label_dir)
    image_ids = open(f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\ImageSets\\Main\\{image_set}.txt').read().strip().split()
    list_file = open(f'{year}_{image_set}.txt', 'w')
    for image_id in image_ids:
        list_file.write(f'D:\\YOLO\\Darknet\\build\\x64\\data\\obj\\{image_id}.jpg\n')
        convert_annotation(year, image_id)
    list_file.close()
 
# 合并 train 和 val 文件
try:
    with open('train.txt', 'w') as f:
        with open('2025_train.txt', 'r') as f1:
            f.write(f1.read())
        with open('2025_val.txt', 'r') as f2:
            f.write(f2.read())
    print("train.txt 已成功生成!")
except Exception as e:
    print(f"生成 train.txt 失败: {e}")
#if os.access("file.txt", os.W_OK):
 #   print("You have write permission to the file.")
#else:
  #  print("You do not have write permission to the file.")
#print("train.txt 已成功生成!")


  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-09-09 10:01
    关注

    上午好☀️☀️☀️️
    本答案参考通义千问

    根据你描述的问题,在运行 voc_labels.py 时,所有标注信息被清空,并且没有生成 2025_train.txt2025_val.txt 文件,这说明代码中存在一些逻辑错误或路径配置问题。


    一、问题分析

    1. 标注信息被清空的原因

    • 在你的 voc_labels.py 中,convert_annotation() 函数直接写入了 labels 目录下的 .txt 文件。
    • 但如果你的 labels 目录中已经存在某些 .txt 文件(比如之前运行过一次),那么每次运行脚本时,它会覆盖这些文件,导致数据丢失。
    • 注意: 如果你期望保留之前的标签文件,应该避免覆盖。如果希望每次都重新生成,则需要确认是否真的要清空已有标签。

    2. 没有生成 2025_train.txt2025_val.txt 的原因

    • 脚本中定义了 sets = [('2025', 'train'), ('2025', 'val')],但在处理过程中并没有正确地将 image_set 写入到对应的 2025_train.txt2025_val.txt
    • 问题出在 for year, image_set in sets: 这部分逻辑year'2025',而 image_set'train''val',但后续写入文件时使用的是 f'{year}_{image_set}.txt',即生成了 2025_train.txt2025_val.txt
    • 然而,在最后合并 train.txt 时,代码尝试读取 2025_train.txt2025_val.txt,但这两个文件可能并未被创建,因为:
      • 文件未被正确保存(如路径错误);
      • 文件写入失败(如权限问题);
      • 文件未被正确命名(如拼写错误)。

    二、解决方案

    1. 修改 voc_labels.py 文件以确保正确生成文件

    修改后的代码如下:

    import xml.etree.ElementTree as ET
    import os
    from os import listdir, getcwd
    from os.path import join
    
    sets = [('2025', 'train'), ('2025', 'val')]
    classes = ["shu"]
    
    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)
    
    def convert_annotation(year, image_id):
        in_file = open(f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\Annotations\\{image_id}.xml')
        out_file = open(f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\labels\\{image_id}.txt', 'w')
        tree = ET.parse(in_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))
            bb = convert((w, h), b)
            out_file.write(f"{cls_id} {' '.join([str(a) for a in bb])}\n")
        out_file.close()
    
    # 获取当前工作目录
    wd = getcwd()
    
    for year, image_set in sets:
        label_dir = f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\labels\\'
        if not os.path.exists(label_dir):
            os.makedirs(label_dir)
        
        # 读取图像ID列表
        image_ids = open(f'D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\ImageSets\\Main\\{image_set}.txt').read().strip().split()
        
        # 创建并写入对应文件
        list_file = open(f'{year}_{image_set}.txt', 'w')
        for image_id in image_ids:
            list_file.write(f'D:\\YOLO\\Darknet\\build\\x64\\data\\obj\\{image_id}.jpg\n')
            convert_annotation(year, image_id)
        list_file.close()
    
    # 合并 train 和 val 文件
    try:
        with open('train.txt', 'w') as f:
            for file_name in ['2025_train.txt', '2025_val.txt']:
                with open(file_name, 'r') as f_in:
                    f.write(f_in.read())
        print("✅ train.txt 已成功生成!")
    except Exception as e:
        print(f"❌ 生成 train.txt 失败: {e}")
    

    三、重点问题说明

    1. 文件路径问题

    • 原路径: D:\\YOLO\\Darknet\\scripts\\VOCdevkit\\VOC{year}\\
    • 建议检查: 确保路径中没有中文字符或特殊符号,否则可能导致文件无法写入。
    • 推荐做法: 使用 os.path.join() 替代硬编码路径。

    2. 文件覆盖问题

    • 如果你不想每次运行都覆盖已有标签文件,可以在 convert_annotation() 中添加判断:
    if os.path.exists(out_file.name):
        print(f"⚠️ 文件 {out_file.name} 已存在,跳过写入。")
    else:
        # 正常写入
    

    3. 权限问题

    • 检查路径权限: 确保你有权限在目标路径下创建和写入文件。
    • 建议: 使用管理员权限运行脚本(右键“以管理员身份运行”)。

    四、验证步骤

    1. 确保目录结构正确:

      VOCdevkit/
      └── VOC2025/
          ├── Annotations/
          ├── ImageSets/
          │   └── Main/
          │       ├── 2025_train.txt
          │       └── 2025_val.txt
          ├── labels/
          └── JPEGImages/
      
    2. 运行 voc_labels.py 后检查:

      • labels/ 目录下是否有 .txt 文件?
      • 2025_train.txt2025_val.txt 是否已生成?
    3. 查看 train.txt 是否包含图片路径:

      • 该文件用于 Darknet 训练时的图像路径列表。

    五、总结

    | 问题 | 解决方案 | |------|----------| | 标注信息被清空 | 确保不重复覆盖已有标签文件 | | 2025_train.txt2025_val.txt 未生成 | 检查路径、权限、文件名拼写 | | 文件路径错误 | 使用 os.path.join() 避免硬编码 |


    如有更多问题,请提供完整的项目目录结构和报错日志,我可以进一步帮助你排查。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 9月18日
  • 已采纳回答 9月10日
  • 创建了问题 9月9日