2d convolución usando python y numpy

Estoy tratando de realizar una convolución 2d en python usando numpy

Tengo una matriz 2d como sigue con el núcleo H_r para las filas y H_c para las columnas

data = np.zeros((nr, nc), dtype=np.float32) #fill array with some data here then convolve for r in range(nr): data[r,:] = np.convolve(data[r,:], H_r, 'same') for c in range(nc): data[:,c] = np.convolve(data[:,c], H_c, 'same') data = data.astype(np.uint8); 

No produce la salida que esperaba, este código se ve bien, creo que el problema está en la conversión de float32 a 8bit. Cuál es la mejor manera de hacer esto

Gracias

Como ya tiene su kernel separado, simplemente debe usar la función sepfir2d de scipy:

 from scipy.signal import sepfir2d convolved = sepfir2d(data, H_r, H_c) 

Por otro lado, el código que tiene allí se ve bien …

Editar [enero 2019]

El siguiente comentario de @Tashus es correcto, y la respuesta de @ dudemeister es, por lo tanto, probablemente más acertada. La función que sugirió también es más eficiente, al evitar una convolución directa en 2D y el número de operaciones que implicaría.

Posible problema

Creo que estás haciendo dos circunvoluciones 1d, la primera por columnas y la segunda por filas, y sustituyendo los resultados de la primera por los resultados de la segunda.

Tenga en cuenta que numpy.convolve con el argumento 'same' devuelve una matriz de igual forma a la más grande proporcionada, de modo que cuando realice la primera convolución, ya habrá completado toda data matriz de data .

Una buena manera de visualizar sus arreglos durante estos pasos es usar diagtwigs de Hinton , para que pueda verificar qué elementos ya tienen un valor.

Solución posible

Puede intentar agregar los resultados de las dos circunvoluciones (use data[:,c] += .. lugar de data[:,c] = en el segundo for loop), si su matriz de convolución es el resultado de usar la una H_r dimensionales H_r y H_c así:

adición de núcleo de convolución

Otra forma de hacerlo sería usar scipy.signal.convolve2d con una matriz de convolución 2d, que es probablemente lo que querías hacer en primer lugar.

Tal vez no sea la solución más optimizada, pero esta es una implementación que usé antes con la biblioteca numpy para Python:

 def convolution2d(image, kernel, bias): m, n = kernel.shape if (m == n): y, x = image.shape y = y - m + 1 x = x - m + 1 new_image = np.zeros((y,x)) for i in range(y): for j in range(x): new_image[i][j] = np.sum(image[i:i+m, j:j+m]*kernel) + bias return new_image 

Espero que este código ayude a otros chicos con la misma duda.

Saludos.

Intenta primero redondear y luego lanzar a uint8:

 data = data.round().astype(np.uint8); 

Este código es incorrecto:

 for r in range(nr): data[r,:] = np.convolve(data[r,:], H_r, 'same') for c in range(nc): data[:,c] = np.convolve(data[:,c], H_c, 'same') 

Ver la transformación de Nussbaumer de convolución multidimensional a una dimensional.