簡體   English   中英

如何使用Python和OpenCV進行多處理?

[英]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數據布局

您可以在Ray文檔中閱讀更多內容 請注意,我是Ray開發人員之一。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM