You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
6.1 KiB
Python

import os
import shutil
import random
def get_all_dirs_with_files(root_dir):
"""递归获取 root_dir 下所有包含文件的目录"""
result = []
for dirpath, dirnames, filenames in os.walk(root_dir):
if filenames:
result.append(dirpath)
return result
def process_directory(dir_path, seq_num, all_pairs):
"""处理单个目录:修改文本文件第一列为序列号,BMP 复制对应的 txt"""
all_files = os.listdir(dir_path)
bmp_files = [f for f in all_files if f.lower().endswith('.bmp')]
txt_files = [f for f in all_files if f.lower().endswith('.txt')]
other_files = [f for f in all_files
if not f.lower().endswith('.bmp') and not f.lower().endswith('.txt')]
text_candidates = txt_files + other_files
if not text_candidates:
print(f" [{os.path.basename(dir_path)}] 未找到文本文件,跳过")
return
text_filename = text_candidates[0]
text_path = os.path.join(dir_path, text_filename)
if not os.path.isfile(text_path):
print(f" [{os.path.basename(dir_path)}] 跳过非文件: {text_filename}")
return
short_name = os.path.basename(dir_path)
print(f" 处理: {short_name} (seq={seq_num}), 文本: {text_filename}")
# 读取文件
try:
with open(text_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
except (UnicodeDecodeError, PermissionError, OSError):
try:
with open(text_path, 'r', encoding='gbk') as f:
lines = f.readlines()
except Exception as e:
print(f" 读取失败: {e}")
return
modified_lines = []
for line in lines:
line = line.rstrip('\n').rstrip('\r')
if not line.strip():
modified_lines.append(line)
continue
parts = line.split()
if parts:
parts[0] = str(seq_num)
modified_lines.append(' '.join(parts))
# 写回
with open(text_path, 'w', encoding='utf-8') as f:
f.write('\n'.join(modified_lines))
print(f" 已修改 {len([l for l in modified_lines if l.strip()])} 行")
# 为每个 BMP 复制/关联文档
if bmp_files:
for bmp_filename in bmp_files:
bmp_basename = os.path.splitext(bmp_filename)[0]
copy_filename = f"{bmp_basename}.txt"
copy_path = os.path.join(dir_path, copy_filename)
if os.path.normpath(text_path) == os.path.normpath(copy_path):
all_pairs.append((os.path.join(dir_path, bmp_filename), copy_path))
else:
shutil.copy2(text_path, copy_path)
all_pairs.append((os.path.join(dir_path, bmp_filename), copy_path))
print(f" BMP 数量: {len(bmp_files)}")
else:
print(f" 无 BMP 图片")
def main():
base_dir = r"D:\xwechat_files\wxid_ttkf0xgmyihv22_2388\msg\file\2026-07\抓图(1)\抓图\新建文件夹\1\1\新建文件夹"
output_dir = os.path.join(os.path.dirname(base_dir.rstrip('\\/')), "yolo_output")
train_img_dir = os.path.join(output_dir, "train", "images")
train_lbl_dir = os.path.join(output_dir, "train", "labels")
val_img_dir = os.path.join(output_dir, "val", "images")
val_lbl_dir = os.path.join(output_dir, "val", "labels")
for d in [train_img_dir, train_lbl_dir, val_img_dir, val_lbl_dir]:
os.makedirs(d, exist_ok=True)
if not os.path.isdir(base_dir):
print(f"错误: 路径不存在: {base_dir}")
return
top_dirs = [d for d in os.listdir(base_dir) if os.path.isdir(os.path.join(base_dir, d))]
top_dirs.sort()
if not top_dirs:
print("没有找到子文件夹")
return
seq_start = 20
all_pairs = [] # (bmp_path, txt_path)
mapping = {} # 顶层文件夹名 -> 序列号
for idx, top_name in enumerate(top_dirs):
top_path = os.path.join(base_dir, top_name)
seq_num = seq_start + idx
mapping[top_name] = seq_num
print(f"\n{'='*50}")
print(f"顶层文件夹: {top_name} -> 序列号: {seq_num}")
# 递归获取该顶层文件夹下所有含文件的目录
leaf_dirs = get_all_dirs_with_files(top_path)
if not leaf_dirs:
print(f" 无文件,跳过")
continue
for leaf_dir in leaf_dirs:
process_directory(leaf_dir, seq_num, all_pairs)
# ---- 输出对应关系 ----
print("\n" + "=" * 50)
print("文件夹与序列号对应关系:")
print("-" * 40)
for name, num in mapping.items():
print(f" {num} : {name}")
print("=" * 50)
# ---- YOLO 格式 train/val 划分 ----
if not all_pairs:
print("\n没有 BMP 图片,跳过 YOLO 输出")
return
random.seed(42)
random.shuffle(all_pairs)
split_idx = int(len(all_pairs) * 0.8)
train_pairs = all_pairs[:split_idx]
val_pairs = all_pairs[split_idx:]
print(f"\n总图片数: {len(all_pairs)}")
print(f"train: {len(train_pairs)} | val: {len(val_pairs)}")
def copy_pairs(pairs, img_dir, lbl_dir):
for bmp_path, txt_path in pairs:
bmp_name = os.path.basename(bmp_path)
txt_name = os.path.basename(txt_path)
dst_bmp = bmp_name
dst_txt = txt_name
counter = 0
while os.path.exists(os.path.join(img_dir, dst_bmp)):
counter += 1
base, ext = os.path.splitext(bmp_name)
dst_bmp = f"{base}_{counter}{ext}"
dst_txt = f"{base}_{counter}.txt"
shutil.copy2(bmp_path, os.path.join(img_dir, dst_bmp))
shutil.copy2(txt_path, os.path.join(lbl_dir, dst_txt))
copy_pairs(train_pairs, train_img_dir, train_lbl_dir)
copy_pairs(val_pairs, val_img_dir, val_lbl_dir)
print(f"\nYOLO 格式输出: {output_dir}")
print(f" train/images/ ({len(train_pairs)} 张)")
print(f" train/labels/ ({len(train_pairs)} 个)")
print(f" val/images/ ({len(val_pairs)} 张)")
print(f" val/labels/ ({len(val_pairs)} 个)")
print("\n全部完成!")
if __name__ == "__main__":
main()