【发布时间】:2022-12-08 23:06:52
【问题描述】:
令人惊讶的是,我看不到对此的任何报道。
我发现了 3 种公认的执行此操作的方法 - Pillow、OpenCV 和 Imageio。结果令我吃惊,所以我将它们作为自答问答(如下)发布。
【问题讨论】:
标签: python numpy opencv python-imaging-library python-imageio
令人惊讶的是,我看不到对此的任何报道。
我发现了 3 种公认的执行此操作的方法 - Pillow、OpenCV 和 Imageio。结果令我吃惊,所以我将它们作为自答问答(如下)发布。
【问题讨论】:
标签: python numpy opencv python-imaging-library python-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 的两倍,比 PIL 快 15 倍(无论如何,使用我的方法)。
【讨论】:
您使用 Pillow 的代码效率很低! Images 与Numpy's array interface 兼容,因此您的转换代码使事情变得复杂。
我会使用以下助手将帧输出到 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 ~140ms,而 Pillow 需要~130ms。
更新:我刚刚玩过 CV2 并注意到它的“挂钟”时间更好(即你正在测量的时间),因为它在其他线程中工作。例如,如果我使用 Jupyter %time magic 运行,我会得到以下输出:
图像IO
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
IE。虽然它在 90 毫秒内完成了循环,但它总共使用了大约 4.5 倍的 CPU 时间。
因此,如果您对完成单个大图像的时间感兴趣,您可能需要使用 CV2。但是如果你批处理大量图像,我建议在 multiprocessing Pool 中使用 Pillow。
【讨论】: