Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an edge preserving blur (similar to a bilateral filter) using a limited set of primitive operations

I have been attempting to duplicate a bilateral filter effect (edge preserving, color-range aware) using the limited set of primitives in the existing toolbox of SVG filters. I've tried a number of approaches. My most successful to date is a three part operation that does Sobel edge detection, dilates the Sobel edges, extracts the pixels corresponding to those edges with a compositing operation, gaussian blurs the source image and then composites back the original edge pixels on top of the blurred image. The result preserves edges, but is not color-range aware.

<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"/>

You can see the original, a gaussianBlur, this filter and in the bottom right, a true bilateral filter:

http://codepen.io/mullany/details/Dbyxt

As you can see, it's not an awful result, but it's not very close to a bilateral filter. This method also only works with greyscale images because it uses luminance differences to find edges - so edges between colors of similar luminance are not detected.

So the question is whether there is a algorithm variant of an edge preserving color range aware filter (guided edge view, bilateral etc.) - that can be constructed using the limited primitives available in SVG - which for those not familiar with SVG are:

  • gaussian blur
  • convolution (any kernel size)
  • erode/dilate
  • color matrix
  • all porter duff compositing operations
  • basic blending ops (multiply, screen, lighten, darken)
  • a component transfer primitive that allows color channels to be transformed with a table lookup (as well as floored/ceilinged to specific values)

Only the RGB color space is available. Multiple iterations are fine, and any directed graph of these operations can be constructed.

Update:

I successfully created a median filter using feBlend lighten and darken as Max and Min operators in a bubble sort (thanks to help from cs.stackexchange.com). However this is inefficient: http://codepen.io/mullany/pen/dmbvz, and lacks the color range awareness of a bilateral filter.

like image 837
Michael Mullany Avatar asked Dec 23 '13 03:12

Michael Mullany


2 Answers

I should qualify this by saying I have no experience in graphics whatsoever, but from a maths perspective I think this would work to emulate the equation that defines the bilateral filter:

  • Given your image I, use the color matrix to produce an image Intensity which holds the intensity of each pixel in a single channel, say R. Channels G and B are zeroed out.

  • For each non-central pixel in your bilateral filter window, construct a convolution matrix which takes the difference between the specific pixel and the central pixel. For example, for a 3x3 window you'd have matrices

     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
    

    You can scale the 1s and -1s here as necessary to emulate the spatial kernel of the bilateral filter.

  • Apply each convolution matrix to the Intensity map, getting (in the 3x3 example) 8 images which represent the change in intensity between a central pixel and its neighbours.

  • For each of the 8 images, apply a component transfer primative to R with a table that emulates the range kernel of the bilateral filter.

  • Use another color matrix to set the G and B channels to match the R channel in all 8 images.

  • Use the multiply operator on each of the 8 and the original image to get 8 new images which represent the 8 terms in the bilateral filter's sum.

  • Use the Porter-Duff operators to superimpose the 8 images, effectively taking a sum of the 8 terms in the bilateral filter. This gives you the final image.

like image 174
Andy Jones Avatar answered Oct 29 '22 01:10

Andy Jones


Have a look at the guided filter.

http://research.microsoft.com/en-us/um/people/kahe/eccv10/

like image 40
YXD Avatar answered Oct 29 '22 01:10

YXD