Как создать размытие, сохраняющее края (аналогично двустороннему фильтру), используя ограниченный набор примитивных операций
Я пытаюсь дублировать эффект двустороннего фильтра (сохранение краев, диапазон значений цвета), используя ограниченный набор примитивов в существующем наборе инструментов фильтров SVG. Я пробовал несколько подходов. Моей самой успешной на сегодняшний день является операция с тремя частями, которая делает обнаружение края Sobel, расширяет границы Sobel, извлекает пиксели, соответствующие этим краям, с помощью операции компоновки, gaussian размывает исходное изображение, а затем компонует обратно исходные пиксели пикселей поверх размытое изображение. Результат сохраняет ребра, но не знает о цветовых диапазонах.
<filter id="surfaceBlur" color-interpolation-filters="sRGB">
<!-- convert source image to luminance map-->
<feColorMatrix type="luminanceToAlpha" />
<!-- sober edge detection-->
<feConvolveMatrix order="3" kernelMatrix="-1 -2 -1
0 0 0
1 2 1 "
preserveAlpha="true"
/>
<feConvolveMatrix order="3" kernelMatrix="-1 0 1
-2 0 2
-1 0 1 "
preserveAlpha="true"
/>
<!-- dilate the edges to produce a wider mask-->
<feMorphology operator="dilate" radius="1"
result="mask"/>
<!-- extract just the detail from the source graphic using the dilated edges -->
<feComposite operator="in" in="SourceGraphic" in2="mask" result="detail" />
<!-- blur the source image -->
<feGaussianBlur stdDeviation="3" in="SourceGraphic" result="backblur"/>
<!-- slap the detail back on top of the blur! -->
<feComposite operator="over" in="detail" in2="backblur"/>
Вы можете увидеть оригинал, gaussianBlur, этот фильтр и в правом нижнем углу, настоящий двусторонний фильтр:
http://codepen.io/mullany/details/Dbyxt
Как вы можете видеть, это не ужасный результат, но он не очень близок к двустороннему фильтру. Этот метод также работает только с изображениями с оттенками серого, поскольку он использует различия яркости для поиска краев - поэтому края между цветами подобной яркости не обнаружены.
Итак, вопрос заключается в том, существует ли алгоритм варианта сохраняющего края диапазона цветового диапазона (ориентированный вид края, двусторонний и т.д.), который может быть построен с использованием ограниченных примитивов, доступных в SVG - для тех, кто не знаком с SVG являются:
- gaussian blur
- свертка (любой размер ядра)
- разъедать/Разбавить
- цветная матрица
- все операции компоновки сапогов портера
- основные операции смешивания (умножение, экран, осветление, затемнение)
- примитив переноса компонента, который позволяет преобразовывать цветовые каналы с помощью поиска в таблице (а также перекрывать/перекрывать определенные значения).
Доступно только цветовое пространство RGB. Многочисленные итерации прекрасны, и любой ориентированный граф этих операций может быть построен.
Update:
Я успешно создал срединный фильтр, используя feBlend lighten и затемненный как операторы Max и Min в сортировке пузырьков (благодаря помощи cs.stackexchange.com). Однако это неэффективно: http://codepen.io/mullany/pen/dmbvz и не имеет понимания цветового диапазона двустороннего фильтра.
Ответы
Ответ 1
Я должен квалифицировать это, говоря, что у меня нет опыта в графике, но с точки зрения математики я думаю, что это сработает, чтобы подражать уравнение, которое определяет двусторонний фильтр:
-
С учетом вашего изображения I
используйте цветовую матрицу для создания изображения Intensity
, которое содержит интенсивность каждого пикселя в одном канале, скажем R. Каналы G и B обнуляются.
-
Для каждого нецентрального пикселя в вашем двустороннем окне фильтра создайте матрицу свертки, которая принимает разницу между конкретным пикселем и центральным пикселем. Например, для окна 3x3 у вас есть матрицы
0 0 0 -1 0 0 0-1 0 0 0-1 0 0 0 0 0 0 0 0 0 0 0 0
-1 1 0 0 1 0 0 1 0 0 1 0 0 1-1 0 1 0 0 1 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-1 0-1 0 -1 0 0
Вы можете масштабировать 1
и -1
здесь, если необходимо, для эмуляции пространственного ядра двустороннего фильтра.
-
Примените каждую матрицу свертки к карте Intensity
, получив (в примере 3x3) 8 изображений, которые представляют изменение интенсивности между центральным пикселем и его соседями.
-
Для каждого из 8 изображений примените примитив переноса компонента к R с таблицей, которая эмулирует ядро диапазона двустороннего фильтра.
-
Используйте другую цветовую матрицу для установки каналов G и B в соответствии с R-каналом на всех 8 изображениях.
-
Используйте оператор умножения для каждого из 8 и исходного изображения, чтобы получить 8 новых изображений, которые представляют 8 членов в сумме двустороннего фильтра.
-
Используйте операторы Porter-Duff для наложения 8 изображений, эффективно беря сумму 8 членов в двустороннем фильтре. Это дает окончательное изображение.
Ответ 2
Посмотрите на управляемый фильтр.
http://research.microsoft.com/en-us/um/people/kahe/eccv10/
Ответ 3
Вот как это сделать, используя чисто обработку изображений: -
-
Используйте Unsharp masking (он в основном затачивает края).
Unsharp Masking
Это можно сделать, добавив лапласиан исходного изображения к исходному изображению.
-
Используйте размытие на заостренном изображении.
Концепция заключается в том, что, поскольку размытие уменьшает интенсивность ребер, поэтому мы увеличиваем интенсивность всех острых краев, а затем применяем размытие, нейтрализующее эффект.
Примечание:. У меня нет идеи маскировки SVG.
Ответ 4
В следующем документе объясняется, как реализовать постоянное временное приближение двустороннего фильтра с использованием интерполяции пространственных фильтров на разных уровнях интенсивности пикселей (только интерполяция + гауссовские фильтры):
[Qingxiong Yang, Kar-Han Tan и Narendra Ahuja, в режиме реального времени O (1) Двусторонняя фильтрация,
Конференция IEEE по распознаванию компьютеров и распознаванию образов (CVPR) 2009]
Реализация java существует здесь: https://code.google.com/p/kanzi/source/browse/java/src/kanzi/filter/FastBilateralFilter.java
Чтобы увидеть результаты фильтра:
java -cp kanzi.jar kanzi.test.TestEffects -filter=FastBilateral -file=...
Оригинальный код C и другие лакомства доступны на http://www.cs.cityu.edu.hk/~qiyang
Ответ 5
Хотя ответ уже принят и вознагражден наградой, я хотел бы попробовать алгоритм анизотропной диффузии. Он применяет закон диффузии на интенсивности пикселей, чтобы сгладить текстуры изображения. Предотвращение диффузии по краям предотвращается и, следовательно, сохраняет края изображения.
Я не очень хорошо знаком с SVG и просто написал очень простой код в Matlab по изображению на сером. Но я предполагаю, что это возможно в SVG, потому что требуются только базовые разностные операции (разница между пикселями i+1
и i
во всех четырех направлениях) и операциями включения/выключения питания.
Код:
diff = I; % original image
lambda = 0.25;
niter = 10;
Co = 20;
for i = 1:niter % iterations
% Construct diffl which is the same as diff but
% has an extra padding of zeros around it.
diffl = zeros(rows+2, cols+2);
diffl(2:rows+1, 2:cols+1) = diff;
% North, South, East and West differences
deltaN = diffl(1:rows,2:cols+1) - diff;
deltaS = diffl(3:rows+2,2:cols+1) - diff;
deltaE = diffl(2:rows+1,3:cols+2) - diff;
deltaW = diffl(2:rows+1,1:cols) - diff;
cN = 1./(1 + (deltaN/Co).^2);
cS = 1./(1 + (deltaS/Co).^2);
cE = 1./(1 + (deltaE/Co).^2);
cW = 1./(1 + (deltaW/Co).^2);
diff = diff + lambda*(cN.*deltaN + cS.*deltaS + cE.*deltaE + cW.*deltaW);
end
Полученный результат:
![enter image description here]()
Надеюсь, это поможет. Благодаря