00001 #include "rgbdtools/map_util.h"
00002 #include <iostream>
00003 #include <fstream>
00004 #include <ros/ros.h>
00005 #include <ros/time.h>
00006 #include <geometry_msgs/PoseStamped.h>
00007
00008
00009 namespace rgbdtools {
00010
00011
00012 void concatenate_clouds(PointCloudT& map_cloud,KeyframeVector keyframes_)
00013 {
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00028
00029
00030
00031
00032
00033
00034
00035
00036 }
00037
00038 void floatMatrixToUintMatrix(
00039 const cv::Mat& mat_in,
00040 cv::Mat& mat_out,
00041 float scale)
00042 {
00043 if (scale == 0)
00044 {
00045
00046 float max_val = 0;
00047
00048 for (int u = 0; u < mat_in.cols; ++u)
00049 for (int v = 0; v < mat_in.rows; ++v)
00050 {
00051 float val_in = mat_in.at<float>(v, u);
00052 if (val_in > max_val) max_val = val_in;
00053 }
00054
00055 scale = 255.0 / max_val;
00056 }
00057
00058 mat_out = cv::Mat::zeros(mat_in.size(), CV_8UC1);
00059 for (int u = 0; u < mat_in.cols; ++u)
00060 for (int v = 0; v < mat_in.rows; ++v)
00061 {
00062 float val_in = mat_in.at<float>(v, u) ;
00063 uint8_t& val_out = mat_out.at<uint8_t>(v, u);
00064
00065 val_out = val_in * scale;
00066 }
00067 }
00068
00069 void thresholdMatrix(
00070 const cv::Mat& mat_in,
00071 cv::Mat& mat_out,
00072 int threshold)
00073 {
00074 mat_out = cv::Mat::zeros(mat_in.size(), CV_8UC1);
00075
00076 for (int u = 0; u < mat_in.cols; ++u)
00077 for (int v = 0; v < mat_in.rows; ++v)
00078 {
00079 uint16_t val_in = mat_in.at<uint16_t>(v, u) ;
00080 uint8_t& val_out = mat_out.at<uint8_t>(v, u);
00081
00082 if (val_in >= threshold) val_out = 1;
00083 }
00084 }
00085
00086 void buildExpectedPhiHistorgtam(
00087 cv::Mat& histogram,
00088 double degrees_per_bin,
00089 double stdev)
00090 {
00091 int n_bins = (int)(360.0 / degrees_per_bin);
00092 histogram = cv::Mat::zeros(1, n_bins, CV_32FC1);
00093
00094 double s = stdev / degrees_per_bin;
00095
00096 double mean[4];
00097 mean[0] = 0.0 / degrees_per_bin;
00098 mean[1] = 90.0 / degrees_per_bin;
00099 mean[2] = 180.0 / degrees_per_bin;
00100 mean[3] = 270.0 / degrees_per_bin;
00101
00102 double a = 1.0 / (s * sqrt(2.0 * M_PI));
00103 double b = 2.0 * s * s;
00104
00105 for (int u = 0; u < n_bins; ++u)
00106 {
00107 float& bin = histogram.at<float>(0, u);
00108
00109
00110 for (int g = 0; g < 4; g++)
00111 {
00112 int x = u - mean[g];
00113
00114
00115 if (x < -n_bins/2) x += n_bins;
00116 if (x >= n_bins/2) x -= n_bins;
00117
00118 float r = a * exp(-x*x / b);
00119
00120 bin += r;
00121 }
00122 }
00123
00124 normalizeHistogram(histogram);
00125 }
00126
00127 void buildPhiHistogram(
00128 const pcl::PointCloud<pcl::PointXYZRGBNormal>& cloud,
00129 cv::Mat& histogram,
00130 double degrees_per_bin)
00131 {
00132 int phi_bins = (int)(360.0 / degrees_per_bin);
00133 histogram = cv::Mat::zeros(1, phi_bins, CV_32FC1);
00134
00135 for (unsigned int i = 0; i < cloud.points.size(); ++i)
00136 {
00137 const pcl::PointXYZRGBNormal& p = cloud.points[i];
00138
00139 double nx = p.normal_x;
00140 double ny = p.normal_y;
00141 double nz = p.normal_z;
00142
00143 if (isnan(nx) || isnan(ny) || isnan(nz)) continue;
00144
00145 double r = sqrt(nx*nx + ny*ny + nz*nz);
00146 double theta = acos(nz/r);
00147 double phi = atan2(ny, nx);
00148
00149 double phi_deg = phi * 180.0 / M_PI;
00150 double theta_deg = theta * 180.0 / M_PI;
00151
00152
00153 if (phi_deg < 0.0) phi_deg += 360.0;
00154
00155
00156 if (std::abs(90-theta_deg) > 3.0) continue;
00157
00158 int idx_phi = (int)(phi_deg / degrees_per_bin);
00159
00160 float& bin = histogram.at<float>(0, idx_phi);
00161 bin = bin + 1.0;
00162 }
00163
00164 normalizeHistogram(histogram);
00165 }
00166
00167 void shiftHistogram(
00168 const cv::Mat& hist_in,
00169 cv::Mat& hist_out,
00170 int bins)
00171 {
00172 hist_out = cv::Mat(hist_in.size(), CV_32FC1);
00173 int w = hist_in.cols;
00174 for (int u = 0; u < w; ++u)
00175 {
00176 int u_shifted = (u + bins) % w;
00177
00178 hist_out.at<float>(0, u_shifted) = hist_in.at<float>(0, u);
00179 }
00180 }
00181
00182 void normalizeHistogram(cv::Mat& histogram)
00183 {
00184 float sum = 0;
00185
00186 for (int u = 0; u < histogram.cols; ++u)
00187 sum += histogram.at<float>(0,u);
00188
00189 histogram = histogram / sum;
00190 }
00191
00192 bool alignHistogram(
00193 const cv::Mat& hist,
00194 const cv::Mat& hist_exp,
00195 double hist_resolution,
00196 double& best_angle)
00197 {
00198
00199 int best_i = 0;
00200 double best_diff = 9999999999;
00201
00202 for (int i = 0; i < 90.0 / hist_resolution; ++i)
00203 {
00204 cv::Mat hist_shifted;
00205 shiftHistogram(hist, hist_shifted, i);
00206
00207 double diff = cv::compareHist(hist_shifted, hist_exp, CV_COMP_BHATTACHARYYA);
00208 if (std::abs(diff) < best_diff)
00209 {
00210 best_diff = std::abs(diff);
00211 best_i = i;
00212 }
00213 }
00214
00215 best_angle = best_i * hist_resolution;
00216
00217 cv::Mat hist_best;
00218 shiftHistogram(hist, hist_best, best_i);
00219 cv::Mat hist_best_img;
00220 createImageFromHistogram(hist_best, hist_best_img);
00221 cv::imshow("hist_best_img", hist_best_img);
00222
00223 return true;
00224 }
00225
00226 void create8bitHistogram(
00227 const cv::Mat& histogram,
00228 cv::Mat& histogram_norm)
00229 {
00230
00231 double min_val, max_val;
00232 cv::Point minLoc, maxLoc;
00233 cv::minMaxLoc(histogram, &min_val, &max_val, &minLoc, &maxLoc);
00234
00235
00236 cv::Mat temp = histogram.clone();
00237 temp = temp * 255.0 / max_val;
00238
00239
00240 histogram_norm = cv::Mat::zeros(histogram.size(), CV_8UC1);
00241 temp.convertTo(histogram_norm, CV_8UC1);
00242 }
00243
00244 void createImageFromHistogram(
00245 const cv::Mat& histogram,
00246 cv::Mat& image)
00247 {
00248
00249 cv::Mat hist_norm;
00250 create8bitHistogram(histogram, hist_norm);
00251
00252 image = cv::Mat::zeros(256, histogram.cols, CV_8UC1);
00253 for (int u = 0; u < histogram.cols; ++u)
00254 {
00255 uint8_t val = hist_norm.at<uint8_t>(0, u);
00256 for (int v = 0; v < val; ++v)
00257 image.at<uint8_t>(255-v, u) = 255;
00258 }
00259 }
00260
00261 void create2DProjectionImage(
00262 const PointCloudT& cloud,
00263 cv::Mat& img,
00264 double min_z,
00265 double max_z)
00266 {
00267
00268 double resolution = 0.02;
00269 double w = 20.0;
00270 double h = 20.0;
00271 double cx = w/2;
00272 double cy = h/2;
00273
00274 img = cv::Mat::zeros(h/resolution, w/resolution, CV_8UC1);
00275
00276 for (unsigned int i = 0; i < cloud.points.size(); ++i)
00277 {
00278 const PointT& p = cloud.points[i];
00279
00280
00281 if (isnan(p.z) || p.z >= max_z || p.z < min_z) continue;
00282
00283 int u = (h - p.x + cx)/resolution;
00284 int v = (p.y + cy)/resolution;
00285
00286 uint8_t& bin = img.at<uint8_t>(v, u);
00287 if(bin < 255) bin++;
00288 }
00289 }
00290
00291 void filterCloudByHeight(
00292 const pcl::PointCloud<pcl::PointXYZRGBNormal>& cloud_in,
00293 pcl::PointCloud<pcl::PointXYZRGBNormal>& cloud_out,
00294 double min_z,
00295 double max_z)
00296 {
00297 for (unsigned int i = 0; i < cloud_in.points.size(); ++i)
00298 {
00299 const pcl::PointXYZRGBNormal& p = cloud_in.points[i];
00300
00301 if (p.z >= min_z && p.z < max_z)
00302 cloud_out.push_back(p);
00303 }
00304 }
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 void pairwiseMatchingRANSAC(
00345 const RGBDFrame& frame_a, const RGBDFrame& frame_b,
00346 double max_eucl_dist_sq,
00347 double max_desc_dist,
00348 double sufficient_inlier_ratio,
00349 int max_ransac_iterations,
00350 std::vector<cv::DMatch>& all_matches,
00351 std::vector<cv::DMatch>& best_inlier_matches,
00352 Eigen::Matrix4f& best_transformation)
00353 {
00354
00355 bool use_ratio_test = true;
00356 float max_desc_ratio = 0.75;
00357
00358
00359 int min_sample_size = 3;
00360
00361 cv::FlannBasedMatcher matcher;
00362 TransformationEstimationSVD svd;
00363
00364 std::vector<cv::DMatch> candidate_matches;
00365
00366
00367
00368
00369
00370 if (use_ratio_test)
00371 {
00372 std::vector<std::vector<cv::DMatch> > all_matches2;
00373
00374 matcher.knnMatch(
00375 frame_b.descriptors, frame_a.descriptors, all_matches2, 2);
00376
00377 for (unsigned int m_idx = 0; m_idx < all_matches2.size(); ++m_idx)
00378 {
00379 const cv::DMatch& match1 = all_matches2[m_idx][0];
00380 const cv::DMatch& match2 = all_matches2[m_idx][1];
00381
00382 double ratio = match1.distance / match2.distance;
00383
00384
00385 if (ratio < max_desc_ratio)
00386 {
00387 int idx_b = match1.queryIdx;
00388 int idx_a = match1.trainIdx;
00389
00390 if (frame_a.kp_valid[idx_a] && frame_b.kp_valid[idx_b])
00391 candidate_matches.push_back(match1);
00392 }
00393 }
00394 }
00395 else
00396 {
00397 matcher.match(
00398 frame_b.descriptors, frame_a.descriptors, all_matches);
00399
00400 for (unsigned int m_idx = 0; m_idx < all_matches.size(); ++m_idx)
00401 {
00402 const cv::DMatch& match = all_matches[m_idx];
00403
00404
00405 if (match.distance < max_desc_dist)
00406 {
00407 int idx_b = match.queryIdx;
00408 int idx_a = match.trainIdx;
00409
00410 if (frame_a.kp_valid[idx_a] && frame_b.kp_valid[idx_b])
00411 candidate_matches.push_back(match);
00412 }
00413 }
00414 }
00415
00416 int size = candidate_matches.size();
00417
00418
00419 if (size < min_sample_size) return;
00420
00421
00422
00423 PointCloudFeature features_a, features_b;
00424
00425 features_a.resize(size);
00426 features_b.resize(size);
00427
00428 for (int m_idx = 0; m_idx < size; ++m_idx)
00429 {
00430 const cv::DMatch& match = candidate_matches[m_idx];
00431 int idx_b = match.queryIdx;
00432 int idx_a = match.trainIdx;
00433
00434 PointFeature& p_a = features_a[m_idx];
00435 p_a.x = frame_a.kp_means[idx_a](0,0);
00436 p_a.y = frame_a.kp_means[idx_a](1,0);
00437 p_a.z = frame_a.kp_means[idx_a](2,0);
00438
00439 PointFeature& p_b = features_b[m_idx];
00440 p_b.x = frame_b.kp_means[idx_b](0,0);
00441 p_b.y = frame_b.kp_means[idx_b](1,0);
00442 p_b.z = frame_b.kp_means[idx_b](2,0);
00443 }
00444
00445
00446
00447 int best_n_inliers = 0;
00448 Eigen::Matrix4f transformation;
00449
00450 for (int iteration = 0; iteration < max_ransac_iterations; ++iteration)
00451 {
00452
00453 IntVector sample_idx;
00454 getRandomIndices(min_sample_size, size, sample_idx);
00455
00456
00457 IntVector inlier_idx;
00458 std::vector<cv::DMatch> inlier_matches;
00459
00460 for (unsigned int s_idx = 0; s_idx < sample_idx.size(); ++s_idx)
00461 {
00462 int m_idx = sample_idx[s_idx];
00463 inlier_idx.push_back(m_idx);
00464 inlier_matches.push_back(candidate_matches[m_idx]);
00465 }
00466
00467
00468 svd.estimateRigidTransformation(
00469 features_b, inlier_idx,
00470 features_a, inlier_idx,
00471 transformation);
00472
00473
00474 PointCloudFeature features_b_tf;
00475 pcl::transformPointCloud(features_b, features_b_tf, transformation);
00476
00477 for (int m_idx = 0; m_idx < size; ++m_idx)
00478 {
00479 const PointFeature& p_a = features_a[m_idx];
00480 const PointFeature& p_b = features_b_tf[m_idx];
00481
00482 float dist_sq = distEuclideanSq(p_a, p_b);
00483
00484 if (dist_sq < max_eucl_dist_sq)
00485 {
00486 inlier_idx.push_back(m_idx);
00487 inlier_matches.push_back(candidate_matches[m_idx]);
00488
00489
00490 svd.estimateRigidTransformation(
00491 features_b, inlier_idx,
00492 features_a, inlier_idx,
00493 transformation);
00494 pcl::transformPointCloud(features_b, features_b_tf, transformation);
00495 }
00496 }
00497
00498
00499 int n_inliers = inlier_idx.size();
00500
00501 if (n_inliers > best_n_inliers)
00502 {
00503 svd.estimateRigidTransformation(
00504 features_b, inlier_idx,
00505 features_a, inlier_idx,
00506 transformation);
00507
00508 best_n_inliers = n_inliers;
00509 best_transformation = transformation;
00510 best_inlier_matches = inlier_matches;
00511 }
00512
00513
00514 double inlier_ratio = (double) n_inliers / (double) size;
00515
00516 if (inlier_ratio > sufficient_inlier_ratio)
00517 break;
00518 }
00519 }
00520
00521 void getRandomIndices(
00522 int k, int n, IntVector& output)
00523 {
00524 while ((int)output.size() < k)
00525 {
00526 int random_number = rand() % n;
00527 bool duplicate = false;
00528
00529 for (unsigned int i = 0; i < output.size(); ++i)
00530 {
00531 if (output[i] == random_number)
00532 {
00533 duplicate = true;
00534 break;
00535 }
00536 }
00537
00538 if (!duplicate)
00539 output.push_back(random_number);
00540 }
00541 }
00542
00543 void get3RandomIndices(
00544 int n, std::set<int>& mask, IntVector& output)
00545 {
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 getRandomIndices(3, n, output);
00563
00564
00565 }
00566
00567 double distEuclideanSq(const PointFeature& a, const PointFeature& b)
00568 {
00569 float dx = a.x - b.x;
00570 float dy = a.y - b.y;
00571 float dz = a.z - b.z;
00572 return dx*dx + dy*dy + dz*dz;
00573 }
00574
00575
00576 void compareAssociationMatrix(
00577 const cv::Mat& a,
00578 const cv::Mat& b,
00579 int& false_pos,
00580 int& false_neg,
00581 int& total)
00582 {
00583 false_pos = 0;
00584 false_neg = 0;
00585 total = 0;
00586
00587
00588 assert(a.rows == a.cols);
00589 assert(b.rows == b.cols);
00590 assert(a.rows == b.rows);
00591
00592 int size = a.rows;
00593
00594 for (int u = 0; u < size; ++u)
00595 for (int v = 0; v < size; ++v)
00596 {
00597 if (u !=v)
00598 {
00599 int val_a = a.at<uint8_t>(v,u);
00600 int val_b = b.at<uint8_t>(v,u);
00601
00602 if (val_a != 0 && val_b == 0) false_neg++;
00603 if (val_a == 0 && val_b != 0) false_pos++;
00604
00605 if (val_a != 0) total++;
00606 }
00607 }
00608 }
00609
00610 void makeSymmetricOR(cv::Mat mat)
00611 {
00612 assert(mat.rows == mat.cols);
00613 int size = mat.rows;
00614
00615 for (int u = 0; u < size; ++u)
00616 for (int v = 0; v < size; ++v)
00617 {
00618 if (mat.at<uint8_t>(v, u) != 0 ||
00619 mat.at<uint8_t>(u, v) != 0)
00620 {
00621 mat.at<uint8_t>(v, u) = 1;
00622 mat.at<uint8_t>(u, v) = 1;
00623 }
00624 }
00625 }
00626
00627 void trainSURFMatcher(
00628 const KeyframeVector& keyframes,
00629 cv::FlannBasedMatcher& matcher)
00630 {
00631 std::vector<cv::Mat> descriptors_vector;
00632 for (unsigned int kf_idx = 0; kf_idx < keyframes.size(); ++kf_idx)
00633 {
00634 const RGBDKeyframe& keyframe = keyframes[kf_idx];
00635 descriptors_vector.push_back(keyframe.descriptors);
00636 }
00637 matcher.add(descriptors_vector);
00638
00639 matcher.train();
00640 }
00641
00642 void trainSURFMatcher_Iterative(
00643 const KeyframeVector& keyframes,u_int min, u_int max,
00644 cv::FlannBasedMatcher& matcher)
00645 {
00646 std::vector<cv::Mat> descriptors_vector;
00647
00648 for (unsigned int kf_idx = min; kf_idx < max; ++kf_idx)
00649 {
00650 const RGBDKeyframe& keyframe = keyframes[kf_idx];
00651 descriptors_vector.push_back(keyframe.descriptors);
00652 }
00653 matcher.add(descriptors_vector);
00654
00655 matcher.train();
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 }