Skip to content

Commit f35d61f

Browse files
tejus-guptatimholy
authored andcommitted
Added Histogram of Gradient Features (#37)
1 parent 4362bbf commit f35d61f

File tree

6 files changed

+225
-4
lines changed

6 files changed

+225
-4
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ os:
44
- osx
55
julia:
66
- nightly
7-
- 0.5
7+
- 0.6
88
notifications:
99
email: false
1010
script:

appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
environment:
22
matrix:
3-
- JULIAVERSION: "julialang/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
4-
- JULIAVERSION: "julialang/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
3+
- JULIAVERSION: "julialang/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
4+
- JULIAVERSION: "julialang/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
55
- JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe"
66
- JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe"
77

src/ImageFeatures.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ include("orb.jl")
1616
include("freak.jl")
1717
include("brisk.jl")
1818
include("houghtransform.jl")
19+
include("hog.jl")
1920

20-
export Keypoint, Keypoints, Feature, Features, Params, BRIEF, ORB, FREAK, BRISK
21+
export Keypoint, Keypoints, Feature, Features, Params, BRIEF, ORB, FREAK, BRISK, HOG
2122

2223
export
2324
#Core

src/hog.jl

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
"""
2+
```
3+
hog_params = HOG([orientations = 9], [cell_size = 8], [block_size = 2], [block_stride = 1], [norm_method = "L2-norm"])
4+
```
5+
6+
Histogram of Oriented Gradient (HOG) is a dense feature desciptor usually used for object detection. See "Histograms of Oriented Gradients for Human Detection" by Dalal and Triggs.
7+
8+
Parameters:
9+
- orientations = number of orientation bins
10+
- cell_size = size of a cell is cell_size x cell_size (in pixels)
11+
- block_size = size of a block is block_size x block_size (in terms of cells)
12+
- block_stride = stride of blocks. Controls how much adjacent blocks overlap.
13+
- norm_method = block normalization method. Options: L2-norm, L2-hys, L1-norm, L2-sqrt.
14+
"""
15+
type HOG <: Params
16+
orientations::Int
17+
cell_size::Int
18+
block_size::Int
19+
block_stride::Int
20+
norm_method::String
21+
end
22+
23+
function HOG(; orientations::Int = 9, cell_size::Int = 8, block_size::Int = 2, block_stride::Int = 1, norm_method::String = "L2-norm")
24+
HOG(orientations, cell_size, block_size, block_stride, norm_method)
25+
end
26+
27+
function create_descriptor{CT<:Images.NumberLike}(img::AbstractArray{CT, 2}, params::HOG)
28+
#compute gradient
29+
gx = imfilter(img, centered([-1 0 1]))
30+
gy = imfilter(img, centered([-1 0 1]'))
31+
mag = hypot.(gx, gy)
32+
phase = orientation.(gx, gy)
33+
34+
create_hog_descriptor(mag, phase, params)
35+
end
36+
37+
function create_descriptor{CT<:Images.Color{T, N} where T where N}(img::AbstractArray{CT, 2}, params::HOG)
38+
#for color images, compute seperate gradient for each color channel and take one with largest norm as pixel's gradient vector
39+
rows, cols = size(img)
40+
gx = channelview(imfilter(img, centered([-1 0 1])))
41+
gy = channelview(imfilter(img, centered([-1 0 1]')))
42+
mag = hypot.(gx, gy)
43+
phase = orientation.(gx, gy)
44+
45+
max_mag = zeros(rows, cols)
46+
max_phase = zeros(rows, cols)
47+
48+
for j in indices(mag, 3)
49+
for i in indices(mag, 2)
50+
ind = indmax(mag[:, i, j])
51+
max_mag[i, j] = mag[ind, i, j]
52+
max_phase[i, j] = phase[ind, i, j]
53+
end
54+
end
55+
56+
create_hog_descriptor(max_mag, max_phase, params)
57+
end
58+
59+
function create_hog_descriptor{T<:Images.NumberLike}(mag::AbstractArray{T, 2}, phase::AbstractArray{T, 2}, params::HOG)
60+
orientations = params.orientations
61+
cell_size = params.cell_size
62+
block_size = params.block_size
63+
block_stride = params.block_stride
64+
65+
rows, cols = size(mag)
66+
if rows%cell_size!=0 || cols%cell_size!=0
67+
error("Height and Width of the image must be a multiple of cell_size.")
68+
end
69+
70+
cell_rows::Int = rows/cell_size
71+
cell_cols::Int = cols/cell_size
72+
if (cell_rows-block_size)%block_stride!=0 || (cell_cols-block_size)%block_stride!=0
73+
error("Block size and block stride don't match.")
74+
end
75+
76+
phase = abs.(phase*180/pi)
77+
78+
#orientation binning for each cell
79+
hist = zeros(Float64, (orientations, cell_rows, cell_cols))
80+
R = CartesianRange(indices(mag))
81+
for i in R
82+
trilinear_interpolate!(hist, mag[i], phase[i], orientations, i, cell_size, cell_rows, cell_cols, rows, cols)
83+
end
84+
85+
function normalize(v, method)
86+
if method == "L2-norm"
87+
return v./sqrt(sum(abs2, v) + 1e-5)
88+
elseif method == "L2-hys"
89+
v = v./(sum(abs2, v) + 1e-5)
90+
v = min.(v, 0.2)
91+
return v./(sum(abs2, v) + 1e-5)
92+
elseif method == "L1-norm"
93+
return v./(sum(abs, v) + 1e-5)
94+
elseif method == "L1-sqrt"
95+
return sqrt.(v./(sum(abs, v) + 1e-5))
96+
end
97+
end
98+
99+
#contrast normalization for each block
100+
descriptor_size::Int = ((cell_rows-block_size)/block_stride + 1) * ((cell_cols-block_size)/block_stride + 1) * (block_size*block_size) * orientations
101+
descriptor = Vector{Float64}(descriptor_size)
102+
block_vector_size = block_size * block_size * orientations
103+
k = 1
104+
for j in 1:block_stride:cell_cols-block_size+1
105+
for i in 1:block_stride:cell_rows-block_size+1
106+
descriptor[block_vector_size*(k-1)+1 : block_vector_size*k] = normalize(hist[:, i:i+block_size-1, j:j+block_size-1][:], params.norm_method)
107+
k += 1
108+
end
109+
end
110+
111+
return descriptor
112+
end
113+
114+
function trilinear_interpolate!(hist, w, θ, orientations, i, cell_size, cell_rows, cell_cols, rows, cols)
115+
bin_θ1 = floor(Int, θ*orientations/180) + 1
116+
bin_θ2 = bin_θ1%orientations + 1
117+
b_θ = 180/orientations
118+
119+
if bin_θ1 != orientations
120+
θ1 = (bin_θ1-1)*180/orientations
121+
θ2 = (bin_θ2-1)*180/orientations
122+
else
123+
θ1 = (bin_θ1-1)*180/orientations
124+
θ2 = 180;
125+
end
126+
127+
if (i[1]<=cell_size/2 || i[1]>=rows-cell_size/2) && (i[2]<=cell_size/2 || i[2]>=cols-cell_size/2)
128+
#linear interpolation for corner points
129+
bin_x = i[1] < cell_size/2 ? 1 : cell_rows
130+
bin_y = i[2] < cell_size/2 ? 1 : cell_cols
131+
132+
hist[bin_θ1, bin_x, bin_y] += w*(1--θ1)/b_θ)
133+
hist[bin_θ2, bin_x, bin_y] += w*(1-(θ2-θ)/b_θ)
134+
135+
elseif i[1]<=cell_size/2 || i[1]>=rows-cell_size/2
136+
#bilinear interpolation for (top/bottom) edge points
137+
bin_x = i[1] < cell_size/2 ? 1 : cell_rows
138+
bin_y1 = floor(Int, (i[2]+cell_size/2)/cell_size)
139+
bin_y2 = bin_y1 + 1
140+
141+
y1 = (bin_y1-1)*cell_size+cell_size/2
142+
y2 = (bin_y2-1)*cell_size+cell_size/2
143+
b_y = cell_size
144+
145+
hist[bin_θ1, bin_x, bin_y1] += w*(1--θ1)/b_θ)*(1-(i[2]-y1)/b_y)
146+
hist[bin_θ1, bin_x, bin_y2] += w*(1--θ1)/b_θ)*(1-(y2-i[2])/b_y)
147+
hist[bin_θ2, bin_x, bin_y1] += w*(1-(θ2-θ)/b_θ)*(1-(i[2]-y1)/b_y)
148+
hist[bin_θ2, bin_x, bin_y2] += w*(1-(θ2-θ)/b_θ)*(1-(y2-i[2])/b_y)
149+
150+
elseif i[2]<=cell_size/2 || i[2]>=cols-cell_size/2
151+
#bilinear interpolation for (left/right) edge points
152+
bin_x1 = floor(Int, (i[1]+cell_size/2)/cell_size)
153+
bin_x2 = bin_x1 + 1
154+
bin_y = i[2] < cell_size/2 ? 1 : cell_cols
155+
156+
x1 = (bin_x1-1)*cell_size+cell_size/2
157+
x2 = (bin_x2-1)*cell_size+cell_size/2
158+
b_x = cell_size
159+
160+
hist[bin_θ1, bin_x1, bin_y] += w*(1--θ1)/b_θ)*(1-(i[1]-x1)/b_x)
161+
hist[bin_θ1, bin_x2, bin_y] += w*(1--θ1)/b_θ)*(1-(x2-i[1])/b_x)
162+
hist[bin_θ2, bin_x1, bin_y] += w*(1-(θ2-θ)/b_θ)*(1-(i[1]-x1)/b_x)
163+
hist[bin_θ2, bin_x2, bin_y] += w*(1-(θ2-θ)/b_θ)*(1-(x2-i[1])/b_x)
164+
else
165+
#trilinear interpolation
166+
bin_x1 = floor(Int, (i[1]+cell_size/2)/cell_size)
167+
bin_x2 = bin_x1 + 1
168+
bin_y1 = floor(Int, (i[2]+cell_size/2)/cell_size)
169+
bin_y2 = bin_y1 + 1
170+
171+
x1 = (bin_x1-1)*cell_size+cell_size/2
172+
x2 = (bin_x2-1)*cell_size+cell_size/2
173+
b_x = cell_size
174+
175+
y1 = (bin_y1-1)*cell_size+cell_size/2
176+
y2 = (bin_y2-1)*cell_size+cell_size/2
177+
b_y = cell_size
178+
179+
hist[bin_θ1, bin_x1, bin_y1] += w*(1--θ1)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(i[2]-y1)/b_y)
180+
hist[bin_θ1, bin_x1, bin_y2] += w*(1--θ1)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(y2-i[2])/b_y)
181+
hist[bin_θ1, bin_x2, bin_y1] += w*(1--θ1)/b_θ)*(1-(x2-i[1])/b_x)*(1-(i[2]-y1)/b_y)
182+
hist[bin_θ1, bin_x2, bin_y2] += w*(1--θ1)/b_θ)*(1-(x2-i[1])/b_x)*(1-(y2-i[2])/b_y)
183+
hist[bin_θ2, bin_x1, bin_y1] += w*(1-(θ2-θ)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(i[2]-y1)/b_y)
184+
hist[bin_θ2, bin_x1, bin_y2] += w*(1-(θ2-θ)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(y2-i[2])/b_y)
185+
hist[bin_θ2, bin_x2, bin_y1] += w*(1-(θ2-θ)/b_θ)*(1-(x2-i[1])/b_x)*(1-(i[2]-y1)/b_y)
186+
hist[bin_θ2, bin_x2, bin_y2] += w*(1-(θ2-θ)/b_θ)*(1-(x2-i[1])/b_x)*(1-(y2-i[2])/b_y)
187+
end
188+
end

