Линейный Низкочастотный Фильтр

1) Фильтр Усреднения = Averaging Filters
Простейшая и популярнейшая форма = 3x3 Фильтр: заменяет каждую точку средним значением ее и 8-ми ее соседей:
Каждому значению прибавляется значение 8 соседей - сумма делится на 9 и округляется.
Обработка границ: в первой и последней строке/столбце к каждой точке прибавлять только существующих соседей и делить на соответствующее число элементов.
Пример 3x3 Фильтр с индексной последовательностью сначала  x, затем y:

      0101 
old = 1870
0651
1010
new[1,1]=(0 + 1 + 0 + 1 + 8 + 7 + 0 + 6 + 5)/9 = 28/9= 3.11= rounded 3 
new[2,1]=(1 + 0 + 1 + 8 + 7 + 0 + 6 + 5 + 1)/9 = 29/9= 3.22= rounded 3
new[1,2]=(1 + 8 + 7 + 0 + 6 + 5 + 1 + 0 + 1)/9 = 29/9= 3.22= rounded 3
new[2,2]=(8 + 7 + 0 + 6 + 5 + 1 + 0 + 1 + 0)/9 = 28/9= 3.11= rounded 3
new[0,0]=( 0 + 1 + 1 + 8)/4 = 10/4= 2.50= rounded 3
new[1,0]=( 0 + 1 + 0 + 1 + 8 + 7)/6 = 17/6= 2.83= rounded 3
new[3,3]=(5 + 1 + 1 + 0 )/4 = 7/4 = 1.75= rounded 2
new[2,3]=(6 + 5 + 1 + 0 + 1 + 0 )/6 = 13/6= 2.16= rounded 2
etc.
      3333 
new = 3333
3332
2222
Разница значений после фильтра практически исчезла - выровнялась.

2) Взвешенный Фильтр Усреднения
понижает действие фильтра через наделение средней точки весом больше единицы  > 1 :
По сравнению со своими 8-мью соседями каждая средняя точка "усиливается" коэффициентом  > 1 и делится соответственно на более высокий знаменатель.
Пример 3x3 с средним весом = 8, означает, что каждый Пиксел имеет столько "права голоса", сколько все 8 его соседей вместе взятые:

      0101 
old = 1870
0651
1010
new[1,1]=(0 + 1 + 0 + 1 + 8*8 + 7 + 0 + 6 + 5)/16= 84/16 =5.25= rounded 5 
new[2,1]=(1 + 0 + 1 + 8 + 7*8 + 0 + 6 + 5 + 1)/16= 77/16 =4.81= rounded 5
new[1,2]=(1 + 8 + 7 + 0 + 6*8 + 5 + 1 + 0 + 1)/16= 69/16 =4.31= rounded 4
new[2,2]=(8 + 7 + 0 + 6 + 5*8 + 1 + 0 + 1 + 0)/16= 60/16 =3.75= rounded 4
new[0,0]=( 0*8 + 1 + 1 + 8)/11= 10/11 =0.91= rounded 1
new[1,0]=( 0 + 1*8 + 0 + 1 + 8 + 7)/13= 24/13 =1.85= rounded 2
new[3,3]=(5 + 1 + 1 + 0*8 )/11= 7/11 =0.63= rounded 1
new[2,3]=(6 + 5 + 1 + 0 + 1*8 + 0 )/13= 20/13 =1.54= rounded 2
etc.
      1331 
new = 2551
1442
1121
Разница значений все еще значительна, новая матрица намного менее размыта, чем в невзвешенном фильтре.

3) Быстрый Фильтр Усреднения = Fast Averaging Filter
С помощью одного дополнительного вспомогательного Изображения  H[old.Height,old.Width] можно уменьшить количество операций суммирования на каждую точку с N*M до 2*M+2*N и таким образом значительно ускорить Фильтр усреднения.
(При Средне-весовом методе = Fog-Filter требуется еще одно вспомогательное Изображение V[old.Height,old.Width].)

Алгоритм без "веса среднего"
:
1 шаг: на левом краю каждой строки первые M Пикселов из old[y,x] складываются и сумма записывается в H[y,M/2].
2 шаг: каждая сумма сдвигается направо по x : H[y,x+1] = H[y,x]-old[y,xleft]+old[y,xright], пока не дойдет до правого края Изображения.
3 шаг: на верхней границе в каждой колонке первые N точек из H[y,x] сложить и сумму sum разделить, округлить и записать: new[y,x] = round( sum/(M*N) ).
4 шаг: каждую сумму сдвинуть вниз по y: sum = sum-H[yupper,x]+H[ylower,x], разделить, округлить и записать: new[y,x] = round( sum/(M*N) ), пока не дойдет до нижней границы Изображения.

