Spaces:
Sleeping
Sleeping
File size: 6,856 Bytes
7064043 8d2001a ae4b7d0 9724d68 509eeda 8ce7fdb c0ff040 8ce7fdb 8d2001a 4a23dca 7064043 b3bc788 4308b33 7064043 4916c5e 7064043 f6894df 84d1725 7064043 63ce649 85cb9b5 f6894df 509eeda cf58581 8ce7fdb 8d2001a 8ce7fdb 7064043 8ce7fdb 86f6646 95eab87 7064043 95a9f65 7064043 6fc3067 95a9f65 40fe7c0 fc8689b f9127d3 831716d 63ce649 95eab87 7064043 c97a584 7064043 9d7c1dd 40fe7c0 190fc64 e399130 40fe7c0 695d1b1 7064043 d408c45 7064043 2938c1f 7064043 831716d ae4b7d0 7064043 cae39fd 63ce649 7064043 63ce649 cae39fd 63ce649 7064043 71f8de2 3b4ac51 7064043 8f01d6b 6fc3067 7064043 f50a5fd 7064043 40fe7c0 8d2001a 7064043 4916c5e 554ca8f 4916c5e cb73941 899baa8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# Dependencies, see also requirement.txt ;)
import gradio as gr
import cv2
import numpy as np
import os
from scenedetect import open_video, SceneManager
from scenedetect.detectors import ContentDetector
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
# —————————————————————————————————————————————————
title = "Scene Edit Detection"
description = "<p style='text-align: center'>Gradio demo of PySceneDetect. <br />Automatically find every shots in a video sequence</p><p style='text-align: center'> 1. gives you timecode in/out for each shot. 2. saves each shot as a splitted mp4 video chunk for you to download. 3. diplays a thumbnail for each shot as a gallery output.<br /> <img id='visitor-badge' alt='visitor badge' src='https://visitor-badge.glitch.me/badge?page_id=gradio-blocks.scene-edit-detection' style='display: inline-block'/></b></p>"
article = "<p style='text-align: center'><a href='http://scenedetect.com/en/latest/' target='_blank'>PySceneDetect website</a> | <a href='https://github.com/Breakthrough/PySceneDetect' target='_blank'>Github Repo</a></p>"
# —————————————————————————————————————————————————
# SET INPUTS
video_input = gr.Video(source="upload", format="mp4", label="Video Sequence", mirror_webcam=False)
threshold = gr.Slider(label="Threshold pixel comparison: if exceeded, triggers a scene cut. Default: 27.0", minimum=15.0, maximum=40.0, value=27.0)
# —————————————————————————————————————————————————
def convert_to_tuple(list):
return tuple(list);
def find_scenes(video_path, threshold):
# file name without extension
filename = os.path.splitext(os.path.basename(video_path))[0]
# Open our video, create a scene manager, and add a detector.
video = open_video(video_path)
scene_manager = SceneManager()
scene_manager.add_detector(
ContentDetector(threshold=threshold))
# Start detection
scene_manager.detect_scenes(video, show_progress=True)
scene_list = scene_manager.get_scene_list()
# Push the list of scenes into data_outputs
data_outputs.append(scene_list)
gradio_components_outputs.append("json")
#print(scene_list)
timecodes = []
timecodes.append({"title": filename + ".mp4", "fps": scene_list[0][0].get_framerate()})
shots = []
stills = []
# For each shot found, set entry and exit points as seconds from frame number
# Then split video into chunks and store them into shots List
# Then extract first frame of each shot as thumbnail for the gallery
for i, shot in enumerate(scene_list):
# STEP 1
# Get timecode in seconds
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)
# Set name template for each shot
target_name = "shot_" + str(i+1) + "_" + str(filename) + ".mp4"
# Split chunk
ffmpeg_extract_subclip(video_path, shot_in, shot_out, targetname=target_name)
# Push chunk into shots List
shots.append(target_name)
# Push each chunk into data_outputs
data_outputs.append(target_name)
gradio_components_outputs.append("video")
# —————————————————————————————————————————————————
# STEP 2
# extract first frame of each shot with cv2
vid = cv2.VideoCapture(video_path)
fps = vid.get(cv2.CAP_PROP_FPS)
print('frames per second =',fps)
frame_id = shot[0].get_frames() # value from scene_list from step 1
vid.set(cv2.CAP_PROP_POS_FRAMES, frame_id)
ret, frame = vid.read()
# Save frame as PNG file
img = str(frame_id) + '_screenshot.png'
cv2.imwrite(img,frame)
# Push image into stills List
stills.append((img, 'shot ' + str(i+1)))
# Push the list of video shots into data_outputs for Gradio file component
data_outputs.append(shots)
gradio_components_outputs.append("file")
# Push the list of still images into data_outputs
data_outputs.append(stills)
gradio_components_outputs.append("gallery")
# This would have been used as gradio outputs,
# if we could set number of outputs after the interface launch
# That's not (yet ?) possible
results = convert_to_tuple(data_outputs)
print(results)
# return List of shots as JSON, List of video chunks, List of still images
# *
# Would be nice to be able to return my results tuple as outputs,
# while number of chunks found is not fixed:
# return results
return timecodes, shots, stills
# —————————————————————————————————————————————————
# SET DATA AND COMPONENTS OUTPUTS
# This would be filled like this:
# data_outputs = [ [List from detection], "video_chunk_n0.mp4", "video_chunk_n1.mp4", ... , "video_chunk_n.mp4", [List of video filepath to download], [List of still images from each shot found] ]
data_outputs = []
# This would be filled like this:
# gradio_components_outputs = [ "json", "video", "video", ... , "video", "file", "gallery" ]
gradio_components_outputs = []
#SET OUTPUTS
# This would be nice if number of outputs could be set after Interface Launch:
# because we do not know how many shots will be detected
# gradio_components_outputs = [ "json", "video", "video", ... , "video", "file", "gallery" ]
# outputs = gradio_components_outputs
# ANOTHER SOLUTION WOULD BE USING A (FUTURE ?) "VIDEO GALLERY" GRADIO COMPONENT FROM LIST :)
outputs = [gr.JSON(label="Shots detected"), gr.File(label="Downloadable Shots"), gr.Gallery(label="Still Images from each shot").style(grid=3)]
# —————————————————————————————————————————————————
print('Hello Sylvain')
gr.Interface(fn=find_scenes, inputs=[video_input, threshold], outputs=outputs, title=title, description=description, article=article).launch() |