Skip to content

Commit 8a4bd35

Browse files
arijitkar98Evizero
authored andcommitted
Added 2D Gabor filter (#57)
* 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.
1 parent 6a4907f commit 8a4bd35

File tree

4 files changed

+117
-2
lines changed

4 files changed

+117
-2
lines changed

src/ImageFiltering.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ ArrayLike{T} = Union{ArrayType{T}, AnyIIR{T}}
5353

5454
include("kernel.jl")
5555
using .Kernel
56-
using .Kernel: Laplacian, reflect, ando3, ando4, ando5, scharr, bickley, prewitt, sobel
56+
using .Kernel: Laplacian, reflect, ando3, ando4, ando5, scharr, bickley, prewitt, sobel, gabor
5757

5858
NDimKernel{N,K} = Union{AbstractArray{K,N},ReshapedOneD{K,N},Laplacian{N}}
5959

src/kernel.jl

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dimensionality. The following kernels are supported:
1111
- `DoG` (Difference-of-Gaussian)
1212
- `LoG` (Laplacian-of-Gaussian)
1313
- `Laplacian`
14+
- `gabor`
1415
1516
See also: [`KernelFactors`](@ref).
1617
"""
@@ -295,7 +296,7 @@ end
295296
"""
296297
Laplacian((true,true,false,...))
297298
Laplacian(dims, N)
298-
Lacplacian()
299+
Laplacian()
299300
300301
Laplacian kernel in `N` dimensions, taking derivatives along the
301302
directions marked as `true` in the supplied tuple. Alternatively, one
@@ -328,6 +329,67 @@ function Base.convert(::Type{AbstractArray}, L::Laplacian{N}) where N
328329
end
329330
_reshape(L::Laplacian{N}, ::Type{Val{N}}) where {N} = L
330331

332+
333+
"""
334+
gabor(size_x,size_y,σ,θ,λ,γ,ψ) -> (k_real,k_complex)
335+
336+
Returns a 2 Dimensional Complex Gabor kernel contained in a tuple where
337+
338+
- `size_x`, `size_y` denote the size of the kernel
339+
- `σ` denotes the standard deviation of the Gaussian envelope
340+
- `θ` represents the orientation of the normal to the parallel stripes of a Gabor function
341+
- `λ` represents the wavelength of the sinusoidal factor
342+
- `γ` is the spatial aspect ratio, and specifies the ellipticity of the support of the Gabor function
343+
- `ψ` is the phase offset
344+
345+
#Citation
346+
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
347+
"""
348+
function gabor(size_x::Integer, size_y::Integer, σ::Real, θ::Real, λ::Real, γ::Real, ψ::Real)
349+
350+
σx = σ
351+
σy = σ/γ
352+
nstds = 3
353+
c = cos(θ)
354+
s = sin(θ)
355+
356+
validate_gabor(σ,λ,γ)
357+
358+
if(size_x > 0)
359+
xmax = floor(Int64,size_x/2)
360+
else
361+
warn("The input parameter size_x should be positive. Using size_x = 6 * σx + 1 (Default value)")
362+
xmax = round(Int64,max(abs(nstds*σx*c),abs(nstds*σy*s),1))
363+
end
364+
365+
if(size_y > 0)
366+
ymax = floor(Int64,size_y/2)
367+
else
368+
warn("The input parameter size_y should be positive. Using size_y = 6 * σy + 1 (Default value)")
369+
ymax = round(Int64,max(abs(nstds*σx*s),abs(nstds*σy*c),1))
370+
end
371+
372+
xmin = -xmax
373+
ymin = -ymax
374+
375+
x = [j for i in xmin:xmax,j in ymin:ymax]
376+
y = [i for i in xmin:xmax,j in ymin:ymax]
377+
xr = x*c + y*s
378+
yr = -x*s + y*c
379+
380+
kernel_real = (exp.(-0.5*(((xr.*xr)/σx^2) + ((yr.*yr)/σy^2))).*cos.(2*/λ)*xr + ψ))
381+
kernel_imag = (exp.(-0.5*(((xr.*xr)/σx^2) + ((yr.*yr)/σy^2))).*sin.(2*/λ)*xr + ψ))
382+
383+
kernel = (kernel_real,kernel_imag)
384+
return kernel
385+
end
386+
387+
function validate_gabor::Real::Real::Real)
388+
if !>0 && λ>0 && γ>0)
389+
throw(ArgumentError("The parameters σ, λ and γ must be positive numbers."))
390+
end
391+
end
392+
331393
"""
332394
reflect(kernel) --> reflectedkernel
333395

test/gabor.jl

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using ImageFiltering, Base.Test
2+
3+
@testset "gabor" begin
4+
σx = 8
5+
σy = 12
6+
size_x = 6*σx+1
7+
size_y = 6*σy+1
8+
γ = σx/σy
9+
kernel = Kernel.gabor(0,0,σx,0,5,γ,0)
10+
@test isequal(size(kernel[1]),(size_x,size_y))
11+
kernel = Kernel.gabor(0,0,σx,π,5,γ,0)
12+
@test isequal(size(kernel[1]),(size_x,size_y))
13+
14+
for x in 0:4, y in 0:4, z in 0:4, t in 0:4
15+
σx = 2*x+1
16+
σy = 2*y+1
17+
λ = 2*z+1
18+
γ = σx/σy
19+
θ = 2*t+1
20+
kernel1 = Kernel.gabor(9,9,σx,θ,λ,γ,0)
21+
kernel2 = Kernel.gabor(9,9,σx,θ+π,λ,γ,0)
22+
@test abs(sum(kernel1[1] - kernel2[1])) < 1e-2
23+
@test abs(sum(kernel1[2] - kernel2[2])) < 1e-2
24+
end
25+
26+
x = [j for i in 0:49,j in 0:49]
27+
wavelengths = (3, 10)
28+
images = [sin.(2*π*x/λ) for λ in wavelengths]
29+
σx = 4
30+
σy = 5
31+
function match_score(image, λ)
32+
gabor_real = imfilter(image,centered(Kernel.gabor(6*σx+1,6*σy+1,σx,0,λ,σx/σy,0)[1]),[border="replicate"])
33+
gabor_imag = imfilter(image,centered(Kernel.gabor(6*σx+1,6*σy+1,σx,0,λ,σx/σy,0)[2]),[border="replicate"])
34+
gabor_result = sqrt.((gabor_real.*gabor_real) + (gabor_imag.*gabor_imag))
35+
return mean(gabor_result)
36+
end
37+
gabor_output = rand(Float64,2,2)
38+
for i = 1:2
39+
for j = 1:2
40+
gabor_output[i,j] = match_score(images[i],wavelengths[j])
41+
end
42+
end
43+
@test gabor_output[1,1] > gabor_output[1,2]
44+
@test gabor_output[2,2] > gabor_output[1,2]
45+
@test gabor_output[1,1] > gabor_output[2,1]
46+
@test gabor_output[2,2] > gabor_output[2,1]
47+
48+
@test_throws ArgumentError Kernel.gabor(9,9,-2,0,5,0.1,0)
49+
@test_throws ArgumentError Kernel.gabor(9,9,2,0,-5,0.1,0)
50+
@test_throws ArgumentError Kernel.gabor(9,9,2,0,5,0,0)
51+
52+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ include("specialty.jl")
1414
include("gradient.jl")
1515
include("mapwindow.jl")
1616
include("basic.jl")
17+
include("gabor.jl")
1718

1819
nothing

0 commit comments

Comments
 (0)