Алгоритм с "весом среднего"
(создает Туман = Fog) с помощью второго вспомогательного Изображения V[y,x]:
1 шаг: аналогично предыдущему алгоритму.
2 шаг: аналогично предыдущему алгоритму.
3 шаг: на верхней границе в каждой колонке первые N точек из H[y,x] складываются и сумма записывается в дополнительный буфер V[y,N/2].
4 шаг: каждая сумма сдвигается по оси y вниз: V[y+1,x] = V[y,x]-H[yupper,x]+H[ylower,x], пока не дойдет до нижней границе.
5 шаг: каждому значению V[y,x] прибавляется weight*old[x,y].
6 шаг: вспомогательное изображение V[y,x] делится, округляется и записывается:
new[y,x] = round( V[y,x]/(M*N+weight) ).

4) Фильтр Гаусса = Gauss Filter

В фильтре усреднения все соседи имеют одинаковое право голоса, независимо
от их расстояния до средней точки. Это не неразумно, т.к. ближних соседей
нужно слушать внимательнее, чем дальних. Можно использовать дистанцию
между точками, как весовой коэффициент, но лучше считать дистанцию
d не
линейно, а с помощью симметричного 3D-колокола Гаусса. 
(→ Нормальное распределение Гаусса): kernel[yy,xx] = e-d*d/a, где e=2.718 число Эйлера, a константа и d переменное расстояние от центра колокола. Этот колокол имеет высоту weight[N/2,N/2] = 1.0 = 100%. Делитель a определяет крутизну сторон колокола. Крутизну лучше выбирать так, чтобы даже удаленные соседи в 4-х углах имели хотя бы вес 0.01 = 1% ( исключение: при размере ядра 3x3 они должны получить не менее ≈ 16%).

Перед фильтрованием с помощью N*N-Гаусс-Фильтра нужно высчитать Ядро с подходящей a , чтобы при максимальном удалении от центра ядра dmax = √2*N/2 = половине диагонали,
вес сохранялся не менее  0.01.
1 шаг: вычисляем a из dmax и нужной величины 0.01: a = -2*(N/2)*(N/2) / Math.Log( 0.01 );
2 шаг: вычисляем матрицу ядра kernel[yy,xx] и его весовую сумму sum_kernel:
for ( yy=0; yy < N; yy++ )
  
for ( xx=0; xx < N; xx++ ) {
      double d = Math.Sqrt( (xx-N/2)*(xx-N/2) + (yy-N/2)*(yy-N/2) );
      sum_kernel += kernel[yy,xx] = (float)( Math.Exp( - d*d / a ) );
   }

3 шаг: Свертка = Convolution = 4 вложенных for-циклов (см ниже).

Fast Gauss Filter : Статистика показывает, что последовательное применение нескольких Сверток с одним малым равно распределённым Ядром сходится к одной Свертке с одним большим нормированным Ядром - Гаусс-Фильтр. Это утверждение легко проверяется: одна Сверка с одним N*N-Гаусс-Фильтром дает почти идентичный результат, как три примененные друг за другом Свертки с тремя идентичными (N/2)*(N/2) невзвешенными фильтрами усреднения. Этот путь экономит время вычисления, если  1) N≥9 и 2) используется Быстрый Фильтр Усреднения, известный как Fast Gauss Filter.

Цели использования Низкочастотного Фильтра:
1) Подавление Шума
2) Создание искусственного Пустого Изображения для коррекции затенения

Для повышения размытия  (Blurring)
, можно сделать следующее:
1) Увеличить размер Фильтра до 5x5, 7x7, 25x25 и т.д. ( из соображений симметрии размеры Фильтра часто нечетные и квадратные)
2) Каскадные Фильтра = многократное применение Фильра друг за другом.

Обработка краев Изображения - это сложно и затратно по времени
. Существует четыре стратегии:
1) Игнорирование границ. Изображение уменьшается - образуется черная рамка.
2) Для начала 1), затем первые и последние Строки/Столбцы из 1) копируются на черные края - рекомендуется.
3) Во время выполнения - ассиметрично уменьшить Ядро и соответствующий делитель - медлено, и действие Фильтра у границы уменьшается.
4) Обработка 8 особых случаев для каждого края и для каждого угла Изображения - для перфекционистов.

Линейный Высокочастотный Фильтр

