Нужно больше разных Blur-ов

  • Tutorial
Размытие изображения посредством фильтра Gaussian Blur широко используется в самых разных задачах. Но иногда хочется чуть большего разнообразия, чем просто один фильтр на все случаи жизни, в котором регулировке поддаётся только один параметр — его размер. В этой статье мы рассмотрим несколько других реализаций размытия.


Введение


Эффект Gaussian Blur является линейной операцией и математически представляет собой свёртку изображения с матрицей фильтра. При этом каждый пиксель в изображении замещается на сумму близлежащих, взятых с определёнными весовыми коэффициентами.

Фильтр называется Gaussian, потому что он строится из функции, известной как гауссиана, $e^{-x^2}$:



двумерный вариант которой получен её вращением относительно оси ординат, $e^{-(x^2+y^2)}$:



Здесь для каждой пары координат $(x,y)$ рассчитывается расстояние до центра по формуле $\sqrt{x^2+y^2}$, которое передаётся как аргумент в функцию гауссианы — и, как легко увидеть, $e^{-\left(\sqrt{x^2+y^2}\right)^2}$ сокращается до $e^{-(x^2+y^2)}$.

Матрица, построенная на отрезке $[-3,3]$ и с некоторым уровнем дискретизации, будет выглядеть так:

$\left( \begin{array}{ccccccc} 1.52 \times 10^{-8} & 2.26 \times 10^{-6} & 0.0000454 & 0.000123 & 0.0000454 & 2.26 \times 10^{-6} & 1.52 \times 10^{-8} \\ 2.26 \times 10^{-6} & 0.000335 & 0.00674 & 0.0183 & 0.00674 & 0.000335 &2.26 \times 10^{-6} \\ 0.0000454 & 0.00674 & 0.135 & 0.368 & 0.135 & 0.00674 & 0.0000454 \\ 0.000123 & 0.0183 & 0.368 & 1.00 & 0.368 & 0.0183 & 0.000123 \\ 0.0000454 & 0.00674 & 0.135 & 0.368 & 0.135 & 0.00674 & 0.0000454 \\ 2.26 \times 10^{-6} & 0.000335 & 0.00674 & 0.0183 & 0.00674 & 0.000335 &2.26 \times 10^{-6} \\ 1.52 \times 10^{-8} & 2.26 \times 10^{-6} & 0.0000454 & 0.000123 & 0.0000454 & 2.26 \times 10^{-6} & 1.52 \times 10^{-8} \\ \end{array} \right) $


Или, если рассматривать значения элементов матрицы как уровень яркости, так:



В терминах обработки сигналов это называется импульсной характеристикой, поскольку именно так будет выглядеть результат свёртки данного фильтра с единичным импульсом (в данном случае — пикселем).

Изначально гауссиана определена на бесконечном интервале. Но за счёт того, что она довольно быстро затухает, можно исключить из вычислений значения, близкие к нулю — поскольку они всё равно не отразятся на результате. В реальных приложениях также необходима нормализация по значению, чтобы после свёртки яркость изображения не изменялась; а в случае размытия изображения, в котором каждый пиксель имеет один и тот же цвет, не должно меняться и само изображение.

Для удобства часто используют нормализацию и по координатам, посредством введения дополнительного параметра $\sigma$ (читается как «сигма») — чтобы рассматривать аргумент в диапазоне $[-1,1]$, а $\sigma$ определяет степень сжатия гауссианы:

$\frac{e^{-\frac{x^2+y^2}{2 \sigma ^2}}}{2 \pi \sigma ^2}$


Нормализующий делитель $2 \pi \sigma ^2$ здесь получен аналитически через определённый интеграл на бесконечности:

$\int_{-\infty }^{\infty } \int_{-\infty }^{\infty } e^{-\frac{x^2+y^2}{2 \sigma ^2}} \, dx dy = 2 \pi \sigma ^2$


За счёт того, что выполняется равенство $e^{-\left(x^2+y^2\right)}=e^{-x^2} e^{-y^2}$, размытие по Гауссу можно реализовать последовательно сначала по строкам, а затем по столбцам — что позволяет достаточно сильно сэкономить на вычислениях. В этом случае необходимо использовать формулу с нормализацией для одномерного случая —

$\frac{e^{-\frac{x^2}{2 \sigma ^2}}}{\sqrt{2 \pi \sigma ^2}}$



