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
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "dlut_place_recognition/place_recognition.h"
00038
00039 #define SAMPLINGSTEP 1
00040 #define CV_SURF_EXTENDED 1
00041 #define FEATURE_LOWE_COLOR CV_RGB(255, 0, 255)
00042 #define SURF_KDTREE_BBF_MAX_NN_CHKS 400
00043 #define SURF_NN_SQ_DIST_RATIO_THR 0.6
00044 #define MINPQ_INIT_NALLOCD 512
00045 #define MAXDIM 9
00046 #define CLUSTERINGNUM 2
00047 #define DANGLE 4
00048 #define MINN 17
00049 #define DISMAX 0.1
00050 #define MIN_AMOUNT 4
00051
00052 template <typename T> int cvSign (T t)
00053 {
00054 return ((t < 0) ? -1 : 1);
00055 }
00056
00057 static __inline int parent (int i)
00058 {
00059 return (i - 1) / 2;
00060 }
00061
00062
00063 static __inline int right (int i)
00064 {
00065 return 2 * i + 2;
00066 }
00067
00068
00069 static __inline int left (int i)
00070 {
00071 return 2 * i + 1;
00072 }
00073
00074
00075 PlaceRecognition::PlaceRecognition ()
00076 {
00077 wrap = 0;
00078 }
00079
00080 PlaceRecognition::~PlaceRecognition ()
00081 {
00082 }
00083
00084
00085 bool PlaceRecognition::extractGlobalFeature (std::vector< std::vector<pcl::PointXYZ> > &points, GlobalFeature* global_feature)
00086 {
00087
00088 if (points.size () > 0)
00089 {
00090 int r = points.size ();
00091 int k_r = 35;
00092 double area = 0;
00093 double dis = 0;
00094
00095 for (int i = 0; i < (int) points[k_r].size () - 1; i++)
00096 {
00097 dis = sqrt ((points[k_r][i].x * points[k_r][i].x) + (points[k_r][i].y * points[k_r][i].y) +
00098 (points[k_r][i].z * points[k_r][i].z));
00099 area += 0.5 * (0.5 / 360) * 2 * PI * dis * dis;
00100 }
00101 global_feature->duty_cycle = area;
00102
00103
00104 for (int i = k_r - 1; i < r - 1; i++)
00105 {
00106 double w_a = 0;
00107 for (int j = 0; j < (int) points[i].size () - 1; j++)
00108 {
00109 dis = sqrt ((points[i][j].x * points[i][j].x) + (points[i][j].y * points[i][j].y) +
00110 (points[i][j].z * points[i][j].z));
00111 w_a += 0.5 * (0.5 / 360) * 2 * PI * dis * dis;
00112 }
00113
00114 if (w_a > area)
00115 {
00116 area = w_a;
00117 }
00118 }
00119 global_feature->area = area;
00120 return true;
00121 }
00122 else
00123 {
00124 QMessageBox::critical (NULL, "Critical", "Extract global spatial features failed!\n"
00125 "NO available data, please load data at first!",
00126 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
00127 return false;
00128 }
00129 }
00130
00131 void PlaceRecognition::cvSURFInitialize ()
00132 {
00133 wrap = cvCreateMat (2, 3, CV_32FC1);
00134 int k = 0;
00135 for (int i = 0; i < SCANOCTAVE; i++)
00136 {
00137 for (int j = 0; j < FILTERSCALE; j++)
00138 {
00139 double scal = ((j * 6 + 9) << i) * 1.2 / 9.;
00140 regions_cache[k] = cvCreateImage (cvSize (cvRound (21 * scal), cvRound (21 * scal)), 8, 1);
00141 k++;
00142 }
00143 }
00144
00145 region_cache = cvCreateImage (cvSize (21, 21), 8, 1);
00146 dx_cache = cvCreateMat (20, 20, CV_64FC1);
00147 dy_cache = cvCreateMat (20, 20, CV_64FC1);
00148 gauss_kernel_cache = cvCreateMat (20, 20, CV_64FC1);
00149 cvSURFGaussian (gauss_kernel_cache, 3.3);
00150
00151 for (int i = 0; i < 3600; i++)
00152 {
00153 cos_cache[i] = cos (i * 0.001745329);
00154 sin_cache[i] = sin (i * 0.001745329);
00155 }
00156 }
00157
00158 void PlaceRecognition::cvSURFGaussian (CvMat* mat, double s)
00159 {
00160 int w = mat->cols;
00161 int h = mat->rows;
00162 double x, y;
00163 double c2 = 1. / (s * s * 2);
00164 double over_exp = 1. / (3.14159 * 2 * s * s);
00165 for (int i = 0; i < w; i++)
00166 for (int j = 0; j < h; j++)
00167 {
00168 x = i - w / 2.;
00169 y = j - h / 2.;
00170 cvmSet (mat, j, i, exp (-(x * x + y * y) * c2) * over_exp);
00171 }
00172 }
00173
00174 CvSeq* PlaceRecognition::cvSURFDescriptor (const CvArr* _img, CvMemStorage* storage, double quality, int flags)
00175 {
00176 IplImage* img = (IplImage*) _img;
00177 CvMat* sum = 0;
00178 sum = cvCreateMat (img->height + 1, img->width + 1, CV_32SC1);
00179 cvIntegral (img, sum);
00180 CvMemStorage* point_storage = cvCreateChildMemStorage (storage);
00181 CvSeq* points = cvFastHessianDetector (sum, point_storage, quality);
00182
00183 CvSeq* descriptors = cvCreateSeq (0, sizeof (CvSeq), sizeof (SURFDescriptor), storage);
00184 int dx_s[] = { 2, 0, 0, 2, 4, 0, -1, 2, 0, 4, 4, 0, 1 };
00185 int dy_s[] = { 2, 0, 0, 4, 2, 0, -1, 0, 2, 4, 4, 0, 1 };
00186 int dx_t[] = { 2, 0, 0, 2, 4, 0, -1, 2, 0, 4, 4, 0, 1 };
00187 int dy_t[] = { 2, 0, 0, 4, 2, 0, -1, 0, 2, 4, 4, 0, 1 };
00188 double x[81], *iter_x;
00189 double y[81], *iter_y;
00190 double angle[81], *iter_angle;
00191 double sumx, sumy;
00192 double temp_mod;
00193 int angle_n;
00194 for (int k = 0; k < points->total; k++)
00195 {
00196 SURFPoint* point = (SURFPoint*) cvGetSeqElem (points, k);
00197 SURFDescriptor descriptor;
00198 descriptor.feature_data = point;
00199 descriptor.x = cvRound (point->x);
00200 descriptor.y = cvRound (point->y);
00201 descriptor.laplacian = point->laplacian;
00202 int size = point->size;
00203 int layer = point->octave * FILTERSCALE + point->scale;
00204 descriptor.s = size * 1.2 / 9.;
00205 descriptor.mod = 0;
00206
00207
00208 iter_x = x;
00209 iter_y = y;
00210 iter_angle = angle;
00211 angle_n = 0;
00212 cvResizeHaarPattern (dx_s, dx_t, 9, size);
00213 cvResizeHaarPattern (dy_s, dy_t, 9, size);
00214 int* sum_ptr = (int*) sum->data.ptr;
00215 double c2 = 1. / (descriptor.s * descriptor.s * 2.5 * 2.5 * 2);
00216 double over_exp = 1. / (3.14159 * 2 * descriptor.s * descriptor.s * 2.5 * 2.5);
00217 for (int j = -6; j <= 2; j++)
00218 {
00219 int y = descriptor.y + j * size / 9;
00220 if ((y >= 0) && (y < sum->rows - size))
00221 {
00222 double ry = j + 2;
00223 for (int i = -6; i <= 2; i++)
00224 {
00225 int x = descriptor.x + i * size / 9;
00226 if ((x >= 0) && (x < sum->cols - size))
00227 {
00228 double rx = j + 2;
00229 double radius = rx * rx + ry * ry;
00230 if (radius <= 16)
00231 {
00232 rx *= descriptor.s;
00233 ry *= descriptor.s;
00234 *iter_x = cvCalHaarPattern (sum_ptr + x + y * sum->cols, dx_t, sum->cols) * exp (-radius * c2) * over_exp;
00235 *iter_y = cvCalHaarPattern (sum_ptr + x + y * sum->cols, dy_t, sum->cols) * exp (-radius * c2) * over_exp;
00236 *iter_angle = cvFastArctan (*iter_y, *iter_x);
00237 iter_x++;
00238 iter_y++;
00239 iter_angle++;
00240 angle_n++;
00241 }
00242 }
00243 }
00244 }
00245 }
00246 double bestx = 0;
00247 double besty = 0;
00248 for (int i = 0; i < 360; i += 5)
00249 {
00250 sumx = 0;
00251 sumy = 0;
00252 iter_x = x;
00253 iter_y = y;
00254 iter_angle = angle;
00255 for (int j = 0; j < angle_n; j++)
00256 {
00257 if (((*iter_angle < i + 60) && (*iter_angle > i)) ||
00258 (((*iter_angle + 360) < i + 60) && ((*iter_angle + 360) > i)))
00259 {
00260 sumx += *iter_x;
00261 sumy += *iter_y;
00262 }
00263 iter_x++;
00264 iter_y++;
00265 iter_angle++;
00266 }
00267 temp_mod = sumx * sumx + sumy * sumy;
00268 if (temp_mod > descriptor.mod)
00269 {
00270 descriptor.mod = temp_mod;
00271 bestx = sumx;
00272 besty = sumy;
00273 }
00274 }
00275 descriptor.dir = cvFastArctan (besty, bestx);
00276
00277
00278
00279 double cos_dir = cos_cache[MAX (cvRound (descriptor.dir * 10) + 3600, 0) % 3600];
00280 double sin_dir = sin_cache[MAX (cvRound (descriptor.dir * 10) + 3600, 0) % 3600];
00281 cvmSet (wrap, 0, 0, cos_dir);
00282 cvmSet (wrap, 0, 1, -sin_dir);
00283 cvmSet (wrap, 0, 2, descriptor.x);
00284 cvmSet (wrap, 1, 0, sin_dir);
00285 cvmSet (wrap, 1, 1, cos_dir);
00286 cvmSet (wrap, 1, 2, descriptor.y);
00287
00288 cvGetQuadrangleSubPix (img, regions_cache[layer], wrap);
00289 cvResize (regions_cache[layer], region_cache, CV_INTER_AREA);
00290 uchar* region_d;
00291 int region_step;
00292 cvGetImageRawData (region_cache, ®ion_d, ®ion_step);
00293 uchar* region_x = region_d + 1;
00294 uchar* region_y = region_d + region_step;
00295 uchar* region_xy = region_d + 1 + region_step;
00296 region_step -= 20;
00297 double* iter_dx = (double*) dx_cache->data.ptr;
00298 double* iter_dy = (double*) dy_cache->data.ptr;
00299 for (int i = 0; i < 20; i++)
00300 {
00301 for (int j = 0; j < 20; j++)
00302 {
00303 *iter_dx = *region_y - *region_d - *region_x + *region_xy;
00304 *iter_dy = *region_x - *region_d - *region_y + *region_xy;
00305 iter_dx++;
00306 iter_dy++;
00307 region_d++;
00308 region_x++;
00309 region_y++;
00310 region_xy++;
00311 }
00312 region_d += region_step;
00313 region_x += region_step;
00314 region_y += region_step;
00315 region_xy += region_step;
00316 }
00317 cvMul (gauss_kernel_cache, dx_cache, dx_cache);
00318 cvMul (gauss_kernel_cache, dy_cache, dy_cache);
00319
00320 double tx, ty;
00321 double* iter_vector = descriptor.vector;
00322 if (flags & CV_SURF_EXTENDED)
00323 {
00324
00325 for (int i = 0; i < 4; i++)
00326 for (int j = 0; j < 4; j++)
00327 {
00328 iter_vector[0] = 0;
00329 iter_vector[1] = 0;
00330 iter_vector[2] = 0;
00331 iter_vector[3] = 0;
00332 iter_vector[4] = 0;
00333 iter_vector[5] = 0;
00334 iter_vector[6] = 0;
00335 iter_vector[7] = 0;
00336 for (int x = i * 5; x < i * 5 + 5; x++)
00337 {
00338 for (int y = j * 5; y < j * 5 + 5; y++)
00339 {
00340 tx = cvGetReal2D (dx_cache, x, y);
00341 ty = cvGetReal2D (dy_cache, x, y);
00342 if (ty >= 0)
00343 {
00344 iter_vector[0] += tx;
00345 iter_vector[1] += fabs (tx);
00346 }
00347 else
00348 {
00349 iter_vector[2] += tx;
00350 iter_vector[3] += fabs (tx);
00351 }
00352 if (tx >= 0)
00353 {
00354 iter_vector[4] += ty;
00355 iter_vector[5] += fabs (ty);
00356 }
00357 else
00358 {
00359 iter_vector[6] += ty;
00360 iter_vector[7] += fabs (ty);
00361 }
00362 }
00363 }
00364
00365 double normalize = 0;
00366 for (int k = 0; k < 8; k++)
00367 normalize += iter_vector[k] * iter_vector[k];
00368 normalize = sqrt (normalize);
00369 for (int k = 0; k < 8; k++)
00370 iter_vector[k] = iter_vector[k] / normalize;
00371 iter_vector += 8;
00372 }
00373 }
00374 else
00375 {
00376
00377 for (int i = 0; i < 4; i++)
00378 for (int j = 0; j < 4; j++)
00379 {
00380 iter_vector[0] = 0;
00381 iter_vector[1] = 0;
00382 iter_vector[2] = 0;
00383 iter_vector[3] = 0;
00384 for (int x = i * 5; x < i * 5 + 5; x++)
00385 {
00386 for (int y = j * 5; y < j * 5 + 5; y++)
00387 {
00388 tx = cvGetReal2D (dx_cache, x, y);
00389 ty = cvGetReal2D (dy_cache, x, y);
00390 iter_vector[0] += tx;
00391 iter_vector[1] += ty;
00392 iter_vector[2] += fabs (tx);
00393 iter_vector[3] += fabs (ty);
00394 }
00395 }
00396 double normalize = 0;
00397 for (int k = 0; k < 4; k++)
00398 normalize += iter_vector[k] * iter_vector[k];
00399 normalize = sqrt (normalize);
00400 for (int k = 0; k < 4; k++)
00401 iter_vector[k] = iter_vector[k] / normalize;
00402 iter_vector += 4;
00403 }
00404 }
00405
00406 cvSeqPush (descriptors, &descriptor);
00407 }
00408 cvReleaseMemStorage (&point_storage);
00409 cvReleaseMat (&sum);
00410
00411 return descriptors;
00412 }
00413
00414 CvSeq* PlaceRecognition::cvFastHessianDetector (const CvMat* sum, CvMemStorage* storage, double quality)
00415 {
00416 CvSeq* points = cvCreateSeq (0, sizeof (CvSeq), sizeof (SURFPoint), storage);
00417 CvMat* hessians[SCANOCTAVE * (FILTERSCALE + 2)];
00418 CvMat* traces[SCANOCTAVE * (FILTERSCALE + 2)];
00419 int size, size_cache[SCANOCTAVE * (FILTERSCALE + 2)];
00420 int scale, scale_cache[SCANOCTAVE * (FILTERSCALE + 2)];
00421 double *hessian_ptr, *hessian_ptr_cache[SCANOCTAVE * (FILTERSCALE + 2)];
00422 double *trace_ptr, *trace_ptr_cache[SCANOCTAVE * (FILTERSCALE + 2)];
00423 int dx_s[] = { 3, 0, 2, 3, 7, 0, 1, 3, 2, 6, 7, 0, -2, 6, 2, 9, 7, 0, 1 };
00424 int dy_s[] = { 3, 2, 0, 7, 3, 0, 1, 2, 3, 7, 6, 0, -2, 2, 6, 7, 9, 0, 1 };
00425 int dxy_s[] = { 4, 1, 1, 4, 4, 0, 1, 5, 1, 8, 4, 0, -1, 1, 5, 4, 8, 0, -1, 5, 5, 8, 8, 0, 1 };
00426 int dx_t[] = { 3, 0, 2, 3, 7, 0, 1, 3, 2, 6, 7, 0, -2, 6, 2, 9, 7, 0, 1 };
00427 int dy_t[] = { 3, 2, 0, 7, 3, 0, 1, 2, 3, 7, 6, 0, -2, 2, 6, 7, 9, 0, 1 };
00428 int dxy_t[] = { 4, 1, 1, 4, 4, 0, 1, 5, 1, 8, 4, 0, -1, 1, 5, 4, 8, 0, -1, 5, 5, 8, 8, 0, 1 };
00429 double dx = 0, dy = 0, dxy = 0;
00430 int k = 0;
00431 int hessian_rows, hessian_rows_cache[SCANOCTAVE * (FILTERSCALE + 2)];
00432 int hessian_cols, hessian_cols_cache[SCANOCTAVE * (FILTERSCALE + 2)];
00433
00434
00435 for (int o = 0; o < SCANOCTAVE; o++)
00436 {
00437 for (int s = -1; s < FILTERSCALE + 1; s++)
00438 {
00439 if (s < 0)
00440 size_cache[k] = size = 7 << o;
00441 else
00442 size_cache[k] = size = (s * 6 + 9) << o;
00443
00444 scale_cache[k] = scale = MAX (size, 9) * SAMPLINGSTEP;
00445 hessian_rows_cache[k] = hessian_rows = (sum->rows) * 9 / scale;
00446 hessian_cols_cache[k] = hessian_cols = (sum->cols) * 9 / scale;
00447 hessians[k] = cvCreateMat (hessian_rows, hessian_cols, CV_64FC1);
00448 traces[k] = cvCreateMat (hessian_rows, hessian_cols, CV_64FC1);
00449 int* sum_ptr = (int*) sum->data.ptr;
00450 cvResizeHaarPattern (dx_s, dx_t, 9, size);
00451 cvResizeHaarPattern (dy_s, dy_t, 9, size);
00452 cvResizeHaarPattern (dxy_s, dxy_t, 9, size);
00453 hessian_ptr_cache[k] = hessian_ptr = (double*) hessians[k]->data.ptr;
00454 trace_ptr_cache[k] = trace_ptr = (double*) traces[k]->data.ptr;
00455 hessian_ptr += 4 / SAMPLINGSTEP + (4 / SAMPLINGSTEP) * hessian_cols;
00456 trace_ptr += 4 / SAMPLINGSTEP + (4 / SAMPLINGSTEP) * hessian_cols;
00457 int oy = 0, y = 0;
00458 for (int j = 0; j < hessian_rows - 9 / SAMPLINGSTEP; j++)
00459 {
00460 int* sum_line_ptr = sum_ptr;
00461 double* trace_line_ptr = trace_ptr;
00462 double* hessian_line_ptr = hessian_ptr;
00463 int ox = 0, x = 0;
00464 for (int i = 0; i < hessian_cols - 9 / SAMPLINGSTEP; i++)
00465 {
00466 dx = cvCalHaarPattern (sum_line_ptr, dx_t, sum->cols);
00467 dy = cvCalHaarPattern (sum_line_ptr, dy_t, sum->cols);
00468 dxy = cvCalHaarPattern (sum_line_ptr, dxy_t, sum->cols);
00469 *hessian_line_ptr = (dx * dy - dxy * dxy * 0.81);
00470 *trace_line_ptr = dx + dy;
00471 x = (i + 1) * scale / 9;
00472 sum_line_ptr += x - ox;
00473 ox = x;
00474 trace_line_ptr++;
00475 hessian_line_ptr++;
00476 }
00477 y = (j + 1) * scale / 9;
00478 sum_ptr += (y - oy) * sum->cols;
00479 oy = y;
00480 trace_ptr += hessian_cols;
00481 hessian_ptr += hessian_cols;
00482 }
00483 k++;
00484 }
00485 }
00486 double min_accept = quality * 300;
00487
00488 k = 0;
00489 for (int o = 0; o < SCANOCTAVE; o++)
00490 {
00491 k++;
00492 for (int s = 0; s < FILTERSCALE; s++)
00493 {
00494 size = size_cache[k];
00495 scale = scale_cache[k];
00496 hessian_rows = hessian_rows_cache[k];
00497 hessian_cols = hessian_cols_cache[k];
00498 int margin = (5 / SAMPLINGSTEP) * scale_cache[k + 1] / scale;
00499 hessian_ptr = hessian_ptr_cache[k] + margin + margin * hessian_cols;
00500 trace_ptr = trace_ptr_cache[k];
00501 for (int j = margin; j < hessian_rows - margin; j++)
00502 {
00503 double* hessian_line_ptr = hessian_ptr;
00504 for (int i = margin; i < hessian_cols - margin; i++)
00505 {
00506 if (*hessian_line_ptr > min_accept)
00507 {
00508 bool suppressed = false;
00509
00510 for (int z = k - 1; z < k + 2; z++)
00511 {
00512 double* temp_hessian_ptr = hessian_ptr_cache[z] + i * scale / scale_cache[z] - 1 +
00513 (j * scale / scale_cache[z] - 1) * hessian_cols_cache[z];
00514 for (int y = 0; y < 3; y++)
00515 {
00516 double* temp_hessian_line_ptr = temp_hessian_ptr;
00517 for (int x = 0; x < 3; x++)
00518 {
00519 if (((z != k) || (y != 1) || (x != 1)) && (*temp_hessian_line_ptr > *hessian_line_ptr))
00520 {
00521 suppressed = true;
00522 break;
00523 }
00524 temp_hessian_line_ptr++;
00525 }
00526 if (suppressed)
00527 break;
00528 temp_hessian_ptr += hessian_cols_cache[z];
00529 }
00530 if (suppressed)
00531 break;
00532 }
00533 if (!suppressed)
00534 {
00535 SURFPoint point = cvSURFPoint (i * scale / 9, j * scale / 9, cvSign (trace_ptr[i + j * hessian_cols]),
00536 size_cache[k], o, s);
00537 cvSeqPush (points, &point);
00538 }
00539 }
00540 hessian_line_ptr++;
00541 }
00542 hessian_ptr += hessian_cols;
00543 }
00544 k++;
00545 }
00546 k++;
00547 }
00548
00549 k = 0;
00550 for (int o = 0; o < SCANOCTAVE; o++)
00551 for (int s = -1; s < FILTERSCALE + 1; s++)
00552 {
00553 cvReleaseMat (&hessians[k]);
00554 cvReleaseMat (&traces[k]);
00555 k++;
00556 }
00557
00558 return points;
00559 }
00560
00561 void PlaceRecognition::cvResizeHaarPattern (int* t_s, int* t_d, int OldSize, int NewSize)
00562 {
00563 int n = t_d[0] = t_s[0];
00564 for (int k = 0; k < n; k++)
00565 {
00566 t_d[1] = t_s[1] * NewSize / OldSize;
00567 t_d[2] = t_s[2] * NewSize / OldSize;
00568 t_d[3] = t_s[3] * NewSize / OldSize;
00569 t_d[4] = t_s[4] * NewSize / OldSize;
00570 t_d[5] = (t_d[3] - t_d[1] + 1) * (t_d[4] - t_d[2] + 1);
00571 t_d[6] = t_s[6];
00572 t_d += 6;
00573 t_s += 6;
00574 }
00575 }
00576
00577 double PlaceRecognition::cvCalHaarPattern (int* origin, int* t, int widthStep)
00578 {
00579 double d = 0;
00580 int *p0 = 0, *p1 = 0, *p2 = 0, *p3 = 0;
00581 int n = t[0];
00582 for (int k = 0; k < n; k++)
00583 {
00584 p0 = origin + t[1] + t[2] * widthStep;
00585 p1 = origin + t[1] + t[4] * widthStep;
00586 p2 = origin + t[3] + t[2] * widthStep;
00587 p3 = origin + t[3] + t[4] * widthStep;
00588 d += (double) ((*p3 - *p2 - *p1 + *p0) * t[6]) / (double) (t[5]);
00589 t += 6;
00590 }
00591 return d;
00592 }
00593
00594 SURFPoint PlaceRecognition::cvSURFPoint (int x, int y, int laplacian, int size, int octave, int scale)
00595 {
00596 SURFPoint p;
00597 p.x = x;
00598 p.y = y;
00599 p.laplacian = laplacian;
00600 p.size = size;
00601 p.octave = octave;
00602 p.scale = scale;
00603 return p;
00604 }
00605
00606 bool PlaceRecognition::drawSURFFeatures (IplImage* img, CvSeq* feat, int n)
00607 {
00608 if (n <= 0 || !feat)
00609 {
00610 QMessageBox::critical (NULL, "Critical", "No corresponding features!\n"
00611 "Please replace another scene to continue!",
00612 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
00613 return false;
00614 }
00615 else
00616 {
00617 drawSURFLoweFeatures (img, feat, n);
00618 return true;
00619 }
00620 }
00621
00622 void PlaceRecognition::drawSURFLoweFeatures (IplImage* img, CvSeq* feat, int n)
00623 {
00624 CvScalar color = CV_RGB (255, 0, 255);
00625
00626 if (img->nChannels > 1)
00627 color = FEATURE_LOWE_COLOR;
00628
00629 for (int i = 0; i < n; i++)
00630 {
00631 SURFDescriptor* feat1 = (SURFDescriptor*) cvGetSeqElem (feat, i);
00632 drawSURFLoweFeature (img, feat1, color);
00633 }
00634 }
00635
00636 void PlaceRecognition::drawSURFLoweFeature (IplImage* img, SURFDescriptor* feat, CvScalar color)
00637 {
00638 int len, hlen, blen, start_x, start_y, end_x, end_y, h1_x, h1_y, h2_x, h2_y;
00639 double scl, ori;
00640 double scale = 5.0;
00641 double hscale = 0.75;
00642 CvPoint start, end, h1, h2;
00643
00644
00645 start_x = cvRound (feat->x);
00646 start_y = cvRound (feat->y);
00647 scl = feat->s;
00648 ori = feat->dir;
00649 len = cvRound (scl * scale);
00650 hlen = cvRound (scl * hscale);
00651 blen = len - hlen;
00652 end_x = cvRound (len * cos (ori)) + start_x;
00653 end_y = cvRound (len * -sin (ori)) + start_y;
00654 h1_x = cvRound (blen * cos (ori + CV_PI / 18.0)) + start_x;
00655 h1_y = cvRound (blen * -sin (ori + CV_PI / 18.0)) + start_y;
00656 h2_x = cvRound (blen * cos (ori - CV_PI / 18.0)) + start_x;
00657 h2_y = cvRound (blen * -sin (ori - CV_PI / 18.0)) + start_y;
00658 start = cvPoint (start_x, start_y);
00659 end = cvPoint (end_x, end_y);
00660 h1 = cvPoint (h1_x, h1_y);
00661 h2 = cvPoint (h2_x, h2_y);
00662
00663 cvLine (img, start, end, color, 1, 8, 0);
00664 cvLine (img, end, h1, color, 1, 8, 0);
00665 cvLine (img, end, h2, color, 1, 8, 0);
00666 }
00667
00668
00669 void PlaceRecognition::readFeaturesFromFile ()
00670 {
00671 surf_descriptors.clear ();
00672 global_descriptors.clear ();
00673
00674 files = QFileDialog::getOpenFileNames (0, "Load database files", ".", "TXT Files (*.txt)");
00675
00676 if (!files.isEmpty ())
00677 {
00678 int file_number = files.size ();
00679
00680 BOOST_FOREACH (QString s, files)
00681 {
00682 QFile file (s);
00683 if (file.open (QIODevice::ReadOnly | QIODevice::Text))
00684 {
00685 GlobalFeature global_feature;
00686 SURFDescriptor tmp_feature;
00687 std::vector< SURFDescriptor > tmp_surf_descriptors;
00688 tmp_surf_descriptors.clear ();
00689
00690
00691 QByteArray line = file.readLine ();
00692 char* sep_str = line.data ();
00693 char sepr[] = " \t\n";
00694
00695 char* str = strtok (sep_str, sepr);
00696 if (str != NULL)
00697 global_feature.area = atof (str);
00698 str = strtok (NULL, sepr);
00699 if (str != NULL)
00700 global_feature.duty_cycle = atof (str);
00701 global_descriptors.push_back (global_feature);
00702
00703
00704 while (!file.atEnd ())
00705 {
00706 line = file.readLine ();
00707 sep_str = line.data ();
00708
00709
00710 str = strtok (sep_str, sepr);
00711 if (str != NULL)
00712 tmp_feature.x = atof (str);
00713 str = strtok (NULL, sepr);
00714 if (str != NULL)
00715 tmp_feature.y = atof (str);
00716
00717 str = strtok (NULL, sepr);
00718 if (str != NULL)
00719 tmp_feature.laplacian = atof (str);
00720
00721
00722 str = strtok (NULL, sepr);
00723 if (str != NULL)
00724 tmp_feature.s = atof (str);
00725
00726
00727 str = strtok (NULL, sepr);
00728 if (str != NULL)
00729 tmp_feature.dir = atof (str);
00730
00731 str = strtok (NULL, sepr);
00732 if (str != NULL)
00733 tmp_feature.mod = atof (str);
00734
00735
00736 str = strtok (NULL, sepr);
00737 if (str != NULL)
00738 tmp_feature.cor_point.x = atof (str);
00739 str = strtok (NULL, sepr);
00740 if (str != NULL)
00741 tmp_feature.cor_point.y = atof (str);
00742 str = strtok (NULL, sepr);
00743 if (str != NULL)
00744 tmp_feature.cor_point.z = atof (str);
00745
00746 for (int i = 0; i < 128; i++)
00747 {
00748 str = strtok (NULL, sepr);
00749 if (str != NULL)
00750 tmp_feature.vector[i] = atof (str);
00751 }
00752
00753 tmp_surf_descriptors.push_back (tmp_feature);
00754 }
00755
00756 surf_descriptors.push_back (tmp_surf_descriptors);
00757 file.close ();
00758 }
00759 else
00760 {
00761 switch (QMessageBox::critical (NULL, "Critical", "Failed to read one database file!\n"
00762 "Would you like to read database files again, ignore it to continue or abort this option?",
00763 QMessageBox::Retry | QMessageBox::Ignore | QMessageBox::Abort, QMessageBox::Retry))
00764 {
00765 case QMessageBox::Retry:
00766 readFeaturesFromFile ();
00767 break;
00768
00769 case QMessageBox::Ignore:
00770 break;
00771
00772 case QMessageBox::Abort:
00773 return;
00774 }
00775 }
00776 }
00777 }
00778 else
00779 {
00780 switch (QMessageBox::critical (NULL, "Critical", "Failed to load database files!\n"
00781 "Would you like to reload them or abort this option?",
00782 QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry))
00783 {
00784 case QMessageBox::Retry:
00785 readFeaturesFromFile ();
00786 break;
00787
00788 case QMessageBox::Abort:
00789 break;
00790 }
00791 }
00792 }
00793
00794
00795 CvSeq* PlaceRecognition::findSURFMatchPairs (CvSeq* sep, int n, std::vector<SURFDescriptor> sfeat, CvMemStorage* storage)
00796 {
00797 SURFDescriptor* feat = 0;
00798 SURFDescriptor** nbrs;
00799 SURFKDNode* kd_root;
00800
00801 CvSeq* correspond = cvCreateSeq (0, sizeof (CvSeq), sizeof (SURFDescriptor), storage);
00802
00803
00804 kd_root = buildKDTree (&sfeat[0], (int) (sfeat.size ()), 1);
00805
00806 int match_num = 0;
00807
00808 for (int i = 0; i < n; i++)
00809 {
00810
00811 feat = (SURFDescriptor*) cvGetSeqElem (sep, i);
00812
00813 int k = KDTreeBbfKnn (kd_root, feat, 2, &nbrs, SURF_KDTREE_BBF_MAX_NN_CHKS, 1);
00814 if (k == 2)
00815 {
00816 double d0 = (double) descrDistSq (feat, nbrs[0], 1);
00817 double d1 = (double) descrDistSq (feat, nbrs[1], 1);
00818 if (d0 < d1 * SURF_NN_SQ_DIST_RATIO_THR)
00819 {
00820 cvSeqPush (correspond, feat);
00821 cvSeqPush (correspond, nbrs[0]);
00822 match_num++;
00823 }
00824 }
00825 free (nbrs);
00826 }
00827
00828
00829 return correspond;
00830 }
00831
00832
00833
00834
00835 SURFKDNode* PlaceRecognition::buildKDTree (SURFDescriptor* features, int n, int flags)
00836 {
00837 SURFKDNode* kd_root;
00838
00839 if (!features || n <= 0)
00840 {
00841 fprintf (stderr, "Warning: kdtree_build(): no features, %s, line %d\n", __FILE__, __LINE__);
00842 return NULL;
00843 }
00844
00845 kd_root = initKDNode (features, n);
00846 expandKDNodeSubtree (kd_root, flags);
00847
00848 return kd_root;
00849 }
00850
00851 SURFKDNode* PlaceRecognition::initKDNode (SURFDescriptor* features, int n)
00852 {
00853 SURFKDNode* kd_node;
00854 kd_node = (SURFKDNode*) malloc (sizeof (SURFKDNode));
00855 memset (kd_node, 0, sizeof (SURFKDNode));
00856 kd_node->ki = -1;
00857 kd_node->features = features;
00858 kd_node->n = n;
00859
00860 return kd_node;
00861 }
00862
00863 void PlaceRecognition::expandKDNodeSubtree (SURFKDNode* kd_node, int flags)
00864 {
00865
00866 if (kd_node->n == 1 || kd_node->n == 0)
00867 {
00868 kd_node->leaf = 1;
00869 return;
00870 }
00871
00872 assignPartKey (kd_node, flags);
00873 partitionFeatures (kd_node);
00874
00875 if (kd_node->kd_left)
00876 expandKDNodeSubtree (kd_node->kd_left, flags);
00877 if (kd_node->kd_right)
00878 expandKDNodeSubtree (kd_node->kd_right, flags);
00879 }
00880
00881 void PlaceRecognition::assignPartKey (SURFKDNode* kd_node, int flags)
00882 {
00883 SURFDescriptor* features;
00884 double kv, x, mean, var, var_max = 0;
00885 double* tmp;
00886 int d, n, i, j, ki = 0;
00887
00888 features = kd_node->features;
00889 n = kd_node->n;
00890 d = (flags & CV_SURF_EXTENDED) ? 128 : 64;
00891
00892
00893 for (j = 0; j < d; j++)
00894 {
00895 mean = var = 0;
00896 for (i = 0; i < n; i++)
00897 mean += features[i].vector[j];
00898 mean /= n;
00899 for (i = 0; i < n; i++)
00900 {
00901 x = features[i].vector[j] - mean;
00902 var += x * x;
00903 }
00904 var /= n;
00905
00906 if (var > var_max)
00907 {
00908 ki = j;
00909 var_max = var;
00910 }
00911 }
00912
00913
00914 tmp = reinterpret_cast < double* >(calloc (n, sizeof (double)));
00915 for (i = 0; i < n; i++)
00916 tmp[i] = features[i].vector[ki];
00917 kv = selectMedian (tmp, n);
00918 free (tmp);
00919
00920 kd_node->ki = ki;
00921 kd_node->kv = kv;
00922 }
00923
00924 double PlaceRecognition::selectMedian (double* array, int n)
00925 {
00926 return selectRank (array, n, (n - 1) / 2);
00927 }
00928
00929 double PlaceRecognition::selectRank (double* array, int n, int r)
00930 {
00931 double *tmp, med;
00932 int gr_5, gr_tot, rem_elts, i, j;
00933
00934
00935 if (n == 1)
00936 return array[0];
00937
00938
00939 gr_5 = n / 5;
00940 gr_tot = cvCeil (n / 5.0);
00941 rem_elts = n % 5;
00942 tmp = array;
00943 for (i = 0; i < gr_5; i++)
00944 {
00945 sortInsertion (tmp, 5);
00946 tmp += 5;
00947 }
00948 sortInsertion (tmp, rem_elts);
00949
00950
00951 tmp = reinterpret_cast < double* >(calloc (gr_tot, sizeof (double)));
00952 for (i = 0, j = 2; i < gr_5; i++, j += 5)
00953 tmp[i] = array[j];
00954 if (rem_elts)
00955 tmp[i++] = array[n - 1 - rem_elts / 2];
00956 med = selectRank (tmp, i, (i - 1) / 2);
00957 free (tmp);
00958
00959
00960 j = partitionArray (array, n, med);
00961 if (r == j)
00962 return med;
00963 else if (r < j)
00964 return selectRank (array, j, r);
00965 else
00966 {
00967 array += j + 1;
00968 return selectRank (array, (n - j - 1), (r - j - 1));
00969 }
00970 }
00971
00972 void PlaceRecognition::sortInsertion (double* array, int n)
00973 {
00974 double k;
00975 int i, j;
00976
00977 for (i = 1; i < n; i++)
00978 {
00979 k = array[i];
00980 j = i - 1;
00981 while (j >= 0 && array[j] > k)
00982 {
00983 array[j + 1] = array[j];
00984 j -= 1;
00985 }
00986 array[j + 1] = k;
00987 }
00988 }
00989
00990 int PlaceRecognition::partitionArray (double* array, int n, double pivot)
00991 {
00992 double tmp;
00993 int p, i, j;
00994
00995 i = -1;
00996 for (j = 0; j < n; j++)
00997 if (array[j] <= pivot)
00998 {
00999 tmp = array[++i];
01000 array[i] = array[j];
01001 array[j] = tmp;
01002 if (array[i] == pivot)
01003 p = i;
01004 }
01005
01006 array[p] = array[i];
01007 array[i] = pivot;
01008
01009 return i;
01010 }
01011
01012 void PlaceRecognition::partitionFeatures (SURFKDNode* kd_node)
01013 {
01014 SURFDescriptor* features, tmp;
01015 double kv;
01016 int n, ki, p, i, j = -1;
01017
01018 features = kd_node->features;
01019 n = kd_node->n;
01020 ki = kd_node->ki;
01021 kv = kd_node->kv;
01022 for (i = 0; i < n; i++)
01023 if (features[i].vector[ki] <= kv)
01024 {
01025 tmp = features[++j];
01026 features[j] = features[i];
01027 features[i] = tmp;
01028 if (features[j].vector[ki] == kv)
01029 p = j;
01030 }
01031 tmp = features[p];
01032 features[p] = features[j];
01033 features[j] = tmp;
01034
01035
01036 if (j == n - 1)
01037 {
01038 kd_node->leaf = 1;
01039 return;
01040 }
01041
01042 kd_node->kd_left = initKDNode (features, j + 1);
01043
01044 kd_node->kd_right = initKDNode (features + (j + 1), (n - j - 1));
01045 }
01046
01047
01048
01049
01050 int PlaceRecognition::KDTreeBbfKnn (SURFKDNode* kd_root, SURFDescriptor* feat, int k,
01051 SURFDescriptor*** nbrs, int max_nn_chks, int flags)
01052 {
01053 SURFKDNode* expl;
01054 MinPq* min_pq;
01055 SURFDescriptor* tree_feat, **_nbrs;
01056 BbfData* bbf_data;
01057 int i, t = 0, n = 0;
01058
01059 if (!nbrs || !feat || !kd_root)
01060 {
01061 fprintf (stderr, "Warning: NULL pointer error, %s, line %d\n", __FILE__, __LINE__);
01062 return -1;
01063 }
01064
01065 _nbrs = reinterpret_cast < SURFDescriptor** >(calloc (k, sizeof (SURFDescriptor*)));
01066 min_pq = initMinPq ();
01067 insertMinPq (min_pq, kd_root, 0);
01068 while (min_pq->n > 0 && t < max_nn_chks)
01069 {
01070 expl = (SURFKDNode*) minPqExtractMin (min_pq);
01071 if (!expl)
01072 {
01073 fprintf (stderr, "Warning: PQ unexpectedly empty, %s line %d\n", __FILE__, __LINE__);
01074 goto fail;
01075 }
01076
01077 expl = exploreToLeaf (expl, feat, min_pq, flags);
01078 if (!expl)
01079 {
01080 fprintf (stderr, "Warning: PQ unexpectedly empty, %s line %d\n", __FILE__, __LINE__);
01081 goto fail;
01082 }
01083
01084 for (i = 0; i < expl->n; i++)
01085 {
01086 tree_feat = &expl->features[i];
01087 bbf_data = (BbfData*) malloc (sizeof (BbfData));
01088 if (!bbf_data)
01089 {
01090 fprintf (stderr, "Warning: unable to allocate memory, %s line %d\n", __FILE__, __LINE__);
01091 goto fail;
01092 }
01093
01094 bbf_data->old_data = tree_feat->feature_data;
01095 bbf_data->d = descrDistSq (feat, tree_feat, flags);
01096 tree_feat->feature_data = bbf_data;
01097 n += insertIntoNbrArray (tree_feat, _nbrs, n, k);
01098 }
01099 t++;
01100 }
01101
01102 releaseMinPq (&min_pq);
01103 for (i = 0; i < n; i++)
01104 {
01105 bbf_data = (BbfData*) _nbrs[i]->feature_data;
01106 _nbrs[i]->feature_data = bbf_data->old_data;
01107 free (bbf_data);
01108 }
01109 *nbrs = _nbrs;
01110 return n;
01111
01112 fail:
01113 releaseMinPq (&min_pq);
01114 for (i = 0; i < n; i++)
01115 {
01116 bbf_data = (BbfData*) _nbrs[i]->feature_data;
01117 _nbrs[i]->feature_data = bbf_data->old_data;
01118 free (bbf_data);
01119 }
01120 free (_nbrs);
01121 *nbrs = NULL;
01122 return -1;
01123 }
01124
01125 MinPq* PlaceRecognition::initMinPq ()
01126 {
01127 MinPq* min_pq;
01128 min_pq = (MinPq*) malloc (sizeof (MinPq));
01129 min_pq->pq_array = (PqNode*) calloc (MINPQ_INIT_NALLOCD, sizeof (PqNode));
01130 min_pq->nallocd = MINPQ_INIT_NALLOCD;
01131 min_pq->n = 0;
01132
01133 return min_pq;
01134 }
01135
01136 int PlaceRecognition::insertMinPq (MinPq* min_pq, void* data, int key)
01137 {
01138 int n = min_pq->n;
01139
01140
01141 if (min_pq->nallocd == n)
01142 {
01143 min_pq->nallocd = doubleArray ((void**) &min_pq->pq_array, min_pq->nallocd, sizeof (PqNode));
01144 if (!min_pq->nallocd)
01145 {
01146 fprintf (stderr, "Warning: unable to allocate memory, %s, line %d\n", __FILE__, __LINE__);
01147 return 1;
01148 }
01149 }
01150
01151 min_pq->pq_array[n].data = data;
01152 min_pq->pq_array[n].key = INT_MAX;
01153 decreasePqNodeKey (min_pq->pq_array, min_pq->n, key);
01154 min_pq->n++;
01155
01156 return 0;
01157 }
01158
01159
01160 void PlaceRecognition::decreasePqNodeKey (PqNode* pq_array, int i, int key)
01161 {
01162 PqNode tmp;
01163
01164 if (key > pq_array[i].key)
01165 return;
01166
01167 pq_array[i].key = key;
01168 while (i > 0 && pq_array[i].key < pq_array[parent (i)].key)
01169 {
01170 tmp = pq_array[parent (i)];
01171 pq_array[parent (i)] = pq_array[i];
01172 pq_array[i] = tmp;
01173 i = parent (i);
01174 }
01175 }
01176
01177
01178
01179
01180
01181
01182
01183
01184 void PlaceRecognition::restoreMinPqOrder (PqNode* pq_array, int i, int n)
01185 {
01186 PqNode tmp;
01187 int l, r, min = i;
01188
01189 l = left (i);
01190 r = right (i);
01191 if (l < n)
01192 if (pq_array[l].key < pq_array[i].key)
01193 min = l;
01194 if (r < n)
01195 if (pq_array[r].key < pq_array[min].key)
01196 min = r;
01197
01198 if (min != i)
01199 {
01200 tmp = pq_array[min];
01201 pq_array[min] = pq_array[i];
01202 pq_array[i] = tmp;
01203 restoreMinPqOrder (pq_array, min, n);
01204 }
01205 }
01206
01207 void* PlaceRecognition::minPqExtractMin (MinPq* min_pq)
01208 {
01209 void* data;
01210
01211 if (min_pq->n < 1)
01212 {
01213 fprintf (stderr, "Warning: PQ empty, %s line %d\n", __FILE__, __LINE__);
01214 return NULL;
01215 }
01216 data = min_pq->pq_array[0].data;
01217 min_pq->n--;
01218 min_pq->pq_array[0] = min_pq->pq_array[min_pq->n];
01219 restoreMinPqOrder (min_pq->pq_array, 0, min_pq->n);
01220
01221 return data;
01222 }
01223
01224 SURFKDNode* PlaceRecognition::exploreToLeaf (SURFKDNode* kd_node, SURFDescriptor* feat, MinPq* min_pq, int flags)
01225 {
01226 SURFKDNode* unexpl, *expl = kd_node;
01227 double kv;
01228 int ki;
01229 int d = (flags & CV_SURF_EXTENDED) ? 128 : 64;
01230
01231 while (expl && !expl->leaf)
01232 {
01233 ki = expl->ki;
01234 kv = expl->kv;
01235
01236 if (ki >= d)
01237 {
01238 fprintf (stderr, "Warning: comparing imcompatible descriptors, %s line %d\n", __FILE__, __LINE__);
01239 return NULL;
01240 }
01241 if (feat->vector[ki] <= kv)
01242 {
01243 unexpl = expl->kd_right;
01244 expl = expl->kd_left;
01245 }
01246 else
01247 {
01248 unexpl = expl->kd_left;
01249 expl = expl->kd_right;
01250 }
01251
01252 if (insertMinPq (min_pq, unexpl, (int) abs (kv - feat->vector[ki])))
01253 {
01254 fprintf (stderr, "Warning: unable to insert into PQ, %s, line %d\n", __FILE__, __LINE__);
01255 return NULL;
01256 }
01257 }
01258
01259 return expl;
01260 }
01261
01262 double PlaceRecognition::descrDistSq (SURFDescriptor* f1, SURFDescriptor* f2, int flags)
01263 {
01264 double diff, dsq = 0;
01265 double *descr1, *descr2;
01266 int i;
01267 int d = (flags & CV_SURF_EXTENDED) ? 128 : 64;
01268
01269 descr1 = f1->vector;
01270 descr2 = f2->vector;
01271
01272 for (i = 0; i < d; i++)
01273 {
01274 diff = descr1[i] - descr2[i];
01275 dsq += diff * diff;
01276 }
01277
01278 return dsq;
01279 }
01280
01281 int PlaceRecognition::insertIntoNbrArray (SURFDescriptor* feat, SURFDescriptor** nbrs, int n, int k)
01282 {
01283 BbfData *fdata, *ndata;
01284 double dn, df;
01285 int i, ret = 0;
01286
01287 if (n == 0)
01288 {
01289 nbrs[0] = feat;
01290 return 1;
01291 }
01292
01293
01294 fdata = (BbfData*) feat->feature_data;
01295 df = fdata->d;
01296 ndata = (BbfData*) nbrs[n - 1]->feature_data;
01297 dn = ndata->d;
01298 if (df >= dn)
01299 {
01300 if (n == k)
01301 {
01302 feat->feature_data = fdata->old_data;
01303 free (fdata);
01304 return 0;
01305 }
01306 nbrs[n] = feat;
01307 return 1;
01308 }
01309
01310
01311 if (n < k)
01312 {
01313 nbrs[n] = nbrs[n - 1];
01314 ret = 1;
01315 }
01316 else
01317 {
01318 nbrs[n - 1]->feature_data = ndata->old_data;
01319 free (ndata);
01320 }
01321 i = n - 2;
01322 while (i >= 0)
01323 {
01324 ndata = (BbfData*) nbrs[i]->feature_data;
01325 dn = ndata->d;
01326 if (dn <= df)
01327 break;
01328 nbrs[i + 1] = nbrs[i];
01329 i--;
01330 }
01331 i++;
01332 nbrs[i] = feat;
01333
01334 return ret;
01335 }
01336
01337 void PlaceRecognition::releaseMinPq (MinPq** min_pq)
01338 {
01339 if (!min_pq)
01340 {
01341 fprintf (stderr, "Warning: NULL pointer error, %s line %d\n", __FILE__, __LINE__);
01342 return;
01343 }
01344 if (*min_pq && (*min_pq)->pq_array)
01345 {
01346 free ((*min_pq)->pq_array);
01347 free (*min_pq);
01348 *min_pq = NULL;
01349 }
01350 }
01351
01352 int PlaceRecognition::doubleArray (void** array, int n, int size)
01353 {
01354 void* tmp;
01355
01356 tmp = realloc (*array, 2 * n * size);
01357 if (!tmp)
01358 {
01359 fprintf (stderr, "Warning: unable to allocate memory in array_double(), %s line %d\n", __FILE__, __LINE__);
01360 if (*array)
01361 free (*array);
01362 *array = NULL;
01363 return 0;
01364 }
01365 *array = tmp;
01366 return n * 2;
01367 }
01368
01369 double PlaceRecognition::getMatchDegree (CvSeq* seq)
01370 {
01371
01372 execute (seq);
01373
01374
01375 int n = seq->total / 2;
01376 if_false_pairs.resize (n);
01377 for (int eff = 0; eff < n; eff++)
01378 {
01379 if_false_pairs[eff] = false;
01380 }
01381 eff_match_pairs = 0;
01382 if ((int) RMatrixPlist.size () <= 0)
01383 for (int eff = 0; eff < n; eff++)
01384 {
01385 if_false_pairs[eff] = true;
01386 }
01387
01388 double RMatrixt[9];
01389 double TVectort[3];
01390 double max_match = -111, match_deg;
01391
01392 for (int i = 0; i < (int) RMatrixPlist.size (); i++)
01393 {
01394 for (int j = 0; j < 9; j++)
01395 {
01396 RMatrixt[j] = RMatrixPlist[i][j];
01397 }
01398 for (int j = 0; j < 3; j++)
01399 TVectort[j] = TVectorPlist[i][j];
01400
01401 match_deg = calculateErr (seq, RMatrixt, TVectort);
01402
01403 if (match_deg > max_match)
01404 {
01405 eff_match_pairs = 0;
01406 for (int number = 0; number < n; number++)
01407 {
01408 if (if_false_pairs[number] == false)
01409 eff_match_pairs++;
01410 }
01411 if (eff_match_pairs >= MIN_AMOUNT)
01412 {
01413 max_match = match_deg;
01414 }
01415 }
01416 }
01417
01418 return (max_match);
01419 }
01420
01421 void PlaceRecognition::execute (CvSeq* seq)
01422 {
01423 transMatrix (seq);
01424 initSelect (seq);
01425 do
01426 {
01427 cutFalseMatrix ();
01428 } while ((int) RMatrixPlist.size () > 10);
01429 }
01430
01431 void PlaceRecognition::transMatrix (CvSeq* seq)
01432 {
01433 RMatrixPlist.clear ();
01434 TVectorPlist.clear ();
01435 int surfpairmum = (seq->total / 2);
01436 if ((seq->total / 2) < 4)
01437 return;
01438
01439 for (int n = 3; n < surfpairmum; n++)
01440 {
01441 if ((int) RMatrixPlist.size () >= 1000)
01442 {
01443 break;
01444 }
01445 for (int m = 2; m < n; m++)
01446 {
01447 if ((int) RMatrixPlist.size () >= 1000)
01448 {
01449 break;
01450 }
01451 for (int j = 1; j < m; j++)
01452 {
01453 if ((int) RMatrixPlist.size () >= 1000)
01454 {
01455 break;
01456 }
01457 for (int i = 0; i < j; i++)
01458 {
01459 SURFDescriptor * tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * i);
01460 sce_points.push_back (tmp->cor_point);
01461 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * j);
01462 sce_points.push_back (tmp->cor_point);
01463 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * m);
01464 sce_points.push_back (tmp->cor_point);
01465 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * n);
01466 sce_points.push_back (tmp->cor_point);
01467 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * i + 1);
01468 lib_points.push_back (tmp->cor_point);
01469 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * j + 1);
01470 lib_points.push_back (tmp->cor_point);
01471 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * m + 1);
01472 lib_points.push_back (tmp->cor_point);
01473 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * n + 1);
01474 lib_points.push_back (tmp->cor_point);
01475 Matrix ();
01476 SVD ();
01477 double* RMatrixp;
01478 double* TVectorp;
01479 RMatrixp = new double[9];
01480 TVectorp = new double[3];
01481 for (int i = 0; i < 9; i++)
01482 {
01483 RMatrixp[i] = RMatrix[i];
01484 }
01485 for (int j = 0; j < 3; j++)
01486 {
01487 TVectorp[j] = TVector[j];
01488 }
01489 RMatrixPlist.push_back (RMatrixp);
01490 TVectorPlist.push_back (TVectorp);
01491 sce_points.clear ();
01492 lib_points.clear ();
01493 if ((int) RMatrixPlist.size () >= 1000)
01494 {
01495 break;
01496 }
01497 }
01498 }
01499 }
01500 }
01501 }
01502
01503
01504 void PlaceRecognition::Matrix ()
01505 {
01506 std::vector < pcl::PointXYZ >::iterator IT1;
01507 std::vector < pcl::PointXYZ >::iterator IT2;
01508 centroid1.x = 0;
01509 centroid1.y = 0;
01510 centroid1.z = 0;
01511 centroid2.x = 0;
01512 centroid2.y = 0;
01513 centroid2.z = 0;
01514
01515 for (IT1 = lib_points.begin (); IT1 != lib_points.end (); IT1++)
01516 {
01517 centroid1.x = centroid1.x + (*IT1).x;
01518 centroid1.y = centroid1.y + (*IT1).y;
01519 centroid1.z = centroid1.z + (*IT1).z;
01520 }
01521 centroid1.x = centroid1.x / lib_points.size ();
01522 centroid1.y = centroid1.y / lib_points.size ();
01523 centroid1.z = centroid1.z / lib_points.size ();
01524 for (IT1 = lib_points.begin (); IT1 != lib_points.end (); IT1++)
01525 {
01526 (*IT1).x = (*IT1).x - centroid1.x;
01527 (*IT1).y = (*IT1).y - centroid1.y;
01528 (*IT1).z = (*IT1).z - centroid1.z;
01529 }
01530
01531 for (IT2 = sce_points.begin (); IT2 != sce_points.end (); IT2++)
01532 {
01533 centroid2.x = centroid2.x + (*IT2).x;
01534 centroid2.y = centroid2.y + (*IT2).y;
01535 centroid2.z = centroid2.z + (*IT2).z;
01536 }
01537 centroid2.x = centroid2.x / sce_points.size ();
01538 centroid2.y = centroid2.y / sce_points.size ();
01539 centroid2.z = centroid2.z / sce_points.size ();
01540 for (IT2 = sce_points.begin (); IT2 != sce_points.end (); IT2++)
01541 {
01542 (*IT2).x = (*IT2).x - centroid2.x;
01543 (*IT2).y = (*IT2).y - centroid2.y;
01544 (*IT2).z = (*IT2).z - centroid2.z;
01545 }
01546
01547
01548 A[0] = 0;
01549 A[1] = 0;
01550 A[2] = 0;
01551 A[3] = 0;
01552 A[4] = 0;
01553 A[5] = 0;
01554 A[6] = 0;
01555 A[7] = 0;
01556 A[8] = 0;
01557
01558 for (IT1 = lib_points.begin (), IT2 = sce_points.begin (); IT1 != lib_points.end (); IT1++, IT2++)
01559 {
01560
01561 A[0] = A[0] + (*IT2).x * (*IT1).x;
01562 A[1] = A[1] + (*IT2).x * (*IT1).y;
01563 A[2] = A[2] + (*IT2).x * (*IT1).z;
01564 A[3] = A[3] + (*IT2).y * (*IT1).x;
01565 A[4] = A[4] + (*IT2).y * (*IT1).y;
01566 A[5] = A[5] + (*IT2).y * (*IT1).z;
01567 A[6] = A[6] + (*IT2).z * (*IT1).x;
01568 A[7] = A[7] + (*IT2).z * (*IT1).y;
01569 A[8] = A[8] + (*IT2).z * (*IT1).z;
01570 }
01571
01572
01573 A_AH[0] = A[0] * A[0] + A[1] * A[1] + A[2] * A[2];
01574 A_AH[1] = A[0] * A[3] + A[1] * A[4] + A[2] * A[5];
01575 A_AH[2] = A[0] * A[6] + A[1] * A[7] + A[2] * A[8];
01576 A_AH[3] = A[3] * A[0] + A[4] * A[1] + A[5] * A[2];
01577 A_AH[4] = A[3] * A[3] + A[4] * A[4] + A[5] * A[5];
01578 A_AH[5] = A[3] * A[6] + A[4] * A[7] + A[5] * A[8];
01579 A_AH[6] = A[6] * A[0] + A[7] * A[1] + A[8] * A[2];
01580 A_AH[7] = A[6] * A[3] + A[7] * A[4] + A[8] * A[5];
01581 A_AH[8] = A[6] * A[6] + A[7] * A[7] + A[8] * A[8];
01582
01583
01584 AH_A[0] = A[0] * A[0] + A[3] * A[3] + A[6] * A[6];
01585 AH_A[1] = A[0] * A[1] + A[3] * A[4] + A[6] * A[7];
01586 AH_A[2] = A[0] * A[2] + A[3] * A[5] + A[6] * A[8];
01587 AH_A[3] = A[1] * A[0] + A[4] * A[3] + A[7] * A[6];
01588 AH_A[4] = A[1] * A[1] + A[4] * A[4] + A[7] * A[7];
01589 AH_A[5] = A[1] * A[2] + A[4] * A[5] + A[7] * A[8];
01590 AH_A[6] = A[2] * A[0] + A[5] * A[3] + A[8] * A[6];
01591 AH_A[7] = A[2] * A[1] + A[5] * A[4] + A[8] * A[7];
01592 AH_A[8] = A[2] * A[2] + A[5] * A[5] + A[8] * A[8];
01593 }
01594
01595
01596 void PlaceRecognition::SVD ()
01597 {
01598 int SUC1 = Jcbi (A_AH, U);
01599 int SUC2 = Jcbi (AH_A, V);
01600
01601 RMatrix[0] = V[0] * U[0] + V[1] * U[1] + V[2] * U[2];
01602 RMatrix[1] = V[0] * U[3] + V[1] * U[4] + V[2] * U[5];
01603 RMatrix[2] = V[0] * U[6] + V[1] * U[7] + V[2] * U[8];
01604 RMatrix[3] = V[3] * U[0] + V[4] * U[1] + V[5] * U[2];
01605 RMatrix[4] = V[3] * U[3] + V[4] * U[4] + V[5] * U[5];
01606 RMatrix[5] = V[3] * U[6] + V[4] * U[7] + V[5] * U[8];
01607 RMatrix[6] = V[6] * U[0] + V[7] * U[1] + V[8] * U[2];
01608 RMatrix[7] = V[6] * U[3] + V[7] * U[4] + V[8] * U[5];
01609 RMatrix[8] = V[6] * U[6] + V[7] * U[7] + V[8] * U[8];
01610
01611 TVector[0] = centroid1.x - RMatrix[0] * centroid2.x - RMatrix[1] * centroid2.y - RMatrix[2] * centroid2.z;
01612 TVector[1] = centroid1.y - RMatrix[3] * centroid2.x - RMatrix[4] * centroid2.y - RMatrix[5] * centroid2.z;
01613 TVector[2] = centroid1.z - RMatrix[6] * centroid2.x - RMatrix[7] * centroid2.y - RMatrix[8] * centroid2.z;
01614 }
01615
01616
01617 int PlaceRecognition::Jcbi (double A[], double V[])
01618 {
01619 int i, j, p, q, u, w, t, s, l;
01620 double fm, cn, sn, omega, x, y, d;
01621 l = 1;
01622 double eps = 0.1;
01623 int jt = 10;
01624 int n = 3;
01625 for (i = 0; i <= n - 1; i++)
01626 {
01627 V[i * n + i] = 1.0;
01628 for (j = 0; j <= n - 1; j++)
01629 if (i != j)
01630 V[i * n + j] = 0.0;
01631 }
01632 while (1 == 1)
01633 {
01634 fm = 0.0;
01635 for (i = 1; i <= n - 1; i++)
01636 for (j = 0; j <= i - 1; j++)
01637 {
01638 d = fabs (A[i * n + j]);
01639 if ((i != j) && (d > fm))
01640 {
01641 fm = d;
01642 p = i;
01643 q = j;
01644 }
01645 }
01646
01647 if (fm < eps)
01648 return (1);
01649 if (l > jt)
01650 return (-1);
01651 l = l + 1;
01652 u = p * n + q;
01653 w = p * n + p;
01654 t = q * n + p;
01655 s = q * n + q;
01656 x = -A[u];
01657 y = (A[s] - A[w]) / 2.0;
01658 omega = x / sqrt (x * x + y * y);
01659 if (y < 0.0)
01660 omega = -omega;
01661 sn = 1.0 + sqrt (1.0 - omega * omega);
01662 sn = omega / sqrt (2.0 * sn);
01663 cn = sqrt (1.0 - sn * sn);
01664 fm = A[w];
01665 A[w] = fm * cn * cn + A[s] * sn * sn + A[u] * omega;
01666 A[s] = fm * sn * sn + A[s] * cn * cn - A[u] * omega;
01667 A[u] = 0.0;
01668 A[t] = 0.0;
01669 for (j = 0; j <= n - 1; j++)
01670 {
01671 if ((j != p) && (j != q))
01672 {
01673 u = p * n + j;
01674 w = q * n + j;
01675 fm = A[u];
01676 A[u] = fm * cn + A[w] * sn;
01677 A[w] = -fm * sn + A[w] * cn;
01678 }
01679 }
01680
01681 for (i = 0; i <= n - 1; i++)
01682 {
01683 if ((i != p) && (i != q))
01684 {
01685 u = i * n + p;
01686 w = i * n + q;
01687 fm = A[u];
01688 A[u] = fm * cn + A[w] * sn;
01689 A[w] = -fm * sn + A[w] * cn;
01690 }
01691 }
01692
01693 for (i = 0; i <= n - 1; i++)
01694 {
01695 u = i * n + p;
01696 w = i * n + q;
01697 fm = V[u];
01698 V[u] = fm * cn + V[w] * sn;
01699 V[w] = -fm * sn + V[w] * cn;
01700 }
01701 }
01702
01703 return (1);
01704 }
01705
01706 void PlaceRecognition::initSelect (CvSeq* seq)
01707 {
01708 std::vector < double* >::iterator Riter;
01709 std::vector < double* >::iterator Titer;
01710 for (Riter = RMatrixPlist.begin (), Titer = TVectorPlist.begin (); Riter < RMatrixPlist.end ();)
01711 {
01712 if (!Marix (seq, *Riter, *Titer))
01713 {
01714 delete[](*Riter);
01715 Riter = RMatrixPlist.erase (Riter);
01716 delete[](*Titer);
01717 Titer = TVectorPlist.erase (Titer);
01718 }
01719 else
01720 {
01721 Riter++;
01722 Titer++;
01723 }
01724 }
01725 }
01726
01727 bool PlaceRecognition::Marix (CvSeq* seq, double* RMatrix, double* TVector)
01728 {
01729 for (int i = 0; i < (seq->total / 2); i++)
01730 {
01731 pcl::PointXYZ tem_point;
01732 SURFDescriptor* tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * i);
01733
01734 tem_point.x = RMatrix[0] * tmp->cor_point.x + RMatrix[1] * tmp->cor_point.y +
01735 RMatrix[2] * tmp->cor_point.z + TVector[0];
01736
01737 tem_point.y = RMatrix[3] * tmp->cor_point.x + RMatrix[4] * tmp->cor_point.y +
01738 RMatrix[5] * tmp->cor_point.z + TVector[1];
01739
01740 tem_point.z = RMatrix[6] * tmp->cor_point.x + RMatrix[7] * tmp->cor_point.y +
01741 RMatrix[8] * tmp->cor_point.z + TVector[2];
01742
01743 tmp = (SURFDescriptor*) cvGetSeqElem (seq, 2 * i + 1);
01744 double dist = sqrt ((tem_point.x - tmp->cor_point.x) * (tem_point.x - tmp->cor_point.x) +
01745 (tem_point.y - tmp->cor_point.y) * (tem_point.y - tmp->cor_point.y) +
01746 (tem_point.z - tmp->cor_point.z) * (tem_point.z - tmp->cor_point.z));
01747
01748 if (dist <= DISMAX)
01749 {
01750 return true;
01751 }
01752 }
01753
01754 return false;
01755 }
01756
01757
01758 void PlaceRecognition::cutFalseMatrix ()
01759 {
01760 int rawDataNum = int (RMatrixPlist.size ());
01761 if (rawDataNum >= 2)
01762 {
01763 CvMat* rawData_matrix = cvCreateMat (rawDataNum, MAXDIM, CV_32FC1);
01764 CvMat* clusters = cvCreateMat (rawDataNum, 1, CV_32SC1);
01765
01766 for (int i = 0; i < rawDataNum; i++)
01767 {
01768 rawData_matrix->data.fl[i * MAXDIM] = RMatrixPlist[i][0];
01769 rawData_matrix->data.fl[i * MAXDIM + 1] = RMatrixPlist[i][1];
01770 rawData_matrix->data.fl[i * MAXDIM + 2] = RMatrixPlist[i][2];
01771 rawData_matrix->data.fl[i * MAXDIM + 3] = RMatrixPlist[i][3];
01772 rawData_matrix->data.fl[i * MAXDIM + 4] = RMatrixPlist[i][4];
01773 rawData_matrix->data.fl[i * MAXDIM + 5] = RMatrixPlist[i][5];
01774 rawData_matrix->data.fl[i * MAXDIM + 6] = RMatrixPlist[i][6];
01775 rawData_matrix->data.fl[i * MAXDIM + 7] = RMatrixPlist[i][7];
01776 rawData_matrix->data.fl[i * MAXDIM + 8] = RMatrixPlist[i][8];
01777 }
01778
01779 cvKMeans2 (rawData_matrix, CLUSTERINGNUM, clusters,
01780 cvTermCriteria (CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 20, 0.01));
01781 int Cluster1Num = 0;
01782 int Clsuter2Num = 0;
01783 for (int j = 0; j < rawDataNum; j++)
01784 {
01785 if (clusters->data.i[j] == 0)
01786 {
01787 Cluster1Num++;
01788 }
01789 else
01790 Clsuter2Num++;
01791 }
01792
01793 int TrueTag;
01794 TrueTag = (int) (Cluster1Num > Clsuter2Num ? 0 : 1);
01795 std::vector < double* >::iterator Riter;
01796 std::vector < double* >::iterator Titer;
01797 int j = 0;
01798 for (Riter = RMatrixPlist.begin (), Titer = TVectorPlist.begin (); Riter < RMatrixPlist.end ();)
01799 {
01800 if (clusters->data.i[j] != TrueTag)
01801 {
01802 delete[](*Riter);
01803 Riter = RMatrixPlist.erase (Riter);
01804 delete[](*Titer);
01805 Titer = TVectorPlist.erase (Titer);
01806 }
01807 else
01808 {
01809 Riter++;
01810 Titer++;
01811 }
01812 j++;
01813 }
01814 }
01815 else
01816 {
01817 return;
01818 }
01819 }
01820
01821 double PlaceRecognition::calculateErr (CvSeq* seq, double RMatrix[9], double TVector[3])
01822 {
01823
01824 int n = seq->total;
01825 if_false_pairs.resize (n);
01826 for (int eff = 0; eff < n; eff++)
01827 {
01828 if_false_pairs[eff] = false;
01829 }
01830 double sum_err = 0;
01831 int counter = n;
01832 for (int i = 0; i < n; i++)
01833 {
01834 SURFDescriptor* tmp1 = (SURFDescriptor*) cvGetSeqElem (seq, 2 * i);
01835 pcl::PointXYZ data = tmp1->cor_point;
01836 pcl::PointXYZ data4;
01837 data4.x = RMatrix[0] * data.x + RMatrix[1] * data.y + RMatrix[2] * data.z + TVector[0];
01838 data4.y = RMatrix[3] * data.x + RMatrix[4] * data.y + RMatrix[5] * data.z + TVector[1];
01839 data4.z = RMatrix[6] * data.x + RMatrix[7] * data.y + RMatrix[8] * data.z + TVector[2];
01840 bool flag = false;
01841 double max = 0.0;
01842 tmp1 = (SURFDescriptor*) cvGetSeqElem (seq, 2 * i + 1);
01843 pcl::PointXYZ data3 = tmp1->cor_point;
01844
01845 double d1 = sqrt ((data4.x - data3.x) * (data4.x - data3.x) +
01846 (data4.y - data3.y) * (data4.y - data3.y) +
01847 (data4.z - data3.z) * (data4.z - data3.z));
01848 double d2 = sqrt ((data4.x * data4.x) + (data4.y * data4.y) + (data4.z * data4.z));
01849 double d3 = sqrt ((data3.x * data3.x) + (data3.y * data3.y) + (data3.z * data3.z));
01850
01851 double alph = acos ((d2 * d2 + d3 * d3 - d1 * d1) / (2 * d2 * d3));
01852 alph = alph * 180 / PI;
01853 if (alph < DANGLE)
01854 {
01855 flag = true;
01856 if (max < (1 - alph / DANGLE))
01857 max = (1 - alph / DANGLE);
01858 }
01859
01860 if (flag == false)
01861 {
01862 if_false_pairs[i] = true;
01863 counter--;
01864 }
01865 sum_err += max;
01866 }
01867
01868 double s = 0;
01869 if (counter > 0 && counter < MINN)
01870 {
01871 double t = -(counter - MINN) * (counter - MINN) / (2 * 3 * 3);
01872 s = (1.0 / counter) * (sum_err) * exp (t);
01873 }
01874 else if (counter <= 0)
01875 s = 0;
01876 else
01877 s = (1.0 / counter) * (sum_err);
01878
01879 return s;
01880 }