You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多文件Dota转Yolo格式程序异常:仅首文件输出正确

问题:多文件Dota转Yolo格式时输出异常

需求与问题现象

我正在编写Dota格式转Yolo格式的程序,需求如下:

  • 读取目录下多个Dota格式文本文件
  • 处理后生成同名Yolo格式文件,输出行数比输入少2行(移除开头两行元数据)
  • 所有坐标值需归一化到0-1范围内

单文件处理时一切正常,但批量处理多个文件时,只有第一个输出文件符合要求,其余文件行数明显偏多,还存在部分坐标值大于1的情况。怀疑是程序没有逐个处理文件,而是同时打开所有输入文件导致的问题。

问题根源分析

从提供的代码片段来看,核心问题有两个:

  1. 全局列表未清空:coordinatesList是定义在文件处理逻辑外的全局变量,每次处理新文件时没有重置为空,导致前一个文件的坐标数据被累积到下一个文件的处理流程中,直接造成后续输出文件行数增多。
  2. 追加写入模式隐患:用"a"模式打开输出文件会追加内容,如果输出目录中存在之前生成的残留文件,会导致新旧内容叠加,进一步加重异常。

另外还有个潜在风险:使用eval(i)转换坐标值,若输入文本中存在非数字内容会直接报错,建议改用float(i)更安全。

修复后的代码实现

把coordinatesList移到每个文件的处理块内部,确保每次处理新文件时都是空列表;同时改用"w"模式打开输出文件(覆盖写入,避免残留内容干扰),并优化部分细节:

import os
import cv2

textDir = "./inputData"
outputDir = "./outputData"

# 确保输出目录存在
os.makedirs(outputDir, exist_ok=True)

# 遍历输入目录下的所有txt文件
for textFile in os.listdir(textDir):
    if not textFile.lower().endswith(".txt"):
        continue
    
    textPath = os.path.join(textDir, textFile)
    # 关键:每个文件处理前重新初始化坐标列表
    coordinatesList = []
    
    # 匹配对应图片(根据你的实际图片路径规则调整)
    imgFileName = textFile.replace(".txt", ".jpg")  # 假设图片是jpg格式
    imgPath = os.path.join("./images", imgFileName)
    img = cv2.imread(imgPath)
    
    if img is None:
        print(f"跳过:无法读取图片 {imgPath}")
        continue
    
    # 读取并处理Dota格式文本
    with open(textPath, "r", encoding="utf-8") as f:
        contents = f.read()
        # 跳过前两行元数据,取后续内容
        targetLines = contents.splitlines()[2:]
        
        for line in targetLines:
            # 移除每行最后两个字段,拆分坐标
            cleanedLine = ' '.join(line.rsplit(' ', 2)[:-2])
            coordinates = cleanedLine.split()
            coordinatesList.append(coordinates)
    
    imageHeight, imageWidth = img.shape[:2]
    print(f"处理文件:{textFile},图片尺寸:{imageWidth}x{imageHeight}")
    
    # 写入Yolo格式输出文件(覆盖模式)
    outputPath = os.path.join(outputDir, textFile)
    with open(outputPath, "w", encoding="utf-8") as outF:
        for coords in coordinatesList:
            # 转换为浮点型坐标
            coordsFloat = [float(coord) for coord in coords]
            coordsX = coordsFloat[::2]
            coordsY = coordsFloat[1::2]
            
            minX, maxX = min(coordsX), max(coordsX)
            minY, maxY = min(coordsY), max(coordsY)
            
            # 归一化计算Yolo格式所需的中心坐标与宽高
            centerX = (minX + maxX) / 2 / imageWidth
            centerY = (minY + maxY) / 2 / imageHeight
            bboxWidth = (maxX - minX) / imageWidth
            bboxHeight = (maxY - minY) / imageHeight
            
            # 确保坐标值在0-1范围内(处理浮点误差或异常输入)
            centerX = max(0.0, min(centerX, 1.0))
            centerY = max(0.0, min(centerY, 1.0))
            bboxWidth = max(0.0, min(bboxWidth, 1.0))
            bboxHeight = max(0.0, min(bboxHeight, 1.0))
            
            # 写入一行Yolo格式内容
            outLine = f"0 {centerX} {centerY} {bboxWidth} {bboxHeight}\n"
            outF.write(outLine)

print("所有文件处理完成")

额外优化说明

  • 使用os.path.join拼接路径,避免Windows/Linux路径分隔符不一致的问题
  • 提前创建输出目录,防止因目录不存在导致写入失败
  • 增加图片读取失败的判断与提示,避免程序崩溃
  • 用with语句管理文件流,自动关闭文件,避免资源泄漏
  • 增加坐标值的边界限制,防止浮点计算误差或异常输入导致值超出0-1范围

内容的提问来源于stack exchange,提问作者Hasan Al-Aref

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:35:40