Skip to content

Commit 1338fa9

Browse files
authored
add a demo for median filters (#185)
* create examples section * build docs with julia 1.x
1 parent 35c0a41 commit 1338fa9

File tree

6 files changed

+124
-4
lines changed

6 files changed

+124
-4
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*.jl.mem
44
docs/build
55
docs/site
6+
docs/Manifest.toml
7+
docs/src/democards
68
/Manifest.toml
79
/.benchmarkci
810
/benchmark/*.json

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Until https://github.com/julia-actions/julia-uploadcodecov/issues/1 get fixed
22
# submit coverage report via travis
33
language: julia
4-
julia: 1.0
4+
julia: 1
55
os: linux
66
notifications:
77
email: false

docs/Project.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
[deps]
2+
DemoCards = "311a05b2-6137-4a5a-b473-18580a3d38b5"
23
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
4+
ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534"
5+
ImageFiltering = "6a3955dd-da59-5b1f-98d4-e7296123deb5"
6+
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
7+
ImageShow = "4e3cecfd-b093-5904-9786-8bbb286a6a31"
8+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
9+
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
10+
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
311

412
[compat]
13+
DemoCards = "0.3"
514
Documenter = "0.24"

docs/demos/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"title": "Examples",
3+
"theme": "grid"
4+
}

docs/demos/filters/median_filter.jl

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# ---
2+
# title: Custom median filters
3+
# cover: assets/median.gif
4+
# author: Johnny Chen
5+
# date: 2020-09-23
6+
# ---
7+
8+
# With median filter as an example, this demo shows how you could construct a custom kernel and
9+
# pass it to [`mapwindow`](@ref) for common stencil operations.
10+
11+
# Unlike other image processing toolboxes, `ImageFiltering.jl` does not provide you an out-of-box
12+
# function for median filters. It instead provides the more general [`mapwindow`](@ref) function,
13+
# which allows you to apply any function to the window around each pixel.
14+
15+
using ImageFiltering, ImageCore, ImageShow # or you could just `using Images`
16+
using TestImages
17+
using Statistics
18+
using Random #hide
19+
Random.seed!(0) #hide
20+
21+
img = Float64[isodd(i) - isodd(j) for i = 1:5, j = 1:5]
22+
img[3, 3] = 1000
23+
img #hide #md
24+
25+
#-
26+
27+
patch_size = (3, 3)
28+
imgm = mapwindow(median, img, patch_size)
29+
30+
# `mapwindow` provides a high-level interface to loop over the image and call a function (`median`
31+
# in this demo) on each patch/window. It's performing an operation that is nearly equivalent to the
32+
# loop below, albeit more efficiently:
33+
34+
## For simplicity, border condition is not included here.
35+
imgm = zeros(axes(img))
36+
R = CartesianIndices(img)
37+
I_first, I_last = first(R), last(R)
38+
Δ = CartesianIndex(patch_size 2)
39+
for I in R
40+
patch = max(I_first, I-Δ):min(I_last, I+Δ)
41+
imgm[I] = median(img[patch])
42+
end
43+
imgm
44+
45+
# Compared to this hand-written loop, `mapwindow` offers additional flexibility in handling the
46+
# borders and allows you to process only a subset of the windows. For some functions (e.g., `min`,
47+
# `max`, and `extrema`), `mapwindow` uses a custom implementation that is far more efficient than
48+
# naively computing the function "freshly" on each window.
49+
50+
# When the input array has `NaN` or some unwanted pixel values, a pre-filtering process is needed to
51+
# exclude them first. This can be done quite easily by compositing a given kernel operation and a
52+
# `filter` operation. Let's still take `median` filter as an example.
53+
54+
img[2,2] = NaN
55+
imgm = mapwindow(median, img, (3,3))
56+
57+
# `NaN` has polluted the output, which is usually not wanted. This can be fixed quite easily by
58+
# compositing a new filter kernel. This way, we only compute the median value on the non-NaN subset
59+
# of each patch/window.
60+
61+
_median(patch) = median(filter(x->!isnan(x), patch))
62+
imgm = mapwindow(_median, img, patch_size)
63+
64+
65+
# ## Impulse (Salt and Pepper) noise removal
66+
67+
# Median filters are quite robust to outliers (unusual values), this property can be used to remove
68+
# salt&pepper noise. An image with `n`-level salt&papper noise is defined as: each pixel `p` has
69+
# `n/2` probabilty to be filled by `0`(the minimal gamut value), `n/2` probabilty to be filled by
70+
# `1`(the maximal gamut value), and `1-n` probablity to be undamaged.
71+
72+
img = testimage("cameraman")
73+
74+
n = 0.2 # noise level
75+
noisy_img = map(img) do p
76+
sp = rand()
77+
if sp < n/2
78+
eltype(img)(gamutmin(eltype(img))...)
79+
elseif sp < n
80+
eltype(img)(gamutmax(eltype(img))...)
81+
else
82+
p
83+
end
84+
end
85+
86+
denoised_img = mapwindow(median!, noisy_img, (5, 5))
87+
88+
mosaicview(img, noisy_img, denoised_img; nrow=1)
89+
90+
91+
## save covers #src
92+
using ImageMagick #src
93+
mkpath("assets") #src
94+
ImageMagick.save("assets/median.gif", cat(noisy_img, denoised_img; dims=3); fps=1) #src

docs/make.jl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
1-
using Documenter, ImageFiltering
1+
using Documenter, DemoCards
2+
using ImageFiltering
3+
4+
demos, demos_cb, demos_assets = makedemos("demos")
5+
6+
assets = []
7+
isnothing(demos_assets) || (push!(assets, demos_assets))
8+
format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true",
9+
assets = assets)
210

311
makedocs(
412
modules = [ImageFiltering, Kernel, KernelFactors, ImageFiltering.MapWindow],
5-
format = Documenter.HTML(),
13+
format = format,
614
sitename = "ImageFiltering",
715
pages = [
8-
"index.md",
16+
"index.md",
17+
demos,
918
"Function reference" => "function_reference.md"
1019
]
1120
)
1221

22+
demos_cb()
23+
1324
deploydocs(
1425
repo = "github.com/JuliaImages/ImageFiltering.jl.git",
1526
push_preview = true

0 commit comments

Comments
 (0)