Spaces:
Paused
Paused
Update web-demos/hugging_face/app.py
Browse files- web-demos/hugging_face/app.py +38 -40
web-demos/hugging_face/app.py
CHANGED
@@ -133,7 +133,6 @@ def get_frames_from_video(video_input, video_state):
|
|
133 |
gr.update(visible=status_ok), gr.update(visible=status_ok, choices=[], value=[]), \
|
134 |
gr.update(visible=True, value=operation_log), gr.update(visible=status_ok, value=operation_log)
|
135 |
|
136 |
-
# get the select frame from gradio slider
|
137 |
def select_template(image_selection_slider, video_state, interactive_state, mask_dropdown):
|
138 |
|
139 |
# images = video_state[1]
|
@@ -365,50 +364,49 @@ def inpaint_video(video_state, *_args):
|
|
365 |
|
366 |
return video_output, operation_log, operation_log
|
367 |
|
368 |
-
|
369 |
# generate video after vos inference
|
370 |
-
def generate_video_from_frames(frames, output_path, fps=30):
|
371 |
"""
|
372 |
-
|
|
|
|
|
|
|
|
|
|
|
373 |
"""
|
374 |
-
|
375 |
-
import cv2
|
376 |
import numpy as np
|
377 |
-
import
|
378 |
-
import
|
379 |
-
|
380 |
-
os
|
381 |
-
|
382 |
-
# Убедимся, что все кадры — одинакового размера
|
383 |
-
h, w, _ = frames[0].shape
|
384 |
-
h, w = h // 2 * 2, w // 2 * 2
|
385 |
-
frames = [cv2.resize(f, (w, h)) for f in frames]
|
386 |
-
|
387 |
-
# Временная папка
|
388 |
-
with tempfile.TemporaryDirectory() as tmpdir:
|
389 |
-
frame_dir = os.path.join(tmpdir, "frames")
|
390 |
-
os.makedirs(frame_dir, exist_ok=True)
|
391 |
-
|
392 |
-
# Сохраняем каждый кадр как PNG
|
393 |
-
for idx, frame in enumerate(frames):
|
394 |
-
cv2.imwrite(os.path.join(frame_dir, f"{idx:05d}.png"), frame)
|
395 |
-
|
396 |
-
# Генерируем видео через ffmpeg
|
397 |
-
ffmpeg_cmd = [
|
398 |
-
"ffmpeg",
|
399 |
-
"-y",
|
400 |
-
"-framerate", str(fps),
|
401 |
-
"-i", os.path.join(frame_dir, "%05d.png"),
|
402 |
-
"-c:v", "libx264",
|
403 |
-
"-preset", "slow", # качество > скорость
|
404 |
-
"-crf", "18", # высокое качество (0 — без потерь)
|
405 |
-
"-pix_fmt", "yuv420p",
|
406 |
-
output_path
|
407 |
-
]
|
408 |
-
|
409 |
-
print("Running ffmpeg:", " ".join(ffmpeg_cmd))
|
410 |
-
subprocess.run(ffmpeg_cmd, check=True)
|
411 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
412 |
return output_path
|
413 |
|
414 |
def restart():
|
|
|
133 |
gr.update(visible=status_ok), gr.update(visible=status_ok, choices=[], value=[]), \
|
134 |
gr.update(visible=True, value=operation_log), gr.update(visible=status_ok, value=operation_log)
|
135 |
|
|
|
136 |
def select_template(image_selection_slider, video_state, interactive_state, mask_dropdown):
|
137 |
|
138 |
# images = video_state[1]
|
|
|
364 |
|
365 |
return video_output, operation_log, operation_log
|
366 |
|
|
|
367 |
# generate video after vos inference
|
368 |
+
def generate_video_from_frames(frames, output_path, fps=30, bitrate=None):
|
369 |
"""
|
370 |
+
Generates a video from a list of frames.
|
371 |
+
|
372 |
+
Args:
|
373 |
+
frames (list of numpy arrays): The frames to include in the video.
|
374 |
+
output_path (str): The path to save the generated video.
|
375 |
+
fps (int, optional): The frame rate of the output video. Defaults to 30.
|
376 |
"""
|
377 |
+
# Приведение fps к обычному float (из np.float64, если нужно)
|
|
|
378 |
import numpy as np
|
379 |
+
import imageio
|
380 |
+
import torch
|
381 |
+
import torchvision
|
382 |
+
import os
|
383 |
+
from fractions import Fraction
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
384 |
|
385 |
+
# Convert fps to a clean format
|
386 |
+
if isinstance(fps, np.generic):
|
387 |
+
fps = fps.item()
|
388 |
+
fps = float(fps)
|
389 |
+
|
390 |
+
# Ensure all frames are the same shape
|
391 |
+
assert all(f.shape == frames[0].shape for f in frames), "All frames must have the same shape"
|
392 |
+
|
393 |
+
# Convert to tensor (T, H, W, C)
|
394 |
+
#frames = torch.from_numpy(np.asarray(frames))
|
395 |
+
|
396 |
+
# Ensure output directory exists
|
397 |
+
if not os.path.exists(os.path.dirname(output_path)):
|
398 |
+
os.makedirs(os.path.dirname(output_path))
|
399 |
+
|
400 |
+
# Write the video
|
401 |
+
#torchvision.io.write_video(output_path, frames, fps=fps, video_codec="libx264")
|
402 |
+
#return output_path
|
403 |
+
if bitrate is not None:
|
404 |
+
writer = imageio.get_writer(output_path, fps=fps, codec='libx264', bitrate=bitrate)
|
405 |
+
else:
|
406 |
+
writer = imageio.get_writer(output_path, fps=fps, codec='libx264')
|
407 |
+
for frame in frames:
|
408 |
+
writer.append_data(frame.astype(np.uint8))
|
409 |
+
writer.close()
|
410 |
return output_path
|
411 |
|
412 |
def restart():
|