From b2428785845e7921b3ff0c451f32ace6120b9235 Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Sun, 25 Feb 2018 19:44:35 +0530 Subject: [PATCH 1/9] Added function to construct 2D Gabor kernel. --- src/kernel.jl | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/kernel.jl b/src/kernel.jl index f19f574..bfc7d38 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -11,6 +11,7 @@ dimensionality. The following kernels are supported: - `DoG` (Difference-of-Gaussian) - `LoG` (Laplacian-of-Gaussian) - `Laplacian` + - `gabor` See also: [`KernelFactors`](@ref). """ @@ -295,7 +296,7 @@ end """ Laplacian((true,true,false,...)) Laplacian(dims, N) - Lacplacian() + Laplacian() Laplacian kernel in `N` dimensions, taking derivatives along the directions marked as `true` in the supplied tuple. Alternatively, one @@ -328,6 +329,54 @@ function Base.convert(::Type{AbstractArray}, L::Laplacian{N}) where N end _reshape(L::Laplacian{N}, ::Type{Val{N}}) where {N} = L + +""" + gabor(k_size,σ,θ,λ,γ,ψ) -> k + +Constructs a 2 Dimensional Gabor kernel where + k_size is the size of the kernel; + σ is the standard deviation of the Gaussian envelope; + θ represents the orientation of the normal to the parallel stripes of a Gabor function; + λ represents the wavelength of the sinusoidal factor; + γ is the spatial aspect ratio, and specifies the ellipticity of the support of the Gabor function; + ψ is the phase offset. +""" +function gabor(k_size::Integer, σ::Real, θ::Real, λ::Real, γ::Real, ψ::Real) + + σx = σ + σy = σ/γ + nstds = 3 + c = cos(θ) + s = sin(θ) + + if(k_size > 0) + xmax = floor(Int64,k_size/2) + ymax = floor(Int64,k_size/2) + else + xmax = round(Int64,max(abs(nstds*σx*c),abs(nstds*σy*s))) + ymax = round(Int64,max(abs(nstds*σx*s),abs(nstds*σy*c))) + end + xmin = -xmax + ymin = -ymax + + kernel = Array{Float64}(ymax - ymin + 1, xmax - xmin + 1) + scale = Float64(1) + ex = -0.5/(σx*σx) + ey = -0.5/(σy*σy) + cscale = 2*π/λ + + for y = ymin:ymax + for x = xmin:xmax + xr = x*c + y*s + yr = -x*s + y*c + v = scale*exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + ψ) + kernel[ymax-y+1,xmax-x+1] = v + end + end + + return kernel +end + """ reflect(kernel) --> reflectedkernel From cbd9a972c4f79ff976c7acb20759663bb49fbf1d Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Sun, 25 Feb 2018 19:45:52 +0530 Subject: [PATCH 2/9] Added gabor to ImageFiltering.jl --- src/ImageFiltering.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageFiltering.jl b/src/ImageFiltering.jl index f9a6b4d..dcec3aa 100644 --- a/src/ImageFiltering.jl +++ b/src/ImageFiltering.jl @@ -53,7 +53,7 @@ ArrayLike{T} = Union{ArrayType{T}, AnyIIR{T}} include("kernel.jl") using .Kernel -using .Kernel: Laplacian, reflect, ando3, ando4, ando5, scharr, bickley, prewitt, sobel +using .Kernel: Laplacian, reflect, ando3, ando4, ando5, scharr, bickley, prewitt, sobel, gabor NDimKernel{N,K} = Union{AbstractArray{K,N},ReshapedOneD{K,N},Laplacian{N}} From c8ce42955f234d57267da1c8bca29b16d6363fc3 Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Sun, 4 Mar 2018 03:32:18 +0530 Subject: [PATCH 3/9] Modified gabor function to include imaginary part of the filter. --- src/kernel.jl | 61 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/kernel.jl b/src/kernel.jl index bfc7d38..cc19d8c 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -331,17 +331,33 @@ _reshape(L::Laplacian{N}, ::Type{Val{N}}) where {N} = L """ - gabor(k_size,σ,θ,λ,γ,ψ) -> k + gabor(size_x,size_y,σ,θ,λ,γ,ψ) -> (k_real,k_complex) -Constructs a 2 Dimensional Gabor kernel where - k_size is the size of the kernel; +Returns a 2 Dimensional Complex Gabor kernel contained in a tuple where + + size_x,size_y is the size of the kernel; σ is the standard deviation of the Gaussian envelope; θ represents the orientation of the normal to the parallel stripes of a Gabor function; λ represents the wavelength of the sinusoidal factor; γ is the spatial aspect ratio, and specifies the ellipticity of the support of the Gabor function; ψ is the phase offset. + +#Citation +N. Petkov and P. Kruizinga, “Computational models of visual neurons specialised in the detection of periodic and aperiodic oriented visual stimuli: bar and grating cells,” Biological Cybernetics, vol. 76, no. 2, pp. 83–96, Feb. 1997. doi.org/10.1007/s004220050323 """ -function gabor(k_size::Integer, σ::Real, θ::Real, λ::Real, γ::Real, ψ::Real) +function gabor(size_x::Integer, size_y::Integer, σ::Real, θ::Real, λ::Real, γ::Real, ψ::Real) + + function validate_gabor(σ,λ,γ) + if(σ>0 && λ>0 && γ>0) + return true + else + return false + end + end + + if(!validate_gabor(σ,λ,γ)) + error("Invalid Input Parameters!") + end σx = σ σy = σ/γ @@ -349,31 +365,30 @@ function gabor(k_size::Integer, σ::Real, θ::Real, λ::Real, γ::Real, ψ::Real c = cos(θ) s = sin(θ) - if(k_size > 0) - xmax = floor(Int64,k_size/2) - ymax = floor(Int64,k_size/2) + if(size_x > 0) + xmax = floor(Int64,size_x/2) else - xmax = round(Int64,max(abs(nstds*σx*c),abs(nstds*σy*s))) - ymax = round(Int64,max(abs(nstds*σx*s),abs(nstds*σy*c))) + xmax = round(Int64,max(abs(nstds*σx*c),abs(nstds*σy*s),1)) end + + if(size_y > 0) + ymax = floor(Int64,size_y/2) + else + ymax = round(Int64,max(abs(nstds*σx*s),abs(nstds*σy*c),1)) + end + xmin = -xmax ymin = -ymax - kernel = Array{Float64}(ymax - ymin + 1, xmax - xmin + 1) - scale = Float64(1) - ex = -0.5/(σx*σx) - ey = -0.5/(σy*σy) - cscale = 2*π/λ - - for y = ymin:ymax - for x = xmin:xmax - xr = x*c + y*s - yr = -x*s + y*c - v = scale*exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + ψ) - kernel[ymax-y+1,xmax-x+1] = v - end - end + x = [j for i in xmin:xmax,j in ymin:ymax] + y = [i for i in xmin:xmax,j in ymin:ymax] + xr = x*c + y*s + yr = -x*s + y*c + + kernel_real = (exp.(-0.5*(((xr.*xr)/σx^2) + ((yr.*yr)/σy^2))).*cos.(2*(π/λ)*xr + ψ)) + kernel_imag = (exp.(-0.5*(((xr.*xr)/σx^2) + ((yr.*yr)/σy^2))).*sin.(2*(π/λ)*xr + ψ)) + kernel = (kernel_real,kernel_imag) return kernel end From ef75994cee51946e0dcaeff298582ed8e6642ebd Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Sun, 4 Mar 2018 03:34:31 +0530 Subject: [PATCH 4/9] Added tests for gabor filter function. --- test/gabor.jl | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 1 + 2 files changed, 49 insertions(+) create mode 100644 test/gabor.jl diff --git a/test/gabor.jl b/test/gabor.jl new file mode 100644 index 0000000..13e878d --- /dev/null +++ b/test/gabor.jl @@ -0,0 +1,48 @@ +using ImageFiltering, Base.Test + +@testset "gabor" begin + σx = 8 + σy = 12 + size_x = 6*σx+1 + size_y = 6*σy+1 + γ = σx/σy + kernel = Kernel.gabor(0,0,σx,0,5,γ,0) + @test isequal(size(kernel[1]),(size_x,size_y)) + kernel = Kernel.gabor(0,0,σx,π,5,γ,0) + @test isequal(size(kernel[1]),(size_x,size_y)) + + for x in 0:4, y in 0:4, z in 0:4, t in 0:4 + σx = 2*x+1 + σy = 2*y+1 + λ = 2*z+1 + γ = σx/σy + θ = 2*t+1 + kernel1 = Kernel.gabor(9,9,σx,θ,λ,γ,0) + kernel2 = Kernel.gabor(9,9,σx,θ+π,λ,γ,0) + @test abs(sum(kernel1[1] - kernel2[1])) < 1e-2 + @test abs(sum(kernel1[2] - kernel2[2])) < 1e-2 + end + + x = [j for i in 0:49,j in 0:49] + wavelengths = (3, 10) + images = [sin.(2*π*x/λ) for λ in wavelengths] + σx = 4 + σy = 5 + function match_score(image, λ) + gabor_real = imfilter(image,centered(Kernel.gabor(6*σx+1,6*σy+1,σx,0,λ,σx/σy,0)[1]),[border="replicate"]) + gabor_imag = imfilter(image,centered(Kernel.gabor(6*σx+1,6*σy+1,σx,0,λ,σx/σy,0)[2]),[border="replicate"]) + gabor_result = sqrt.((gabor_real.*gabor_real) + (gabor_imag.*gabor_imag)) + return mean(gabor_result) + end + rabor_result = rand(Float64,2,2) + for i = 1:2 + for j = 1:2 + rabor_result[i,j] = match_score(images[i],wavelengths[j]) + end + end + @test rabor_result[1,1] > rabor_result[1,2] + @test rabor_result[2,2] > rabor_result[1,2] + @test rabor_result[1,1] > rabor_result[2,1] + @test rabor_result[2,2] > rabor_result[2,1] + +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index c8b124d..c43170d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -14,5 +14,6 @@ include("specialty.jl") include("gradient.jl") include("mapwindow.jl") include("basic.jl") +include("gabor.jl") nothing From 02fdf8302f4d09928069923dcbaa46d467fa42ea Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Mon, 5 Mar 2018 19:01:37 +0530 Subject: [PATCH 5/9] Modified gabor function and placed validate_gabor outside of gabor. --- src/kernel.jl | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/kernel.jl b/src/kernel.jl index cc19d8c..452d7ba 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -347,24 +347,14 @@ N. Petkov and P. Kruizinga, “Computational models of visual neurons specialise """ function gabor(size_x::Integer, size_y::Integer, σ::Real, θ::Real, λ::Real, γ::Real, ψ::Real) - function validate_gabor(σ,λ,γ) - if(σ>0 && λ>0 && γ>0) - return true - else - return false - end - end - - if(!validate_gabor(σ,λ,γ)) - error("Invalid Input Parameters!") - end - σx = σ σy = σ/γ nstds = 3 c = cos(θ) s = sin(θ) + validate_gabor(σ,λ,γ) + if(size_x > 0) xmax = floor(Int64,size_x/2) else @@ -392,6 +382,10 @@ function gabor(size_x::Integer, size_y::Integer, σ::Real, θ::Real, λ::Real, return kernel end +function validate_gabor(σ::Real,λ::Real,γ::Real) + @assert (σ>0 && λ>0 && γ>0) "The parameters σ, λ and γ must be positive numbers." +end + """ reflect(kernel) --> reflectedkernel From 3087c49ee258f3c468aca6191414438959125675 Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Mon, 5 Mar 2018 19:04:35 +0530 Subject: [PATCH 6/9] Added warnings for cases when size_x or size_y is not positive. --- src/kernel.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernel.jl b/src/kernel.jl index 452d7ba..b5fc460 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -358,12 +358,14 @@ function gabor(size_x::Integer, size_y::Integer, σ::Real, θ::Real, λ::Real, if(size_x > 0) xmax = floor(Int64,size_x/2) else + warn("The input parameter size_x should be positive. Using size_x = 6 * σx + 1 (Default value)") xmax = round(Int64,max(abs(nstds*σx*c),abs(nstds*σy*s),1)) end if(size_y > 0) ymax = floor(Int64,size_y/2) else + warn("The input parameter size_y should be positive. Using size_y = 6 * σy + 1 (Default value)") ymax = round(Int64,max(abs(nstds*σx*s),abs(nstds*σy*c),1)) end From 10b0f171e71119e8e77953aa233cc9eef28ca8de Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Mon, 5 Mar 2018 19:06:49 +0530 Subject: [PATCH 7/9] Added test cases for errors/exceptions. --- test/gabor.jl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/gabor.jl b/test/gabor.jl index 13e878d..1fd8993 100644 --- a/test/gabor.jl +++ b/test/gabor.jl @@ -34,15 +34,19 @@ using ImageFiltering, Base.Test gabor_result = sqrt.((gabor_real.*gabor_real) + (gabor_imag.*gabor_imag)) return mean(gabor_result) end - rabor_result = rand(Float64,2,2) + gabor_output = rand(Float64,2,2) for i = 1:2 for j = 1:2 - rabor_result[i,j] = match_score(images[i],wavelengths[j]) + gabor_output[i,j] = match_score(images[i],wavelengths[j]) end end - @test rabor_result[1,1] > rabor_result[1,2] - @test rabor_result[2,2] > rabor_result[1,2] - @test rabor_result[1,1] > rabor_result[2,1] - @test rabor_result[2,2] > rabor_result[2,1] + @test gabor_output[1,1] > gabor_output[1,2] + @test gabor_output[2,2] > gabor_output[1,2] + @test gabor_output[1,1] > gabor_output[2,1] + @test gabor_output[2,2] > gabor_output[2,1] + + @test_throws AssertionError Kernel.gabor(9,9,-2,0,5,0.1,0) + @test_throws AssertionError Kernel.gabor(9,9,2,0,-5,0.1,0) + @test_throws AssertionError Kernel.gabor(9,9,2,0,5,0,0) end \ No newline at end of file From 7fe602df9d59eaa67d07d15a1ea8dc28e60cbee9 Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Mon, 5 Mar 2018 19:21:12 +0530 Subject: [PATCH 8/9] Changed error type from AssertionError to ArgumentError. --- src/kernel.jl | 4 +++- test/gabor.jl | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/kernel.jl b/src/kernel.jl index b5fc460..6e18a0a 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -385,7 +385,9 @@ function gabor(size_x::Integer, size_y::Integer, σ::Real, θ::Real, λ::Real, end function validate_gabor(σ::Real,λ::Real,γ::Real) - @assert (σ>0 && λ>0 && γ>0) "The parameters σ, λ and γ must be positive numbers." + if !(σ>0 && λ>0 && γ>0) + throw(ArgumentError("The parameters σ, λ and γ must be positive numbers.")) + end end """ diff --git a/test/gabor.jl b/test/gabor.jl index 1fd8993..9863aad 100644 --- a/test/gabor.jl +++ b/test/gabor.jl @@ -45,8 +45,8 @@ using ImageFiltering, Base.Test @test gabor_output[1,1] > gabor_output[2,1] @test gabor_output[2,2] > gabor_output[2,1] - @test_throws AssertionError Kernel.gabor(9,9,-2,0,5,0.1,0) - @test_throws AssertionError Kernel.gabor(9,9,2,0,-5,0.1,0) - @test_throws AssertionError Kernel.gabor(9,9,2,0,5,0,0) + @test_throws ArgumentError Kernel.gabor(9,9,-2,0,5,0.1,0) + @test_throws ArgumentError Kernel.gabor(9,9,2,0,-5,0.1,0) + @test_throws ArgumentError Kernel.gabor(9,9,2,0,5,0,0) end \ No newline at end of file From 890cca1b6f9783d05eaf723fa2dbf20521f0b76b Mon Sep 17 00:00:00 2001 From: arijitkar98 Date: Wed, 7 Mar 2018 16:42:55 +0530 Subject: [PATCH 9/9] Added bullet points in docstring. --- src/kernel.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernel.jl b/src/kernel.jl index 6e18a0a..a461ff7 100644 --- a/src/kernel.jl +++ b/src/kernel.jl @@ -335,12 +335,12 @@ _reshape(L::Laplacian{N}, ::Type{Val{N}}) where {N} = L Returns a 2 Dimensional Complex Gabor kernel contained in a tuple where - size_x,size_y is the size of the kernel; - σ is the standard deviation of the Gaussian envelope; - θ represents the orientation of the normal to the parallel stripes of a Gabor function; - λ represents the wavelength of the sinusoidal factor; - γ is the spatial aspect ratio, and specifies the ellipticity of the support of the Gabor function; - ψ is the phase offset. + - `size_x`, `size_y` denote the size of the kernel + - `σ` denotes the standard deviation of the Gaussian envelope + - `θ` represents the orientation of the normal to the parallel stripes of a Gabor function + - `λ` represents the wavelength of the sinusoidal factor + - `γ` is the spatial aspect ratio, and specifies the ellipticity of the support of the Gabor function + - `ψ` is the phase offset #Citation N. Petkov and P. Kruizinga, “Computational models of visual neurons specialised in the detection of periodic and aperiodic oriented visual stimuli: bar and grating cells,” Biological Cybernetics, vol. 76, no. 2, pp. 83–96, Feb. 1997. doi.org/10.1007/s004220050323