Начало


Для произвольного фильтра нам нужно сначала определить собственную функцию затухания от одной переменной $f$, из которой вращением получается функция от двух переменных путём замены $x$ на $\sqrt{x^2+y^2}$, где $x$ и $y$ это координаты элемента матрицы в диапазоне $(-1,1)$, и которая далее используется для заполнения элементов матрицы. Нормализацию будем считать не аналитически, а непосредственным суммированием всех элементов матрицы — это и проще, и точнее — поскольку после дискретизации функция получается «прореженной», и значение нормализации будет зависеть от уровня дискретизации.

В случае, если элементы матрицы нумеруются с нуля, координата $x$ или $y$ считается по формуле

$\frac{2 index}{size-1}-1$


где $index$ — порядковый номер элемента в строке или столбце, а $size$ — общее количество элементов.

Например, для матрицы 5 на 5 это будет выглядеть так:

$\left( \begin{array}{ccccc} f(-1,-1) & f\left(-\frac{1}{2},-1\right) & f(0,-1) & f\left(\frac{1}{2},-1\right) & f(1,-1) \\ f\left(-1,-\frac{1}{2}\right) & f\left(-\frac{1}{2},-\frac{1}{2}\right) & f\left(0,-\frac{1}{2}\right) & f\left(\frac{1}{2},-\frac{1}{2}\right) & f\left(1,-\frac{1}{2}\right) \\ f(-1,0) & f\left(-\frac{1}{2},0\right) & f(0,0) & f\left(\frac{1}{2},0\right) & f(1,0) \\ f\left(-1,\frac{1}{2}\right) & f\left(-\frac{1}{2},\frac{1}{2}\right) & f\left(0,\frac{1}{2}\right) & f\left(\frac{1}{2},\frac{1}{2}\right) & f\left(1,\frac{1}{2}\right) \\ f(-1,1) & f\left(-\frac{1}{2},1\right) & f(0,1) & f\left(\frac{1}{2},1\right) & f(1,1) \\ \end{array} \right)$


Или, если исключить граничные значения, которые всё равно равны нулю, то координаты будут считаться по формуле

$\frac{2 index-size+1}{size}$


а матрица соответственно примет вид

$\left( \begin{array}{ccccc} f\left(-\frac{4}{5},-\frac{4}{5}\right) & f\left(-\frac{2}{5},-\frac{4}{5}\right) & f\left(0,-\frac{4}{5}\right) & f\left(\frac{2}{5},-\frac{4}{5}\right) & f\left(\frac{4}{5},-\frac{4}{5}\right) \\ f\left(-\frac{4}{5},-\frac{2}{5}\right) & f\left(-\frac{2}{5},-\frac{2}{5}\right) & f\left(0,-\frac{2}{5}\right) & f\left(\frac{2}{5},-\frac{2}{5}\right) & f\left(\frac{4}{5},-\frac{2}{5}\right) \\ f\left(-\frac{4}{5},0\right) & f\left(-\frac{2}{5},0\right) & f(0,0) & f\left(\frac{2}{5},0\right) & f\left(\frac{4}{5},0\right) \\ f\left(-\frac{4}{5},\frac{2}{5}\right) & f\left(-\frac{2}{5},\frac{2}{5}\right) & f\left(0,\frac{2}{5}\right) & f\left(\frac{2}{5},\frac{2}{5}\right) & f\left(\frac{4}{5},\frac{2}{5}\right) \\ f\left(-\frac{4}{5},\frac{4}{5}\right) & f\left(-\frac{2}{5},\frac{4}{5}\right) & f\left(0,\frac{4}{5}\right) & f\left(\frac{2}{5},\frac{4}{5}\right) & f\left(\frac{4}{5},\frac{4}{5}\right) \\ \end{array} \right)$


После того, как элементы матрицы были рассчитаны по формуле, необходимо посчитать их сумму и поделить матрицу на неё. К примеру, если у нас получилась матрица

$\left( \begin{array}{ccc} 1 & 4 & 1 \\ 4 & 20 & 4 \\ 1 & 4 & 1 \\ \end{array} \right)$


то суммой всех её элементов будет 40, и после нормализации она примет вид

