Как использовать Python и OpenCV с многопроцессорной обработкой?

Я использую Python 3.4.3 и OpenCV 3.0.0 для обработки (с применением различных фильтров) очень большого изображения (80 000 x 60 000) в памяти, и я бы хотел использовать несколько ядер процессора для повышения производительности. После некоторого чтения я пришел к двум возможным методам: 1) Используйте модуль python multiprocessing, пусть каждый процесс обрабатывает кусочек большого изображения и присоединяется к результатам после завершения обработки (И это, вероятно, должно выполняться в системе POSIX? ) 2) Поскольку NumPy поддерживает OpenMP, а OpenCV использует NumPy, я могу просто оставить многопроцессорность NumPy?

Итак, мой вопрос:

Какой из них будет лучшим решением? (Если они не кажутся разумными, каким будет возможный подход?)

Если вариант 2 хорош, должен ли я создавать как NumPy, так и OpenCV с помощью OpenMP? Как я могу сделать многопроцессорную обработку? (Я не мог найти полезную инструкцию..)

2 ответа

Прочитав несколько сообщений SO, я придумал способ использовать OpenCV в Python3 с multiprocessing. Я рекомендую делать это на linux, потому что согласно этому сообщению , порожденные процессы обмениваются памятью со своим родителем, пока контент не изменяется. Вот минимальный пример:

import cv2
import multiprocessing as mp
import numpy as np
import psutil
img = cv2.imread('test.tiff', cv2.IMREAD_ANYDEPTH) # here I'm using a indexed 16-bit tiff as an example.
num_processes = 4
kernel_size = 11
tile_size = img.shape[0]/num_processes # Assuming img.shape[0] is divisible by 4 in this case
output = mp.Queue()
def mp_filter(x, output):
 print(psutil.virtual_memory()) # monitor memory usage
 output.put(x, cv2.GaussianBlue(img[img.shape[0]/num_processes*x:img.shape[0]/num_processes*(x+1), :], 
 (kernel_size, kernel_size), kernel_size/5))
 # note that you actually have to process a slightly larger block and leave out the border.
if __name__ == 'main':
 processes = [mp.Processes(target=mp_slice, args=(x, output)) for x in range(num_processes)]
 for p in processes:
 p.start()
 result = []
 for ii in range(num_processes):
 result.append(output.get(True))
 for p in processes:
 p.join()

Вместо использования Queue другим способом сбора результата от процессов является создание общего массива через модуль multiprocessing. (Импортировать ctypes)

result = mp.Array(ctypes.c_uint16, img.shape[0]*img.shape[1], lock = False)

то каждый процесс может писать в разные части массива, предполагая, что нет перекрытия. Однако создание большого mp.Array на удивление медленное. Это фактически не соответствует цели ускорения операции. Поэтому используйте его только тогда, когда добавленное время не сильно сравнивается с общим временем вычисления. Этот массив можно преобразовать в массив numpy:

result_np = np.frombuffer(result, dtypye=ctypes.c_uint16)


Я не знаю, какие фильтры вам нужны, но если это достаточно просто, вы можете рассмотреть libvips. Это система обработки изображений для очень больших изображений (больше, чем объем памяти, который у вас есть). Он вышел из серии проектов по созданию изображений в области научных исследований, финансируемых ЕС, поэтому основное внимание уделяется типам операций, которые необходимы для захвата и сравнения изображений: свертки, ранга, морфологии, арифметики, анализа цвета, повторной дискретизации, гистограмм и т.д.,

очень быстро (быстрее, чем OpenCV, по крайней мере, по некоторым критериям), требуется небольшая память и поставляется с высокоуровневое связывание с Python. Он работает на Linux, OS X и Windows. Он обрабатывает все многопроцессорные процессы для вас, и все это автоматически.

licensed under cc by-sa 3.0 with attribution.