检测场景变化并将视频按场景分开

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}")

代码说明:

  1. process_video 函数:

    • 该函数负责处理单个视频文件,使用 PySceneDetect 检测场景变化,并将每个场景的开始和结束时间戳记录到文件中。
    • 每个视频处理后,场景的开始和结束时间以秒为单位保存在文件中,文件会追加写入。
  2. process_all_videos_in_folder 函数:

    • 该函数负责遍历文件夹中的所有 .mp4 视频文件,并调用 process_video 函数处理每个视频。
    • 它将所有时间戳写入同一个文件,并清空文件以确保每次运行时都是新的记录。
  3. 输出文件 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)

代码说明:

  1. process_video() :这个函数用于处理每个视频,使用 moviepy 库的 ffmpeg_extract_subclip 函数将视频从第一个场景结束时间点剪切到视频末尾。

  2. parse_timestamp_file():这个函数读取并解析你的时间戳文件,提取每个视频的第一个场景结束时间。

  3. main() :主函数中,通过遍历 video_folder 中的所有视频,并根据 timestamp_file 中的时间戳对每个视频进行剪切操作,删除第一个场景并将其余部分保存到 output_folder

  4. 对于没有场景信息的文件 :通过 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
相关推荐
Mr.简锋1 小时前
opencv视频读写
人工智能·opencv·音视频
春末的南方城市2 小时前
开源音乐分离器Audio Decomposition:可实现盲源音频分离,无需外部乐器分离库,从头开始制作。将音乐转换为五线谱的程序
人工智能·计算机视觉·aigc·音视频
Hali_Botebie2 小时前
采样率22050,那么CHUNK_SIZE 一次传输的音频数据大小设置多少合适?unity接收后出现卡顿的问题的思路
音视频
风之馨技术录3 小时前
智谱AI清影升级:引领AI视频进入音效新时代
人工智能·音视频
晚点吧3 小时前
视频横屏转竖屏播放-使用人脸识别+目标跟踪实现
人工智能·目标跟踪·音视频
EasyCVR4 小时前
ISUP协议视频平台EasyCVR视频设备轨迹回放平台智慧农业视频远程监控管理方案
服务器·网络·数据库·音视频
cuijiecheng20186 小时前
音视频入门基础:MPEG2-TS专题(3)——TS Header简介
音视频
学编程的小程13 小时前
【安全通信】告别信息泄露:搭建你的开源视频聊天系统briefing
安全·开源·音视频
芯视音赖工13 小时前
传统型视频展台方案分享
音视频
melonbo14 小时前
音频采样数据格式
音视频