当前位置: 首页 > news >正文

告别混乱!用Python+shutil一键整理UCF101数据集(附完整代码)

告别混乱!用Python+shutil一键整理UCF101数据集(附完整代码)

刚接触行为识别的研究者,十有八九会在UCF101这类经典数据集的预处理环节卡壳——下载的压缩包解压后,视频文件散落在101个子目录中,而官方提供的训练/测试划分文件又需要手动匹配。这种目录结构的混乱不仅拖慢实验进度,更可能因人为操作失误导致数据泄露(训练集混入测试样本)。本文将用不到100行Python代码解决这个痛点,实现从原始压缩包到标准目录结构的全自动转换。

1. 为什么需要自动化预处理?

UCF101的官方文件结构设计存在三个典型问题:

  • 原始视频存放方式:按类别存放在101个独立文件夹,文件名仅含序号(如v_ApplyEyeMakeup_g01_c01.avi
  • 划分文件格式特殊trainlist01.txt仅记录相对路径(如ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c01.avi
  • 多版本划分方案:提供三种不同的训练测试划分(01/02/03),手动操作易混淆

手动整理时常见的翻车现场包括:

  • 错误地将同一视频同时放入train和test目录
  • 因路径拼接错误导致文件复制失败
  • 需要重复处理三种划分方案时效率低下
# 典型问题示例:手动处理时的路径拼接陷阱 wrong_path = os.path.join("UCF-101", "ApplyEyeMakeup_v_ApplyEyeMakeup_g01_c01.avi") # 错误! correct_path = os.path.join("UCF-101", "ApplyEyeMakeup", "v_ApplyEyeMakeup_g01_c01.avi") # 正确

2. 工程化解决方案设计

我们的脚本需要实现以下核心功能:

  1. 智能路径解析:自动识别原始压缩包解压后的嵌套目录结构
  2. 多划分方案支持:通过命令行参数指定使用哪种划分(01/02/03)
  3. 原子化操作:确保文件移动过程的幂等性(重复执行不报错)

2.1 目录结构设计目标

最终生成的标准化结构应满足:

dataset/ ├── test/ │ ├── ApplyEyeMakeup/ │ │ ├── v_ApplyEyeMakeup_g01_c01.avi │ │ └── ... ├── train/ │ ├── ApplyLipstick/ │ │ ├── v_ApplyLipstick_g01_c01.avi │ │ └── ... └── splits/ # 原始划分文件备份

2.2 关键技术实现

使用shutil库的三大核心方法:

  • shutil.move():原子化文件移动(比复制+删除更安全)
  • os.makedirs():递归创建目录(避免父目录不存在时报错)
  • os.path.exists():操作前检查路径有效性
import shutil import os from pathlib import Path def safe_move(src, dst): """线程安全的文件移动操作""" Path(dst).parent.mkdir(parents=True, exist_ok=True) if Path(src).exists(): shutil.move(src, dst)

3. 完整实现代码

以下代码支持三种划分方案,通过--split参数指定(默认为01):

#!/usr/bin/env python3 import argparse import shutil from pathlib import Path def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("--data_root", type=str, required=True, help="UCF101解压后的根目录(含UCF-101文件夹和划分文件)") parser.add_argument("--output_dir", type=str, default="dataset", help="输出目录路径") parser.add_argument("--split", type=str, choices=["01", "02", "03"], default="01", help="使用的划分方案(01/02/03)") return parser.parse_args() def main(): args = parse_args() src_videos = Path(args.data_root) / "UCF-101" splits_dir = Path(args.data_root) / "UCF101TrainTestSplits" # 创建输出目录 (Path(args.output_dir)/"splits").mkdir(parents=True, exist_ok=True) # 处理测试集 with open(splits_dir/f"testlist{args.split}.txt") as f: for line in f: video_rel_path = line.strip() class_name, video_name = video_rel_path.split('/') src = src_videos / video_rel_path dst = Path(args.output_dir)/"test"/class_name/video_name safe_move(src, dst) # 剩余文件作为训练集 for class_dir in src_videos.iterdir(): if class_dir.is_dir(): for video in class_dir.glob("*.avi"): dst = Path(args.output_dir)/"train"/class_dir.name/video.name safe_move(video, dst) def safe_move(src, dst): dst.parent.mkdir(parents=True, exist_ok=True) if src.exists(): shutil.move(str(src), str(dst)) if __name__ == "__main__": main()

4. 进阶使用技巧

4.1 与帧提取工具联动

整理后的目录可直接配合FFmpeg进行帧提取:

# 批量提取训练集视频帧 find dataset/train -name "*.avi" | xargs -I {} ffmpeg -i {} {.}/frame_%04d.jpg

4.2 异常处理增强

建议添加以下安全检查:

  1. 验证原始文件是否完整(101个类别文件夹)
  2. 移动文件后校验MD5确保数据一致性
  3. 记录操作日志便于回溯
# MD5校验示例 import hashlib def get_file_md5(file_path): with open(file_path, 'rb') as f: return hashlib.md5(f.read()).hexdigest()

4.3 性能优化方案

当处理超大规模数据时:

  • 使用多线程加速(concurrent.futures.ThreadPoolExecutor
  • 先复制再删除替代直接移动(避免跨磁盘操作慢)
  • 使用rsync替代shutil(支持断点续传)
from concurrent.futures import ThreadPoolExecutor def batch_move(file_pairs, workers=4): with ThreadPoolExecutor(max_workers=workers) as executor: executor.map(lambda x: safe_move(*x), file_pairs)

5. 常见问题解决方案

Q1:执行时报PermissionError怎么办?

  • 方案:确保脚本有写入权限,或使用sudo执行
  • 预防:提前用os.access()检查权限

Q2:如何验证划分是否正确?

# 检查训练测试集无交集 train_videos = set(p.name for p in Path("dataset/train").glob("*/*.avi")) test_videos = set(p.name for p in Path("dataset/test").glob("*/*.avi")) assert not (train_videos & test_videos), "存在数据泄露!"

Q3:需要处理其他视频格式怎么办? 修改代码中的视频扩展名过滤条件:

# 原版只处理.avi for video in class_dir.glob("*.avi"): # 支持多种格式 VIDEO_EXTS = {'.avi', '.mp4', '.mov'} for video in class_dir.iterdir(): if video.suffix.lower() in VIDEO_EXTS:
http://www.jsqmd.com/news/585130/

相关文章:

  • FireRed-OCR Studio惊艳案例:化学分子式+反应方程式+表格数据同步结构化提取
  • 网易云音乐API隐藏功能挖掘:这些官方文档没写的接口实测可用
  • Wan2.2-I2V-A14B镜像使用手册:start_webui.sh与start_api.sh源码解析
  • 2026年比较好的回拨外呼系统/电话外呼系统优质供应商推荐 - 行业平台推荐
  • 【深度解析】2009-2024年华证ESG评级数据:上市公司可持续发展全景透视
  • 当咨询变成“流量入口”,AI电商客服正在改变什么?
  • 2026年3月必看!含聚胺的环保硬挺剂,优质厂商推荐评测,行业内评价高的聚胺生产厂家选哪家精选实力品牌分析发布 - 品牌推荐师
  • 别再复制粘贴了!深入理解STM32中IIR滤波器的差分方程与状态变量
  • 2026年评价高的东莞高周波机/高周波机/双头气压高周波机/双头油压高周波机公司对比推荐 - 行业平台推荐
  • EcomGPT-中英文-7B电商模型文件处理实战:C语言读写操作日志与模型交互记录
  • 2026年质量好的单头转盘高周波机/东莞高周波机/高周波用户口碑推荐厂家 - 行业平台推荐
  • Graphormer模型Web服务部署:Node.js后端与前端交互全栈实践
  • 西门子WinCC Flexible安装卡在重启提示?3步搞定注册表清理(附详细截图)
  • EasyAnimateV5-7b-zh-InP模型在微信小程序中的应用:短视频生成功能实现
  • AI修图新体验:PowerPaint-V1极速图像消除,5步上手实战
  • C语言从入门到进阶——第18讲:内存函数
  • YOLOE镜像从入门到精通:环境激活、代码预测、训练微调全流程
  • 别只盯着树莓派!聊聊GEC6818这块国产ARM板在嵌入式学习中的独特优势与避坑指南
  • DeepSeek-OCR-2实战:精准提取合同条款,自动生成结构化法律文书
  • SpringBoot+MybatisPlus分页实战:IPage拦截器原理与5个常见坑点解析
  • 2026年热门的量热仪/微机全自动量热仪/鹤壁全自动量热仪厂家推荐与选型指南 - 行业平台推荐
  • 保姆级教程:在PHPStudy环境下复现CTFHub MySQL注入题(附WAF绕过Payload分析)
  • 别再写“超级循环“了!裸机系统跑得快的秘密,全在架构上
  • Ostrakon-VL赋能Agent开发:构建具备视觉感知的自动化工作流
  • 利用卷积神经网络原理优化万象熔炉·丹青幻境的图像生成效果
  • SecGPT-14B领域适配:让OpenClaw更好理解医疗行业安全策略
  • 2026年3月,找回收电力物资服务,这些选择别错过!回收电力物资口碑推荐技术领航,品质之选 - 品牌推荐师
  • MogFace人脸检测模型-WebUI开源可部署:基于CVPR2022论文复现的全栈可商用方案
  • 2026年知名的自动工业分析仪/微机全自动工业分析仪/鹤壁全自动工业分析仪/双炉工业分析仪深度厂家推荐 - 行业平台推荐
  • 013、软件定时器(Software Timers)管理与应用:从一次内存泄漏说起