00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <algorithm>
00028 #include <iostream>
00029 #include <fstream>
00030
00031 using namespace std;
00032
00033 #include <stdlib.h>
00034 #include <math.h>
00035
00036 #include "yape.h"
00037
00038 const unsigned int yape_bin_size = 1000;
00039 const int yape_tmp_points_array_size = 10000;
00040
00041 bool operator <(const keypoint &p1, const keypoint &p2)
00042 {
00043 return p1.score > p2.score;
00044 }
00045
00046 yape::yape(int _width, int _height)
00047 : tmp_points(16)
00048 {
00049 width = _width;
00050 height = _height;
00051
00052 radius = 3;
00053 tau = 4;
00054 minimal_neighbor_number = 4;
00055
00056 activate_bins();
00057 set_bins_number(4, 4);
00058
00059 disactivate_subpixel();
00060
00061 set_minimal_neighbor_number(3);
00062
00063 init_for_monoscale();
00064 }
00065
00066 yape::~yape()
00067 {
00068 if (Dirs) delete Dirs;
00069 if (Dirs_nb) delete[] Dirs_nb;
00070 if (scores) cvReleaseImage(&scores);
00071 if (filtered_image) cvReleaseImage(&filtered_image);
00072 }
00073
00074 int yape::static_detect(IplImage * image, keypoint * points, int max_point_number, int _radius, int _tau)
00075 {
00076 yape * pe = new yape(image->width, image->height);
00077
00078 pe->set_radius(_radius);
00079 pe->set_tau(_tau);
00080 int point_number = pe->detect(image, points, max_point_number);
00081
00082 delete pe;
00083
00084 return point_number;
00085 }
00086
00087 void yape::set_radius(int _radius)
00088 {
00089 radius = _radius;
00090 }
00091
00092 void yape::set_tau(int _tau)
00093 {
00094 tau = _tau;
00095 }
00096
00097 void yape::init_for_monoscale(void)
00098 {
00099 scores = cvCreateImage(cvSize(width, height), IPL_DEPTH_16S, 1);
00100 cvSetZero(scores);
00101 filtered_image = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
00102
00103 Dirs = new dir_table;
00104 memset(Dirs,0,sizeof(dir_table));
00105 Dirs_nb = new int[yape_max_radius];
00106 memset(Dirs_nb,0,sizeof(int)*yape_max_radius);
00107 for(int R = 1; R < yape_max_radius; R++)
00108 precompute_directions(filtered_image, Dirs->t[R], &(Dirs_nb[R]), R);
00109 }
00110
00111 void yape::reserve_tmp_arrays(void)
00112 {
00113 if (use_bins)
00114 for(int i = 0; i < bin_nb_u; i++)
00115 for(int j = 0; j < bin_nb_v; j++)
00116 {
00117 bins[i][j].clear();
00118 bins[i][j].reserve(yape_bin_size);
00119 }
00120 else
00121 {
00122 tmp_points.clear();
00123 tmp_points.reserve(yape_tmp_points_array_size);
00124 }
00125 }
00126
00127 void yape::precompute_directions(IplImage * image, short * _Dirs, int * _Dirs_nb, int R)
00128 {
00129 int widthStep = image->widthStep;
00130
00131 int i = 0;
00132 int x, y;
00133
00134 x = R;
00135 for(y = 0; y < x; y++, i++)
00136 {
00137 x = int(sqrt(double(R * R - y * y)) + 0.5);
00138 _Dirs[i] = short(x + widthStep * y);
00139 }
00140 for(x-- ; x < y && x >= 0; x--, i++)
00141 {
00142 y = int(sqrt(double(R * R - x * x)) + 0.5);
00143 _Dirs[i] = short(x + widthStep * y);
00144 }
00145 for( ; -x < y; x--, i++)
00146 {
00147 y = int(sqrt(double(R * R - x * x)) + 0.5);
00148 _Dirs[i] = short(x + widthStep * y);
00149 }
00150 for(y-- ; y >= 0; y--, i++)
00151 {
00152 x = int(-sqrt(double(R * R - y * y)) - 0.5);
00153 _Dirs[i] = short(x + widthStep * y);
00154 }
00155 for(; y > x; y--, i++)
00156 {
00157 x = int(-sqrt(double(R * R - y * y)) - 0.5);
00158 _Dirs[i] = short(x + widthStep * y);
00159 }
00160 for(x++ ; x <= 0; x++, i++)
00161 {
00162 y = int(-sqrt(double(R * R - x * x)) - 0.5);
00163 _Dirs[i] = short(x + widthStep * y);
00164 }
00165 for( ; x < -y; x++, i++)
00166 {
00167 y = int(-sqrt(double(R * R - x * x)) - 0.5);
00168 _Dirs[i] = short(x + widthStep * y);
00169 }
00170 for(y++ ; y < 0; y++, i++)
00171 {
00172 x = int(sqrt(double(R * R - y * y)) + 0.5);
00173 _Dirs[i] = short(x + widthStep * y);
00174 }
00175
00176 *_Dirs_nb = i;
00177 _Dirs[i] = _Dirs[0];
00178 _Dirs[i + 1] = _Dirs[1];
00179 }
00180
00181 bool yape::double_check(IplImage * image, int x, int y, short * dirs, unsigned char dirs_nb)
00182 {
00183 unsigned char * I = (unsigned char *)(image->imageData + y * image->widthStep);
00184 int Ip = I[x] + tau;
00185 int Im = I[x] - tau;
00186 int A;
00187
00188 for(A = dirs_nb / 2 - 2; A <= dirs_nb / 2 + 2; A++)
00189 for(int i = 0; i < dirs_nb - A; i++)
00190 {
00191 if (I[x+dirs[i]] > Im && I[x+dirs[i]] < Ip && I[x+dirs[i+A]] > Im && I[x+dirs[i+A]] < Ip)
00192 return false;
00193 }
00194
00195 return true;
00196 }
00197
00198 #define A_INF (A < Im)
00199 #define A_SUP (A > Ip)
00200 #define A_NOT_INF (A >= Im)
00201 #define A_NOT_SUP (A <= Ip)
00202
00203 #define B0_INF (B0 < Im)
00204 #define B0_SUP (B0 > Ip)
00205 #define B0_NOT_INF (B0 >= Im)
00206 #define B0_NOT_SUP (B0 <= Ip)
00207
00208 #define B1_INF (B1 < Im)
00209 #define B1_SUP (B1 > Ip)
00210 #define B1_NOT_INF (B1 >= Im)
00211 #define B1_NOT_SUP (B1 <= Ip)
00212
00213 #define B2_INF (B2 < Im)
00214 #define B2_SUP (B2 > Ip)
00215 #define B2_NOT_INF (B2 >= Im)
00216 #define B2_NOT_SUP (B2 <= Ip)
00217
00218 #define GET_A() A = I[x+dirs[a]]
00219 #define GET_B0() B0 = I[x+dirs[b]]
00220 #define GET_B1() b++; B1 = I[x+dirs[b]]
00221 #define GET_B2() b++; B2 = I[x+dirs[b]]
00222
00223 #define GOTO_STATE(s) { score -= A + B1; state = (s); break; }
00224 #define GOTO_END_NOT_AN_INTEREST_POINT { Scores[x] = 0; return; }
00225 #define PUT_B2_IN_B1_AND_GET_B2() B1 = B2; GET_B2()
00226
00227 #define B1_NOT_INF_B2_NOT_INF 0
00228 #define B1_NOT_SUP_B2_NOT_SUP 1
00229 #define B1_INF_B2_INF 2
00230 #define B1_SUP_B2_SUP 3
00231 #define B1_INF_B2_NOT_SUP 4
00232 #define B1_SUP_B2_NOT_INF 5
00233 #define B1_SUP_B2_INF 6
00234 #define B1_INF_B2_SUP 7
00235 #define B1_EQUAL_B2_NOT_SUP 8
00236 #define B1_EQUAL_B2_NOT_INF 9
00237
00238 void yape::perform_one_point(const unsigned char * I, const int x, short * Scores,
00239 const int Im, const int Ip,
00240 const short * dirs, const unsigned char opposite, const unsigned char dirs_nb)
00241 {
00242 int score = 0;
00243 unsigned char a = 0, b = opposite - 1;
00244 int A, B0, B1, B2;
00245 unsigned char state;
00246
00247
00248 GET_A();
00249 if (A_NOT_SUP) {
00250 if (A_NOT_INF) {
00251 GET_B0();
00252 if (B0_NOT_SUP) {
00253 if (B0_NOT_INF) GOTO_END_NOT_AN_INTEREST_POINT
00254 else {
00255 GET_B1();
00256 if (B1_SUP) {
00257 GET_B2();
00258 if (B2_SUP) state = B1_SUP_B2_SUP;
00259 else if (B2_INF) state = B1_SUP_B2_INF;
00260 else GOTO_END_NOT_AN_INTEREST_POINT
00261 }
00262 else {
00263 GET_B2();
00264 if (B2_SUP) state = B1_INF_B2_SUP;
00265 else if (B2_INF) state = B1_INF_B2_INF;
00266 else GOTO_END_NOT_AN_INTEREST_POINT
00267 }
00268
00269 }
00270 }
00271 else {
00272 GET_B1();
00273 if (B1_SUP) {
00274 GET_B2();
00275 if (B2_SUP) state = B1_SUP_B2_SUP;
00276 else if (B2_INF) state = B1_SUP_B2_INF;
00277 else GOTO_END_NOT_AN_INTEREST_POINT
00278 }
00279 else if (B1_INF) {
00280 GET_B2();
00281 if (B2_SUP) state = B1_INF_B2_SUP;
00282 else if (B2_INF) state = B1_INF_B2_INF;
00283 else GOTO_END_NOT_AN_INTEREST_POINT
00284 }
00285 else GOTO_END_NOT_AN_INTEREST_POINT
00286 }
00287 }
00288 else {
00289 GET_B0();
00290 if (B0_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00291 GET_B1();
00292 if (B1_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00293 GET_B2();
00294 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00295 state = B1_NOT_SUP_B2_NOT_SUP;
00296 }
00297 }
00298 else
00299 {
00300 GET_B0();
00301 if (B0_INF) GOTO_END_NOT_AN_INTEREST_POINT
00302 GET_B1();
00303 if (B1_INF) GOTO_END_NOT_AN_INTEREST_POINT
00304 GET_B2();
00305 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00306 state = B1_NOT_INF_B2_NOT_INF;
00307 }
00308
00309 for(a = 1; a <= opposite; a++)
00310 {
00311 GET_A();
00312
00313 switch(state)
00314 {
00315 case B1_NOT_INF_B2_NOT_INF:
00316 if (A_SUP) {
00317 PUT_B2_IN_B1_AND_GET_B2();
00318 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00319 GOTO_STATE(B1_NOT_INF_B2_NOT_INF);
00320 }
00321 if (A_INF) {
00322 if (B1_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00323 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00324 PUT_B2_IN_B1_AND_GET_B2();
00325 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00326 GOTO_STATE(B1_EQUAL_B2_NOT_SUP);
00327 }
00328
00329 if (B1_NOT_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00330 if (B2_NOT_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00331 PUT_B2_IN_B1_AND_GET_B2();
00332 if (B2_SUP) GOTO_STATE(B1_SUP_B2_SUP);
00333 if (B2_INF) GOTO_STATE(B1_SUP_B2_INF);
00334 GOTO_END_NOT_AN_INTEREST_POINT
00335
00336 case B1_NOT_SUP_B2_NOT_SUP:
00337 if (A_INF) {
00338 PUT_B2_IN_B1_AND_GET_B2();
00339 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00340 GOTO_STATE(B1_NOT_SUP_B2_NOT_SUP);
00341 }
00342 if (A_SUP) {
00343 if (B1_INF) GOTO_END_NOT_AN_INTEREST_POINT
00344 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00345 PUT_B2_IN_B1_AND_GET_B2();
00346 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00347 GOTO_STATE(B1_EQUAL_B2_NOT_INF);
00348 }
00349
00350 if (B1_NOT_INF) GOTO_END_NOT_AN_INTEREST_POINT
00351 if (B2_NOT_INF) GOTO_END_NOT_AN_INTEREST_POINT
00352 PUT_B2_IN_B1_AND_GET_B2();
00353 if (B2_INF) GOTO_STATE(B1_INF_B2_INF);
00354 if (B2_SUP) GOTO_STATE(B1_INF_B2_SUP);
00355 GOTO_END_NOT_AN_INTEREST_POINT
00356
00357 case B1_INF_B2_INF:
00358 if (A_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00359 PUT_B2_IN_B1_AND_GET_B2();
00360 if (A_INF)
00361 {
00362 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00363 GOTO_STATE(B1_INF_B2_NOT_SUP);
00364 }
00365
00366 if (B2_SUP) GOTO_STATE(B1_INF_B2_SUP);
00367 if (B2_INF) GOTO_STATE(B1_INF_B2_INF);
00368 GOTO_END_NOT_AN_INTEREST_POINT
00369
00370 case B1_SUP_B2_SUP:
00371 if (A_INF) GOTO_END_NOT_AN_INTEREST_POINT
00372 PUT_B2_IN_B1_AND_GET_B2();
00373 if (A_SUP) {
00374 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00375 GOTO_STATE(B1_SUP_B2_NOT_INF);
00376 }
00377
00378 if (B2_SUP) GOTO_STATE(B1_SUP_B2_SUP);
00379 if (B2_INF) GOTO_STATE(B1_SUP_B2_INF);
00380 GOTO_END_NOT_AN_INTEREST_POINT
00381
00382 case B1_INF_B2_NOT_SUP:
00383 if (A_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00384 if (A_INF) {
00385 PUT_B2_IN_B1_AND_GET_B2();
00386 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00387 GOTO_STATE(B1_NOT_SUP_B2_NOT_SUP);
00388 }
00389 if (B2_NOT_INF) GOTO_END_NOT_AN_INTEREST_POINT
00390 PUT_B2_IN_B1_AND_GET_B2();
00391 if (B2_INF) GOTO_STATE(B1_INF_B2_INF);
00392 if (B2_SUP) GOTO_STATE(B1_INF_B2_SUP);
00393 GOTO_END_NOT_AN_INTEREST_POINT
00394
00395 case B1_SUP_B2_NOT_INF:
00396 if (A_INF) GOTO_END_NOT_AN_INTEREST_POINT
00397 if (A_SUP) {
00398 PUT_B2_IN_B1_AND_GET_B2();
00399 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00400 GOTO_STATE(B1_NOT_INF_B2_NOT_INF);
00401 }
00402
00403 if (B2_NOT_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00404 PUT_B2_IN_B1_AND_GET_B2();
00405 if (B2_SUP) GOTO_STATE(B1_SUP_B2_SUP);
00406 if (B2_INF) GOTO_STATE(B1_SUP_B2_INF);
00407 GOTO_END_NOT_AN_INTEREST_POINT
00408
00409 case B1_INF_B2_SUP:
00410 if (A_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00411 if (A_INF) GOTO_END_NOT_AN_INTEREST_POINT
00412 PUT_B2_IN_B1_AND_GET_B2();
00413
00414 if (B2_SUP) GOTO_STATE(B1_SUP_B2_SUP);
00415 if (B2_INF) GOTO_STATE(B1_SUP_B2_INF);
00416 GOTO_END_NOT_AN_INTEREST_POINT
00417
00418 case B1_SUP_B2_INF:
00419 if (A_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00420 if (A_INF) GOTO_END_NOT_AN_INTEREST_POINT
00421 PUT_B2_IN_B1_AND_GET_B2();
00422
00423 if (B2_INF) GOTO_STATE(B1_INF_B2_INF);
00424 if (B2_SUP) GOTO_STATE(B1_INF_B2_SUP);
00425 GOTO_END_NOT_AN_INTEREST_POINT
00426
00427 case B1_EQUAL_B2_NOT_SUP:
00428 if (A_SUP) {
00429 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00430 PUT_B2_IN_B1_AND_GET_B2();
00431 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00432 GOTO_STATE(B1_EQUAL_B2_NOT_INF);
00433 }
00434 if (A_INF) {
00435 PUT_B2_IN_B1_AND_GET_B2();
00436 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00437 GOTO_STATE(B1_NOT_SUP_B2_NOT_SUP);
00438 }
00439 GOTO_END_NOT_AN_INTEREST_POINT
00440
00441 case B1_EQUAL_B2_NOT_INF:
00442 if (A_INF) {
00443 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00444 PUT_B2_IN_B1_AND_GET_B2();
00445 if (B2_SUP) GOTO_END_NOT_AN_INTEREST_POINT
00446 GOTO_STATE(B1_EQUAL_B2_NOT_SUP);
00447 }
00448 if (A_SUP) {
00449 PUT_B2_IN_B1_AND_GET_B2();
00450 if (B2_INF) GOTO_END_NOT_AN_INTEREST_POINT
00451 GOTO_STATE(B1_NOT_INF_B2_NOT_INF);
00452 }
00453 GOTO_END_NOT_AN_INTEREST_POINT
00454
00455 default:
00456 cout << "PB default" << endl;
00457 }
00458 }
00459
00460 Scores[x] = short(score + dirs_nb * I[x]);
00461 }
00462
00463 int yape::detect(IplImage * image, keypoint * points, int max_point_number, IplImage * _filtered_image)
00464 {
00465 IplImage * used_filtered_image;
00466
00467 if (_filtered_image == 0)
00468 {
00469 int gaussian_filter_size = 3;
00470
00471 if (radius >= 5) gaussian_filter_size = 5;
00472 if (radius >= 7) gaussian_filter_size = 7;
00473 cvSmooth(image, filtered_image, CV_GAUSSIAN, gaussian_filter_size, gaussian_filter_size);
00474
00475 used_filtered_image = filtered_image;
00476 }
00477 else
00478 used_filtered_image = _filtered_image;
00479
00480 reserve_tmp_arrays();
00481
00482 raw_detect(used_filtered_image);
00483
00484 get_local_maxima(image, radius, 0);
00485
00486 int points_nb = pick_best_points(points, max_point_number);
00487
00488 if (use_subpixel)
00489 for(int i = 0; i < points_nb; i++)
00490 subpix_refine(used_filtered_image, points + i);
00491
00492 return points_nb;
00493 }
00494
00495 static unsigned mymin(unsigned a, unsigned b)
00496 {
00497 return (a<b ? a:b);
00498 }
00499
00503 int yape::pick_best_points(keypoint * points, unsigned int max_point_number)
00504 {
00505 if (use_bins)
00506 {
00507 unsigned int N = 0;
00508 for(int i = 0; i < bin_nb_u; i++)
00509 {
00510 for(int j = 0; j < bin_nb_v; j++)
00511 {
00512 if (bins[i][j].size() > 0){
00513 sort(bins[i][j].begin(), bins[i][j].end());
00514 N += bins[i][j].size();
00515 }
00516 }
00517 }
00518
00519 N = max_point_number;
00520 unsigned int N_per_bin = N / (bin_nb_u * bin_nb_v);
00521 int points_nb = 0;
00522 for(int i = 0; i < bin_nb_u; i++)
00523 {
00524 for(int j = 0; j < bin_nb_v; j++)
00525 {
00526 for(unsigned int k = 0; k < mymin(N_per_bin, bins[i][j].size()); k++, points_nb++)
00527 points[points_nb] = bins[i][j][k];
00528 }
00529 }
00530
00531 return points_nb;
00532 }
00533 else
00534 if (tmp_points.size() > 0)
00535 {
00536 sort(tmp_points.begin(), tmp_points.end());
00537
00538 int score_threshold = 5;
00539
00540 int tot_pts = tmp_points.size()<max_point_number ? tmp_points.size() : max_point_number;
00541
00542 int points_nb = 0;
00543 for(points_nb = 0;
00544 points_nb<tot_pts && tmp_points[points_nb].score>score_threshold;
00545 points_nb++)
00546 points[points_nb] = tmp_points[points_nb];
00547
00548 return points_nb;
00549 }
00550
00551 return 0;
00552 }
00553
00558 void yape::raw_detect(IplImage *im) {
00559 unsigned int R = radius;
00560 short * dirs = Dirs->t[R];
00561 unsigned char dirs_nb = (unsigned char)(Dirs_nb[R]);
00562 unsigned char opposite = dirs_nb / 2;
00563
00564 CvRect roi = cvGetImageROI(im);
00565
00566 if (roi.x < int(R+1)) roi.x = R+1;
00567 if (roi.y < int(R+1)) roi.y = R+1;
00568 if ((roi.x + roi.width) > int(im->width-R-2)) roi.width = im->width - R - roi.x - 2;
00569 if ((roi.y + roi.height) > int(im->height-R-2)) roi.height = im->height - R - roi.y - 2;
00570
00571 unsigned int xend = roi.x + roi.width;
00572 unsigned int yend = roi.y + roi.height;
00573
00574
00575 #ifdef _OPENMP
00576 #pragma omp parallel for schedule(static) if (roi.height>1024)
00577 #endif
00578 for(int y = roi.y; y < (int)yend; y++)
00579 {
00580 unsigned char * I = (unsigned char *)(im->imageData + y*im->widthStep);
00581 short * Scores = (short *)(scores->imageData + y*scores->widthStep);
00582
00583 for(unsigned int x = roi.x; x < xend; x++)
00584 {
00585 int Ip = I[x] + tau;
00586 int Im = I[x] - tau;
00587
00588 if (Im<I[x+R] && I[x+R]<Ip && Im<I[x-R] && I[x-R]<Ip)
00589
00590 Scores[x] = 0;
00591 else
00592 perform_one_point(I, x, Scores, Im, Ip, dirs, opposite, dirs_nb);
00593 }
00594 }
00595 }
00596
00597 #define Dx 1
00598 #define Dy next_line
00599
00600 #define W (-Dx)
00601 #define E (+Dx)
00602 #define N (-Dy)
00603 #define S (+Dy)
00604
00605 #define MINIMAL_SCORE (0 / radius)
00606
00607 inline bool yape::third_check(const short * Sb, const int next_line)
00608 {
00609 int n = 0;
00610
00611 if (Sb[E] != 0) n++;
00612 if (Sb[W] != 0) n++;
00613 if (Sb[S] != 0) n++;
00614 if (Sb[S+E] != 0) n++;
00615 if (Sb[S+W] != 0) n++;
00616 if (Sb[N] != 0) n++;
00617 if (Sb[N+E] != 0) n++;
00618 if (Sb[N+W] != 0) n++;
00619
00620 return n >= minimal_neighbor_number;
00621 }
00622
00623
00624 static inline bool is_local_maxima(const short *p, int neighborhood, const IplImage *scores)
00625 {
00626 #ifdef CONSIDER_ABS_VALUE_ONLY
00627 unsigned v = abs(p[0]);
00628 if (v < 5) return false;
00629
00630 int step = scores->widthStep / 2;
00631
00632 p -= step*neighborhood;
00633 for (int y= -neighborhood; y<=neighborhood; ++y) {
00634 for (int x= -neighborhood; x<=neighborhood; ++x) {
00635 if (abs(p[x]) > v)
00636 return false;
00637 }
00638 p += step;
00639 }
00640 return true;
00641 #else
00642 int v = p[0];
00643
00644 int step = scores->widthStep / 2;
00645
00646 if (v > 0) {
00647 p -= step*neighborhood;
00648 for (int y= -neighborhood; y<=neighborhood; ++y) {
00649 for (int x= -neighborhood; x<=neighborhood; ++x) {
00650 if (p[x] > v)
00651 return false;
00652 }
00653 p += step;
00654 }
00655 } else {
00656 p -= step*neighborhood;
00657 for (int y= -neighborhood; y<=neighborhood; ++y) {
00658 for (int x= -neighborhood; x<=neighborhood; ++x) {
00659 if (p[x] < v)
00660 return false;
00661 }
00662 p += step;
00663 }
00664 }
00665
00666 return true;
00667
00668 #endif
00669 }
00670
00674 int yape::get_local_maxima(IplImage * image, int R, float scale )
00675 {
00676 int nbpts=0;
00677
00678 const int next_line = scores->widthStep / sizeof(short);
00679 int h = scores->height;
00680 int w = scores->width;
00681
00682 CvRect roi = cvGetImageROI(image);
00683
00684 if (roi.x < int(R+1)) roi.x = R+1;
00685 if (roi.y < int(R+1)) roi.y = R+1;
00686 if ((roi.x + roi.width) > int(scores->width-R-2)) roi.width = scores->width - R - roi.x - 2;
00687 if ((roi.y + roi.height) > int(scores->height-R-2)) roi.height = scores->height - R - roi.y - 2;
00688
00689 unsigned int xend = roi.x + roi.width;
00690 unsigned int yend = roi.y + roi.height;
00691
00692 for(unsigned int y = roi.y; y < yend; y++)
00693 {
00694 short * Scores = (short *)(scores->imageData + y * scores->widthStep);
00695
00696 for(unsigned int x = roi.x; x < xend; x++)
00697 {
00698 short * Sb = Scores + x;
00699
00700
00701 if (abs(Sb[0]) < 3)
00702 ++x;
00703 else
00704 {
00705 if (third_check(Sb, next_line) && is_local_maxima(Sb, R, scores))
00706 {
00707 keypoint p;
00708 p.u = float(x);
00709 p.v = float(y);
00710 p.scale = scale;
00711 p.score = float(abs(Sb[0]));
00712
00713 if (use_bins)
00714 {
00715 int bin_u_index = (bin_nb_u * x) / w;
00716 int bin_v_index = (bin_nb_v * y) / h;
00717
00718 if (bin_u_index >= bin_nb_u)
00719 bin_u_index = bin_nb_u - 1;
00720 if (bin_v_index >= bin_nb_v)
00721 bin_v_index = bin_nb_v - 1;
00722
00723 if (bins[bin_u_index][bin_v_index].size() < yape_bin_size)
00724 bins[bin_u_index][bin_v_index].push_back(p);
00725 }
00726 else
00727 tmp_points.push_back(p);
00728
00729 nbpts++;
00730 x += R-1;
00731 }
00732 }
00733 }
00734 }
00735 return nbpts;
00736 }
00737
00739
00741
00742 static float fit_quadratic_2x2(float x[2], float L[3][3])
00743 {
00744 float H[2][2];
00745 float b[2];
00746
00747 b[0] = -(L[1][2] - L[1][0]) / 2.0f;
00748 b[1] = -(L[2][1] - L[0][1]) / 2.0f;
00749
00750 H[0][0] = L[1][0] - 2.0f * L[1][1] + L[1][2];
00751 H[1][1] = L[0][1] - 2.0f * L[1][1] + L[2][1];
00752 H[0][1] = H[1][0] = (L[0][0] - L[0][2] - L[2][0] + L[2][2]) / 4.0f;
00753
00754 float t4 = 1/(H[0][0]*H[1][1]-H[0][1]*H[1][0]);
00755 x[0] = H[1][1]*t4*b[0]-H[0][1]*t4*b[1];
00756 x[1] = -H[1][0]*t4*b[0]+H[0][0]*t4*b[1];
00757
00758 return 0.5f * (b[0] * x[0] + b[1] * x[1]);
00759 }
00760
00761 void yape::subpix_refine(IplImage *im, keypoint *p)
00762 {
00763 float L[3][3];
00764
00765 int px = (int) p->u;
00766 int py = (int) p->v;
00767 int dirs_nb = Dirs_nb[radius];
00768 short * dirs = Dirs->t[radius];
00769
00770 if ((px<= radius) || (px >= (scores->width-radius)) || (py <= radius) || (py >= (scores->height-radius)))
00771 return;
00772
00773 assert(px>0 && px<(im->width-1));
00774 assert(py>0 && py<(im->height-1));
00775
00776 unsigned char * I = (unsigned char *) (im->imageData + py*im->widthStep) + px;
00777 short * s = (short *) (scores->imageData + py*scores->widthStep) + px;
00778 int line = scores->widthStep/sizeof(short);
00779
00780 for (int y=0; y<3; ++y) {
00781 int offset = (y-1)*line - 1;
00782 for (int x=0; x<3; ++x) {
00783 if (s[ offset + x]==0) {
00784
00785 int score = 0;
00786 int I_offset = (y-1)*im->widthStep + x;
00787 for (int d=0; d<dirs_nb; ++d)
00788 score += I[ I_offset + dirs[d]];
00789 L[y][x] = -float(score - dirs_nb*(int)I[I_offset + x]);
00790 } else {
00791 L[y][x] = (float)s[ offset + x];
00792 }
00793 }
00794 }
00795
00796 float delta[2];
00797 p->score += fit_quadratic_2x2(delta, L);
00798
00799 if ((delta[0] >= -1) && (delta[0] <= 1))
00800 p->u += delta[0];
00801 else
00802 p->u+=0.5f;
00803 if ((delta[1] >= -1) && (delta[1] <= 1))
00804 p->v += delta[1];
00805 else
00806 p->v+=0.5f;
00807 }
00808
00810
00812
00817 pyr_yape::pyr_yape(int w, int h, int nbLev)
00818 : yape (w,h)
00819 {
00820 internal_pim = 0;
00821 distortParams=0;
00822 pscores = new PyrImage(scores, nbLev);
00823 pDirs[0] = Dirs;
00824 pDirs_nb[0] = Dirs_nb;
00825 equalize = false;
00826
00827 PyrImage pim(cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1),nbLev);
00828
00829 for (int i=1; i<nbLev; i++) {
00830 cvSetZero(pscores->images[i]);
00831 pDirs[i] = new dir_table;
00832 pDirs_nb[i] = new int[yape_max_radius];
00833 for(int R = 1; R < yape_max_radius; R++)
00834 precompute_directions(pim[i], pDirs[i]->t[R], &(pDirs_nb[i][R]), R);
00835 }
00836 }
00837
00838 pyr_yape::~pyr_yape()
00839 {
00840 if (internal_pim) delete internal_pim;
00841
00842 for (int i=0; i<pscores->nbLev; i++) {
00843 delete pDirs[i];
00844 delete[] pDirs_nb[i];
00845 }
00846 Dirs=0;
00847 Dirs_nb=0;
00848 delete pscores;
00849 pscores = 0;
00850 scores = 0;
00851 }
00852
00853 void pyr_yape::select_level(int l)
00854 {
00855 scores = pscores->images[l];
00856 Dirs = pDirs[l];
00857 Dirs_nb = pDirs_nb[l];
00858 }
00859
00863 int pyr_yape::detect(PyrImage *image, keypoint *points, int max_point_number)
00864 {
00865 reserve_tmp_arrays();
00866
00867 for (int i=image->nbLev-1; i>=0; --i)
00868 {
00869 select_level(i);
00870 raw_detect(image->images[i]);
00871 get_local_maxima(image->images[i], radius, float(i));
00872 }
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905 int n = pick_best_points(points, max_point_number);
00906 for (int i = 0; i < n; i++) {
00907 int l =(int)points[i].scale;
00908 select_level(l);
00909 subpix_refine(image->images[l], points + i);
00910 if (distortParams) {
00911 float uv[2];
00912 undistort(PyrImage::convCoordf(points[i].u, l, 0),
00913 PyrImage::convCoordf(points[i].v, l, 0),
00914 uv, *distortParams);
00915 points[i].u_undist = uv[0];
00916 points[i].v_undist = uv[1];
00917 } else {
00918 points[i].u_undist = PyrImage::convCoordf(points[i].u, l, 0);
00919 points[i].v_undist = PyrImage::convCoordf(points[i].v, l, 0);
00920 }
00921 }
00922
00923 return n;
00924 }
00925
00941 int pyr_yape::pyramidBlurDetect(IplImage *im, keypoint *points, int max_point_number, PyrImage *caller_pim)
00942 {
00943 assert(im->nChannels == 1);
00944
00945 PyrImage *pim;
00946
00947 if (caller_pim == 0)
00948 {
00949 if (internal_pim && ((internal_pim->images[0]->width != im->width)
00950 || (internal_pim->images[0]->height != im->height)))
00951 {
00952 delete internal_pim;
00953 internal_pim = 0;
00954 }
00955
00956 if (internal_pim == 0)
00957 internal_pim = new PyrImage(cvCreateImage(cvGetSize(im), IPL_DEPTH_8U, 1), pscores->nbLev);
00958
00959 pim = internal_pim;
00960 }
00961 else
00962 {
00963 pim = caller_pim;
00964 assert (im->width == caller_pim->images[0]->width);
00965 }
00966
00967 int gaussian_filter_size = 3;
00968 if (radius >= 5) gaussian_filter_size = 5;
00969 if (radius >= 7) gaussian_filter_size = 7;
00970 cvSmooth(im, pim->images[0], CV_GAUSSIAN, gaussian_filter_size, gaussian_filter_size);
00971
00972
00973
00974 pim->build();
00975
00976 return detect(pim, points, max_point_number);
00977 }
00978
00979
00980 void pyr_yape::stat_points(keypoint *points, int nb_pts)
00981 {
00982 int *histogram = new int[pscores->nbLev];
00983
00984 for (int l=0; l< pscores->nbLev; ++l) histogram[l]=0;
00985
00986 for (int i=0; i<nb_pts; ++i)
00987 histogram[(int)(points[i].scale)]++;
00988
00989 for (int l=0; l< pscores->nbLev; ++l)
00990 cout << "Level " << l << ": " << histogram[l] << " keypoints ("
00991 << 100.0f * (float)histogram[l]/(float)nb_pts << "%)\n";
00992
00993 delete[] histogram;
00994 }
00995
00996 void pyr_yape::cmp_orientation(PyrImage *im, keypoint *points, int nbpts) {
00997
00998 for (int i=0; i<nbpts; i++) {
00999 keypoint *k = points + i;
01000 if (k->scale < im->nbLev-1) {
01001 int u = cvRound(k->u * .5f);
01002 int v = cvRound(k->v * .5f);
01003 IplImage * levim = im->images[k->scale+1];
01004 unsigned char *pix = &CV_IMAGE_ELEM(levim, unsigned char, v, u);
01005 int dx = pix[2]-pix[-2];
01006 int dy = pix[-2*levim->widthStep]-pix[2*levim->widthStep];
01007 k->orientation = atan2f((float)dy,(float)dx);
01008 } else {
01009 int u = cvRound(k->u);
01010 int v = cvRound(k->v);
01011 IplImage * levim = im->images[k->scale];
01012 unsigned char *pix = &CV_IMAGE_ELEM(levim, unsigned char, v, u);
01013 int dx = pix[2]-pix[-2];
01014 int dy = pix[-2*levim->widthStep]-pix[2*levim->widthStep];
01015 k->orientation = atan2f((float)dy,(float)dx);
01016 }
01017
01018 }
01019 }
01020
01021