00001
00002 #include "sdet_nms.h"
00003
00004
00005
00006 #include <vcl_cstdio.h>
00007 #include <vcl_cstdlib.h>
00008 #include <vnl/vnl_matrix.h>
00009 #include <vnl/algo/vnl_svd.h>
00010 #include <vgl/vgl_homg_point_2d.h>
00011 #include <vgl/vgl_homg_line_2d.h>
00012 #include <vgl/algo/vgl_homg_operators_2d.h>
00013
00014
00015
00016
00017
00018
00019 sdet_nms::sdet_nms():
00020 thresh_(0.0),
00021 parabola_fit_type_(sdet_nms_params::PFIT_3_POINTS),
00022 margin_(1),
00023 rel_thresh_(2.5),
00024 use_adaptive_thresh_(true),
00025 dir_x_(vil_image_view<double>(0,0,1)),
00026 dir_y_(vil_image_view<double>(0,0,1)),
00027 grad_mag_(vil_image_view<double>(0,0,1)),
00028 x_(0,0, 0.0),
00029 y_(0,0, 0.0),
00030 dir_(0,0, 0.0),
00031 mag_(0,0, 0.0),
00032 deriv_(0,0, 0.0)
00033 {
00034 }
00035
00036
00037 sdet_nms::sdet_nms(const sdet_nms_params& nsp, const vil_image_view<double>& dir_x,
00038 const vil_image_view<double>& dir_y, const vil_image_view<double>& grad_mag) :
00039 thresh_(nsp.thresh_),
00040 parabola_fit_type_(nsp.pfit_type_),
00041 margin_(nsp.margin_),
00042 rel_thresh_(nsp.rel_thresh_),
00043 use_adaptive_thresh_(nsp.use_adaptive_thresh_),
00044 dir_x_(dir_x),
00045 dir_y_(dir_y),
00046 grad_mag_(grad_mag),
00047 x_(grad_mag.nj(), grad_mag.ni(), 0.0),
00048 y_(grad_mag.nj(), grad_mag.ni(), 0.0),
00049 dir_(grad_mag.nj(), grad_mag.ni(), 0.0),
00050 mag_(grad_mag.nj(), grad_mag.ni(), 0.0),
00051 deriv_(grad_mag.nj(), grad_mag.ni(), 0.0)
00052 {
00053 }
00054
00055
00056
00057
00058 void sdet_nms::apply(bool collect_tokens,
00059 vcl_vector<vgl_point_2d<double> >& loc,
00060 vcl_vector<double>& orientation,
00061 vcl_vector<double>& mag)
00062 {
00063 vcl_vector<double> d2f;
00064 vcl_vector<vgl_point_2d<int> > pix_loc;
00065
00066
00067 apply(collect_tokens, loc, orientation, mag, d2f, pix_loc);
00068 }
00069
00070 void sdet_nms::apply(bool collect_tokens,
00071 vcl_vector<vgl_point_2d<double> >& loc,
00072 vcl_vector<double>& orientation,
00073 vcl_vector<double>& mag,
00074 vcl_vector<double>& d2f)
00075 {
00076 vcl_vector<vgl_point_2d<int> > pix_loc;
00077
00078
00079 apply(collect_tokens, loc, orientation, mag, d2f, pix_loc);
00080 }
00081
00082
00083 void sdet_nms::apply(bool collect_tokens,
00084 vcl_vector<vgl_point_2d<double> >& loc,
00085 vcl_vector<double>& orientation,
00086 vcl_vector<double>& mag,
00087 vcl_vector<double>& d2f,
00088 vcl_vector<vgl_point_2d<int> >& pix_loc)
00089 {
00090 double f[3], s_list[3];
00091
00092
00093 for (unsigned x = margin_; x < grad_mag_.ni()-margin_; x++) {
00094 for (unsigned y = margin_; y < grad_mag_.nj()-margin_; y++)
00095 {
00096 if (grad_mag_(x,y) < thresh_)
00097 continue;
00098
00099 double gx = dir_x_(x,y);
00100 double gy = dir_y_(x,y);
00101 vgl_vector_2d<double> direction(gx,gy);
00102 normalize(direction);
00103
00104
00105 if (vcl_abs(direction.x()) < 10e-6 && vcl_abs(direction.y()) < 10e-6)
00106 continue;
00107
00108
00109 int face_num = intersected_face_number(direction); assert(face_num != -1);
00110 double s = intersection_parameter(direction, face_num); assert(s != -1000);
00111 f_values(x, y, direction, s, face_num, f);
00112 s_list[0] = -s; s_list[1] = 0.0; s_list[2] = s;
00113
00114
00115
00116
00117
00118
00119
00120 double max_val = f[1];
00121 double grad_val = 0.0;
00122
00123
00124 double s_star = (parabola_fit_type_ == sdet_nms_params::PFIT_3_POINTS) ?
00125 subpixel_s(s_list, f, max_val, grad_val) : subpixel_s(x, y, direction, max_val);
00126
00127 if (vcl_fabs(s_star)< 0.7)
00128 {
00129
00130 x_(y,x) = x + s_star * direction.x();
00131 y_(y,x) = y + s_star * direction.y();
00132 dir_(y,x) = vcl_atan2(direction.x(), -direction.y());
00133 mag_(y,x) = max_val;
00134 deriv_(y,x) = grad_val;
00135 }
00136
00137 }
00138 }
00139
00140
00141 for (unsigned x = margin_; x < grad_mag_.ni()-margin_; x++) {
00142 for (unsigned y = margin_; y < grad_mag_.nj()-margin_; y++)
00143 {
00144 if (mag_(y,x)==0.0)
00145 continue;
00146
00147
00148
00149
00150 for (int ii=-1; ii<2; ii++) {
00151 for (int jj=-1; jj<2; jj++) {
00152
00153 if (ii==0 && jj==0) continue;
00154
00155
00156 if (mag_(y+jj,x+ii)>0.0) {
00157 double dx = x_(y+jj,x+ii) - x_(y,x);
00158 double dy = y_(y+jj,x+ii) - y_(y,x);
00159
00160 if ((dx*dx+dy*dy)<0.1) {
00161 mag_(y,x)=0.0;
00162 continue;
00163 }
00164 }
00165 }
00166 }
00167 }
00168 }
00169
00170
00171 if (collect_tokens) {
00172 for (unsigned x = margin_; x < grad_mag_.ni()-margin_; x++) {
00173 for (unsigned y = margin_; y < grad_mag_.nj()-margin_; y++)
00174 {
00175 if (mag_(y,x)==0.0)
00176 continue;
00177
00178 loc.push_back(vgl_point_2d<double>(x_(y,x), y_(y,x)));
00179 orientation.push_back(dir_(y,x));
00180 mag.push_back(mag_(y,x));
00181 d2f.push_back(deriv_(y,x));
00182
00183
00184 pix_loc.push_back(vgl_point_2d<int>(x, y));
00185 }
00186 }
00187 }
00188 }
00189
00190 int sdet_nms::intersected_face_number(const vgl_vector_2d<double>& direction)
00191 {
00192 if (direction.x() >= 0 && direction.y() >= 0)
00193 {
00194 if (direction.x() >= direction.y())
00195 return 1;
00196 else
00197 return 2;
00198 }
00199 else if (direction.x() < 0 && direction.y() >= 0)
00200 {
00201 if (vcl_abs(direction.x()) < direction.y())
00202 return 3;
00203 else
00204 return 4;
00205 }
00206 else if (direction.x() < 0 && direction.y() < 0)
00207 {
00208 if (vcl_abs(direction.x()) >= vcl_abs(direction.y()))
00209 return 5;
00210 else
00211 return 6;
00212 }
00213 else if (direction.x() >= 0 && direction.y() < 0)
00214 {
00215 if (direction.x() < vcl_abs(direction.y()))
00216 return 7;
00217 else
00218 return 8;
00219 }
00220 return -1;
00221 }
00222
00223 double sdet_nms::intersection_parameter(const vgl_vector_2d<double>& direction, int face_num)
00224 {
00225 if (face_num == 1 || face_num == 8)
00226 return 1.0/direction.x();
00227 else if (face_num == 2 || face_num == 3)
00228 return 1.0/direction.y();
00229 else if (face_num == 4 || face_num == 5)
00230 return -1.0/direction.x();
00231 else if (face_num == 6 || face_num == 7)
00232 return -1.0/direction.y();
00233 return -1000.0;
00234 }
00235
00236 void sdet_nms::f_values(int x, int y, const vgl_vector_2d<double>& direction, double s, int face_num, double *f)
00237 {
00238 int corners[4];
00239 get_relative_corner_coordinates(face_num, corners);
00240
00241 vgl_vector_2d<double> intersection_point = s * direction;
00242 vgl_vector_2d<double> corner1(corners[0], corners[1]);
00243 vgl_vector_2d<double> corner2(corners[2], corners[3]);
00244 double distance1 = length(intersection_point - corner1);
00245 double distance2 = length(intersection_point - corner2);
00246 double value1 = grad_mag_(x+corners[0], y+corners[1]);
00247 double value2 = grad_mag_(x+corners[2], y+corners[3]);
00248 double f_plus = value1 * distance2 + value2 * distance1;
00249
00250 intersection_point = -s * direction;
00251 corner1.set(-corners[0], -corners[1]);
00252 corner2.set(-corners[2], -corners[3]);
00253 distance1 = length(intersection_point - corner1);
00254 distance2 = length(intersection_point - corner2);
00255 value1 = grad_mag_(x-corners[0], y-corners[1]);
00256 value2 = grad_mag_(x-corners[2], y-corners[3]);
00257 double f_minus = value1 * distance2 + value2 * distance1;
00258
00259 f[0] = f_minus;
00260 f[1] = grad_mag_(x,y);
00261 f[2] = f_plus;
00262 }
00263
00264 void sdet_nms::get_relative_corner_coordinates(int face_num, int *corners)
00265 {
00266 switch (face_num)
00267 {
00268 case 1:
00269 corners[0] = 1;
00270 corners[1] = 0;
00271 corners[2] = 1;
00272 corners[3] = 1;
00273 break;
00274 case 2:
00275 corners[0] = 1;
00276 corners[1] = 1;
00277 corners[2] = 0;
00278 corners[3] = 1;
00279 break;
00280 case 3:
00281 corners[0] = 0;
00282 corners[1] = 1;
00283 corners[2] = -1;
00284 corners[3] = 1;
00285 break;
00286 case 4:
00287 corners[0] = -1;
00288 corners[1] = 1;
00289 corners[2] = -1;
00290 corners[3] = 0;
00291 break;
00292 case 5:
00293 corners[0] = -1;
00294 corners[1] = 0;
00295 corners[2] = -1;
00296 corners[3] = -1;
00297 break;
00298 case 6:
00299 corners[0] = -1;
00300 corners[1] = -1;
00301 corners[2] = 0;
00302 corners[3] = -1;
00303 break;
00304 case 7:
00305 corners[0] = 0;
00306 corners[1] = -1;
00307 corners[2] = 1;
00308 corners[3] = -1;
00309 break;
00310 case 8:
00311 corners[0] = 1;
00312 corners[1] = -1;
00313 corners[2] = 1;
00314 corners[3] = 0;
00315 break;
00316 default:
00317 corners[0] = 0;
00318 corners[1] = 0;
00319 corners[2] = 0;
00320 corners[3] = 0;
00321 }
00322 }
00323
00324 double sdet_nms::subpixel_s(double *s, double *f, double &max_f, double &max_d)
00325 {
00326
00327
00328
00329
00330
00331
00332
00333 double A = -(f[1] - (f[0]+f[2])/2.0)/(s[2]*s[2]);
00334 double B = -(f[0]-f[2])/(2*s[2]);
00335 double C = f[1];
00336
00337 double s_star = -B/(2*A);
00338
00339 max_f = A*s_star*s_star + B*s_star + C;
00340
00341
00342 double d2f = 2*A;
00343 max_d = d2f;
00344
00345 if (A<0) {
00346 if (use_adaptive_thresh_) {
00347 #if 0 // no longer used...
00348
00349 double d2fp = 2*A*s[2] + B;
00350 double d2fm = 2*A*s[0] + B;
00351 if (vcl_fabs(d2fp)>rel_thresh_ || vcl_fabs(d2fm)>rel_thresh_)
00352 #endif
00353 if (d2f<-rel_thresh_)
00354 return s_star;
00355 else
00356 return 5.0;
00357 }
00358 else
00359 return s_star;
00360 }
00361 else
00362 return 5.0;
00363
00364
00365 #if 0
00366
00367
00368 float
00369 gevd_float_operators::InterpolateParabola(float y_1, float y_0, float y_2,
00370 float&y)
00371 {
00372 float diff1 = y_2 - y_1;
00373 float diff2 = 2 * y_0 - y_1 - y_2;
00374 y = y_0 + diff1 * diff1 / (8 * diff2);
00375 return diff1 / (2 * diff2);
00376 }
00377 #endif // 0
00378 }
00379
00380 double sdet_nms::subpixel_s(int x, int y, const vgl_vector_2d<double>& direction, double &max_f)
00381 {
00382 double d;
00383 double s;
00384 double f;
00385 vgl_homg_point_2d<double> p1(0.0, 0.0);
00386 vgl_homg_point_2d<double> p2(direction.x(), direction.y());
00387 vgl_homg_line_2d<double> line1(p1,p2);
00388
00389 vnl_matrix<double> A(9, 3);
00390 vnl_matrix<double> B(9, 1);
00391 vnl_matrix<double> P(3, 1);
00392 int index = 0;
00393 for (int j = -1; j <= 1; j++)
00394 {
00395 for (int i = -1; i <= 1; i++)
00396 {
00397 find_distance_s_and_f_for_point(i, j, line1, d, s, direction);
00398 f = grad_mag_(x+i,y+j);
00399 A(index, 0) = vcl_pow(s,2.0);
00400 A(index, 1) = s;
00401 A(index, 2) = 1.0;
00402 B(index, 0) = f;
00403 index++;
00404 }
00405 }
00406
00407
00408
00409
00410 vnl_svd<double> svd(A);
00411 P = svd.solve(B);
00412 double s_star = -P(1,0)/(2*P(0,0));
00413
00414
00415 max_f = P(0,0)*s_star*s_star + P(1,0)*s_star + P(2,0);
00416
00417 if (P(0,0)<0)
00418 return s_star;
00419 else
00420 return 5.0;
00421 }
00422
00423 void sdet_nms::find_distance_s_and_f_for_point(int x, int y, vgl_homg_line_2d<double> line,
00424 double &d, double &s, const vgl_vector_2d<double>& direction)
00425 {
00426 vgl_homg_point_2d<double> point(x,y);
00427 vgl_homg_line_2d<double> perp_line = vgl_homg_operators_2d<double>::perp_line_through_point(line, point);
00428 vgl_homg_point_2d<double> intersection_point_homg = vgl_homg_operators_2d<double>::intersection(line, perp_line);
00429 vgl_point_2d<double> intersection_point(intersection_point_homg);
00430 vgl_vector_2d<double> d_helper(x-intersection_point.x(), y-intersection_point.y());
00431 d = length(d_helper);
00432 s = intersection_point.x() / direction.x();
00433 }
00434
00435
00436
00437
00438 void sdet_nms::clear()
00439 {
00440 mag_.clear();
00441 }