Как делают меня гауссова размытость изображение, не используя встроенных гауссовых функций?

Я хочу размыть свое изображение с помощью собственной Гауссовой формулы размытости. Я прочитал статью Wikipedia, но я не уверен, как реализовать это.

Как я использую формулу для решения весов?

Я не хочу использовать любого созданного в функциях как то, что имеет MATLAB

54
задан hippietrail 9 September 2019 в 08:51
поделиться

4 ответа

На самом деле написать простое размытие по Гауссу довольно просто. Это делается точно так же, как и любой другой фильтр свертки. Единственная разница между прямоугольным фильтром и гауссовым фильтром - это используемая вами матрица.

Представьте, что у вас есть изображение, определенное следующим образом:

 0  1  2  3  4  5  6  7  8  9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

Матрица прямоугольного фильтра 3x3 определяется следующим образом:

0.111 0.111 0.111
0.111 0.111 0.111
0.111 0.111 0.111

Чтобы применить размытие по Гауссу, вы будет делать следующее:

Для пикселя 11 вам нужно будет загрузить пиксели 0, 1, 2, 10, 11, 12, 20, 21, 22.

вы умножите пиксель 0 на верхнюю левую часть фильтр размытия 3x3. Пиксель 1 вверху посередине, пиксель 2, пиксель 3 вверху справа, пиксель 10 посередине слева и т. Д.

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

Пограничные случаи становятся немного сложнее. Какие значения вы используете для значений края текстуры? Один из способов - это перевернуть на другую сторону. Это хорошо подходит для изображения, которое позже будет выложено плиткой. Другой способ - протолкнуть пиксель в окружающие места.

Итак, для верхнего левого угла вы можете разместить образцы следующим образом:

 0  0  1
 0  0  1
10 10 11

Я надеюсь, вы видите, как это можно легко распространить на большие ядра фильтров (например, 5x5 или 9x9 так далее).

Разница между гауссовым фильтром и блочным фильтром заключается в числах, которые входят в матрицу. Гауссовский фильтр использует гауссовское распределение по строке и столбцу.

например, для фильтра, произвольно определенного как (т.е. это не гауссово, но, вероятно, не за горами)

0.1 0.8 0.1

первый столбец будет таким же, но умноженным на первый элемент строки выше.

0.01 0.8 0.1
0.08 
0.01 

второй столбец будет таким же, но значения будут умножены на 0. 8 в строке выше (и так далее).

0.01 0.08 0.01
0.08 0.64 0.08
0.01 0.08 0.01

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

Такие фильтры могут делать много интересных вещей. Вы можете выполнить обнаружение края с помощью такого фильтра, вычтя окружающие пиксели из текущего пикселя. Это оставит после себя только действительно большие изменения цвета (высокие частоты).

Редактировать: Ядро фильтра 5x5 определяется точно так же, как указано выше.

например, если ваша строка равна 0,1 0,2 0,4 0,2 0,1, то если вы умножите каждое значение в них на первый элемент, чтобы сформировать столбец, а затем умножьте каждое на второй элемент, чтобы сформировать во втором столбце и так далее вы получите фильтр

0.01 0.02 0.04 0.02 0.01
0.02 0.04 0.08 0.04 0.02
0.04 0.08 0.16 0.08 0.04
0.02 0.04 0.08 0.04 0.02
0.01 0.02 0.04 0.02 0.01

, занимающий произвольные позиции, вы можете увидеть, что позиция 0, 0 просто 0,1 * 0,1. Позиция 0, 2 равна 0,1 * 0,4, позиция 2, 2 равна 0,4 * 0,4, а позиция 1, 2 равна 0,2 * 0,4.

Надеюсь, это дает вам достаточно хорошее объяснение.

0 просто 0,1 * 0,1. Позиция 0, 2 равна 0,1 * 0,4, позиция 2, 2 равна 0,4 * 0,4, а позиция 1, 2 равна 0,2 * 0,4.

Надеюсь, это дает вам достаточно хорошее объяснение.

0 просто 0,1 * 0,1. Позиция 0, 2 равна 0,1 * 0,4, позиция 2, 2 равна 0,4 * 0,4, а позиция 1, 2 равна 0,2 * 0,4.

Надеюсь, это дает вам достаточно хорошее объяснение.

129
ответ дан 7 November 2019 в 07:43
поделиться

Чтобы использовать ядро ​​фильтра, описанное в статье Википедии, вам необходимо реализовать (дискретную) свертку . Идея заключается в том, что у вас есть небольшая матрица значений (ядро), вы перемещаете это ядро ​​от пикселя к пикселю в изображении (т.е. так, чтобы центр матрицы находился на пикселе), умножаете элементы матрицы на перекрывающееся изображение элементов, просуммируйте все значения в результате и замените старое значение пикселя этой суммой.

Размытие по Гауссу можно разделить на две одномерные свертки (одну вертикальную и одну горизонтальную) вместо двумерной свертки, что также немного ускоряет процесс.

9
ответ дан 7 November 2019 в 07:43
поделиться

Я не понимаю, есть ли вы хотите ограничить это определенными технологиями , но если нет SVG (ScalableVectorGraphics) , имеет реализацию Gaussian Blur. Я считаю, что это применимо ко всем примитивам, включая пиксели.

3
ответ дан 7 November 2019 в 07:43
поделиться

Вот псевдокод для кода, который я использовал в C # для вычисления ядра. Я не осмеливаюсь сказать, что правильно отношусь к конечным условиям:

double[] kernel = new double[radius * 2 + 1];
double twoRadiusSquaredRecip = 1.0 / (2.0 * radius * radius);
double sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * Math.PI) * radius);
double radiusModifier = 1.0;

int r = -radius;
for (int i = 0; i < kernel.Length; i++)
{
    double x = r * radiusModifier;
    x *= x;
    kernel[i] =
    sqrtTwoPiTimesRadiusRecip * Exp(-x * sqrtTwoPiTimesRadiusRecip);
    r++;
}

double div = Sum(kernel);
for (int i = 0; i < kernel.Length; i++)
{
    kernel[i] /= div;
}

Надеюсь, это поможет.

11
ответ дан 7 November 2019 в 07:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: