Асинхронно считывает и обрабатывает изображение в python

контекст

Я часто оказывался в следующей ситуации:

  • У меня есть список имен файлов изображений, которые мне нужно обработать
  • Я читаю каждое изображение последовательно, используя, например, scipy.misc.imread
  • Затем я делаю какую-то обработку на каждом изображении и возвращаю результат
  • Я сохраняю результат по имени файла изображения в полке

Проблема в том, что простое считывание изображения занимает незначительное количество времени, иногда сравнимое или даже дольше, чем обработка изображения.

Вопрос

Поэтому я думал, что в идеале я мог бы читать изображение n + 1 во время обработки изображения n. Или даже лучше обрабатывать и считывать сразу несколько изображений автоматически оптимальным образом?

Я читал о многопроцессорности, потоках, скручивании, gevent и т. Д., Но я не могу понять, какой из них использовать и как реализовать эту идею. У кого-нибудь есть решение этой проблемы?

Минимальный пример

# generate a list of images scipy.misc.imsave("lena.png", scipy.misc.lena()) files = ['lena.png'] * 100 # a simple image processing task def process_image(im, threshold=128): label, n = scipy.ndimage.label(im > threshold) return n # my current main loop for f in files: im = scipy.misc.imread(f) print process_image(im) 

2 Solutions collect form web for “Асинхронно считывает и обрабатывает изображение в python”

Ответ Филиппа хорош, но он создаст только пару процессов (одно чтение, одно вычисление), которое вряд ли позволит создать современную систему с двумя ядрами. Вот альтернатива использования multiprocessing.Pool (в частности, его метод карты), который создает процессы, которые выполняют как аспекты чтения, так и вычисления, но которые должны лучше использовать все доступные вам ядра (при условии, что в них больше файлов, чем ядер).

 #!/usr/bin/env python import multiprocessing import scipy import scipy.misc import scipy.ndimage class Processor: def __init__(self,threshold): self._threshold=threshold def __call__(self,filename): im = scipy.misc.imread(filename) label,n = scipy.ndimage.label(im > self._threshold) return n def main(): scipy.misc.imsave("lena.png", scipy.misc.lena()) files = ['lena.png'] * 100 proc=Processor(128) pool=multiprocessing.Pool() results=pool.map(proc,files) print results if __name__ == "__main__": main() 

Если я увеличу количество изображений до 500 и использую аргументы processes=N для Pool , тогда я получаю

 Processes Runtime 1 6.2s 2 3.2s 4 1.8s 8 1.5s 

на моем четырехъядерном гиперпотоке i7.

Если у вас появятся более реалистичные варианты использования (то есть фактические разные изображения), ваши процессы могут тратить больше времени на загрузку изображений из хранилища (при моем тестировании, они загружаются практически мгновенно с кэшированного диска), а затем это может быть стоит явно создавать больше процессов, чем ядра, чтобы получить больше перекрытий вычислений и загрузки. Только ваше собственное тестирование масштабируемости на реалистичной нагрузке и HW может рассказать вам, что на самом деле лучше для вас.

Многопроцессорный пакет довольно прост в использовании. Посмотрите пример Queues для руководства. Вы будете следовать модели потребителя-производителя. Вы хотите, чтобы один (или более) процесс продюсера просматривал изображения и один (или несколько) потребительских процессов, выполняющих обработку изображений.

Ваш пример будет выглядеть примерно так:

 from multiprocessing import Process, Queue import scipy def process_images(q): while not q.empty: im = q.get() # Do stuff def read_images(q, files): for f in files: q.put(scipy.misc.imread(f)) if __name__ == '__main__': q = Queue() producer = Process(target=read_images, args=(q, files)) producer.start() consumer = Process(target=process_images, args=(q)) consumer.start() 

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

  • Проблема с типом данных с использованием scipy.spatial
  • Передача данных в реальном времени с Python на MATLAB
  • K ближайший сосед в python
  • Вычислить нормальную форму матрицы Джорда в Python / NumPy
  • выбор правильного типа данных для машинного обучения
  • Использование диапазона при фантазии индексирования?
  • передача аргументов функции для подгонки
  • Как рассчитать вероятность скручивания кривой в scipy?
  • Python - лучший язык программирования в мире.