Spaces:
Paused
Paused
Update web-demos/hugging_face/app.py
Browse files- web-demos/hugging_face/app.py +38 -38
web-demos/hugging_face/app.py
CHANGED
@@ -365,48 +365,48 @@ def inpaint_video(video_state, *_args):
|
|
365 |
|
366 |
|
367 |
# generate video after vos inference
|
368 |
-
def generate_video_from_frames(frames, output_path, fps=30
|
369 |
"""
|
370 |
-
|
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 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
#
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
os.makedirs(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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():
|
|
|
365 |
|
366 |
|
367 |
# generate video after vos inference
|
368 |
+
def generate_video_from_frames(frames, output_path, fps=30):
|
369 |
"""
|
370 |
+
Save high-quality video using ffmpeg and CRF.
|
|
|
|
|
|
|
|
|
|
|
371 |
"""
|
|
|
|
|
|
|
|
|
|
|
372 |
import os
|
373 |
+
import cv2
|
374 |
+
import numpy as np
|
375 |
+
import subprocess
|
376 |
+
import tempfile
|
377 |
+
|
378 |
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
379 |
+
|
380 |
+
# Убедимся, что все кадры — одинакового размера
|
381 |
+
h, w, _ = frames[0].shape
|
382 |
+
h, w = h // 2 * 2, w // 2 * 2
|
383 |
+
frames = [cv2.resize(f, (w, h)) for f in frames]
|
384 |
+
|
385 |
+
# Временная папка
|
386 |
+
with tempfile.TemporaryDirectory() as tmpdir:
|
387 |
+
frame_dir = os.path.join(tmpdir, "frames")
|
388 |
+
os.makedirs(frame_dir, exist_ok=True)
|
389 |
+
|
390 |
+
# Сохраняем каждый кадр как PNG
|
391 |
+
for idx, frame in enumerate(frames):
|
392 |
+
cv2.imwrite(os.path.join(frame_dir, f"{idx:05d}.png"), frame)
|
393 |
+
|
394 |
+
# Генерируем видео через ffmpeg
|
395 |
+
ffmpeg_cmd = [
|
396 |
+
"ffmpeg",
|
397 |
+
"-y",
|
398 |
+
"-framerate", str(fps),
|
399 |
+
"-i", os.path.join(frame_dir, "%05d.png"),
|
400 |
+
"-c:v", "libx264",
|
401 |
+
"-preset", "slow", # качество > скорость
|
402 |
+
"-crf", "18", # высокое качество (0 — без потерь)
|
403 |
+
"-pix_fmt", "yuv420p",
|
404 |
+
output_path
|
405 |
+
]
|
406 |
+
|
407 |
+
print("Running ffmpeg:", " ".join(ffmpeg_cmd))
|
408 |
+
subprocess.run(ffmpeg_cmd, check=True)
|
409 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
410 |
return output_path
|
411 |
|
412 |
def restart():
|