Skip to content

Commit

Permalink
Added 2D Gabor filter (#57)
Browse files Browse the repository at this point in the history
* Added function to construct 2D Gabor kernel.

* Modified gabor function to include imaginary part of the filter.

* Added tests for gabor filter function.

* Modified gabor function and placed validate_gabor outside of gabor.

* Added warnings for cases when size_x or size_y is not positive.

* Added test cases for errors/exceptions.
  • Loading branch information
arijitkar98 authored and Evizero committed Mar 7, 2018
1 parent 6a4907f commit 8a4bd35
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/ImageFiltering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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}}

Expand Down
64 changes: 63 additions & 1 deletion src/kernel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dimensionality. The following kernels are supported:
- `DoG` (Difference-of-Gaussian)
- `LoG` (Laplacian-of-Gaussian)
- `Laplacian`
- `gabor`
See also: [`KernelFactors`](@ref).
"""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -328,6 +329,67 @@ function Base.convert(::Type{AbstractArray}, L::Laplacian{N}) where N
end
_reshape(L::Laplacian{N}, ::Type{Val{N}}) where {N} = L


"""
gabor(size_x,size_y,σ,θ,λ,γ,ψ) -> (k_real,k_complex)
Returns a 2 Dimensional Complex Gabor kernel contained in a tuple where
- `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
"""
function gabor(size_x::Integer, size_y::Integer, σ::Real, θ::Real, λ::Real, γ::Real, ψ::Real)

σx = σ
σy = σ/γ
nstds = 3
c = cos(θ)
s = sin(θ)

validate_gabor(σ,λ,γ)

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

xmin = -xmax
ymin = -ymax

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

function validate_gabor::Real::Real::Real)
if !>0 && λ>0 && γ>0)
throw(ArgumentError("The parameters σ, λ and γ must be positive numbers."))
end
end

"""
reflect(kernel) --> reflectedkernel
Expand Down
52 changes: 52 additions & 0 deletions test/gabor.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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
gabor_output = rand(Float64,2,2)
for i = 1:2
for j = 1:2
gabor_output[i,j] = match_score(images[i],wavelengths[j])
end
end
@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 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
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ include("specialty.jl")
include("gradient.jl")
include("mapwindow.jl")
include("basic.jl")
include("gabor.jl")

nothing

0 comments on commit 8a4bd35

Please sign in to comment.