|
| 1 | +# --- |
| 2 | +# title: Max min filters |
| 3 | +# cover: assets/max_min.gif |
| 4 | +# author: Deeptendu Santra |
| 5 | +# date: 2020-10-08 |
| 6 | +# --- |
| 7 | + |
| 8 | +# In this tutorial we see how can we can effectively use max and min filter to distinguish |
| 9 | +# between smooth and texture edges in grayscale images. |
| 10 | + |
| 11 | +# We will use the [`mapwindow`](@ref) function in `ImageFiltering.jl` which provides a general |
| 12 | +# functionality to apply any function to the window around each pixel. |
| 13 | + |
| 14 | +using ImageCore, ImageShow, ImageFiltering |
| 15 | +using TestImages |
| 16 | + |
| 17 | +img = Gray.(testimage("house");) # Original Image |
| 18 | + |
| 19 | +# We can use the `minimum` function to compute the minimum of the grayscale values in the given |
| 20 | +# matrix or array. For example: |
| 21 | +minimum([Gray(0.7),Gray(0.5),Gray(0.0)]) # Should return Gray(0.0) i.e black. |
| 22 | +# |
| 23 | +filter_size = (15, 15) |
| 24 | +## Using the `mapwindow` function, we create an image of the local minimum. |
| 25 | +## `mapwindow` maps the given function over a moving window of given size. |
| 26 | +img_min = mapwindow(minimum, img, filter_size) |
| 27 | +## Similarly for maximum |
| 28 | +img_max = mapwindow(maximum, img, filter_size) |
| 29 | +## The max(min) filter |
| 30 | +img_max_min = mapwindow(maximum, img_min, filter_size) |
| 31 | +## The min(max) filter |
| 32 | +img_min_max = mapwindow(minimum, img_max, filter_size) |
| 33 | +mosaicview(img_min, img_max, img_max_min, img_min_max; nrow=1) |
| 34 | + |
| 35 | +# Now that we are done with the basic filtered images, we proceed to the next part |
| 36 | +# which is edge detection using these filters. |
| 37 | + |
| 38 | +# For edge detection, we need to define thresholds for our image. The threshold is an important tool |
| 39 | +# to binarize a grayscale image. The threshold value for a given pixel practically |
| 40 | +# decides if the pixel visible or not in the output image. However, appyling a global threshold might not consider the |
| 41 | +# variation of colors/brightness within the image. Thus we consider an adaptive type theresholding method |
| 42 | +# here using max/min results. |
| 43 | + |
| 44 | +# The max(min) and min(max) filter effectively follows the smooth edges of the image. Therefore, |
| 45 | +# their average also follows the smooth parts of the image. If we use this image as a threshold for the original |
| 46 | +# image, the smooth parts of the original image will get filtered out, leaving only the texture and/or noise behind. |
| 47 | +# So we can use the average of `img_max_min` and `img_min_max` as the texture threshold. |
| 48 | + |
| 49 | +# The average of min and max filters also gives us the smooth edges, but it also includes the noise in the image. |
| 50 | +# So using average of `img_min` and `img_max` as a threshold will yeild only texture. |
| 51 | + |
| 52 | +img_texture_noise_threshold = (img_max_min + img_max_min) ./ 2 |
| 53 | +img_texture_threshold = (img_max + img_min) ./ 2 |
| 54 | +mosaicview(img_texture_noise_threshold, img_texture_threshold; nrow=1) |
| 55 | +# |
| 56 | +## The Dynamic Gist is obtained by subtracting the img_texture_threshold from the original image. |
| 57 | +## The filtered image gives us the texture of the image. |
| 58 | +img_dynamic_gist = img - img_texture_threshold |
| 59 | +## The Texture Gist is obtained by subtracting img_texture_noise_threshold from the original image. |
| 60 | +## The filtered image gives us the texture along with the noise of the image. |
| 61 | +img_texture_gist = img - img_texture_noise_threshold |
| 62 | +mosaicview(img_dynamic_gist, img_texture_gist; nrow=1) |
| 63 | +# |
| 64 | +## We extract out the smooth/ramp parts of the image. |
| 65 | +## The darker section of the image consist of the ramp edges. The brighter pixels are mostly noise. |
| 66 | +ramp = img_dynamic_gist - img_texture_gist |
| 67 | +## Filtered-out edges |
| 68 | +edge = img_max - img_min |
| 69 | +## Smoothed-out version of edge |
| 70 | +edge_smoothed = img_min_max - img_max_min |
| 71 | +mosaicview(img, ramp, edge, edge_smoothed; nrow=2) |
| 72 | + |
| 73 | +# # References |
| 74 | + |
| 75 | +# Verbeek, P. W., Vrooman, H. A., & Van Vliet, L. J. (1988). [Low-level image processing by max-min filters](https://core.ac.uk/download/pdf/194053536.pdf). Signal Processing, 15(3), 249-258. |
| 76 | + |
| 77 | +## save covers #src |
| 78 | +using ImageMagick #src |
| 79 | +mkpath("assets") #src |
| 80 | +ImageMagick.save("assets/max_min.gif", cat(img, edge, edge_smoothed, map(clamp01nan, ramp);dims=3);fps=1) #src |
0 commit comments