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


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

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

Я не хочу использовать какие-либо встроенные функции, такие как MATLAB

5   51   2009-11-08 14:38:12

5 ответов:

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

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

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

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

Edit: ядро фильтра 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.

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

вот псевдокод для кода, который я использовал в 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;
}

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

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

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

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

Ну, гауссово ядро является сепарабельным ядром.
Следовательно, все, что вам нужно, это функция, которая поддерживает Сепарабельную 2D свертку, такую как - ImageConvolutionSeparableKernel().

после того, как вы его получили, все, что нужно, это оболочка для создания 1D гауссовского ядра и отправки его в функцию, как это сделано в ImageConvolutionGaussianKernel().

код представляет собой прямую реализацию C 2D-свертки изображения, ускоренной SIMD (SSE) и многопоточностью (OpenMP).

весь проект дается по - Свертка Изображения-GitHub.