简体   繁体   English

如何在 Python 中将 3 维数组(在本例中为滤波器组)与 2 维图像(单色)进行卷积?

[英]How to convolve a 3 dimensional array (in this case a filter bank) with a 2 dimensional image (monochrome) in Python?

I have a function definition that takes in an image that is monochromatic and 2 dimensional, and a filter bank that is a 3 dimensional array (48 2D filters).我有一个 function 定义,它接收单色和二维的图像,以及一个 3 维阵列(48 个 2D 滤波器)的滤波器组。 I need to convolve the two to find the feature vector at each pixel location.我需要对两者进行卷积以找到每个像素位置的特征向量。 How do I do that?我怎么做?

I have tried scipy.ndimage.convolve() but get the error "filter weights array has incorrect shape."我试过scipy.ndimage.convolve()但得到错误“过滤器权重数组的形状不正确”。

To make things simple, simply loop over the temporal dimension of your filter bank, then apply convolution to the image and each filter within the filter bank.为简单起见,只需遍历滤波器组的时间维度,然后将卷积应用于图像和滤波器组中的每个滤波器。 After, stack the results into a 3D matrix.之后,将结果堆叠到 3D 矩阵中。 This is actually what I would do for readability.这实际上是我为了可读性所做的。

Suppose your image is stored in img and your filters are stored in filters .假设您的图像存储在img中,而您的过滤器存储在filters中。 img is of size M x N and your filters are of size R x C x D with D being the total number of filters you have. img的大小为M x N ,您的过滤器大小为R x C x D ,其中D是您拥有的过滤器总数。

As you've eluded to using scipy.ndimage.convolve , we can just use that.正如您避免使用scipy.ndimage.convolve ,我们可以使用它。 However, it's possible to use cv2.filter2D too.但是,也可以使用cv2.filter2D I'll show you how to use both.我将向您展示如何使用这两种方法。

Method #1 - Using scipy.ndimage.convolve方法 #1 - 使用scipy.ndimage.convolve

import scipy.ndimage
import numpy as np

outputs = []
D = filters.shape[2]
for i in range(D):
    filt = filters[...,i]
    out = scipy.ndimage.convolve(img, filt)
    outputs.append(out)

outputs = np.dstack(outputs)

The above is straight forward.以上是直截了当的。 Create an empty list to store our convolution results, then extract the total number of filters we have.创建一个空列表来存储我们的卷积结果,然后提取我们拥有的过滤器总数。 After, we loop over each filter, convolve the image with said filter and append it to the list.之后,我们遍历每个过滤器,将图像与所述过滤器和 append 卷积到列表中。 We then use numpy.dstack to stack all of the 2D responses together to a 3D matrix.然后我们使用numpy.dstack将所有 2D 响应叠加到 3D 矩阵中。

Method #2 - Using cv2.filter2D方法 #2 - 使用cv2.filter2D

import cv2
import numpy as np

outputs = []
D = filters.shape[2]
for i in range(D):
    filt = filters[...,i]
    filt = filt[::-1, ::-1]
    out = cv2.filter2D(img, -1, filt)
    outputs.append(out)

outputs = np.dstack(outputs)

This is exactly the same as Method #1 with the exception of calling cv2.filter2D instead.除了调用cv2.filter2D之外,这与方法 #1 完全相同。 Also take note that I had to rotate the kernel by 180 degrees as cv2.filter2D performs correlation and not convolution.另请注意,我必须将 kernel 旋转 180 度,因为cv2.filter2D执行相关而不是卷积。 To perform convolution with cv2.filter2D , you need to rotate the kernel first prior to running the method.要使用cv2.filter2D执行卷积,您需要在运行该方法之前先旋转 kernel。 Take note that the second parameter to cv2.filter2D is the output data type of the result.请注意, cv2.filter2D的第二个参数是结果的 output 数据类型。 We set this to -1 to say that it will be whatever the input data type is.我们将其设置为-1表示它将是任何输入数据类型。


Note on indexing索引注意事项

If you want to avoid indexing into your filter bank all together and let the for loop do that for you, you can shift the channels around so that the number of filters is the first channel.如果您想避免一起索引到您的过滤器库并让for循环为您执行此操作,您可以移动通道,以便过滤器的数量是第一个通道。 You can then construct the resulting 3D output matrix by list comprehension:然后,您可以通过列表理解构造生成的 3D output 矩阵:

filters = filters.transpose((2, 0, 1))
outputs = np.dstack([scipy.ndimage.convolve(img, filt) for filt in filters])

You can make the monochrome image a 3D array by either padding zeros or replicating the image itself.您可以通过填充零或复制图像本身来使单色图像成为 3D 数组。 The number of such paddings would depend on the depth of convolution kernel.这种填充的数量将取决于卷积 kernel 的深度。 For example, let d be the depth of the convolution kernel and I is your image, then例如,设 d 为卷积 kernel 的深度,I 为您的图像,则

I_pad = np.empty((I.shape[0], I.shape[1], 0))

# Do this for copying the image across channels
I_pad = [np.concatenate((I_pad, I), axis=-1) for _ in range(d)]

# Do this for zero padding
I_pad = [np.concatenate((I_pad, np.zeros(size(I))), axis=-1) for _ in range(d)]

Then carry out the convolution.然后进行卷积。 Hope it helps希望能帮助到你

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

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