(原创)使用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}")


