segmentacion ruido para mediana imagenes gaussiano filtros filtro python optimization numpy python-imaging-library scipy

para - ruido gaussiano python



La convolución más rápida en 2D o el filtro de imagen en Python (5)

Varios usuarios han preguntado acerca de la velocidad o el consumo de memoria de las circunvoluciones de imágenes en números o caracteres [ 1 , 2 , 3 , 4 ]. A partir de las respuestas y mi experiencia con Numpy, creo que este puede ser un problema importante en comparación con Matlab o IDL.

Ninguna de las respuestas hasta ahora ha abordado la pregunta general, de modo que aquí está: "¿Cuál es el método más rápido para calcular una convolución 2D en Python?" Los módulos comunes de python son juegos justos: numpy, scipy y PIL (¿otros?). Por el bien de una comparación desafiante, me gustaría proponer las siguientes reglas:

  1. Las matrices de entrada son 2048x2048 y 32x32, respectivamente.
  2. Punto de flotación de precisión simple o doble son aceptables.
  3. El tiempo dedicado a convertir su matriz de entrada al formato apropiado no cuenta, solo el paso de convolución.
  4. Reemplazar la matriz de entrada con su salida es aceptable (¿admite eso alguna biblioteca de Python?)
  5. Las llamadas directas de DLL a bibliotecas comunes de C son correctas - lapack o scalapack
  6. PyCUDA está en lo cierto. No es justo usar su hardware de GPU personalizado.

En mi máquina, una convolución circular hecha a mano con FFT parece estar en ayunas:

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))

Tenga en cuenta que esto podría tratar las áreas cercanas a los bordes de manera diferente a otras formas, porque es una convolución circular.


He estado intentando mejorar la velocidad de convolución en mi aplicación y he estado usando signal.correlate que es aproximadamente 20 veces más lento que signal.correlate2d , mis matrices de entrada son más pequeñas ( 27x27 and 5x5 ). A partir de 2018, esto es lo que observé en mi máquina (Dell Inspiron 13, Core i5) para las matrices especificadas en la pregunta real.

OpenCV hizo lo mejor, pero la advertencia es que no da opciones de "modo". La entrada y la salida son del mismo tamaño.

>>> 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


Hice algunos experimentos con esto también. Mi conjetura es que la convolución de SciPy no usa la biblioteca BLAS para acelerar el cálculo. Usando BLAS, pude codificar una convolución 2D que era comparable en velocidad a la de MATLAB. Es más trabajo, pero lo mejor es recodificar la convolución en C ++.

Aquí está la parte apretada del bucle (perdone las referencias a matrices basadas en weird (), es mi clase de conveniencia para matrices MATLAB) La parte clave es que no itera sobre la imagen, itera sobre el filtro y deja que BLAS iterar sobre la imagen, porque normalmente la imagen es mucho más grande que el filtro.

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); } } }


Realmente depende de lo que quiera hacer ... La mayoría de las veces, no necesita una convolución 2D totalmente genérica (lea: más lento) ... (es decir, si el filtro es separable, en su lugar, use dos circunvoluciones 1D). ... Esta es la razón por la que los diversos scipy.ndimage.gaussian , scipy.ndimage.uniform , son mucho más rápidos que lo mismo implementado como una convolución nD genérica.)

En cualquier caso, como punto de comparación:

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

Esto lleva 6,9 segundos en mi máquina ...

Compara esto con 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

Esto toma alrededor de 10.8 segundos. Sin embargo, con diferentes tamaños de entrada, el uso de fft para hacer una convolución puede ser considerablemente más rápido (aunque parece que no puedo dar un buen ejemplo, en este momento ...).


Scipy tiene una función fftconvolve , que puede usarse para señales 1D y 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()