Я пытаюсь найти самый быстрый способ прочитать кучу изображений из каталога в массив numpy. Моя конечная цель - вычислить такие статистические данные, как max, min и nth percentile пикселей из всех этих изображений. Это просто и быстро, когда пиксели из всех изображений находятся в одном большом массиве numpy, так как я могу использовать встроенные методы массива, такие как .max
и .min
, и функцию np.percentile
.
Ниже приведены несколько примерных таймингов с 25 tiff-изображениями (512x512 пикселей). Эти тесты ориентированы на использование %%timit
в jupyter-ноутбуке. Различия слишком малы, чтобы иметь какие-либо практические последствия только для 25 изображений, но я намерен читать тысячи изображений в будущем.
# Imports
import os
import skimage.io as io
import numpy as np
-
Добавление в список
%%timeit imgs = [] img_path = '/path/to/imgs/' for img in os.listdir(img_path): imgs.append(io.imread(os.path.join(img_path, img))) ## 32.2 ms ± 355 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
-
Использование словаря
%%timeit imgs = {} img_path = '/path/to/imgs/' for img in os.listdir(img_path): imgs[num] = io.imread(os.path.join(img_path, img)) ## 33.3 ms ± 402 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Для перечисленных выше и словарных подходов я попытался заменить цикл соответствующим пониманием с аналогичными результатами по времени. Я также пробовал перераспределять словарные ключи без существенной разницы во времени. Чтобы получить изображения из списка в большой массив, я бы использовал np.concatenate(imgs)
, который занимает всего ~ 1 мс.
-
Предварительное выделение массива numpy по первому размеру
%%timeit imgs = np.ndarray((512*25,512), dtype='uint16') img_path = '/path/to/imgs/' for num, img in enumerate(os.listdir(img_path)): imgs[num*512:(num+1)*512, :] = io.imread(os.path.join(img_path, img)) ## 33.5 ms ± 804 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
-
Предварительное выделение numpy по третьему размеру
%%timeit imgs = np.ndarray((512,512,25), dtype='uint16') img_path = '/path/to/imgs/' for num, img in enumerate(os.listdir(img_path)): imgs[:, :, num] = io.imread(os.path.join(img_path, img)) ## 71.2 ms ± 2.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Первоначально я думал, что методы превалирования numpy будут быстрее, поскольку в цикле динамического расширения переменных нет, но это, похоже, не так. Подход, который я нахожу наиболее интуитивным, является последним, когда каждое изображение занимает отдельные размеры вдоль третьей оси массива, но это также самое медленное. Дополнительное время не связано с самим предварительным использованием, которое занимает только 1 мс.
У меня есть три вопроса относительно этого:
- Почему превалирование numpy приближается не быстрее, чем словарный список и список решений?
- Какой самый быстрый способ чтения в тысячах изображений в один массив с большим количеством символов?
- Могу ли я извлечь пользу из внешнего вида numpy и scikit-image, для еще более быстрого модуля для чтения изображений? Я пробовал
plt.imread()
, но модульscikit-image.io
работает быстрее.