Плавное увеличение изображения с использованием OpenCV (CV2) и Python

Вопрос или проблема

Я создаю видео из набора изображений, генерируя каждую рамку видео с помощью Python и библиотеки CV2. Это работает.

Чтобы сделать видео более динамичным (вместо просто набора неподвижных изображений, которые появляются одно за другим), я добавил эффект зума к каждому изображению. Я в основном вычисляю для каждой рамки, насколько зум мне нужно применить, а затем немного изменяю размер рамки, используя следующий код.

        # Извлекаем увеличенную часть изображения, используя координаты с плавающей точкой
        zoomed_image = cv2.resize(current_image[int(y1):int(y2), int(x1):int(x2)], (res_w, res_h), interpolation=cv2.INTER_LINEAR)

Я работаю с ограничением метода cv2.resize, который принимает только целочисленные значения для координат x и y.

Это хорошо работает, когда я применяю, скажем, 5% зум к изображению, которое отображается в течение очень короткого времени. В этом случае, даже если я конвертирую x и y в целые числа, они в итоге оказываются разными для каждой рамки (при 30 fps), и следующая рамка оказывается немного другого размера по сравнению с предыдущей. Зум выходит плавным.

Но когда эффект зума применяется к изображению на более длительный срок, конвертация в целые числа приводит к тому, что несколько рамок имеют одни и те же координаты x или y, или и x, и y одинаковыми на 3-5 рамок. Это делает эффект зума рваным.

Существует ли лучший способ изменить размер изображения для цели зума, где я мог бы использовать плавающие значения координат x и y, которые я вычислил, вместо их преобразования в целые числа?

Или есть ли лучший способ применить эффект зума другим способом к каждой рамке?

Ответ или решение

Для реализации плавного эффекта зума на наборе изображений с использованием библиотеки OpenCV (CV2) в Python, вы сталкиваетесь с проблемой резкого изменения координат при преобразовании их в целые числа. Это может вызвать "дергание" при длительном отображении изображений с эффектом зума. Однако есть подход, который позволяет решить эту проблему.

Решение

Чтобы избежать проблемы с конверсией координат в целые числа, давайте будем работать с плавающей точкой и использовать метод обрезки изображения на основе плавающих значений, перед применением функции cv2.resize. Вот как это можно реализовать:

  1. Координаты зума: Рассчитайте координаты для текущего зума в виде чисел с плавающей запятой.
  2. Обрезка изображения: Вместо того чтобы округлять координаты до целого числа, непосредственно используйте плавающие значения для обрезки изображения.
  3. Смещение: После обрезки изображения необходимо скорректировать его размеры, чтобы получить плавный эффект зума.

Пример кода

Ниже приведен пример реализации данного подхода:

import cv2
import numpy as np

def smooth_zoom(current_image, zoom_factor, duration, fps):
    h, w = current_image.shape[:2]
    zoom_steps = int(duration * fps)
    zoomed_frames = []

    # Определяем начальные и конечные коордианты обрезки
    for step in range(zoom_steps):
        alpha = step / zoom_steps
        current_zoom = 1 + (zoom_factor - 1) * alpha  # Линейная интерполяция
        new_h = int(h / current_zoom)
        new_w = int(w / current_zoom)

        # Центрируем обрезку
        x1 = (w - new_w) / 2
        y1 = (h - new_h) / 2
        x2 = (w + new_w) / 2
        y2 = (h + new_h) / 2

        # Используем плавающие числа для обрезки
        crop_image = current_image[int(y1):int(y2), int(x1):int(x2)]
        resized_image = cv2.resize(crop_image, (w, h), interpolation=cv2.INTER_LINEAR)
        zoomed_frames.append(resized_image)

    return zoomed_frames

# Пример использования
current_image = cv2.imread('your_image.jpg')
zoom_factor = 1.5  # Пример зума в 1.5 раза
duration = 2  # Продолжительность зума в секундах
fps = 30  # Частота кадров

frames = smooth_zoom(current_image, zoom_factor, duration, fps)

# Сохраняем видео
video_output = cv2.VideoWriter('zoomed_video.avi', cv2.VideoWriter_fourcc(*'XVID'), fps, (current_image.shape[1], current_image.shape[0]))

for frame in frames:
    video_output.write(frame)

video_output.release()

Пояснения к коду:

  • Координаты: Мы определяем границы обрезки по центру изображения, чтобы обеспечить симметричный зум.
  • Линейная интерполяция: Мы плавно изменяем коэффициент зума от 1 до zoom_factor в течение указанного времени. Это позволяет избежать резких переходов.
  • Запись видео: После получения каждого кадра с эффектом зума вы можете использовать cv2.VideoWriter для создания видеофайла.

Заключение

Данный подход позволяет применять эффект зума без "дергания" и делает эффект более плавным за счет использования плавающих чисел для расчёта координат. Настраивая zoom_factor и duration, вы сможете артистически контролировать эффект в соответствии со своими требованиями.

Оцените материал
Добавить комментарий

Капча загружается...