1 // This is brl/bseg/sdet/sdet_nonmax_suppression.cxx
2 #include <iostream>
3 #include <cstdlib>
4 #include "sdet_nonmax_suppression.h"
5 //:
6 // \file
7 #ifdef _MSC_VER
8 # include "vcl_msvc_warnings.h"
9 #endif
10 #include <vsol/vsol_point_2d.h>
11 #include <vsol/vsol_line_2d.h>
12 #include "vgl/vgl_point_2d.h"
13 #include "vnl/vnl_matrix.h"
14 #include <vnl/algo/vnl_svd.h>
15 #include "vgl/vgl_homg_point_2d.h"
16 #include <vgl/algo/vgl_homg_operators_2d.h>
17 #include <cassert>
18
19 //---------------------------------------------------------------
20 // Constructors
21 //
22 //----------------------------------------------------------------
23
24 //: Constructor from a parameter block, and gradients along x and y directions given as arrays
25 //
sdet_nonmax_suppression(sdet_nonmax_suppression_params & nsp,vbl_array_2d<double> & grad_x,vbl_array_2d<double> & grad_y)26 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
27 vbl_array_2d<double> &grad_x,
28 vbl_array_2d<double> &grad_y)
29 : sdet_nonmax_suppression_params(nsp)
30 {
31 width_ = grad_x.rows();
32 height_ = grad_x.cols();
33 grad_x_.resize(width_, height_);
34 grad_y_.resize(width_, height_);
35 grad_mag_.resize(width_, height_);
36 grad_x_ = grad_x;
37 grad_y_ = grad_y;
38
39 for (int j = 0; j < height_; j++)
40 {
41 for (int i = 0; i < width_; i++)
42 {
43 double val = std::sqrt(std::pow(grad_x_(i,j),2.0) + std::pow(grad_y_(i,j),2.0));
44 grad_mag_(i,j) = val;
45 if (val > max_grad_mag_)
46 max_grad_mag_ = val;
47 }
48 }
49 points_valid_ = false;
50 parabola_fit_type_ = nsp.pfit_type_;
51 }
52
53 //: Constructor from a parameter block, gradient magnitudes given as an array and directions given as component arrays
54 //
sdet_nonmax_suppression(sdet_nonmax_suppression_params & nsp,vbl_array_2d<double> & dir_x,vbl_array_2d<double> & dir_y,vbl_array_2d<double> & grad_mag)55 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
56 vbl_array_2d<double> &dir_x,
57 vbl_array_2d<double> &dir_y,
58 vbl_array_2d<double> &grad_mag)
59 : sdet_nonmax_suppression_params(nsp)
60 {
61 width_ = grad_mag.rows();
62 height_ = grad_mag.cols();
63 grad_x_.resize(width_, height_);
64 grad_y_.resize(width_, height_);
65 grad_mag_.resize(width_, height_);
66 grad_x_ = dir_x;
67 grad_y_ = dir_y;
68 grad_mag_ = grad_mag;
69
70 for (int j = 0; j < height_; j++)
71 {
72 for (int i = 0; i < width_; i++)
73 {
74 double val = grad_mag_(i,j);
75 if (val > max_grad_mag_)
76 max_grad_mag_ = val;
77 }
78 }
79 points_valid_ = false;
80 parabola_fit_type_ = nsp.pfit_type_;
81 }
82
83 //: Constructor from a parameter block, gradient magnitudes given as an array and the search directions
84 //
sdet_nonmax_suppression(sdet_nonmax_suppression_params & nsp,vbl_array_2d<double> & grad_mag,vbl_array_2d<vgl_vector_2d<double>> & directions)85 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
86 vbl_array_2d<double> &grad_mag,
87 vbl_array_2d<vgl_vector_2d <double> > &directions)
88 : sdet_nonmax_suppression_params(nsp)
89 {
90 width_ = grad_mag.rows();
91 height_ = grad_mag.cols();
92 grad_x_.resize(width_, height_);
93 grad_y_.resize(width_, height_);
94 grad_mag_.resize(width_, height_);
95 grad_mag_ = grad_mag;
96 for (int j = 0; j < height_; j++)
97 {
98 for (int i = 0; i < width_; i++)
99 {
100 vgl_vector_2d<double> direction = directions(i,j);
101 normalize(direction);
102 grad_x_(i,j) = grad_mag_(i,j) * direction.x();
103 grad_y_(i,j) = grad_mag_(i,j) * direction.y();
104 double val = grad_mag_(i,j);
105 if (val > max_grad_mag_)
106 max_grad_mag_ = val;
107 }
108 }
109 points_valid_ = false;
110 parabola_fit_type_ = nsp.pfit_type_;
111 }
112
113 //: Constructor from a parameter block, and gradients along x and y directions given as images
114 //
sdet_nonmax_suppression(sdet_nonmax_suppression_params & nsp,vil_image_view<double> & grad_x,vil_image_view<double> & grad_y)115 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
116 vil_image_view<double> &grad_x,
117 vil_image_view<double> &grad_y)
118 : sdet_nonmax_suppression_params(nsp)
119 {
120 width_ = grad_x.ni();
121 height_ = grad_x.nj();
122 grad_x_.resize(width_, height_);
123 grad_y_.resize(width_, height_);
124 grad_mag_.resize(width_, height_);
125
126 for (int j = 0; j < height_; j++)
127 {
128 for (int i = 0; i < width_; i++)
129 {
130 double val_x = grad_x(i,j);
131 double val_y = grad_y(i,j);
132 grad_x_(i,j) = val_x;
133 grad_y_(i,j) = val_y;
134 double val = std::sqrt(std::pow(val_x,2.0) + std::pow(val_y,2.0));
135 grad_mag_(i,j) = val;
136 if (val > max_grad_mag_)
137 max_grad_mag_ = val;
138 }
139 }
140 points_valid_ = false;
141 parabola_fit_type_ = nsp.pfit_type_;
142 }
143
144 //: Constructor from a parameter block, gradient magnitudes given as an image and directions given as component image
145 //
sdet_nonmax_suppression(sdet_nonmax_suppression_params & nsp,vil_image_view<double> & dir_x,vil_image_view<double> & dir_y,vil_image_view<double> & grad_mag)146 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
147 vil_image_view<double> &dir_x,
148 vil_image_view<double> &dir_y,
149 vil_image_view<double> &grad_mag)
150 : sdet_nonmax_suppression_params(nsp)
151 {
152 width_ = grad_mag.ni();
153 height_ = grad_mag.nj();
154 grad_x_.resize(width_, height_);
155 grad_y_.resize(width_, height_);
156 grad_mag_.resize(width_, height_);
157
158 for (int j = 0; j < height_; j++)
159 {
160 for (int i = 0; i < width_; i++)
161 {
162 grad_x_(i,j) = dir_x(i,j);
163 grad_y_(i,j) = dir_y(i,j);
164 double val = grad_mag(i,j);
165 grad_mag_(i,j) = val;
166 if (val > max_grad_mag_)
167 max_grad_mag_ = val;
168 }
169 }
170 points_valid_ = false;
171 parabola_fit_type_ = nsp.pfit_type_;
172 }
173
174 //: Constructor from a parameter block, gradient magnitudes given as an image and the search directions
175 //
sdet_nonmax_suppression(sdet_nonmax_suppression_params & nsp,vil_image_view<double> & grad_mag,vbl_array_2d<vgl_vector_2d<double>> & directions)176 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
177 vil_image_view<double> &grad_mag,
178 vbl_array_2d<vgl_vector_2d <double> > &directions)
179 : sdet_nonmax_suppression_params(nsp)
180 {
181 width_ = grad_mag.ni();
182 height_ = grad_mag.nj();
183 grad_x_.resize(width_, height_);
184 grad_y_.resize(width_, height_);
185 grad_mag_.resize(width_, height_);
186 for (int j = 0; j < height_; j++)
187 {
188 for (int i = 0; i < width_; i++)
189 {
190 double val = grad_mag(i,j);
191 grad_mag_(i,j) = val;
192 vgl_vector_2d<double> direction = directions(i,j);
193 normalize(direction);
194 grad_x_(i,j) = val * direction.x();
195 grad_y_(i,j) = val * direction.y();
196 if (val > max_grad_mag_)
197 max_grad_mag_ = val;
198 }
199 }
200 points_valid_ = false;
201 parabola_fit_type_ = nsp.pfit_type_;
202 }
203
204 //:Default Destructor
205 sdet_nonmax_suppression::~sdet_nonmax_suppression()
206 = default;
207
208 //-------------------------------------------------------------------------
209 //: Apply the algorithm
210 //
apply()211 void sdet_nonmax_suppression::apply()
212 {
213 if (points_valid_)
214 return;
215 points_.clear();
216
217 // run non-maximum suppression at every point
218
219 for (int y = 1; y < height_-1; y++)
220 {
221 for (int x = 1; x < width_-1; x++)
222 {
223 //if (grad_mag_(x,y) > max_grad_mag_ * thresh_ / 100.0)
224 if (grad_mag_(x,y) > thresh_)
225 {
226 double gx = grad_x_(x,y);
227 double gy = grad_y_(x,y);
228 vgl_vector_2d<double> direction(gx,gy);
229 normalize(direction);
230 if (std::abs(gx) > 10e-6 && std::abs(gy) > 10e-6)
231 {
232 int face_num = intersected_face_number(gx, gy);
233 assert(face_num != -1);
234 double s = intersection_parameter(gx, gy, face_num);
235 assert(s != -1000);
236 double f[3];
237 f_values(x, y, gx, gy, s, face_num, f);
238 double s_list[3];
239 s_list[0] = -s;
240 s_list[1] = 0.0;
241 s_list[2] = s;
242 if (f[1] > f[0] && f[1] > f[2])
243 {
244 double s_star = (parabola_fit_type_ == PFIT_3_POINTS)
245 ? subpixel_s(s_list, f)
246 : subpixel_s(x, y, direction);
247 if (-1.5 < s_star && s_star < 1.5)
248 {
249 vgl_point_2d<double> subpix(x + s_star * direction.x(), y + s_star * direction.y());
250 vsol_point_2d_sptr p = new vsol_point_2d(subpix.x(), subpix.y());
251 vsol_point_2d_sptr line_start = new vsol_point_2d(subpix.x()-direction.y()*0.5, subpix.y()+direction.x()*0.5);
252 vsol_point_2d_sptr line_end = new vsol_point_2d(subpix.x()+direction.y()*0.5, subpix.y()-direction.x()*0.5);
253 vsol_line_2d_sptr l = new vsol_line_2d(line_start, line_end);
254 points_.push_back(p);
255 lines_.push_back(l);
256 directions_.push_back(direction);
257 }
258 }
259 }
260 }
261 }
262 }
263 points_valid_ = true;
264 }
265
intersected_face_number(double gx,double gy)266 int sdet_nonmax_suppression::intersected_face_number(double gx, double gy)
267 {
268 if (gx >= 0 && gy >= 0)
269 {
270 if (gx >= gy)
271 return 1;
272 else
273 return 2;
274 }
275 else if (gx < 0 && gy >= 0)
276 {
277 if (std::abs(gx) < gy)
278 return 3;
279 else
280 return 4;
281 }
282 else if (gx < 0 && gy < 0)
283 {
284 if (std::abs(gx) >= std::abs(gy))
285 return 5;
286 else
287 return 6;
288 }
289 else if (gx >= 0 && gy < 0)
290 {
291 if (gx < std::abs(gy))
292 return 7;
293 else
294 return 8;
295 }
296 return -1;
297 }
298
intersection_parameter(double gx,double gy,int face_num)299 double sdet_nonmax_suppression::intersection_parameter(double gx, double gy, int face_num)
300 {
301 vgl_vector_2d<double> direction(gx,gy);
302 normalize(direction);
303 if (face_num == 1 || face_num == 8)
304 return 1.0/direction.x();
305 else if (face_num == 2 || face_num == 3)
306 return 1.0/direction.y();
307 else if (face_num == 4 || face_num == 5)
308 return -1.0/direction.x();
309 else if (face_num == 6 || face_num == 7)
310 return -1.0/direction.y();
311 return -1000.0;
312 }
313
f_values(int x,int y,double gx,double gy,double s,int face_num,double * f)314 void sdet_nonmax_suppression::f_values(int x, int y, double gx, double gy, double s, int face_num, double *f)
315 {
316 vgl_vector_2d<double> direction(gx,gy);
317 normalize(direction);
318
319 int corners[4];
320 get_relative_corner_coordinates(face_num, corners);
321
322 vgl_vector_2d<double> intersection_point = s * direction;
323 vgl_vector_2d<double> corner1(corners[0], corners[1]); //have to convert to double for subtraction
324 vgl_vector_2d<double> corner2(corners[2], corners[3]); //have to convert to double for subtraction
325 double distance1 = length(intersection_point - corner1);
326 double distance2 = length(intersection_point - corner2);
327 double value1 = grad_mag_(x+corners[0], y+corners[1]);
328 double value2 = grad_mag_(x+corners[2], y+corners[3]);
329 double f_plus = value1 * distance2 + value2 * distance1;
330
331 intersection_point = -s * direction;
332 corner1.set(-corners[0], -corners[1]); //have to convert to double for subtraction
333 corner2.set(-corners[2], -corners[3]); //have to convert to double for subtraction
334 distance1 = length(intersection_point - corner1);
335 distance2 = length(intersection_point - corner2);
336 value1 = grad_mag_(x-corners[0], y-corners[1]);
337 value2 = grad_mag_(x-corners[2], y-corners[3]);
338 double f_minus = value1 * distance2 + value2 * distance1;
339
340 f[0] = f_minus;
341 f[1] = grad_mag_(x,y);
342 f[2] = f_plus;
343 }
344
get_relative_corner_coordinates(int face_num,int * corners)345 void sdet_nonmax_suppression::get_relative_corner_coordinates(int face_num, int *corners)
346 {
347 switch (face_num)
348 {
349 case 1:
350 corners[0] = 1;
351 corners[1] = 0;
352 corners[2] = 1;
353 corners[3] = 1;
354 break;
355 case 2:
356 corners[0] = 1;
357 corners[1] = 1;
358 corners[2] = 0;
359 corners[3] = 1;
360 break;
361 case 3:
362 corners[0] = 0;
363 corners[1] = 1;
364 corners[2] = -1;
365 corners[3] = 1;
366 break;
367 case 4:
368 corners[0] = -1;
369 corners[1] = 1;
370 corners[2] = -1;
371 corners[3] = 0;
372 break;
373 case 5:
374 corners[0] = -1;
375 corners[1] = 0;
376 corners[2] = -1;
377 corners[3] = -1;
378 break;
379 case 6:
380 corners[0] = -1;
381 corners[1] = -1;
382 corners[2] = 0;
383 corners[3] = -1;
384 break;
385 case 7:
386 corners[0] = 0;
387 corners[1] = -1;
388 corners[2] = 1;
389 corners[3] = -1;
390 break;
391 case 8:
392 corners[0] = 1;
393 corners[1] = -1;
394 corners[2] = 1;
395 corners[3] = 0;
396 break;
397 default:
398 corners[0] = 0;
399 corners[1] = 0;
400 corners[2] = 0;
401 corners[3] = 0;
402 }
403 }
404
subpixel_s(const double * s,const double * f)405 double sdet_nonmax_suppression::subpixel_s(const double *s, const double *f)
406 {
407 double A = f[2] / ((s[2]-s[0])*(s[2]-s[1]));
408 double B = f[1] / ((s[1]-s[0])*(s[1]-s[2]));
409 double C = f[0] / ((s[0]-s[1])*(s[0]-s[2]));
410 double s_star = ((A+B)*s[0] + (A+C)*s[1] + (B+C)*s[2]) / (2*(A+B+C));
411 return s_star;
412 }
413
subpixel_s(int x,int y,vgl_vector_2d<double> direction)414 double sdet_nonmax_suppression::subpixel_s(int x, int y, vgl_vector_2d<double> direction)
415 {
416 double d;
417 double s;
418 double f;
419 vgl_homg_point_2d<double> p1(0.0, 0.0);
420 vgl_homg_point_2d<double> p2(direction.x(), direction.y());
421 vgl_homg_line_2d<double> line1(p1,p2);
422 //construct the matrices
423 vnl_matrix<double> A(9, 3);
424 vnl_matrix<double> B(9, 1);
425 vnl_matrix<double> P(3, 1);
426 int index = 0;
427 for (int j = -1; j <= 1; j++)
428 {
429 for (int i = -1; i <= 1; i++)
430 {
431 find_distance_s_and_f_for_point(i, j, line1, d, s, direction);
432 f = grad_mag_(x+i,y+j);
433 A(index, 0) = std::pow(s,2.0);
434 A(index, 1) = s;
435 A(index, 2) = 1.0;
436 B(index, 0) = f;
437 index++;
438 }
439 }
440 #if 0
441 vnl_matrix<double> A_trans = A.transpose();
442 P = (vnl_matrix_inverse<double>(A_trans*A) * A_trans) * B;
443 #else
444 vnl_svd<double> svd(A);
445 P = svd.solve(B);
446 #endif
447 double s_star = -P(1,0)/(2*P(0,0));
448 return s_star;
449 }
450
find_distance_s_and_f_for_point(int x,int y,vgl_homg_line_2d<double> line,double & d,double & s,vgl_vector_2d<double> direction)451 void sdet_nonmax_suppression::find_distance_s_and_f_for_point(int x, int y, vgl_homg_line_2d<double> line,
452 double &d, double &s, vgl_vector_2d<double> direction)
453 {
454 vgl_homg_point_2d<double> point(x,y);
455 vgl_homg_line_2d<double> perp_line = vgl_homg_operators_2d<double>::perp_line_through_point(line, point);
456 vgl_homg_point_2d<double> intersection_point_homg = vgl_homg_operators_2d<double>::intersection(line, perp_line);
457 vgl_point_2d<double> intersection_point(intersection_point_homg);
458 vgl_vector_2d<double> d_helper(x-intersection_point.x(), y-intersection_point.y());
459 d = length(d_helper);
460 s = intersection_point.x() / direction.x();
461 }
462
463 //----------------------------------------------------------
464 //: Clear internal storage
465 //
clear()466 void sdet_nonmax_suppression::clear()
467 {
468 points_.clear();
469 points_valid_ = false;
470 }
471