Свертка изображений с четным ядром

Я хочу выполнить простую свертку 2D-изображения, но мое ядро ​​имеет четные размеры. Какие индексы я должен выбрать для своего центра ядра? Я попытался поискать в поиске ответа и искать существующие коды. Люди обычно центрируют свое ядро, поэтому перед новым 0 будет еще один образец. Итак, если у нас есть ядро ​​4x4, центрированные индексы должны быть -2 -1 0 +1, Это верно? И если это так, то почему это так? Может кто-нибудь объяснить, почему -2 -1 0 +1 в то время как правильно -1 0 +1 +2 не является? Имейте в виду, что я хочу выполнить свертку без использования БПФ.

2 ответа

Решение

Если я правильно понимаю ваш вопрос, то для ядер четного размера вы правы в том, что принято центрировать ядро так, чтобы перед новым нулем оставался еще один образец.

Так, для ядра ширины 4 центрированные индексы будут -2 -1 0 +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) { }
}

Поразмыслив над сверткой равного размера и ее применением в Temporal Convolutional Networks, я решил, что следующий эксперимент даст ответ для центрирования свертки равного размера в 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.]. Таким образом, для тензорного потока центрирование ядра даже по размеру будет следующим для 4-ядер:-1 0 +1 +2 и для 2*n размер ядра: -(n-1), -(n-2),... -1, 0, +1,... +(n-1), +n,

Другие вопросы по тегам