簡體   English   中英

Python中速度最快的2D卷積或圖像濾鏡

[英]Fastest 2D convolution or image filter in Python

幾個用戶詢問在numpy的或SciPy的圖像卷積的速度或存儲器消耗[ 1234 ]。 從回答和我使用Numpy的經驗來看,我認為與Matlab或IDL相比,這可能是numpy的一個主要缺點。

到目前為止,答案都沒有解決整個問題,所以這里是:“在Python中計算2D卷積的最快方法是什么?” 常見的python模塊是公平游戲:numpy,scipy和PIL(其他?)。 為了進行具有挑戰性的比較,我想提出以下規則:

  1. 輸入矩陣分別為2048x2048和32x32。
  2. 單精度或雙精度浮點都是可以接受的。
  3. 將輸入矩陣轉換為適當格式所花費的時間不計算 - 只是卷積步驟。
  4. 用你的輸出替換輸入矩陣是可以接受的(任何python庫支持嗎?)
  5. 對常見C庫的直接DLL調用是好的 - lapack或scalapack
  6. PyCUDA就出局了。 使用自定義GPU硬件是不公平的。

在我的機器上,使用FFT的手工制作的循環卷積似乎很禁止:

import numpy
x = numpy.random.random((2048, 2048)).astype(numpy.float32)
y = numpy.random.random((32, 32)).astype(numpy.float32)
z = numpy.fft.irfft2(numpy.fft.rfft2(x) * numpy.fft.rfft2(y, x.shape))

請注意,這可能會以不同於其他方式的方式處理靠近邊緣的區域,因為它是循環卷積。

這實際上取決於你想要做什么...很多時候,你不需要一個完全通用的(讀取:慢速)2D卷積...(即如果過濾器是可分離的,你使用兩個1D卷積代替...這就是為什么各種scipy.ndimage.gaussianscipy.ndimage.uniform ,比通用nD卷數實現的速度快得多。)

無論如何,作為比較點:

t = timeit.timeit(stmt='ndimage.convolve(x, y, output=x)', number=1,
setup="""
import numpy as np
from scipy import ndimage
x = np.random.random((2048, 2048)).astype(np.float32)
y = np.random.random((32, 32)).astype(np.float32)
""")
print t

我的機器需要6.9秒...

將此與fftconvolve進行比較

t = timeit.timeit(stmt="signal.fftconvolve(x, y, mode='same')", number=1,
setup="""
import numpy as np
from scipy import signal
x = np.random.random((2048, 2048)).astype(np.float32)
y = np.random.random((32, 32)).astype(np.float32)
""")
print t

這需要大約10.8秒。 但是,使用不同的輸入大小,使用fft進行卷積可以相當快(雖然我似乎無法想出一個很好的例子,目前......)。

我也做了一些實驗。 我的猜測是SciPy卷積不使用BLAS庫來加速計算。 使用BLAS,我能夠編寫一個速度與MATLAB相當的2D卷積。 這是更多的工作,但最好的辦法是用C ++重新編碼卷積。

這是循環的緊湊部分(請原諒基於怪異()的數組引用,它是我的MATLAB數組的便利類)關鍵部分是你不迭代圖像,迭代過濾器讓BLAS迭代圖像,因為通常圖像比過濾器大得多。

for(int n = 0; n < filt.numCols; n++)
  {
    for(int m = 0; m < filt.numRows; m++)
    {
      const double filt_val = filt(filt.numRows-1-m,filt.numCols-1-n);
      for (int i =0; i < diffN; i++)
      {
        double *out_ptr = &outImage(0,i);
        const double *im_ptr = &image(m,i+n);
        cblas_daxpy(diffM,filt_val,im_ptr, 1, out_ptr,1);

      }
   }
 }

我一直在努力提高我的應用程序的卷積速度,我一直在使用signal.correlate這恰好是慢約20倍signal.correlate2d ,我輸入矩陣是小( 27x27 and 5x5 截至2018年,這是我在我的機器(Dell Inspiron 13,Core i5)上觀察到的實際問題中指定矩陣的情況。

OpenCV做得最好,但需要注意的是它沒有給出“模式”選項。 輸入和輸出具有相同的大小。

>>> img= np.random.rand(2048,2048)
>>> kernel = np.ones((32,32), dtype=np.float)
>>> t1= time.time();dst1 = cv2.filter2D(img,-1,kernel);print(time.time()-t1)
0.208490133286
>>> t1= time.time();dst2 = signal.correlate(img,kernel,mode='valid',method='fft');print(time.time()-t1)
0.582989931107
>>> t1= time.time();dst3 = signal.convolve2d(img,kernel,mode='valid');print(time.time()-t1)
11.2672450542
>>> t1= time.time();dst4 = signal.correlate2d(img,kernel,mode='valid');print(time.time()-t1)
11.2443971634
>>> t1= time.time();dst5 = signal.fftconvolve(img,kernel,mode='valid');print(time.time()-t1)
0.581533193588

Scipy具有fftconvolve功能,可用於1D和2D信號。

from scipy import signal
from scipy import misc
import numpy as np
import matplotlib.pyplot as plt

face = misc.face(gray=True)
kernel = np.outer(signal.gaussian(70, 8), signal.gaussian(70, 8))
blurred = signal.fftconvolve(face, kernel, mode='same')

fig, (ax_orig, ax_kernel, ax_blurred) = plt.subplots(3, 1, figsize=(6, 15))
ax_orig.imshow(face, cmap='gray')
ax_orig.set_title('Original')
ax_orig.set_axis_off()
ax_kernel.imshow(kernel, cmap='gray')
ax_kernel.set_title('Gaussian kernel')
ax_kernel.set_axis_off()
ax_blurred.imshow(blurred, cmap='gray')
ax_blurred.set_title('Blurred')
ax_blurred.set_axis_off()
fig.show()

暫無
暫無

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

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