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

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

Ответ 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

Надеюсь, это поможет. Благодаря