1. PySceneDetect
PySceneDetect
是一个功能强大的 Python 库,专门用于检测视频中的场景变化。它可以自动检测视频中不同场景的切换,并返回场景的时间段。你可以使用这些信息来进一步将视频分割为不同的片段
通过 pip 安装 PySceneDetect:
pip install scenedetect[opencv]
处理一个视频:
python
from scenedetect import VideoManager, SceneManager
from scenedetect.detectors import ContentDetector
# 设置视频文件路径
video_path = "input_video.mp4"
# 创建视频管理器和场景管理器
video_manager = VideoManager([video_path])
scene_manager = SceneManager()
# 使用内容检测器检测场景变化
scene_manager.add_detector(ContentDetector())
# 开始处理视频
video_manager.set_downscale_factor()
video_manager.start()
# 检测场景
scene_manager.detect_scenes(video_manager)
# 获取检测到的场景列表
scene_list = scene_manager.get_scene_list()
# 打印每个场景的起始和结束时间(秒)
for i, scene in enumerate(scene_list):
print(f"Scene {i+1}: Start = {scene[0].get_seconds()} sec, End = {scene[1].get_seconds()} sec")
解释:
ContentDetector()
用于检测视频中的场景变化(通过内容变化检测)。你可以调整threshold
来控制检测灵敏度。scene_list
会包含每个场景的起始和结束时间,你可以根据这些信息分割视频
批量处理视频
处理文件夹中的所有 .mp4
视频,并将时间戳信息存储到一个文本文件中
python
import os
from scenedetect import VideoManager, SceneManager
from scenedetect.detectors import ContentDetector
# 定义函数来处理单个视频并记录时间戳
def process_video(video_path, output_file):
# 创建视频管理器和场景管理器
video_manager = VideoManager([video_path])
scene_manager = SceneManager()
# 使用内容检测器检测场景变化
scene_manager.add_detector(ContentDetector())
# 开始处理视频
video_manager.set_downscale_factor()
video_manager.start()
# 检测场景
scene_manager.detect_scenes(video_manager)
# 获取检测到的场景列表
scene_list = scene_manager.get_scene_list()
# 写入时间戳信息到文件
with open(output_file, 'a') as f:
f.write(f"Video: {os.path.basename(video_path)}\n")
for i, scene in enumerate(scene_list):
start_time = scene[0].get_seconds()
end_time = scene[1].get_seconds()
f.write(f"Scene {i+1}: Start = {start_time:.2f} sec, End = {end_time:.2f} sec\n")
f.write("\n")
# 处理文件夹中的所有视频
def process_all_videos_in_folder(folder_path, output_file):
# 清空或创建输出文件
open(output_file, 'w').close()
# 遍历文件夹中的所有文件
for filename in os.listdir(folder_path):
# 只处理 .mp4 文件
if filename.endswith(".mp4"):
video_path = os.path.join(folder_path, filename)
print(f"Processing {filename}...")
process_video(video_path, output_file)
# 设置视频文件夹路径和输出文件路径
video_folder = "xxxxxx" # 替换为你的视频文件夹路径
output_file = "scene_timestamps.txt" # 场景切换时间戳的输出文件
# 处理文件夹中的所有视频并记录场景切换时间戳
process_all_videos_in_folder(video_folder, output_file)
print(f"场景切换时间戳已记录到 {output_file}")
代码说明:
-
process_video
函数:- 该函数负责处理单个视频文件,使用
PySceneDetect
检测场景变化,并将每个场景的开始和结束时间戳记录到文件中。 - 每个视频处理后,场景的开始和结束时间以秒为单位保存在文件中,文件会追加写入。
- 该函数负责处理单个视频文件,使用
-
process_all_videos_in_folder
函数:- 该函数负责遍历文件夹中的所有
.mp4
视频文件,并调用process_video
函数处理每个视频。 - 它将所有时间戳写入同一个文件,并清空文件以确保每次运行时都是新的记录。
- 该函数负责遍历文件夹中的所有
-
输出文件
scene_timestamps.txt
:- 所有视频的场景切换时间戳将被记录在
scene_timestamps.txt
文件中。每个视频的时间戳会被标注为Video: [文件名]
,每个场景的时间戳按Scene [n]: Start = x sec, End = y sec
格式记录。
- 所有视频的场景切换时间戳将被记录在
删除指定的场景:
需要安装 moviepy
库:pip install moviepy
这个脚本会读取你已有的场景时间戳信息,并自动处理所有视频,删除第一个场景。
利用现有的时间戳信息,通过视频处理库(如 moviepy
)剪掉指定的视频片段。具体来说,你需要读取每个视频的第一个场景的结束时间(例如 Scene 1: End = xx.xx sec
),并从这个时间点开始保留视频的剩余部分。
python
import os
import shutil
from moviepy.editor import VideoFileClip
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
# 定义函数处理单个视频文件,删除第一个场景
def process_video(video_path, scene_start, output_folder):
# 提取视频的文件名和扩展名
video_name = os.path.basename(video_path)
output_video_path = os.path.join(output_folder, f"trimmed_{video_name}")
# 使用 moviepy 获取视频的总时长
with VideoFileClip(video_path) as video_clip:
video_duration = video_clip.duration
# 如果场景结束时间存在,则从该时间剪切到视频结束
if scene_start is not None:
ffmpeg_extract_subclip(video_path, scene_start, video_duration, targetname=output_video_path)
print(f"Processed {video_name}, saved as {output_video_path}")
else:
print(f"No scene information for {video_name}. Retaining full video...")
# 如果没有场景信息,保留原始视频文件
shutil.copy(video_path, output_video_path)
# 解析时间戳文件
def parse_timestamp_file(timestamp_file):
video_scenes = {}
# 打开并读取时间戳文件
with open(timestamp_file, 'r') as file:
current_video = None
for line in file:
line = line.strip()
if line.startswith("Video:"):
# 获取视频文件名
current_video = line.split(":")[1].strip()
video_scenes[current_video] = []
elif line.startswith("Scene 1:"):
# 获取第一个场景的结束时间
end_time_str = line.split("End =")[1].strip().replace(" sec", "")
video_scenes[current_video].append(float(end_time_str))
return video_scenes
# 主函数
def main(video_folder, timestamp_file, output_folder):
# 创建输出文件夹,如果不存在则创建
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 解析时间戳文件,获取每个视频的第一个场景结束时间
video_scenes = parse_timestamp_file(timestamp_file)
# 遍历视频文件并处理
for video_name, scene_times in video_scenes.items():
video_path = os.path.join(video_folder, video_name)
if os.path.exists(video_path):
if scene_times: # 如果有场景信息
first_scene_end_time = scene_times[0] # 获取第一个场景的结束时间
# 处理视频,删除第一个场景
process_video(video_path, first_scene_end_time, output_folder)
else:
# 没有场景信息,保留完整视频
print(f"Retaining full video for {video_name} (no scene information).")
output_video_path = os.path.join(output_folder, f"trimmed_{video_name}")
shutil.copy(video_path, output_video_path)
else:
print(f"Video file {video_name} not found!")
# 文件路径和文件夹
video_folder = "path/to/your/videos" # 视频文件夹路径
timestamp_file = "timestamps.txt" # 时间戳文件路径
output_folder = "path/to/output/videos" # 输出文件夹路径
# 运行主函数
main(video_folder, timestamp_file, output_folder)
代码说明:
-
process_video()
:这个函数用于处理每个视频,使用moviepy
库的ffmpeg_extract_subclip
函数将视频从第一个场景结束时间点剪切到视频末尾。 -
parse_timestamp_file()
:这个函数读取并解析你的时间戳文件,提取每个视频的第一个场景结束时间。 -
main()
:主函数中,通过遍历video_folder
中的所有视频,并根据timestamp_file
中的时间戳对每个视频进行剪切操作,删除第一个场景并将其余部分保存到output_folder
。 -
对于没有场景信息的文件 :通过
shutil.copy()
函数将视频直接复制到输出文件夹中,不进行任何剪辑。当视频没有场景信息时,打印提示信息Retaining full video for {video_name}
,并将原视频文件完整保留。
输入与输出:
- 输入视频文件和时间戳文件,时间戳文件包含每个视频的场景时间段信息(如你的示例)。
- 输出剪切掉第一个场景后的新视频,并保存到指定的
output_folder
中。
2. Shotdetect
Shotdetect
是另一个专门用于视频场景变化检测的工具,适用于复杂的视频场景切割。它基于阈值或视觉内容的变化来检测场景切换。
安装:
python
pip install shotdetect
使用:
python
shotdetect -i input_video.mp4 -o output/ detect-content
解释:
-i
参数指定输入视频文件。-o
参数指定输出目录。detect-content
命令会根据视频内容检测场景变化,并将每个检测到的场景保存在输出目录中。
你还可以在检测后使用 split-video
选项自动分割视频:
python
shotdetect -i input_video.mp4 -o output/ detect-content split-video
这个命令会自动将每个检测到的场景分割为独立的视频文件,存储在输出目录中。
3. ffmpeg + 变化检测
如果你不想使用专门的 Python 库,还可以通过 ffmpeg
的场景检测功能。ffmpeg
可以根据视频帧的内容差异检测场景变化。它输出场景切换的时间戳,然后你可以使用这些时间戳来切割视频。
python
ffmpeg -i input_video.mp4 -filter:v "select='gt(scene,0.4)',showinfo" -f null - 2> scene_changes.txt
解释:
- 这个命令会输出场景切换的时间戳到
scene_changes.txt
文件中。 gt(scene,0.4)
参数控制场景变化检测的阈值,0.4 是阈值,可以根据需要调整。
之后你可以使用 ffmpeg
的切割命令来按场景分割视频。例如:
python
ffmpeg -i input_video.mp4 -ss [start_time] -to [end_time] -c copy output_clip.mp4