89 lines
3.1 KiB
Python
89 lines
3.1 KiB
Python
|
|
"""
|
|||
|
|
Утилиты для создания видео из последовательности изображений
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import cv2
|
|||
|
|
import numpy as np
|
|||
|
|
from pathlib import Path
|
|||
|
|
from typing import List
|
|||
|
|
from utils.image_processor import ImageProcessor
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VideoCreator:
|
|||
|
|
"""Создатель видео из серии изображений"""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def create_timelapse(image_paths: List[Path], output_path: Path, fps: int = 10) -> Path:
|
|||
|
|
"""
|
|||
|
|
Создает видео из последовательности изображений
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
image_paths: Список путей к изображениям
|
|||
|
|
output_path: Путь для сохранения видео
|
|||
|
|
fps: Кадров в секунду
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Путь к созданному видео
|
|||
|
|
"""
|
|||
|
|
if not image_paths:
|
|||
|
|
raise ValueError("Нет изображений для создания видео")
|
|||
|
|
|
|||
|
|
# Загружаем первое изображение для определения размера
|
|||
|
|
first_img = ImageProcessor.load_jp2(str(image_paths[0]))
|
|||
|
|
if first_img is None:
|
|||
|
|
raise ValueError("Не удалось загрузить первое изображение")
|
|||
|
|
|
|||
|
|
height, width = first_img.shape[:2]
|
|||
|
|
|
|||
|
|
# Определяем кодек и создаем VideoWriter
|
|||
|
|
output_str = str(output_path)
|
|||
|
|
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
|||
|
|
video_writer = cv2.VideoWriter(output_str, fourcc, fps, (width, height))
|
|||
|
|
|
|||
|
|
# Добавляем все изображения
|
|||
|
|
for img_path in image_paths:
|
|||
|
|
# Загружаем изображение
|
|||
|
|
img_data = ImageProcessor.load_jp2(str(img_path))
|
|||
|
|
|
|||
|
|
if img_data is not None:
|
|||
|
|
# Конвертируем RGB в BGR для OpenCV
|
|||
|
|
img_bgr = cv2.cvtColor(img_data, cv2.COLOR_RGB2BGR)
|
|||
|
|
video_writer.write(img_bgr)
|
|||
|
|
|
|||
|
|
video_writer.release()
|
|||
|
|
|
|||
|
|
return output_path
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def create_gif(image_paths: List[Path], output_path: Path, duration: int = 200) -> Path:
|
|||
|
|
"""
|
|||
|
|
Создает GIF анимацию из изображений
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
image_paths: Список путей к изображениям
|
|||
|
|
output_path: Путь для сохранения GIF
|
|||
|
|
duration: Длительность кадра в миллисекундах
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Путь к созданному GIF
|
|||
|
|
"""
|
|||
|
|
from PIL import Image
|
|||
|
|
|
|||
|
|
images = []
|
|||
|
|
for img_path in image_paths:
|
|||
|
|
img_data = ImageProcessor.load_jp2(str(img_path))
|
|||
|
|
if img_data is not None:
|
|||
|
|
pil_image = Image.fromarray(img_data)
|
|||
|
|
images.append(pil_image)
|
|||
|
|
|
|||
|
|
if images:
|
|||
|
|
# Сохраняем GIF
|
|||
|
|
images[0].save(
|
|||
|
|
output_path,
|
|||
|
|
save_all=True,
|
|||
|
|
append_images=images[1:],
|
|||
|
|
duration=duration,
|
|||
|
|
loop=0
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return output_path
|