From fae59c0db72044d92209b663e5e34fe3744cced6 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 4 Sep 2021 08:42:43 -0500 Subject: [PATCH 1/3] Add `box` and `laplacian2d` These come from Images.jl and are part of moving most/all code out to make it a meta-package. --- src/kernel.jl | 42 ++++++++++++++++++++++++++++++++++++++++++ src/kernelfactors.jl | 13 +++++++++++++ test/specialty.jl | 11 +++++++++++ 3 files changed, 66 insertions(+) diff --git a/src/kernel.jl b/src/kernel.jl index e1e1797..9349247 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -36,6 +36,14 @@ function product2d(kf) k1[1].*k1[2], k2[1].*k2[2] end +""" + kern = box(m, n) + kern = box((m, n, ...)) + +Return a box kernel computing a moving average. `m, n, ...` specify the size of the kernel, which is centered around zero. +""" +box(sz::Dims) = broadcast(*, KernelFactors.box(sz)...) + """ ```julia diff1, diff2 = sobel() @@ -380,6 +388,40 @@ function Base.convert(::Type{AbstractArray}, L::Laplacian{N}) where N end _reshape(L::Laplacian{N}, ::Val{N}) where {N} = L +""" + laplacian2d(alpha::Number) + +Construct a weighted discrete Laplacian approximation in 2d. `alpha` controls the weighting of the faces +relative to the corners. + +# Examples + +```jldoctest +julia> Kernel.laplacian2d(0) # the standard Laplacian +3×3 OffsetArray(::Matrix{Float64}, -1:1, -1:1) with eltype Float64 with indices -1:1×-1:1: + 0.0 1.0 0.0 + 1.0 -4.0 1.0 + 0.0 1.0 0.0 + +julia> Kernel.laplacian2d(1) # a corner-focused Laplacian +3×3 OffsetArray(::Matrix{Float64}, -1:1, -1:1) with eltype Float64 with indices -1:1×-1:1: + 0.5 0.0 0.5 + 0.0 -2.0 0.0 + 0.5 0.0 0.5 + +julia> Kernel.laplacian2d(0.5) # equal weight for face-pixels and corner-pixels. +3×3 OffsetArray(::Matrix{Float64}, -1:1, -1:1) with eltype Float64 with indices -1:1×-1:1: + 0.333333 0.333333 0.333333 + 0.333333 -2.66667 0.333333 + 0.333333 0.333333 0.333333 +``` +""" +function laplacian2d(alpha::Number=0) + lc = alpha/(1 + alpha) + lb = (1 - alpha)/(1 + alpha) + lm = -4/(1 + alpha) + return centered([lc lb lc; lb lm lb; lc lb lc]) +end """ gabor(size_x,size_y,σ,θ,λ,γ,ψ) -> (k_real,k_complex) diff --git a/src/kernelfactors.jl b/src/kernelfactors.jl index 704e80d..8e8f6e3 100644 --- a/src/kernelfactors.jl +++ b/src/kernelfactors.jl @@ -3,6 +3,7 @@ each stored in terms of their factors. The following kernels are supported: + - `box` - `sobel` - `prewitt` - `ando3`, `ando4`, and `ando5` (the latter in 2d only) @@ -148,6 +149,18 @@ end #### FIR filters +""" + kern1, kern2 = box(m, n) + kerns = box((m, n, ...)) + +Return a tuple of "flat" kernels, where, for example, `kern1[i] == 1/m` and has length `m`. +""" +function box(sz::Dims) + all(isodd, sz) || throw(ArgumentError("kernel dimensions must be odd, got $sz")) + return kernelfactors(ntuple(d -> centered([1/sz[d] for i=1:sz[d]]), length(sz))) +end +box(sz::Int...) = box(sz) + ## gradients """ diff --git a/test/specialty.jl b/test/specialty.jl index b7790bd..f9bf1ed 100644 --- a/test/specialty.jl +++ b/test/specialty.jl @@ -150,6 +150,17 @@ using ImageFiltering: IdentityUnitRange z z z z edgecoef*c] end end + # The doctests seem adequate for laplacian2d + end + + @testset "box" begin + @test KernelFactors.box(3) == (centered([1/3, 1/3, 1/3]),) + @test KernelFactors.box(3, 5) == (centered(reshape([1/3, 1/3, 1/3], 3, 1)), centered([1/5, 1/5, 1/5, 1/5, 1/5]')) + @test KernelFactors.box((3,5,7)) == KernelFactors.box(3, 5, 7) + @test Kernel.box((3,)) == centered([1/3, 1/3, 1/3]) + @test Kernel.box((3, 5)) == centered([1/3, 1/3, 1/3] .* [1/5, 1/5, 1/5, 1/5, 1/5]') + @test_throws ArgumentError KernelFactors.box((3, 4, 5)) + @test_throws ArgumentError Kernel.box((3, 4, 5)) end @testset "gaussian" begin From 5ed6c11940b1287609097958a5bd8c91d7470cbc Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 4 Sep 2021 09:24:35 -0500 Subject: [PATCH 2/3] improve test coverage --- test/specialty.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/specialty.jl b/test/specialty.jl index f9bf1ed..83a90bc 100644 --- a/test/specialty.jl +++ b/test/specialty.jl @@ -150,7 +150,9 @@ using ImageFiltering: IdentityUnitRange z z z z edgecoef*c] end end - # The doctests seem adequate for laplacian2d + @test Kernel.laplacian2d(0.5) ≈ centered([ 1/3 1/3 1/3; + 1/3 -8/3 1/3; + 1/3 1/3 1/3]) end @testset "box" begin From e12a6ad642711642aa9c55b7bc4629207f93b27d Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sun, 5 Sep 2021 16:51:04 -0500 Subject: [PATCH 3/3] fix docstring --- src/kernel.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernel.jl b/src/kernel.jl index 9349247..7aee08c 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -37,12 +37,13 @@ function product2d(kf) end """ - kern = box(m, n) kern = box((m, n, ...)) Return a box kernel computing a moving average. `m, n, ...` specify the size of the kernel, which is centered around zero. """ box(sz::Dims) = broadcast(*, KernelFactors.box(sz)...) +# We don't support box(m::Int...) mostly because of `gaussian(σ::Real) = gaussian((σ, σ))` defaulting to +# isotropic 2d rather than a 1d Gaussian. """ ```julia