svjack's picture
Update app.py
db7320d verified
# Dependencies, see also requirement.txt ;)
import gradio as gr
import cv2
import numpy as np
import os
from datetime import datetime # 新增时间模块
from scenedetect import open_video, SceneManager
from scenedetect.detectors import ContentDetector
from moviepy.editor import VideoFileClip
def convert_to_tuple(list):
return tuple(list)
def clear_app():
return None, 27, None, None, None
def find_scenes(video_path, threshold):
# 创建时间戳目录
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
output_dir = f"output_{timestamp}"
os.makedirs(output_dir, exist_ok=True)
filename = os.path.splitext(os.path.basename(video_path))[0]
video = open_video(video_path)
scene_manager = SceneManager()
scene_manager.add_detector(ContentDetector(threshold=threshold))
scene_manager.detect_scenes(video, show_progress=True)
scene_list = scene_manager.get_scene_list()
data_outputs = [] # 改为局部变量
gradio_components_outputs = [] # 改为局部变量
data_outputs.append(scene_list)
gradio_components_outputs.append("json")
timecodes = []
if not scene_list:
gr.Warning("No scenes detected in this video")
return None, None, None
timecodes.append({"title": filename + ".mp4", "fps": scene_list[0][0].get_framerate()})
shots = []
stills = []
for i, shot in enumerate(scene_list):
framerate = shot[0].get_framerate()
shot_in = shot[0].get_frames() / framerate
shot_out = shot[1].get_frames() / framerate
tc_in = shot[0].get_timecode()
tc_out = shot[1].get_timecode()
frame_in = shot[0].get_frames()
frame_out = shot[1].get_frames()
timecode = {"tc_in": tc_in, "tc_out": tc_out, "frame_in": frame_in, "frame_out": frame_out}
timecodes.append(timecode)
# 修改输出路径到时间戳目录
target_name = os.path.join(output_dir, f"shot_{i+1}_{filename}.mp4")
with VideoFileClip(video_path) as clip:
subclip = clip.subclip(shot_in, shot_out)
subclip.write_videofile(
target_name,
codec="libx264",
audio_codec="aac",
threads=4,
preset="fast",
ffmpeg_params=["-crf", "23"]
)
shots.append(target_name)
data_outputs.append(target_name)
gradio_components_outputs.append("video")
vid = cv2.VideoCapture(video_path)
frame_id = shot[0].get_frames()
vid.set(cv2.CAP_PROP_POS_FRAMES, frame_id)
ret, frame = vid.read()
# 修改截图保存路径
img = os.path.join(output_dir, f"{frame_id}_screenshot.png")
cv2.imwrite(img, frame)
stills.append((img, f'shot {i+1}'))
vid.release()
data_outputs.append(shots)
gradio_components_outputs.append("file")
data_outputs.append(stills)
gradio_components_outputs.append("gallery")
results = convert_to_tuple(data_outputs)
print(f"所有输出文件保存在:{os.path.abspath(output_dir)}")
return timecodes, shots, stills
with gr.Blocks() as demo:
with gr.Column():
gr.Markdown("""
# Scene Edit Detection
Automatically find all the shots in a video.
Accepts mp4 format. Works only with videos that have cuts in them.
""")
with gr.Row():
with gr.Column():
video_input = gr.Video(sources="upload", format="mp4", label="视频输入", mirror_webcam=False)
threshold = gr.Slider(label="场景切换检测阈值(越低越敏感)", minimum=15.0, maximum=40.0, value=27.0)
with gr.Row():
clear_button = gr.Button("清除")
run_button = gr.Button("开始处理", variant="primary")
with gr.Column():
json_output = gr.JSON(label="场景分析结果")
file_output = gr.File(label="下载分割片段")
gallery_output = gr.Gallery(label="场景缩略图", object_fit="cover", columns=3)
run_button.click(fn=find_scenes, inputs=[video_input, threshold], outputs=[json_output, file_output, gallery_output])
clear_button.click(fn=clear_app, inputs=None, outputs=[video_input, threshold, json_output, file_output, gallery_output])
# 添加示例部分
gr.Examples(
examples=[
["anime_kiss.mp4", 27],
],
inputs=[video_input, threshold],
outputs=[json_output, file_output, gallery_output],
fn=find_scenes,
cache_examples=False,
label="示例视频"
)
demo.queue().launch(debug=True, share=True)