简体   繁体   English

python中的3D卷积

[英]3D convolution in python

I need to wite a code to perform a 3D convolution in python using numpy, with 3x3 kernels.我需要编写一个代码来使用 numpy 和 3x3 内核在 python 中执行 3D 卷积。 I've done it right for 2D arrays like B&W images but when i try to extend it to 3D arrays like RGB is a mess.我已经对像黑白图像这样的 2D 阵列做了正确的处理,但是当我尝试将它扩展到像 RGB 这样的 3D 阵列时是一团糟。 I need help to improve my method.我需要帮助来改进我的方法。 Here is the 2D code:这是二维代码:

def convolucion_3x3(arreglo, kernel):
  (dim_x, dim_y) = arreglo.shape
  (ker_x, ker_y) = kernel.shape

  matriz_convolucionada = np.zeros((dim_x, dim_y))

  for i in range(dim_x):
    for j in range(dim_y):
      resultado = 0
      for x in range(-1, 2):
        try:
          if i + x not in range(dim_x):
              raise ValueError()
          for y in range(-1, 2):
            try:
              if j + y not in range(dim_y):
                  raise ValueError()

              resultado += arreglo[i + x, j + y] * kernel[x + 1][y + 1]
              '''
              Para el kernel sumo un 1 a cada índice para que lo corra desde 0 hasta 2 y no de -1 a 1
              '''
            except ValueError:
                pass
        except ValueError:
            pass
      matriz_convolucionada[i][j] = resultado
  return matriz_convolucionada

The next one is my attempt to the RGB images:下一个是我对 RGB 图像的尝试:

def convolucion(arreglo, kernel): (dim_x, dim_y, dim_z) = arreglo.shape (ker_x, ker_y) = kernel.shape def卷积(arreglo,内核):(dim_x,dim_y,dim_z)= arreglo.shape(ker_x,ker_y)= kernel.shape

matriz_convolucionada = np.zeros((dim_x, dim_y, dim_z))

for k in range(dim_z):
    for i in range(dim_x):
        for j in range(dim_y):
            resultado = 0
            for x in range(-1, 2):
                try:
                    if i + x not in range(dim_x):
                        raise ValueError()

                    for y in range(-1, 2):
                        try:
                            if j + y not in range(dim_y):
                                raise ValueError()

                            resultado += arreglo[i + x, j + y, k] * kernel[x + 1][y + 1]

                            '''
                            Para el kernel sumo un 1 a cada índice para que lo corra desde 0 hasta 2 y no de -1 a 1
                            '''

                        except ValueError:
                            pass

                except ValueError:
                    pass

            matriz_convolucionada[i][j][k] = resultado

return matriz_convolucionada

While looping through would work, it can also be difficult to follow the nested loops.虽然循环可以工作,但也很难遵循嵌套循环。 You might consider invoking the convolution theorem to perform the convolution easier.您可能会考虑调用卷积定理来更轻松地执行卷积。 See here .这里

Using numpy's fft module, you can compute an n-dimensional discrete Fourier transform of the original stack of images and multiply it by the n-dimensional Fourier transform (documentation found here )of a kernel of the same size .使用 numpy 的 fft 模块,您可以计算原始图像堆栈的 n 维离散傅里叶变换,并将其乘以相同大小的内核的 n 维傅里叶变换( 此处提供文档)。 Since your 2D kernel is a 3x3 array, it's a 3x3xz square 'pillar.'由于您的 2D 内核是一个 3x3 阵列,因此它是一个 3x3xz 方形“支柱”。 You can just pad this array with zeros to increase the dimensions accordingly.您可以只用零填充此数组以相应地增加维度。

Try this:试试这个:

import numpy as np
import math

radius = 2
r2 = np.arange(-radius, radius+1)**2
sphere = r2[:, None, None] + r2[:, None] + r2
sphere -= np.max(sphere)
sphere = -sphere*2
array_len = 10*radius

array = np.zeros((array_len, array_len, array_len))
center = slice(array_len//2-radius,
               array_len//2+radius+1), slice(array_len//2-radius,
                                             array_len//2+radius+1),slice(array_len//2-radius,
                                                                          array_len//2+radius+1)
array[center] = sphere


k_len = 3
kernel_2D = np.ones((k_len,k_len))
kernel = np.zeros_like(array)

center_k = slice(array_len//2-math.ceil(k_len/2),
           array_len//2+k_len//2), slice(array_len//2-math.ceil(k_len/2),
                                         array_len//2+k_len//2)
for i in range(kernel.shape[2]):
    kernel[center_k+(i,)] = kernel_2D

def fft(array):
  fft = np.fft.ifftshift(np.fft.fftn(np.fft.fftshift(array)))
  return fft

def ifft(array):
  ifft = np.fft.fftshift(np.fft.ifftn(np.fft.ifftshift(array)))
  return ifft

def conv_3D(array, kernel):
  conv = np.abs(ifft(fft(array)*fft(kernel)))
  return conv

conv = conv_3D(array, kernel)

This convolves a sphere of radius 2 with a pillar of side length 3.这将半径为 2 的球体与边长为 3 的柱子进行卷积。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM