13

我想执行一个简单的 2D 图像卷积,但我的内核是均匀大小的。我应该为我的内核中心选择哪些索引?我尝试在谷歌上搜索答案并查看现有代码。人们通常将他们的内核居中,因此在新的 0 之前会有一个样本。所以,如果我们有一个 4x4 内核,居中的索引应该是-2 -1 0 +1. 那是对的吗?如果是,为什么会这样?有人可以解释为什么-2 -1 0 +1是正确的而-1 0 +1 +2不是正确的吗?请记住,我想在不使用 FFT 的情况下执行卷积。

4

3 回答 3

10

如果我正确理解了您的问题,那么对于即使大小的内核,您是正确的,将内核居中是惯例,以便在新零之前还有一个样本。

因此,对于宽度为 4 的内核,居中的索引将-2 -1 0 +1如您上面所说。

然而,这实际上只是一个约定——无论如何都很少使用不对称卷积,并且不对称的确切性质(左/右等)与“正确”结果无关。我想大多数实现都以这种方式运行的原因是,它们可以在给定相同输入的情况下给出可比较的结果。

在频域中执行卷积时,无论如何都会填充内核以匹配图像大小,并且您已经声明您正在空间域中执行卷积。

我对为什么首先需要使用均匀大小的内核更感兴趣。

于 2013-06-11T06:48:26.710 回答
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) { }
}
于 2016-07-12T12:27:46.897 回答
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.]

正如您所看到的“相同”填充输入数组在开头填充了 1 个零,最后填充了 2 个零:[0. 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 0. 0.]。因此对于 tensorflow,即使大小的内核中心将遵循 4-kernel:-1 0 +1 +22*n大小的内核:-(n-1), -(n-2),... -1, 0, +1,... +(n-1), +n,

于 2019-09-16T13:20:56.003 回答