Удивительно, но я не видел никакого освещения этого.
Я нашел 3 признанных способа сделать это - Pillow, OpenCV и Imageio. Результаты меня удивили, поэтому я опубликовал их в виде ответов на вопросы (ниже).






Кажется, это стандартный способ загрузки GIF в каждой библиотеке:
import os
import cv2
import time
import imageio
import numpy as np
from tqdm import tqdm
from glob import glob
from PIL import Image, ImageSequence
gifs = glob(os.path.join("/folder/of/gifs", "*"))
print(f"Found {len(gifs)} GIFs")
def load_gif_as_video_pil(gif_path):
im = Image.open(gif_path)
frames = []
for frame in ImageSequence.Iterator(im):
frame = np.array(frame.copy().convert('RGB').getdata(), dtype=np.uint8).reshape(frame.size[1],
frame.size[0],
3)
frames.append(frame)
return np.array(frames)
def load_gif_as_video_imageio(gif_path):
return imageio.mimread(gif_path)
def load_gif_as_video_opencv(filename):
gif = cv2.VideoCapture(filename)
frames = []
while True:
ret, frame = gif.read()
if not ret:
break
frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
return np.array(frames)
start = time.time()
[load_gif_as_video_imageio(path) for path in tqdm(gifs)]
end = time.time()
print(f"ImageIO: {end - start}")
start = time.time()
[load_gif_as_video_opencv(path) for path in tqdm(gifs)]
end = time.time()
print(f"OpenCV: {end - start}")
start = time.time()
[load_gif_as_video_pil(path) for path in tqdm(gifs)]
end = time.time()
print(f"PIL: {end - start}")
Более 250 GIF-файлов, вот результаты:
100%|██████████| 250/250 [00:13<00:00, 18.32it/s]
ImageIO: 13.829721689224243
100%|██████████| 250/250 [00:06<00:00, 39.04it/s]
OpenCV: 6.478164434432983
100%|██████████| 250/250 [03:00<00:00, 1.38it/s]
PIL: 181.03292179107666
OpenCV в два раза быстрее, чем imageio, что в 15 раз быстрее, чем PIL (во всяком случае, с использованием моего метода).
Ваш код с использованием Pillow очень неэффективен! Images совместимы с интерфейсом массива Numpy, поэтому ваш код преобразования усложняет ситуацию.
Я бы использовал следующий помощник, чтобы получить кадры в массив Numpy:
from PIL import Image, ImageSequence
import numpy as np
def load_frames(image: Image, mode='RGBA'):
return np.array([
np.array(frame.convert(mode))
for frame in ImageSequence.Iterator(image)
])
with Image.open('animated.gif') as im:
frames = load_frames(im)
Это работает в основном в то же время, что и другие. Например, с размером 400x400 пикселей, 21 кадром, GIF, который у меня есть, mimread занимает ~140 мс, а Pillow — ~130 мс.
Обновление: я только что поиграл с CV2 и заметил, что его «настенные часы» лучше (то есть то, что вы измеряли), потому что он работает в других потоках. Например, если я запускаю Jupyter %time magic, я получаю следующий результат:
ImageIO
CPU times: user 135 ms, sys: 9.81 ms, total: 145 ms
Wall time: 145 ms
ПИЛ
CPU times: user 127 ms, sys: 3.03 ms, total: 130 ms
Wall time: 130 ms
CV2
CPU times: user 309 ms, sys: 95 ms, total: 404 ms
Wall time: 89.7 ms
т.е. хотя он завершает цикл за 90 мс, он использует примерно в 4,5 раза больше процессорного времени.
Поэтому, если вас интересует время, необходимое для создания одного большого изображения, вы можете использовать CV2. Но если вы выполняете пакетную обработку большого количества изображений, я бы предложил использовать Pillow в многопроцессорном пуле.
добро пожаловать. просить «лучшее» по-прежнему просить рекомендации (библиотек), что не по теме. пожалуйста, просмотрите справочный центр