Линейный Высокочастотный Фильтр содержит положительные и отрицательные веса. Они тянут однородные области(обычно на 0) вниз, неважно яркие или темные, и усиливают разницу значений серого в Изображении = Выделение Краев.
Простой Высокочастотный Фильтр = Фильтр Лапласа содержит веса +1 и -1. Он назван по имени математика Пьера Лапласа в 1800 году.

Порядок вычислений: для каждого Пиксела рассчитываются 4 разницы значений с его 4-мя соседями и максимальное значение записывается в  new. Три других разницы игнорируются.
Плюсы: 1) предпочтение крутым перепадам значений серого 2) уменьшает до нуля гомогенные площади 3) работает просто и быстро
Минусы: усиливает шумность.

Свёртка = Convolution

Свертка = Convolution = линейная фильтрация - это математическая формулировка для всех видов линейной фильтрации: Низкочастотной, Высокочастотной и смеси обеих = полосовой.
Идея состоит в том, что фильтрационные веса формулируются в виде маленькой матрицы (часто квадратной с нечетным количеством строк и колонок), называемой Ядром. 
Порядок вычисления для фильтров представляет собой своего рода скользящее матричное умножение со сложением результатов и последующей нормировкой и округлением до целого числа.

Плюсы: 1) все виды и размеры линейных фильтров имеют единый порядок вычислений. 2) скорость через Convolution-ASICs = Application Specific Integrated Circuits, разработанных специально для Свёртки.
Минусы: 1) чрезмерная сложность для простых Ядер, которые содержат единичные веса. 2) порядок вычислений не применим на краях Изображений, где Ядро выходит за края.

Порядок расчетов: локально скользящее умножение и сложение матрицы Изображения old[y,x] с одной (относительно Изображения малой) Фильтр-Матрицей kernel[yy,xx] с двумя индексами 0 <= xx <= 2*Mh и 0 <= yy <= 2*Nh. Можно представить, что Ядро - маленькая матрица kernel[yy,xx] расписана на прозрачной пленке, которая лежит на большой матрице Изображения old[y,x] и через два вложенных цикла for проходит по всем Строкам/Колонкам.
Шаг 1: каждое отдельное число Ядра умножается с находящимся под ним значением серого из 
old[y,x].
Шаг 2: затем все результаты суммируются.
Шаг 3: полученная сумма делится на 
divisor ≥ 1, округляется и, если отрицательна, с помощью offset смещается в диапазон между 0 и 255.
Шаг 4: полученный результат попадает в результирующую матрицу Изображения
 new на место [y,x].
Края Изображения, где пленка kernel[yy,xx] заходит за край old[y,x], остается неопределенной.

Классическая реализация Свертки
:

const int Mh = M/2, Nh = N/2, offset = ???; //M*N = размер Ядра, offset обычно = 0 
float sum; const float divisor = ?.???; //divisor = сумма всех значений Ядра (обычно)
for ( int y=Nh; y < old.Height-Nh; y++ )
for ( int x=Mh; x < old.Width-Mh; x++ )
{
sum = 0.0f;
for ( int yy=-Nh; yy <= Nh; yy++ )
for ( int xx=-Mh; xx <= Mh; xx++ )
sum += kernel[yy+Nh,xx+Mh] * old[y+yy,x+xx];
new[y,x] = offset + Convert.ToByte( sum / divisor );
}

Популярные Ядра Свёртки

1) Невзвешенный Фильтр Усреднения имеет квадратную форму нечетного размера 3x3, 5x5 ... 25x25.
Все значения Ядра kernel[yy,xx] = 1, offset=0, divisor=1f/(Сумма Ядра Свёртки).
Невзвешенные Фильтра Усреднения алгоритмически быстрее, так как все мультипликаторы Ядра
kernel[yy,xx] равны 1 и поэтому множители просто игнорируются
.

2) Взвешанный Фильтр Усреднения уменьшает сильное действие невзвешенного Фильтра Усреднения так, что в центре Ядра kernel[yy,xx] располагаются высокие мультипликаторы, а ближе к краям - низкие. Нормировка - offset=0 и divisor=1f/(сумма мультипликаторов).

Исключение: если средний вес значительно превосходит все остальные, то фильтр теряет свое действие:
3) Краевой Фильтр - линейный Высокочастотный Фильтр . Примеры:
     +1 +2 +1      +1 +1 +1       +5 +5 +5 
