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

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

1. PySceneDetect

PySceneDetect 是一个功能强大的 Python 库,专门用于检测视频中的场景变化。它可以自动检测视频中不同场景的切换,并返回场景的时间段。你可以使用这些信息来进一步将视频分割为不同的片段

通过 pip 安装 PySceneDetect:

pip install scenedetect[opencv]

处理一个视频:

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 视频,并将时间戳信息存储到一个文本文件中

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),并从这个时间点开始保留视频的剩余部分。

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 是另一个专门用于视频场景变化检测的工具,适用于复杂的视频场景切割。它基于阈值或视觉内容的变化来检测场景切换。

安装:

pip install shotdetect

使用:

shotdetect -i input_video.mp4 -o output/ detect-content

解释

  • -i 参数指定输入视频文件。
  • -o 参数指定输出目录。
  • detect-content 命令会根据视频内容检测场景变化,并将每个检测到的场景保存在输出目录中。

你还可以在检测后使用 split-video 选项自动分割视频:

shotdetect -i input_video.mp4 -o output/ detect-content split-video

这个命令会自动将每个检测到的场景分割为独立的视频文件,存储在输出目录中。

3. ffmpeg + 变化检测

如果你不想使用专门的 Python 库,还可以通过 ffmpeg 的场景检测功能。ffmpeg 可以根据视频帧的内容差异检测场景变化。它输出场景切换的时间戳,然后你可以使用这些时间戳来切割视频。

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 的切割命令来按场景分割视频。例如:

ffmpeg -i input_video.mp4 -ss [start_time] -to [end_time] -c copy output_clip.mp4


http://www.kler.cn/a/308407.html

相关文章:

  • 844.比较含退格的字符串
  • ❤React-React 组件基础(类组件)
  • [代码随想录Day10打卡] 理论基础 232.用栈实现队列 225. 用队列实现栈 20. 有效的括号 1047. 删除字符串中的所有相邻重复项
  • FatLab:我的编程课程系列
  • 移动端【01】面试系统的MVVM重构实践
  • ubuntu ros 解决建完图后 保存的地图非常小的问题
  • 特殊类的设计与类型转换
  • Axure RP实战:打造高效图形旋转验证码
  • [网络]TCP/IP协议 之 数据链路层和DNS
  • GFS 分布式文件系统 GlusterFS
  • Flip动画的实现示例demo
  • 星火AI图片理解API文档
  • SpringBoot项目请求返回json空字段过滤
  • Element-UI 组件实现面包屑导航栏
  • 怎么使用ai 免费生成ppt?这4个工具可以帮忙
  • 人工智能与机器学习原理精解【20】
  • 信息安全工程师(6)网络信息安全现状与问题
  • 3D点云目标检测数据集标注工具 保姆级教程——CVAT (附json转kitti代码)
  • COMDEL电源CX2500S RF13.56MHZ RF GENERATOR手侧
  • 唯徳知识产权管理系统 DownloadFileWordTemplate 文件读取漏洞复现
  • ubuntu 遇到的一些问题及解决办法
  • rabbitmq容器化部署
  • 钻机、塔吊等大型工程设备,如何远程维护、实时采集运行数据?
  • TypeScript:高级类型
  • 主流敏捷工具scrum工具
  • linux-centos 设置系统时间