(原创)使用FFmpeg截取多个视频中的图片,创建训练集
代码使用 Python 中的 subprocess 模块和 FFmpeg、FFprobe 工具来从视频文件中截取多个截图,并使用 PIL 库来检查截图文件是否损坏,如果损坏了就不保存该文件。
下面是代码的具体流程:
首先读取配置文件或命令行参数来指定截图数量、截图大小、截图时间间隔和截图质量等参数,并指定视频文件所在文件夹路径和截图保存文件夹路径以及 FFmpeg 和 FFprobe 的路径。
然后获取视频文件所在文件夹下的所有子文件夹名称,遍历每个子文件夹,对每个视频文件进行处理。
对于每个视频文件,使用 FFprobe 工具获取视频文件的总时长(duration),然后计算出要截取的多个截图的时间点和时间间隔。
对于每个视频文件,创建一个与视频文件同名的子文件夹,用于保存该视频文件的多个截图。
对于每个视频文件,使用 FFmpeg 工具在第1、第5、第10帧处截取三个截图,并在每隔一定时间间隔处截取 num_screenshots 个截图,共计 num_screenshots + 3 个截图。截图保存在之前创建的子文件夹中。
对于每个截图文件,使用 PIL 库打开该文件,如果文件无法正常打开,就说明该文件已经损坏,需要将其删除。
对于每个截图文件,检查其文件大小是否小于2KB,如果是则删除该文件。
如果处理视频文件时出现异常,就打印错误信息。
import os import shlex import subprocess from PIL import Image # 读取配置文件或命令行参数来指定截图数量、截图大小等参数 num_screenshots = 5 screenshot_size = '-1:480' screenshot_interval = 'not(mod(n\,100))' quality = '2' # 视频文件所在文件夹路径和截图保存文件夹路径 video_folder = "C:/Users/ChanRa1n/Desktop/VideoLibary" img_folder = "C:/Users/ChanRa1n/Desktop/TestVideo_img" # FFmpeg和FFprobe的路径 ffmpeg_path = "C:/Program Files/ffmpeg-2023-07-10-git-1c61c24f5f-full_build/bin/ffmpeg" ffprobe_path = "C:/Program Files/ffmpeg-2023-07-10-git-1c61c24f5f-full_build/bin/ffprobe" # 获取所有子文件夹名称 subfolders = [f for f in os.listdir(video_folder) if os.path.isdir(os.path.join(video_folder, f))] # 遍历所有子文件夹,对每个视频截取多个图片并保存到对应的子文件夹为名的目录下 for subfolder in subfolders: try: # 获取视频文件列表 video_folder_path = os.path.join(video_folder, subfolder) video_files = [f for f in os.listdir(video_folder_path) if os.path.isfile(os.path.join(video_folder_path, f))] # 遍历视频文件列表,对每个视频截取多个图片 for video_file in video_files: # 获取视频文件路径和文件名 video_path = os.path.join(video_folder_path, video_file) video_name = os.path.splitext(video_file)[0] # 创建截图保存文件夹 img_subfolder = os.path.join(img_folder, subfolder) os.makedirs(img_subfolder, exist_ok=True) # 截取多个图片,分别在第1、第5、第10帧和每隔一定时间间隔 cmd = shlex.split(f"{ffprobe_path} -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 {shlex.quote(video_path)}") duration = float(subprocess.check_output(cmd).decode('utf-8').strip()) interval = duration / (num_screenshots + 3) for i, time in enumerate([1, 5, 10]): img_name = f"{video_name}_{i+1}.jpg" img_path = os.path.join(img_subfolder, img_name) cmd = shlex.split(f"{ffmpeg_path} -ss {time} -i {shlex.quote(video_path)} -vframes 1 -q:v {quality} {shlex.quote(img_path)}") subprocess.run(cmd, check=True, shell=False) # 使用PIL库检查截图文件是否损坏,如果损坏了就删除该文件 try: with Image.open(img_path) as im: pass except Exception as e: os.remove(img_path) continue for i in range(1, num_screenshots+1): img_name = f"{video_name}_{i+3}.jpg" img_path = os.path.join(img_subfolder, img_name) cmd = shlex.split(f"{ffmpeg_path} -ss {interval*(i-1)} -i {shlex.quote(video_path)} -vframes 1 -q:v {quality} {shlex.quote(img_path)}") subprocess.run(cmd, check=True, shell=False) # 使用PIL库检查截图文件是否损坏,如果损坏了就删除该文件 try: with Image.open(img_path) as im: pass except Exception as e: os.remove(img_path) # 检查文件大小,如果小于2KB则删除 if os.path.getsize(img_path) < 2048: os.remove(img_path) except Exception as e: print(f"Error processing videos in {subfolder}: {e}")