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
0 commit comments