将Python中的动画GIF加载到numpy数组中的最快方法

jgwigjjp  于 2022-12-13  发布在  Python
关注(0)|答案(2)|浏览(180)

令人惊讶的是,我看不到任何关于这方面的报道。
我发现了3种公认的方法-- Pillow、OpenCV和Imageio。结果让我很惊讶,所以我把它们作为一个自我回答的Q&A(如下)发布出来。

csbfibhn

csbfibhn1#

使用Pillow的代码效率非常低!ImageNumpy'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)

这和其他的运行时间基本上是一样的。例如,我有一个400 X400像素,21帧,GIF,它需要MimRead ~ 140 ms,而枕头需要~ 130 ms。
更新:我刚刚玩过CV 2,注意到它的“挂钟”时间更好(即您所测量的时间),因为它在其他线程中工作。例如,如果我使用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

CV 2型

CPU times: user 309 ms, sys: 95 ms, total: 404 ms
Wall time: 89.7 ms

也就是说,虽然它在90毫秒内完成了循环,但它总共使用了大约4.5倍的CPU时间。
因此,如果您对完成单个大图像所需的时间感兴趣,您可能希望使用CV 2。但如果您要批处理大量图像,我建议在多处理Pool中使用Pillow。

o2gm4chl

o2gm4chl2#

这似乎是在每个库中加载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的两倍,imageio比PIL快15倍(无论如何,使用我的方法)。

相关问题