[英]How to use Python and OpenCV with multiprocessing?
我正在使用Python 3.4.3和OpenCV 3.0.0來處理(應用各種過濾器)內存中非常大的圖像(80,000 x 60,000),我想使用多個CPU內核來提高性能。 經過一些閱讀,我得出了兩種可能的方法:1)使用python的multiprocessing
模塊,讓每個進程處理一大片大圖像並在處理完成后加入結果(這可能應該在POSIX系統上執行?)2 )由於NumPy支持OpenMP,而OpenCV使用NumPy,我可以將多處理留給NumPy嗎?
所以我的問題是:
哪一個會是更好的解決方案? (如果它們看起來不合理,那么可能的方法是什么?)
如果選項2是好的,我應該用OpenMP構建NumPy和OpenCV嗎? 我如何實際進行多處理? (我真的找不到有用的指示..)
我不知道你需要什么類型的過濾器,但如果它相當簡單,你可以考慮libvips 。 它是一個圖像處理系統,用於非常大的圖像(大於您擁有的內存量)。 它來自一系列由歐盟資助的科學藝術成像項目,因此重點關注圖像捕獲和比較所需的操作類型:卷積,等級,形態,算術,顏色分析,重采樣,直方圖等等。
它速度快(比OpenCV快,至少在一些基准測試中),需要很少的內存 ,並且有一個高級Python綁定 。 它適用於Linux,OS X和Windows。 它會自動為您處理所有多處理。
在閱讀了一些SO帖子之后,我想出了一種在Python3中使用OpenCV
進行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.GaussianBlur(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.Process(target=mp_filter, 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)
這可以用Ray完成,它是一個用於並行和分布式Python的庫。 Ray有關“任務”的原因,而不是使用fork-join模型,這提供了一些額外的靈活性(例如,即使在分配工作進程之后,您在共享內存中放置值),相同的代碼在多台機器上運行,您可以將任務組合在一起等
import cv2
import numpy as np
import ray
num_tasks = 4
kernel_size = 11
@ray.remote
def mp_filter(image, i):
lower = image.shape[0] // num_tasks * i
upper = image.shape[0] // num_tasks * (i + 1)
return cv2.GaussianBlur(image[lower:upper, :],
(kernel_size, kernel_size), kernel_size // 5)
if __name__ == '__main__':
ray.init()
# Load the image and store it once in shared memory.
image = np.random.normal(size=(1000, 1000))
image_id = ray.put(image)
result_ids = [mp_filter.remote(image_id, i) for i in range(num_tasks)]
results = ray.get(result_ids)
請注意,您可以在共享內存中存儲多個numpy數組,如果您的Python對象包含numpy數組(如包含numpy數組的字典),您也可以受益。 在引擎蓋下,它使用Plasma共享內存對象存儲和Apache Arrow數據布局 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.