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()