使用偶数大小的卷积核进行图像卷积

13

我想执行一个简单的2D图像卷积,但我的卷积核的大小是偶数。 我应该选择哪些索引作为卷积核中心? 我尝试在谷歌上寻找答案并查看现有代码。 人们通常将卷积核居中,以便新的零值之前有一个样本。 因此,如果我们有一个4x4的卷积核,则中心索引应为-2 -1 0 +1。 这是正确的吗? 如果确实如此,为什么会这样呢? 有人能解释一下为什么-2 -1 0 +1是正确的,而-1 0 +1 +2不是吗? 请记住,我想执行卷积,而不使用FFT。

3个回答

10

如果我正确理解你的问题,那么对于偶数大小的卷积核,你说的居中是惯例,以便在新零点之前有一个样本。

因此,对于宽度为4的卷积核,居中的索引将是-2 -1 0 +1,正如你上面所说。

然而,这确实只是一种惯例——不对称的卷积很少使用,而不对称性质(向左/右等)与“正确”结果无关。我想大多数实现之所以表现出这种方式,是为了在给定相同输入时能够提供可比较的结果。

在频域中执行卷积时,卷积核会被填充以匹配图像大小,而你已经说明正在在空间域中执行卷积。

我更感兴趣的是你为什么需要首先使用偶数大小的卷积核。


非常感谢你的回答,我的朋友!我想使用点扩散函数(PSF)卷积一些图像。这个PSF恰好是偶数大小的(44x44)。我猜我可以将PSF调整大小/重采样为43x43,但我对偶数大小内核的情况有点好奇。再次感谢! - AstrOne
@AstrOne 没问题,我建议按照你的建议重新采样PSF,尽管在那么大的内核上,这可能不会有太大的区别。 - Roger Rowland
1
这里有一个针对偶数大小卷积核的答案 - palimboa
谢谢你的回答。"将核心对齐到中心"是什么意思?-2 -1 0 +1 是什么?它似乎是核心中的一些坐标,但是相对于哪个位置呢? - Thunder

1
正确答案是返回左上角像素的结果,无论您的矩阵是否均匀大小。然后,您可以在简单的扫描线中执行操作,而且不需要内存。
private static void applyBlur(int[] pixels, int stride) {
    int v0, v1, v2, r, g, b;
    int pos;
    pos = 0;
    try {
        while (true) {
            v0 = pixels[pos];
            v1 = pixels[pos+1];
            v2 = pixels[pos+2];

            r = ((v0 >> 16) & 0xFF) + ((v1 >> 16) & 0xFF) + ((v2 >> 16) & 0xFF);
            g = ((v0 >> 8 ) & 0xFF) + ((v1 >>  8) & 0xFF) + ((v2 >>  8) & 0xFF);
            b = ((v0      ) & 0xFF) + ((v1      ) & 0xFF) + ((v2      ) & 0xFF);
            r/=3;
            g/=3;
            b/=3;
            pixels[pos++] = r << 16 | g << 8 | b;
        }
    }
    catch (ArrayIndexOutOfBoundsException e) { }
    pos = 0;
    try {
    while (true) {
            v0 = pixels[pos];
            v1 = pixels[pos+stride];
            v2 = pixels[pos+stride+stride];

            r = ((v0 >> 16) & 0xFF) + ((v1 >> 16) & 0xFF) + ((v2 >> 16) & 0xFF);
            g = ((v0 >> 8 ) & 0xFF) + ((v1 >>  8) & 0xFF) + ((v2 >>  8) & 0xFF);
            b = ((v0      ) & 0xFF) + ((v1      ) & 0xFF) + ((v2      ) & 0xFF);
            r/=3;
            g/=3;
            b/=3;
            pixels[pos++] = r << 16 | g << 8 | b;
        }
    }
    catch (ArrayIndexOutOfBoundsException e) { }
}

0
经过对偶数卷积及其在时间卷积网络中的应用进行一些思考后,我决定执行以下实验以回答关于在tensorflow/keras中如何实现偶数大小卷积居中的问题:
import keras
import numpy as np
import tensorflow as tf
import keras.backend as K
import keras.layers as layers
from keras.layers import Conv2D, Input
from keras.initializers import Constant

if __name__ == '__main__':
    inputs = Input(shape=(None,1,1))
    even_conv = Conv2D(1,(4,1),padding="same",
                       kernel_initializer=Constant(value=1.),use_bias=False)(inputs)
    f = K.function(inputs=[inputs],outputs=[even_conv])
    test_input = np.arange(10)[np.newaxis,...,np.newaxis,np.newaxis].astype(np.float)
    result = f(inputs=[test_input])[0]
    print(np.squeeze(test_input))
    # [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
    print(np.squeeze(result))
    # [ 3.  6. 10. 14. 18. 22. 26. 30. 24. 17.]

如您所见,“same”填充的输入数组在开头填充了1个零,在结尾处填充了2个零:[0. 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 0. 0.]。因此,对于TensorFlow,针对4个内核的偶数大小的核心居中将遵循以下规则:-1 0 +1 +2,而对于2*n大小的核心:-(n-1), -(n-2),... -1, 0, +1,... +(n-1), +n,


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接