test/hog.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Base.Test, ImageFeatures, Images
2+
import ImageFeatures.trilinear_interpolate!
3+
4+
@testset "HOG Feature" begin
5+
img = rand(128, 64)
6+
@test length(create_descriptor(img, HOG())) == 3780
7+
8+
img = rand(RGB, 128, 64)
9+
@test length(create_descriptor(img, HOG())) == 3780
10+
11+
#tests for function trilinear_interpolate!
12+
rows = 12
13+
cols = 12
14+
cell_size = 4
15+
cell_rows::Int = rows/cell_size
16+
cell_cols::Int = cols/cell_size
17+
orientations = 9
18+
19+
hist = zeros(9, 3, 3)
20+
trilinear_interpolate!(hist, 1, 170, orientations, CartesianIndex(1, 1), cell_size, cell_rows, cell_cols, rows, cols)
21+
@test hist[1, 1, 1] == hist[9, 1, 1] == 0.5
22+
23+
hist = zeros(9, 3, 3)
24+
trilinear_interpolate!(hist, 1, 150, orientations, CartesianIndex(1, 4), cell_size, cell_rows, cell_cols, rows, cols)
25+
@test hist[8, 1, 1] == hist[9, 1, 1] == hist[8, 1, 2] == hist[9, 1, 2] == 0.25
26+
27+
hist = zeros(9, 3, 3)
28+
trilinear_interpolate!(hist, 1, 145, orientations, CartesianIndex(4, 4), cell_size, cell_rows, cell_cols, rows, cols)
29+
@test hist[8, 1, 1] == hist[8, 1, 2] == hist[8, 2, 1] == hist[8, 2, 2] == 0.1875
30+
@test hist[9, 1, 1] == hist[9, 1, 2] == hist[9, 2, 1] == hist[9, 2, 2] == 0.0625
31+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ tests = [
5656
"freak.jl",
5757
"brisk.jl",
5858
"houghtransform.jl",
59+
"hog.jl"
5960
]
6061

6162
for t in tests

0 commit comments

Comments
 (0)