$\left( \begin{array}{ccc} \frac{1}{40} & \frac{1}{10} & \frac{1}{40} \\ \frac{1}{10} & \frac{1}{2} & \frac{1}{10} \\ \frac{1}{40} & \frac{1}{10} & \frac{1}{40} \\ \end{array} \right)$


и суммой всех её элементов станет 1.

Линейное затухание


Для начала возьмём самую простую функцию — линию:

$\left\{ \begin{array}{ll} 1-x, & x<1 \\ 0, & x \geqslant 1 \\ \end{array} \right.$




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



Мягкое линейное затухание


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

$1-\frac{n x-x^n}{n-1}$


в которой $n$ определяет «жёсткость» стыковки, $n>1$. Для, например, $n=3$ получим

$\left\{ \begin{array}{ll} 1-\frac{3 x-x^3}{2}, & x<1 \\ 0, & x \geqslant 1 \\ \end{array} \right.$




а сам фильтр будет выглядеть как



Гиперболическое затухание


Фильтр можно сделать более «острым» и более плавно уходящим в ноль, взяв в качестве образующей другую функцию — например, гиперболу, а плавный переход к нулю обеспечив путём суммирования с параболой.



После всех вычислений и упрощений получим формулу

$\left\{ \begin{array}{ll} \frac{(x-1)^2 (k x+k+1)}{(k+1) (k x+1)}, & x<1 \\ 0, & x \geqslant 1 \\ \end{array} \right.$


в которой параметр $k>0$ определяет характер затухания:



а сам фильтр будет выглядеть (для $k=5$) как



Имитация эффекта боке


Можно пойти и другим путём — делать вершину фильтра не острой, а тупой. Наиболее простой способ реализовать это — задать функцию затухания как константу:

$\left\{ \begin{array}{ll} 1, & x<1 \\ 0, & x \geqslant 1 \\ \end{array} \right.$




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

$\left\{ \begin{array}{ll} \left(1-x^n\right)^2, & x<1 \\ 0, & x \geqslant 1 \\ \end{array} \right.$


Варьируя параметр $n$, можно получить широкий спектр вариантов фильтра:

$n=0.5$


$n=2$


$n=10$


$n=50$



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

$\left\{ \begin{array}{ll} \left(1-x^n\right)^2 \left(d+x^m\right), & x<1 \\ 0, & x \geqslant 1 \\ \end{array} \right.$


Здесь параметр $d$ определяет высоту центра, а $m$ — резкость перехода к краям.
Для $d=0.2, m=2, n=10$ получим



а для $d=0, m=12, n=2$



Вариации гауссианы


Можно модифицировать и непосредственно саму функцию гауссианы. Наиболее очевидный способ для этого — параметрировать показатель степени — мы сейчас рассматривать не будем, а возьмём более интересный вариант:

$\left\{ \begin{array}{ll} e^{\frac{k x^2}{x^2-1}}, & -1<x<1 \\ 0, & otherwise \\ \end{array} \right.$


За счёт того, что при $x$ стремящемся к единице знаменатель $x^2-1$ стремится к нулю, дробь $\frac{k x^2}{x^2-1}$ стремится к минус бесконечности, а сама экспонента также стремится к нулю. Таким образом, деление на $x^2-1$ позволяет сжать область определения функции с $(-\infty, \infty)$ до $(-1,1)$. При этом, при $x=\pm 1$ за счёт деления на ноль ($1^2-1=0$) значение функции не определено, но имеет два предела — предел с одной стороны (изнутри) равен нулю, а с другой стороны — бесконечности:

$\underset{x\to 1^-}{\text{lim}}e^{\frac{k x^2}{x^2-1}}=0$


$\underset{x\to 1^+}{\text{lim}}e^{\frac{k x^2}{x^2-1}}=\infty$


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

Параметр $k$ определяет схожесть с гауссианой — чем он больше, тем сильнее получается схожесть — за счёт того, что всё более линейный участок $\frac{1}{x^2-1}$ приходиться на центр функции. Можно было бы предположить, что за счёт этого в пределе можно получить оригинальную гауссиану — но, к сожалению, нет — функции всё-таки разные.



Теперь можно посмотреть, что получилось:

$k=5$


$k=2$


$k=0.5$


$k=0.1$


$k=0.01$



Вариации формы


Изменив функцию перехода от двух координат к одной $\sqrt{x^2+y^2}$, можно получить и другие фигуры, а не только диск. Например:

$f\left(\frac{\left| x-y\right| +\left| x+y\right|}{2}\right)$




$f(\left| x\right| +\left| y\right| )$




Перейдя на комплексные числа, можно конструировать и более сложные фигуры:

$ f\left( \frac{ \left| \Re\left((x+i y) (-1)^{\frac{0}{3}}\right)\right| + \left| \Re\left((x+i y) (-1)^{\frac{1}{3}}\right)\right| + \left| \Re\left((x+i y) (-1)^{\frac{2}{3}}\right)\right| }{\sqrt{3}} \right) $





$f\biggl(10\left| \Re\left((x+i y) (-1)^{\frac{1}{8}}\right)\right|\biggr) \cdot f(\left| x+i y\right|)$




$f\biggl(\biggl| 5 \left| x+i y\right| (x+i y) \Re\biggl(\cos \left(\frac{5}{2} \arg (x+i y)\right)\biggr)\biggr| \biggr) \cdot f(\left| x+i y\right| ) $





При этом нужно следить, чтобы при преобразовании координат не выходить за пределы интервала $(0,1)$ — ну или наоборот, доопределить функцию затухания для отрицательных значений аргумента.

Несколько конкретных примеров


Статья была бы не полной без практического испытания на конкретных изображениях. Поскольку у нас не научная работа, то и изображение Лены мы брать не будем — а возьмём что-нибудь мягкое и пушистое:



Гауссиана




Гиперболическое затухание




Крест




Кольцо




Одностороннее затухание




Те же фильтры, но для текста:








Заключение


Аналогичным образом можно строить и более сложные фильтры, в том числе и с усилением резкости или выделением контуров; а также модифицировать уже рассмотренные.

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

Более подробно вывод функций для стыковки с константой рассматривается здесь. В качестве функции затухания также могут быть использованы оконные функции, рассмотренные здесь — нужно лишь масштабировать аргумент c (0,1) на ($\frac{1}{2}$,1) или изначально считать оконные функции по формуле $\frac{1}{2} \left(f\left(\frac{t x+1}{t-1}\right)-f\left(\frac{t x-1}{t-1}\right)\right)$.

Исходный документ Wolfram Mathematica для этой статьи можно скачать здесь.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 11

    +4
    Изображение Лены мы брать не будем — а возьмём что-нибудь мягкое и пушистое
    А ещё лучше взять что-нибудь с огромным динамическим диапазоном (HDR), тогда работа фильтров раскроется во всей красе!
      0
      Также не стоит забывать про гамма-коррекцию, используемую в стандарте sRGB (и не только в алгоритмах размытия, но и в любых алгоритмах, в которых значение одного пикселя конечного изображения зависит более чем от одного пикселя исходного изображения).
      Картинка
      image
      –1
      Тема раскрыта не полностью.
      Blur не ограничивается матрицами свёртки, при этом, являясь их частным решением.
      Так же — фильтр резкости, по-сути является частной реализацией Blur, но не рассмотрен.
      Более того, сами матрицы свертки суммируются с исходным изображением неправильно.
      Так при наложении фильтра, блендинг выполняется не усреднением исходного значения компонент цветов, а должен выбираться из максимума цветовых компонент буфера-источника и буфера-приемника. Тогда результирующее изображение имеет более «ламповый» и реалистичный вид, избавляясь от пелены (которая, в свою очередь, является погрешностью).
      В дополнении: фильтр должен применяться не сразу к буферу источнику, а считаться в отдельный буфер-приемник, после чего выполняется «Альфа-блендинг» буферов.
      В противном случае, возникает вторая ошибка на этапе применения: данные полученные для текущей строки, учитывают результат предыдущей (уже вычисленной строки).
        +3
        Тема раскрыта не полностью.
        Само собой — об этом сказано прямым текстом в заключении. Сама же статья является tutorial — руководством к конструированию своих собственных фильтров.

        Blur не ограничивается матрицами свёртки, при этом, являясь их частным решением.
        Выражение «матрицами свёртки» некорректно точно так же, как и «матрица сложения» или «число свёртки»; и сама по себе матрица решением чего бы то ни было не является. Свёртка — это математическая операция, в то время как матрица — это данные, упорядоченный набор чисел. В данном случае корректно говорить «ядро свёртки» или хотя бы «матрица фильтра», потому что у нас ещё есть «матрица изображения», которые для операции свёртки совершенно равнозначны.

        Так же — фильтр резкости, по-сути является частной реализацией Blur, но не рассмотрен.
        Фильтр резкости — sharpen — является полной противоположностью размытию и никак не может быть его частной реализацией. Линейный фильтр резкости, как и размытие, как и выделение контуров — хоть и тоже реализуется через свёртку, но это по-прежнему разные типы фильтров.

        Более того, сами матрицы свертки суммируются с исходным изображением неправильно.
        Здесь матрицы не суммируются и не должны суммироваться. Операция свёртки != операция сложения.

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

        Блендинг же — это совершенно отдельная операция, причём между двумя изображениями, а не изображением и ядром фильтра, и реализуются не через свёртку, а через сложение с масштабированием независимо для каждого пикселя.

        В дополнении: фильтр должен применяться не сразу к буферу источнику, а считаться в отдельный буфер-приемник, после чего выполняется «Альфа-блендинг» буферов.
        Непонятно, откуда вы сделали вывод, что в примерах к статье буфер-приёмник не использовался. Более того — при реализации свёртки через дискретное преобразование Фурье без него вполне можно обойтись и даже — в некоторых случаях эта операция может быть обратимой.

        И «Альфа-блендинг» буферов после свёртки выполняться не должен (хотя может, как и множество других операций, включая повторную свёртку).

        В противном случае, возникает вторая ошибка на этапе применения: данные полученные для текущей строки, учитывают результат предыдущей (уже вычисленной строки).
        Фильтры с бесконечной импульсной характеристикой (рекурсивные) именно так и работает — и это не является ошибкой. В этой статье они также не рассматривались, но рассматривались, например, здесь.
        0
        двумерный вариант Gaussian получен её вращением относительно оси ординат

        Извините, но нет! Двумерный вариант Gaussian получается перемножением одномерных функций по двум осям, что и позволяет повсюду безболезненно использовать размытие по Гауссу.
          +1
          Извините, но не соглашусь. То, что выполняется равенство

          — это, конечно, интересное свойство и удобно для вычислений — но является лишь свойством самой экспоненты и на другие функции автоматически не распространяется. Физическим смыслом перехода к двум координатам здесь является именно вращение. Но за замечание спасибо — добавлю уточнение.
            –1
            С вашей стороны странно опустить такое удобное для вычислений свойство, учитывая что тема статьи — как раз обработка сигналов.
            Вращение при потере производительности не дает никаких плюсов в вычислении гауссианы.
            При этом другие представленные фильтры далеко не всегда основаны на вращении.
            И поясните пожалуйста, что такое «физический смысл перехода к двум координатам», как вращение может быть физическим смыслом и причем тут физика, если статья целиком посвящена вычислительной математике.
              0

              Ну как минимум если мы хотим чтоб фильтр был изотропным, то есть не зависил от поворота картинки. То есть если мы повернем картинку и применим фильтр, то результат должен быть таким же, как если применить фильтр и потом повернуть результат. Вот и физический смысл. Оттуда же и вращение. Хотя тема вообще намного более глубокая, я так понимаю. Группы вращения, сферические гармоники, вот это все.

                0
                При повороте на угол, кратный 90 градусам, результат не зависит от порядка поворот<->фильтр для любого фильтра. При повороте на произвольный угол, будет разница для любого фильтра, так как после любой операции идет интерполяция на двумерную сетку.
                Для устранения разницы, изображения должны задаваться и обрабатываться в полярных координатах, но и при этом разницы не будет только при вращении вокруг фиксированного начала координат. Или переходить на векторную графику
            0
            А вот если бы нашей задачей стояла не равномерное размытие во всех направлениях, а разбивка изображения на перекрывающиеся блоки для сжатия с использованием модифицированного косинусного преобразования (рассматриваемое, например, в работе Rikus Muller «Applying the MDCT to Image Compression» (pdf)), вот тогда бы нам потребовалось именно перемножение одномерных оконных функций.
            +1
            С вашей стороны странно опустить такое удобное для вычислений свойство, учитывая что тема статьи — как раз обработка сигналов.
            Упустил потому, что статья посвящена не фильтру Гаусса — а наоборот, всем прочим, а в терминах обработка сигналов это как раз-таки двумерная свёртка, а не две последовательных одномерных.

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

            Only users with full accounts can post comments. Log in, please.