多文件Dota转Yolo格式程序异常:仅首文件输出正确
问题:多文件Dota转Yolo格式时输出异常
需求与问题现象
我正在编写Dota格式转Yolo格式的程序,需求如下:
- 读取目录下多个Dota格式文本文件
- 处理后生成同名Yolo格式文件,输出行数比输入少2行(移除开头两行元数据)
- 所有坐标值需归一化到0-1范围内
单文件处理时一切正常,但批量处理多个文件时,只有第一个输出文件符合要求,其余文件行数明显偏多,还存在部分坐标值大于1的情况。怀疑是程序没有逐个处理文件,而是同时打开所有输入文件导致的问题。
问题根源分析
从提供的代码片段来看,核心问题有两个:
- 全局列表未清空:
coordinatesList是定义在文件处理逻辑外的全局变量,每次处理新文件时没有重置为空,导致前一个文件的坐标数据被累积到下一个文件的处理流程中,直接造成后续输出文件行数增多。 - 追加写入模式隐患:用
"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
相关产品推荐
相关产品推荐