k1 = 0 0 0 k2 = 0 0 0 k3 = -3 -3 -3
-1 -2 -1 -1 -1 -1 -3 -3 -3
k1k2 и k3 возвращают высокие положительные значения на горизонтальных краях между светлой областью вверху и темной областью внизу, и большие негативные значения при темной области вверху и светлой внизу.

4) Комбинации Краевых Фильтров  используют множество различных Краевых Фильтров друг за другом 
и комбинируют их результаты в одном результирующем Изображении.
Важные подгруппы: Градиентные Фильтра имеют два симметричных Ядра V1 и V2 с 9-ю значениями.
Эти два Ядра дают два результата s1 и s2 на Пиксел. Мы можем рассматривать эти значения, как
вектор направления наибольшего падения = Градиент. В результирующее Изображение записывается
sqrt(s1*s1 + s2*s2) = значение Градиента. Так как Градиент всегда положителен, то значения
верх-них, лево-право симметричны (в отличии от простых Краевых Фильтров).
Примеры:
                    +1 +2 +1         +1 0 -1 
Собель (Sobel): k1 = 0 0 0 k2 = +2 0 -2 //популярный Градиентный Фильтр
-1 -2 -1 +1 0 -1
                      +1 +1 +1       +1 0 -1 
Прюитт (Prewitt): k1 = 0 0 0 k2 = +1 0 -1 //немного слабее, чем Собель
-1 -1 -1 +1 0 -1
                    +5 +5 +5         +5 -3 -3 
Кирш (Kirsch): k1 = -3 -3 -3 k2 = +5 -3 -3 //немного сильнее, чем Собель
-3 -3 -3 +5 -3 -3
 Оригинал
Прюитт
Собель

5) Полосной Фильтр имеет одновременно свойства Низкочастотного (в середине) и
Высокочастотного (по краям) Фильтров. Их размеры (обычно больше чем 9х9) и веса аккуратно
подобраны для Радаров, Рентген-томографов и Ядерно-Магнитно-Резонансных-томографов.
Важная подгруппа: Сомбреро-Фильтр имеет круглую симметрию и высокие положительные
значения в центре Ядра kernel[yy,xx], которые резко падают до негативных значений, и ближе к
краям снова подымаются до низких положительных значений.
Знамениты фильтра размером 9х9 от Рамачандрана и Лакшми Нараяна,
и фильтр 9х9 от Шеппа и Логана. Оба Фильтра активно применяются в Компьютерной Томографии.

Нелинейные Фильтры

Нелинейными называются все фильтра, которые не используют Свёртку.
Нелинейные фильтра также используют окошко с нечетным количеством колонок и строк, скользящее
над оригинальным Изображением, но не имеющее Ядра kernel[yy,xx], которое заменяет одно или
более вычислений, которые из множества покрытых значений вычисляют новое значение для
результирующего Изображения
new[y,x].

1) Медианный Фильтр:

Популярный нелинейный фильтр:Он сортирует все попавшие
в
NxN
-окно значения -N/2≤yy,xx≤+N/2 из old[y+yy,x+xx]
во вспомогательном массиве размером
N*N
в возрастающем
порядке и берет значение, находящееся посередине, как результирующее
new[y,x]
.
Плюс: Подавление шума без размывания.
Минусы:1) уничтожение деталей..2) сортировка - затратна по времени.
Пример справа: рассчет Медианного Фильтра раз
мером 3x3

2) Сигма-Фильтр:
является селективным Фильтром Усреднения. Он усредняет только те значения, которые
отличаются от центрального пиксела не более чем на значение sigma=σ , а остальные пикселы
игнорируются.
Алгоритм почти идентичен нормальному Фильтру Усреднения.
Только во внутреннем цикле суммирование меняется следующим образом:

if ( Math.Abs(old[y,x]-old[y+yy,x+xx]) <= sigma ) { 
sum += old[y+yy,x+xx]; divisor++;
}


Пример 3x3-Фильтр с σ=3 и индексацией y,x:
2189
1278 → new[1,1]=(2+1+1+2+1+3)/6=10/6≈2;  new[1,2]=(8+9+7+8+9+7)/6=48/6=8;
1397

Выводы: очень важный "хитрый" фильтр - позволяет и сглаживать значения и
сохранять края объектов не размытыми.

Плюс: подавление шума без размытия.
Минусы:
1) если σ слишко мала, то никакого усреднения не происходит, а если σ слишком велика, то
происходит такое же размытие, как и при Низкочастотном Фильтре.
2) медленнее чем Фильтр Усреднения - быстрое усреднение невозможно.
3) невозможно использование весов.