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

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

2 ответов


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

Итак, для ядра шириной 4 центрированные индексы будут -2 -1 0 +1 Как вы сказали выше.

однако это действительно просто соглашение-асимметричная свертка очень редко используется в любом случае и точный характер асимметрии (слева / справа и т. д.) нет отношение к" правильному " результату. Я бы предположил, что причина, по которой большинство реализаций ведут себя таким образом, заключается в том, что они могут давать сопоставимые результаты при одинаковых входных данных.

при выполнении свертки в частотной области ядро все равно дополняется, чтобы соответствовать размеру изображения, и вы уже заявили, что выполняете свертку в пространственной области.

меня гораздо больше интересует, почему вам нужно использовать ядро четного размера в первое место.


правильный ответ-вернуть пиксель результатов в верхнем левом углу, независимо от того, имеет ли ваша матрица равномерный размер или нет. Затем вы можете просто выполнить операцию в простой scanline, и они не требуют памяти.

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) { }
}