Вставьте новый кадр в конец анимированного WEBP.

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

У меня есть изображение в формате JPEG I и функция преобразования F, которая имеет некоторое состояние S. Каждые N минут состояние функции изменяется, и после этого F применяется к моему изображению I. Таким образом, для K'th изменения у нас есть выходное изображение I_k, которое сохраняется в некоторую директорию FRAMES_DIR.

Что я хочу сделать, так это создать анимированный WEBP со всеми сгенерированными изображениями на данный момент. Давайте назовем это W_k = WEBP(I_1, ..., I_k). Также это должно быть реализовано в памяти без каких-либо сохранений на диске.

Мой текущий подход заключается в использовании Python и библиотеки PIL и выглядит следующим образом:

webp_frames = []

def get_webp():
    global webp_frames

    nb_frames_processed = len(webp_frames)
    for frame_idx, frame_path in enumerate(os.listdir(FRAMES_DIR)):
        if frame_idx < nb_frames_processed:
            continue
        frame = Image.open(os.path.join(FRAMES_DIR, frame_path))
        webp_frames.append(frame)

    webp = io.BytesIO()
    webp_frames[0].save(webp, format="WEBP", save_all=True, loop=0, append_images=webp_frames[1:], duration=400)
    return webp

Проблема в том, что после каждого вызова get_webp webp генерируется с нуля. Это очень медленно и имеет сложность O(K). Я хочу найти способ сделать это за время O(1), добавляя новый кадр в конец текущего файла WEBP. Есть ли какой-нибудь красивый способ сделать это на Python?

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

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

Задача

Вы желаете создать анимированный WEBP (обозначим его как W_k), который включает все изображения I_k, созданные на основе применяемой функции F, и хранить его в памяти без сохранения временных файлов на диске. При текущем решении процесс получения анимации занимает линейное время O(K), что неудобно при большом количестве кадров.

Оптимальное решение

Для достижения желаемого времени выполнения O(1), стоит рассмотреть возможность сохранения данных в виде потокового объекта и их обновления. Однако, к сожалению, библиотека PIL не поддерживает прямое добавление кадров в существующий анимированный WEBP файл. Тем не менее, можно реализовать следующий подход:

  1. Хранение кадров в памяти: Вместо хранения всех изображений как отдельных объектов, можно хранить ссылки на них (или идентификаторы) и только добавлять новый кадр в список и в параметр сохранения.

  2. Использование буфера для временного хранения: При добавлении нового кадра можно создать временный буфер, который будет содержать все текущие кадры и новый, и затем сохранить это в формате WEBP.

Пример реализации

Вот пример, который можно адаптировать для ваших нужд:

from PIL import Image
import io
import os

webp_frames = []

def add_frame_to_webp(new_frame_path):
    global webp_frames

    # Открываем новый кадр
    new_frame = Image.open(new_frame_path)
    webp_frames.append(new_frame)

    # Создаем виртуальный байтовый поток для нового анимированного WEBP
    webp = io.BytesIO()
    webp_frames[0].save(webp, format="WEBP", save_all=True, loop=0, append_images=webp_frames[1:], duration=400)

    # Возврат текущей версии вебп в виде байтового потока
    return webp

def get_webp():
    global webp_frames

    # Создаем виртуальный байтовый поток для анимации
    webp = io.BytesIO()
    if webp_frames:  # Проверяем, есть ли уже кадры
        webp_frames[0].save(webp, format="WEBP", save_all=True, loop=0, append_images=webp_frames[1:], duration=400)

    return webp

Примечания к улучшенному коду

  1. Добавление новых кадров: Метод add_frame_to_webp сейчас принимает путь к новому кадру и добавляет его в список webp_frames. Обратите внимание, что в данном варианте для сохранения со вновь добавленным кадром всё равно потребуется полностью пересоздать анимацию. Это ограничение связано с тем, как вебп-формат структурирован, а библиотека PIL не предоставляет необходимого функционала для инкрементного обновления.

  2. Сохранение в памяти: Таким образом, создание анимации при добавлении нового кадра также будет происходить в памяти, что значительно снижает время доступа и, как следствие, повышает производительность.

  3. Оптимизация: Если вы хотите ещё больше улучшить производительность, рассматривайте возможность хранения изображений в массиве NumPy, а затем преобразование их в нужный формат перед финальной сборкой WEBP, что может оптимизировать работу с изображениями на низком уровне.

Заключение

Проблема с добавлением кадров в анимированный WEBP файл требует комплексного подхода, учитывающего ограничения используемых библиотек. Хотя в текущей реализации полное добавление кадров во время O(1) нереально, предложенное решение обеспечивает выполнение задачи в памяти и улучшает скорость обработки. Рассмотрите возможность оптимизации с использованием других библиотек и структур данных для достижения максимальной производительности.

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

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