$search
00001 #include "vfh_recognition/vfh_recognition.h" 00002 #include <pcl/filters/statistical_outlier_removal.h> 00003 #include <pcl/filters/radius_outlier_removal.h> 00004 #include <pcl/segmentation/extract_clusters.h> 00005 #include <fstream> 00006 #include <iostream> 00007 #include <pcl/segmentation/segment_differences.h> 00008 00009 #include <boost/random.hpp> 00010 #include <boost/random/normal_distribution.hpp> 00011 #include <sys/time.h> 00012 #include <stdio.h> 00013 #include <unistd.h> 00014 #include <utility> 00015 00016 #include <pcl/common/time.h> 00017 #include <algorithm> 00018 #include <Eigen/StdVector> 00019 00020 namespace vfh_recognition 00021 { 00022 00023 typedef struct 00024 { 00025 bool 00026 operator() (std::pair<double, size_t> const& a, std::pair<double, size_t> const& b) 00027 { 00028 return a.first > b.first; 00029 } 00030 } peaks_ordering; 00031 00032 typedef pcl::KdTree<pcl::PointNormal>::Ptr KdTreePtr; 00033 00034 template<template<class > class Distance> 00035 VFHRecognizer<Distance>::VFHRecognizer () 00036 { 00037 index_ = NULL; 00038 apply_voxel_grid_ = true; 00039 apply_radius_removal_ = true; 00040 icp_iterations_ = 0; 00041 perform_icp_ = false; 00042 this->use_old_vfh_ = false; 00043 normalize_vfh_bins_ = true; 00044 use_cluster_centroids_ = false; 00045 view_id_being_processed_ = -1; 00046 fill_size_component_ = false; 00047 } 00048 00049 template<template<class > class Distance> 00050 VFHRecognizer<Distance>::~VFHRecognizer () 00051 { 00052 //free memory... 00053 delete index_; 00054 free (data_.data); 00055 } 00056 00057 template<template<class > class Distance> 00058 void 00059 VFHRecognizer<Distance>::computeVFHRollOrientation ( 00060 pcl::PointCloud<pcl::PointNormal>::Ptr input, 00061 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_orientation_signature, 00062 Eigen::Vector3f & centroid, cv::Mat & frequency_domain) 00063 { 00064 Eigen::Vector3f plane_normal; 00065 plane_normal[0] = -centroid[0]; 00066 plane_normal[1] = -centroid[1]; 00067 plane_normal[2] = -centroid[2]; 00068 Eigen::Vector3f z_vector = Eigen::Vector3f::UnitZ (); 00069 plane_normal.normalize (); 00070 Eigen::Vector3f axis = plane_normal.cross (z_vector); 00071 double rotation = -asin (axis.norm ()); 00072 axis.normalize (); 00073 00074 unsigned int nbins = nr_bins; 00075 int bin_angle = 360 / nbins; 00076 Eigen::VectorXf orientation_hist; 00077 orientation_hist.setZero (nbins); 00078 00079 Eigen::Affine3f transformPC (Eigen::AngleAxisf (rotation, axis)); 00080 00081 pcl::PointCloud < pcl::PointNormal > grid; 00082 pcl::transformPointCloudWithNormals (*input, grid, transformPC); 00083 00084 cv::Mat hist = cv::Mat_<float>::zeros (nbins, 1); 00085 00086 double sum_w = 0, w = 0; 00087 int bin = 0; 00088 for (size_t i = 0; i < grid.points.size (); ++i) 00089 { 00090 bin = (int)(((atan2 (grid.points[i].normal_y, grid.points[i].normal_x) + PI) * 180 / PI) / bin_angle) % nbins; 00091 w 00092 = sqrt ( 00093 grid.points[i].normal_y * grid.points[i].normal_y + grid.points[i].normal_x 00094 * grid.points[i].normal_x); 00095 //w = grid.points[i].normal_y * grid.points[i].normal_y + grid.points[i].normal_x * grid.points[i].normal_x; 00096 orientation_hist[bin] += w; 00097 sum_w += w; 00098 hist.at<float> (bin) += w; 00099 } 00100 00101 for (size_t i = 0; i < nbins; ++i) 00102 { 00103 orientation_hist[i] /= sum_w; 00104 hist.at<float> (i) /= sum_w; 00105 } 00106 00107 cv::dft (hist, frequency_domain); 00108 00109 //transform to vfh_signature 00110 vfh_orientation_signature->points.resize (1); 00111 vfh_orientation_signature->width = 1; 00112 vfh_orientation_signature->height = 1; 00113 00114 //no sliding window... 00115 for (size_t i = 0; i < nbins; ++i) 00116 { 00117 vfh_orientation_signature->points[0].histogram[i] = orientation_hist[i]; 00118 } 00119 00120 //sliding window implementation 00121 /*int wsize = 5; 00122 double sum_wsize = 0; 00123 //bootstrap window 00124 for (int i = -wsize / 2; i <= wsize / 2; ++i) 00125 { 00126 sum_wsize += orientation_hist[(i + nbins) % nbins]; 00127 } 00128 vfh_orientation_signature->points[0].histogram[0] = sum_wsize / double (wsize); 00129 00130 for (size_t i = 1; i < nbins; ++i) 00131 { 00132 int idx = (int)i; 00133 sum_wsize += orientation_hist[((idx - wsize / 2 - 1) + nbins) % nbins] * -1 + orientation_hist[(idx + wsize / 2 00134 + nbins) % nbins]; 00135 vfh_orientation_signature->points[0].histogram[i] = sum_wsize / double (wsize); 00136 } 00137 00138 struct timeval start; 00139 gettimeofday (&start, NULL);*/ 00140 00141 /*std::stringstream path_vfh_orientation; 00142 path_vfh_orientation << "/u/aaldoma/data/vfhs_roll_orientation/vfh_orientation_input_inside:" << start.tv_usec << ".pcd"; 00143 //std::cout << path_vfh_orientation.str() << std::endl; 00144 pcl::io::savePCDFileBinary (path_vfh_orientation.str(), *vfh_orientation_signature); 00145 00146 std::stringstream path_vfh_point_cloud; 00147 path_vfh_point_cloud << "/tmp/vfh_orientation_point_cloud:" << start.tv_usec << ".pcd"; 00148 //std::cout << path_vfh_point_cloud.str() << std::endl; 00149 pcl::io::savePCDFileBinary (path_vfh_point_cloud.str(), grid);*/ 00150 } 00151 00152 template<template<class > class Distance> 00153 void 00154 VFHRecognizer<Distance>::filterNormalsWithHighCurvature (pcl::PointCloud<pcl::PointNormal> & cloud, 00155 std::vector<int> & indices_out, 00156 std::vector<int> & indices_in, float threshold) 00157 { 00158 indices_out.resize (cloud.points.size ()); 00159 indices_in.resize (cloud.points.size ()); 00160 00161 size_t in, out; 00162 in = out = 0; 00163 00164 for (size_t i = 0; i < cloud.points.size (); i++) 00165 { 00166 if (cloud.points[i].curvature > threshold) 00167 { 00168 indices_out[out] = i; 00169 out++; 00170 } 00171 else 00172 { 00173 indices_in[in] = i; 00174 in++; 00175 } 00176 } 00177 00178 indices_out.resize (out); 00179 indices_in.resize (in); 00180 } 00181 00182 template<template<class > class Distance> 00183 bool 00184 VFHRecognizer<Distance>::computeNormals (pcl::PointCloud<pcl::PointXYZ>::Ptr input, 00185 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_normals) 00186 { 00187 typedef pcl::NormalEstimation<pcl::PointNormal, pcl::PointNormal> NormalEstimation; 00188 NormalEstimation n3d; 00189 00190 pcl::PointCloud<pcl::PointXYZ>::Ptr grid (new pcl::PointCloud<pcl::PointXYZ> ()); 00191 double leafSize = 0.005; 00192 00193 if (apply_voxel_grid_) 00194 { 00195 pcl::VoxelGrid < pcl::PointXYZ > grid_; 00196 grid_.setInputCloud (input); 00197 grid_.setLeafSize (leafSize, leafSize, leafSize); 00198 grid_.filter (*grid); 00199 } 00200 else 00201 { 00202 ROS_WARN ("Do not apply voxel gridding"); 00203 copyPointCloud (*input, *grid); 00204 } 00205 00206 if (apply_radius_removal_) 00207 { 00208 //in synthetic views the render grazes some parts of the objects that are barely seen from that VP 00209 //thus creating a very sparse set of points that causes the normals to be very noisy!! 00210 //remove these points 00211 pcl::PointCloud < pcl::PointXYZ > gridFiltered; 00212 pcl::RadiusOutlierRemoval < pcl::PointXYZ > sor; 00213 sor.setInputCloud (grid); 00214 sor.setRadiusSearch (leafSize * 3); 00215 sor.setMinNeighborsInRadius (10); 00216 sor.filter (gridFiltered); 00217 copyPointCloud (gridFiltered, *cloud_normals); 00218 } 00219 else 00220 { 00221 copyPointCloud (*grid, *cloud_normals); 00222 ROS_WARN ("Do not apply radius removal"); 00223 } 00224 00225 if (cloud_normals->points.size () == 0) 00226 { 00227 ROS_WARN ("Cloud has no points after voxel grid and filtering, wont be able to compute normals or VFH!"); 00228 return false; 00229 } 00230 00231 KdTreePtr normals_tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointNormal> > (false); 00232 normals_tree->setInputCloud (cloud_normals); 00233 n3d.setRadiusSearch (leafSize * 3); 00234 n3d.setSearchMethod (normals_tree); 00235 n3d.setInputCloud (cloud_normals); 00236 n3d.compute (*cloud_normals); 00237 00238 //check nans... 00239 int j = 0; 00240 for (size_t i = 0; i < cloud_normals->points.size (); ++i) 00241 { 00242 if (!pcl_isfinite (cloud_normals->points[i].normal_x) || !pcl_isfinite (cloud_normals->points[i].normal_y) 00243 || !pcl_isfinite (cloud_normals->points[i].normal_z)) 00244 continue; 00245 cloud_normals->points[j] = cloud_normals->points[i]; 00246 j++; 00247 } 00248 00249 cloud_normals->points.resize (j); 00250 cloud_normals->width = j; 00251 cloud_normals->height = 1; 00252 return true; 00253 } 00254 00255 template<template<class > class Distance> 00256 bool 00257 VFHRecognizer<Distance>::computeVFH (pcl::PointCloud<pcl::PointXYZ>::Ptr input, 00258 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_normals, 00259 std::vector<pcl::PointCloud<pcl::VFHSignature308>,Eigen::aligned_allocator< pcl::PointCloud<pcl::VFHSignature308> > > & vfh_signatures, 00260 std::vector<Eigen::Vector3f> & centroids_dominant_orientations) 00261 { 00262 computeNormals (input, cloud_normals); 00263 00264 //std::stringstream normals_path; 00265 //normals_path << "/u/aaldoma/data/clusters/normals.pcd"; 00266 //std::cout << normals_path.str() << std::endl; 00267 //pcl::io::savePCDFileASCII (normals_path.str(), *cloud_normals); 00268 00269 if (!(this->use_old_vfh_)) 00270 { 00271 ROS_WARN ("USING CVFH..."); 00272 typedef pcl::CVFHEstimation<pcl::PointNormal, pcl::PointNormal, pcl::VFHSignature308> CVFHEstimator; 00273 pcl::PointCloud < pcl::VFHSignature308 > cvfh_signatures; 00274 00275 CVFHEstimator cvfh; 00276 pcl::KdTree<pcl::PointNormal>::Ptr cvfh_tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointNormal> > (); 00277 //cvfh_tree->setInputCloud (cloud_normals); 00278 cvfh.setSearchMethod (cvfh_tree); 00279 cvfh.setInputCloud (cloud_normals); 00280 cvfh.setInputNormals (cloud_normals); 00281 cvfh.compute (cvfh_signatures); 00282 00283 for (size_t i = 0; i < cvfh_signatures.points.size (); i++) 00284 { 00285 pcl::PointCloud < pcl::VFHSignature308 > vfh_signature; 00286 vfh_signature.points.resize (1); 00287 vfh_signature.width = vfh_signature.height = 1; 00288 for (int d = 0; d < 308; ++d) 00289 vfh_signature.points[0].histogram[d] = cvfh_signatures.points[i].histogram[d]; 00290 00291 vfh_signatures.push_back (vfh_signature); 00292 00293 /*std::stringstream path_vfh_point_cloud; 00294 path_vfh_point_cloud << "/u/aaldoma/data/vfhs/vfh.pcd"; 00295 std::cout << path_vfh_point_cloud.str() << std::endl; 00296 pcl::io::savePCDFileBinary (path_vfh_point_cloud.str(), vfh_signature);*/ 00297 } 00298 00299 cvfh.getCentroidClusters (centroids_dominant_orientations); 00300 } 00301 else 00302 { 00303 00304 ROS_WARN ("USING VFH..."); 00305 typedef pcl::VFHEstimation<pcl::PointNormal, pcl::PointNormal, pcl::VFHSignature308> VFHEstimator; 00306 VFHEstimator vfh; 00307 00308 Eigen::Vector4f avg_centroid; 00309 pcl::compute3DCentroid (*cloud_normals, avg_centroid); 00310 Eigen::Vector3f cloud_centroid (avg_centroid[0], avg_centroid[1], avg_centroid[2]); 00311 00312 pcl::KdTree<pcl::PointNormal>::Ptr vfh_tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointNormal> > (); 00313 vfh_tree->setInputCloud (cloud_normals); 00314 vfh.setSearchMethod (vfh_tree); 00315 vfh.setInputCloud (cloud_normals); 00316 vfh.setInputNormals (cloud_normals); 00317 vfh.setUseGivenCentroid (false); 00318 vfh.setFillSizeComponent (true); 00319 vfh.setNormalizeDistance (true); 00320 vfh.setUseGivenNormal (false); 00321 vfh.setNormalizeDistance (true); 00322 vfh.setNormalizeBins (true); 00323 00324 pcl::PointCloud < pcl::VFHSignature308 > vfh_signature; 00325 vfh.compute (vfh_signature); 00326 vfh_signatures.push_back (vfh_signature); 00327 00328 //std::stringstream path_vfh_orientation; 00329 //path_vfh_orientation << "/u/aaldoma/data/vfhs/vfh_input_oldVFH.pcd"; 00330 //std::cout << "Saving VFH histogram to:" << path_vfh_orientation.str () << std::endl; 00331 //pcl::io::savePCDFileASCII (path_vfh_orientation.str (), vfh_signature); 00332 00333 centroids_dominant_orientations.push_back (cloud_centroid); 00334 } 00335 00336 return true; 00337 } 00338 00339 template<template<class > class Distance> 00340 bool 00341 VFHRecognizer<Distance>::loadFileList (std::vector<vfh_model_db> &models, const std::string &filename) 00342 { 00343 std::ifstream fs; 00344 fs.open (filename.c_str ()); 00345 if (!fs.is_open () || fs.fail ()) 00346 return (false); 00347 00348 std::string line; 00349 while (!fs.eof ()) 00350 { 00351 getline (fs, line); 00352 if (line.empty ()) 00353 continue; 00354 vfh_model_db m; 00355 m.first = std::string (line.c_str ()); 00356 models.push_back (m); 00357 } 00358 fs.close (); 00359 return (true); 00360 } 00361 00362 template<template<class > class Distance> 00363 void 00364 VFHRecognizer<Distance>::saveFileList (const std::vector<vfh_model_db> &models, const std::string &filename) 00365 { 00366 std::ofstream fs; 00367 fs.open (filename.c_str ()); 00368 for (size_t i = 0; i < models.size (); ++i) 00369 fs << models[i].first << "\n"; 00370 fs.close (); 00371 } 00372 00373 template<template<class > class Distance> 00374 void 00375 VFHRecognizer<Distance>::nearestKSearch (flann::Index<DistT> * index, const vfh_model_db &model, int k, 00376 flann::Matrix<int> &indices, flann::Matrix<float> &distances) 00377 { 00378 flann::Matrix<float> p = flann::Matrix<float> (new float[model.second.size ()], 1, model.second.size ()); 00379 memcpy (&p.data[0], &model.second[0], p.cols * p.rows * sizeof(float)); 00380 00381 indices = flann::Matrix<int> (new int[k], 1, k); 00382 distances = flann::Matrix<float> (new float[k], 1, k); 00383 index->knnSearch (p, indices, distances, k, flann::SearchParams (512)); 00384 p.free (); 00385 } 00386 00387 template<template<class > class Distance> 00388 void 00389 VFHRecognizer<Distance>::getRollRotationAngles (std::vector<int> * roll_angles) 00390 { 00391 for (size_t i = 0; i < roll_rotation_angles_.size (); i++) 00392 { 00393 roll_angles->push_back (roll_rotation_angles_.at (i)); 00394 } 00395 } 00396 00397 template<template<class > class Distance> 00398 void 00399 VFHRecognizer<Distance>::getICPTransformations (std::vector<Eigen::Matrix4f,Eigen::aligned_allocator< Eigen::Matrix4f > > * icp_transformations) 00400 { 00401 for (size_t i = 0; i < icp_transformations_.size (); i++) 00402 { 00403 icp_transformations->push_back (icp_transformations_.at (i)); 00404 } 00405 } 00406 00407 template<template<class > class Distance> 00408 void 00409 VFHRecognizer<Distance>::getCentroids (std::vector<Eigen::Vector4f,Eigen::aligned_allocator< Eigen::Vector4f > > * centroids) 00410 { 00411 for (size_t i = 0; i < centroid_inputs_.size (); i++) 00412 { 00413 centroids->push_back (centroid_inputs_.at (i)); 00414 } 00415 } 00416 00417 template<template<class > class Distance> 00418 void 00419 VFHRecognizer<Distance>::getCentroidsResults (std::vector<Eigen::Vector4f,Eigen::aligned_allocator< Eigen::Vector4f > > * centroids) 00420 { 00421 for (size_t i = 0; i < centroid_results_.size (); i++) 00422 { 00423 centroids->push_back (centroid_results_.at (i)); 00424 } 00425 } 00426 00427 template<template<class > class Distance> 00428 int 00429 VFHRecognizer<Distance>::computeAngleRollOrientationFrequency (cv::Mat & hist_fft, cv::Mat & hist_fft_input, 00430 int nr_bins_, Eigen::Vector4f centroid_view, 00431 Eigen::Vector4f centroid_input, 00432 const pcl::PointCloud<pcl::PointNormal> & view, 00433 const pcl::PointCloud<pcl::PointNormal> & input, 00434 int jj, 00435 pcl::PointCloud<pcl::VFHSignature308> & hist_view, 00436 pcl::PointCloud<pcl::VFHSignature308> & hist_input) 00437 { 00438 00439 for (size_t i = 2; i < (size_t)nr_bins_; i += 2) 00440 { 00441 hist_fft.at<float> (i) = -hist_fft.at<float> (i); 00442 } 00443 00444 //int nr_bins_after_padding = 90; 00445 int nr_bins_after_padding = 180; 00446 int peak_distance = 4; 00447 cv::Mat multAB = cv::Mat_<float>::zeros (nr_bins_after_padding, 1); 00448 00449 float a, b, c, d; 00450 00451 multAB.at<float> (0) = hist_fft.at<float> (0) * hist_fft_input.at<float> (0); 00452 00453 size_t cutoff = 5; 00454 cutoff = nr_bins_ - 1; 00455 for (size_t i = 1; i < cutoff; i += 2) 00456 { 00457 a = hist_fft.at<float> (i); 00458 b = hist_fft.at<float> (i + 1); 00459 c = hist_fft_input.at<float> (i); 00460 d = hist_fft_input.at<float> (i + 1); 00461 multAB.at<float> (i) = a * c - b * d; 00462 multAB.at<float> (i + 1) = b * c + a * d; 00463 00464 float tmp = sqrt ( 00465 multAB.at<float> (i) * multAB.at<float> (i) + multAB.at<float> (i + 1) 00466 * multAB.at<float> (i + 1)); 00467 00468 multAB.at<float> (i) /= tmp; 00469 multAB.at<float> (i + 1) /= tmp; 00470 } 00471 00472 multAB.at<float> (nr_bins_ - 1) = hist_fft.at<float> (nr_bins_ - 1) * hist_fft_input.at<float> (nr_bins_ - 1); 00473 00474 cv::Mat invAB; 00475 cv::idft (multAB, invAB, cv::DFT_SCALE); 00476 00477 std::vector < std::pair<double, int> > scored_peaks (nr_bins_after_padding); 00478 00479 pcl::PointCloud < pcl::VFHSignature308 > cross_power; 00480 cross_power.points.resize (1); 00481 cross_power.width = cross_power.height = 1; 00482 00483 for (size_t i = 0; i < (size_t)nr_bins_after_padding; i++) 00484 { 00485 scored_peaks[i] = std::make_pair<double, size_t> (invAB.at<float> (i), (int)i); 00486 cross_power.points[0].histogram[i] = invAB.at<float> (i); 00487 } 00488 00489 /*std::stringstream path_vfh_orientation; 00490 path_vfh_orientation << "/u/aaldoma/data/vfhs_roll_orientation/cross_input_" << jj << ".pcd"; 00491 std::cout << path_vfh_orientation.str() << std::endl; 00492 pcl::io::savePCDFileBinary (path_vfh_orientation.str(), cross_power);*/ 00493 00494 std::sort (scored_peaks.begin (), scored_peaks.end (), peaks_ordering ()); 00495 std::vector<int> peaks; 00496 00497 // we look at the upper 20% quantile 00498 for (size_t i = 0; i < (size_t) (0.2 * nr_bins_after_padding); i++) 00499 { 00500 if (scored_peaks[i].first >= scored_peaks[0].first * 0.8) 00501 { 00502 bool insert = true; 00503 00504 for (size_t j = 0; j < peaks.size (); j++) 00505 { //check inserted peaks, first pick always inserted 00506 //std::cout << peaks[j] << " " << scored_peaks[i].second << " " << fabs ((int)peaks[j] - (int)scored_peaks[i].second) << std::endl; 00507 if (fabs (peaks[j] - scored_peaks[i].second) <= peak_distance || 00508 fabs ( peaks[j] - (scored_peaks[i].second - nr_bins_after_padding)) <= peak_distance) 00509 { 00510 insert = false; 00511 break; 00512 } 00513 } 00514 00515 if (insert) { 00516 std::cout << "Inserted:" << (float)scored_peaks[i].first << " " << scored_peaks[i].second << std::endl; 00517 peaks.push_back (scored_peaks[i].second); 00518 } 00519 } 00520 } 00521 00522 int max_idx = 0; 00523 int NUM_PEAKS_CHECKED = 0; 00524 pcl::PointCloud<pcl::PointNormal>::Ptr input_ptr (new pcl::PointCloud<pcl::PointNormal> (input)); 00525 double max_score = std::numeric_limits<double>::min (); 00526 00527 //PCLVisualizer vis ("roll orientation"); 00528 00529 for (size_t i = 0; i < peaks.size (); i++) 00530 { 00531 pcl::PointCloud < pcl::PointNormal > cloud_xyz; 00532 cloud_xyz = view; 00533 00534 pcl::PointCloud<pcl::PointNormal>::Ptr gridTransformed (new pcl::PointCloud<pcl::PointNormal> ()); 00535 00536 double current_angle = peaks[i] * (360 / nr_bins_after_padding); 00537 Eigen::Affine3f final_trans; 00538 computeRollTransform (centroid_input, centroid_view, current_angle, final_trans); 00539 00540 pcl::transformPointCloudWithNormals (cloud_xyz, *gridTransformed, final_trans); 00541 00542 //translate result point cloud so centroids match... 00543 Eigen::Vector3f centr (centroid_view[0], centroid_view[1], centroid_view[2]); 00544 centr = final_trans * centr; 00545 Eigen::Vector4f diff = Eigen::Vector4f::Zero (); 00546 diff[0] = -centroid_input[0] + centr[0]; 00547 diff[1] = -centroid_input[1] + centr[1]; 00548 diff[2] = -centroid_input[2] + centr[2]; 00549 00550 cloud_xyz = *gridTransformed; 00551 00552 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_xyz_demean (new pcl::PointCloud<pcl::PointNormal> ()); 00553 00554 pcl::demeanPointCloud (cloud_xyz, diff, *cloud_xyz_demean); 00555 00556 pcl::SegmentDifferences < pcl::PointNormal > seg; 00557 typedef pcl::KdTree<pcl::PointNormal>::Ptr KdTreePtr; 00558 KdTreePtr normals_tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointNormal> > (true); 00559 seg.setDistanceThreshold (0.005 * 0.005); //1cm 00560 seg.setSearchMethod (normals_tree); 00561 seg.setInputCloud (input_ptr); 00562 seg.setTargetCloud (cloud_xyz_demean); 00563 00564 pcl::PointCloud < pcl::PointNormal > difference; 00565 seg.segment (difference); 00566 00567 //int smallest_pointcloud = std::min(input.points.size(),cloud_xyz_demean->points.size()); 00568 double fscore = input.points.size () - difference.points.size (); //number of inliers 00570 00571 //std::cout << "angle checked as peak:" << peaks[i] * (360 / nr_bins_after_padding) << " fscore:" << fscore << std::endl; 00572 00573 if (fscore > max_score) 00574 { 00575 max_score = fscore; 00576 max_idx = peaks[i]; 00577 } 00578 00579 NUM_PEAKS_CHECKED++; 00580 } 00581 00582 std::cout << "NUM_PEAKS_CHECKED:" << NUM_PEAKS_CHECKED << " " << max_idx << std::endl; 00583 return max_idx * (360 / nr_bins_after_padding); 00584 } 00585 00586 template<template<class > class Distance> 00587 void 00588 VFHRecognizer<Distance>::computeTransformToZAxes (Eigen::Vector4f & centroid, Eigen::Affine3f & transform) 00589 { 00590 Eigen::Vector3f plane_normal; 00591 plane_normal[0] = -centroid[0]; 00592 plane_normal[1] = -centroid[1]; 00593 plane_normal[2] = -centroid[2]; 00594 Eigen::Vector3f z_vector = Eigen::Vector3f::UnitZ (); 00595 plane_normal.normalize (); 00596 Eigen::Vector3f axis = plane_normal.cross (z_vector); 00597 double rotation = -asin (axis.norm ()); 00598 axis.normalize (); 00599 transform = Eigen::Affine3f (Eigen::AngleAxisf (rotation, axis)); 00600 } 00601 00602 template<template<class > class Distance> 00603 void 00604 VFHRecognizer<Distance>::computeRollTransform (Eigen::Vector4f & centroidInput, Eigen::Vector4f & centroidResult, 00605 double roll_angle, Eigen::Affine3f & final_trans) 00606 { 00607 Eigen::Affine3f transformInputToZ; 00608 computeTransformToZAxes (centroidInput, transformInputToZ); //use current cluster centroid 00609 //std::cout << transformInputToZ.matrix() << std::endl; 00610 transformInputToZ = transformInputToZ.inverse (); 00611 00612 Eigen::Affine3f transformRoll (Eigen::AngleAxisf (-(roll_angle * M_PI / 180), Eigen::Vector3f::UnitZ ())); 00613 00614 Eigen::Affine3f transformDBResultToZ; 00615 computeTransformToZAxes (centroidResult, transformDBResultToZ); //use current cluster centroid 00616 00617 final_trans = transformInputToZ * transformRoll * transformDBResultToZ; 00618 } 00619 00620 template<template<class > class Distance> 00621 bool 00622 VFHRecognizer<Distance>::detect_ (const sensor_msgs::PointCloud2ConstPtr& msg, int nModels, 00623 std::vector<std::string>& model_ids, std::vector<geometry_msgs::Pose> & poses, 00624 std::vector<float>& confidences, std::vector<std::string>& vfh_ids, 00625 bool use_fitness_score) 00626 { 00627 00628 //reset stuff from one detection to the following 00629 roll_rotation_angles_.clear (); 00630 icp_transformations_.clear (); 00631 centroid_inputs_.clear (); 00632 centroid_results_.clear (); 00633 roll_histogram_errors_.clear (); 00634 roll_histogram_errors_flipped_.clear (); 00635 fitness_scores_.clear (); 00636 00637 PointCloudAndNormals::Ptr cloud_normals (new PointCloudAndNormals ()); 00638 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_signature (new pcl::PointCloud<pcl::VFHSignature308> ()); 00639 00640 PointCloud::Ptr cloud (new PointCloud ()); 00641 00642 pcl::fromROSMsg (*msg, *cloud); 00643 00644 //compute CVFH for the point cloud 00645 std::vector<pcl::PointCloud<pcl::VFHSignature308>,Eigen::aligned_allocator< pcl::PointCloud<pcl::VFHSignature308> > > vfh_signatures; 00646 std::vector < Eigen::Vector3f > centroids_dominant_orientations; 00647 00648 computeVFH (cloud, cloud_normals, vfh_signatures, centroids_dominant_orientations); //centroids of the input clusters... 00649 00650 //TODO: Deactivate this... 00651 pcl::copyPointCloud (vfh_signatures[0], vfh_histogram_processed); 00652 pcl::copyPointCloud (*cloud_normals, input_filtered); 00653 00654 //allocate space for roll histograms and for input centroids 00655 std::vector < pcl::PointCloud<pcl::VFHSignature308>::Ptr > orientation_histogram_rolls_input; //(vfh_signatures.size (),NULL); 00656 std::vector < cv::Mat > frequency_domain_hists_input; 00657 orientation_histogram_rolls_input.resize (vfh_signatures.size ()); 00658 frequency_domain_hists_input.resize (vfh_signatures.size ()); 00659 std::vector < Eigen::Vector3f > centroids_input; 00660 centroids_input.resize (vfh_signatures.size ()); 00661 00662 Eigen::Vector4f centroidInput; 00663 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_xyz_demean_input (new pcl::PointCloud<pcl::PointNormal> ()); 00664 00665 pcl::compute3DCentroid (*cloud_normals, centroidInput); 00666 pcl::demeanPointCloud (*cloud_normals, centroidInput, *cloud_xyz_demean_input); 00667 00668 if (use_cluster_centroids_) 00669 { 00670 for (size_t jj = 0; jj < vfh_signatures.size (); jj++) 00671 { 00672 //for each VFH, compute the orientation histogram 00673 //using the cluster centroids 00674 pcl::PointCloud<pcl::VFHSignature308>::Ptr 00675 vfh_o_signatureInput (new pcl::PointCloud<pcl::VFHSignature308> ()); 00676 Eigen::Vector3f ci3f (centroids_dominant_orientations[jj][0], centroids_dominant_orientations[jj][1], 00677 centroids_dominant_orientations[jj][2]); 00678 00679 cv::Mat frequency_domain_input; 00680 computeVFHRollOrientation (cloud_normals, vfh_o_signatureInput, ci3f, frequency_domain_input); 00681 orientation_histogram_rolls_input[jj] = vfh_o_signatureInput; 00682 frequency_domain_hists_input[jj] = frequency_domain_input; 00683 centroids_input[jj] = ci3f; 00684 00685 /*std::stringstream path_vfh_orientation; 00686 path_vfh_orientation << "/u/aaldoma/data/vfhs_roll_orientation/vfh_orientation_input_" << jj << ".pcd"; 00687 std::cout << path_vfh_orientation.str() << std::endl; 00688 pcl::io::savePCDFileBinary (path_vfh_orientation.str(), *vfh_o_signatureInput);*/ 00689 } 00690 } 00691 else 00692 { 00693 //compute one orientation histogram for the whole view 00694 //using the centroid of the whole view 00695 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_o_signatureInput (new pcl::PointCloud<pcl::VFHSignature308> ()); 00696 Eigen::Vector3f ci3f (centroidInput[0], centroidInput[1], centroidInput[2]); 00697 cv::Mat frequency_domain_input; 00698 computeVFHRollOrientation (cloud_normals, vfh_o_signatureInput, ci3f, frequency_domain_input); 00699 orientation_histogram_rolls_input[0] = vfh_o_signatureInput; 00700 frequency_domain_hists_input[0] = frequency_domain_input; 00701 centroids_input[0] = ci3f; 00702 } 00703 00704 double fscore = 0; 00705 std::vector<index_score> index_scores; 00706 std::vector<int> model_indices; 00707 std::vector<int> roll_input_indices; 00708 std::vector<int> input_centroid_indices; 00709 std::vector<float> roll_histogram_errors; 00710 std::vector<float> roll_histogram_errors_flipped; 00711 int counter = 0; 00712 00713 //search for all different dominant orientations 00714 for (size_t jj = 0; jj < vfh_signatures.size (); jj++) 00715 { 00716 float* hist = vfh_signatures[jj].points[0].histogram; 00717 std::vector<float> std_hist (hist, hist + 308); 00718 vfh_model_db histogram ("", std_hist); 00719 00720 //size_t k = nModels*5; 00721 //size_t k = 15; 00722 size_t k = nModels; 00723 flann::Matrix<int> indices; 00724 flann::Matrix<float> distances; 00725 00726 nearestKSearch (index_, histogram, k, indices, distances); 00727 00728 for (size_t i = 0; i < k; ++i, ++counter) 00729 { 00730 std::string vfh_id = models_.at (indices[0][i]).first; 00731 model_indices.push_back (indices[0][i]); 00732 00733 fscore = distances[0][i]; 00734 index_score is; 00735 is.first = counter; 00736 is.second = fscore; 00737 index_scores.push_back (is); 00738 if (use_cluster_centroids_) 00739 { 00740 roll_input_indices.push_back (jj); 00741 input_centroid_indices.push_back (jj); 00742 } 00743 else 00744 { 00745 roll_input_indices.push_back (0); //we will have just one of them 00746 input_centroid_indices.push_back (0); 00747 } 00748 } 00749 } 00750 00751 //at this point, the VFHs have been searched and concatenated into 00752 //an unsorted list (index_scores) 00753 //sort the list by index score as we might have performed more than one search 00754 std::sort (index_scores.begin (), index_scores.end (), ICPredicate); 00755 00756 std::vector<index_score> index_scores_short; 00757 std::vector<Eigen::Vector4f,Eigen::aligned_allocator< Eigen::Vector4f > > centroids; 00758 std::vector<Eigen::Vector4f,Eigen::aligned_allocator< Eigen::Vector4f > > centroidsInput; 00759 std::vector<Eigen::Matrix4f,Eigen::aligned_allocator< Eigen::Matrix4f > > icp_transformations; 00760 //std::vector < Eigen::Vector4f > centroids; 00761 //std::vector < Eigen::Vector4f > centroidsInput; 00762 //std::vector < Eigen::Matrix4f > icp_transformations; 00763 std::vector<int> roll_rotation_angles; 00764 std::vector<int> model_indices_short; //points to the vfh_ids in models 00765 00766 //std::cout << "Number of total models:" << nModels << " size of index_scores:" << index_scores.size() << std::endl; 00767 counter = 0; 00768 00769 { 00770 pcl::ScopeTime t ("-------- fitness score, ICP and so on..."); 00771 00772 //process nModels, computing roll orientation and ICP as needed 00773 for (size_t i = 0; i < (size_t)nModels; ++i) 00774 { 00775 //model_indices[index_scores.at (i).first] points to models_, first gives vfh_id 00776 //we want model_indices_short to do the same 00777 std::string vfh_id = models_.at (model_indices[index_scores.at (i).first]).first; 00778 00779 std::cout << "vfh_id:" << vfh_id << " " << index_scores.at (i).first << " " 00780 << model_indices[index_scores.at (i).first] << " " << i << std::endl; 00781 00782 model_indices_short.push_back (model_indices[index_scores.at (i).first]); 00783 00784 pcl::PointCloud < pcl::VFHSignature308 > vfh_orientation_signature; 00785 00786 //get VFH Roll orientation 00787 if (use_cluster_centroids_) 00788 { 00789 //get the roll orientation for the VFH_id 00790 getVFHRollOrientationFromId (vfh_orientation_signature, vfh_id); 00791 00792 /*std::stringstream path_vfh_orientation; 00793 path_vfh_orientation << "/u/aaldoma/data/vfhs_roll_orientation/vfh_orientation_view_" << i << ".pcd"; 00794 std::cout << path_vfh_orientation.str() << std::endl; 00795 pcl::io::savePCDFileBinary (path_vfh_orientation.str(), vfh_orientation_signature);*/ 00796 00797 } 00798 else 00799 { 00800 //get the roll orientation for the view associated with vfh_id 00801 getVFHRollOrientationFromIdThroughView (vfh_orientation_signature, vfh_id); 00802 } 00803 00804 //Minimize square errors between histograms (vfh_orientation_signature and vfh_orientation_signatureInput) 00805 //vfh_orientation_signatureInput does not change 00806 double error = -1.0; 00807 double error_flipped = -1.0; 00808 int angle; 00809 00810 //pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_o_signatureInput_ptr; 00811 //vfh_o_signatureInput_ptr = orientation_histogram_rolls_input[roll_input_indices[index_scores.at (i).first]]; //access the correct roll histogram 00812 //std::cout << "INDEX TO ROLL HISTOGRAM:" << roll_input_indices[index_scores.at (i).first] << std::endl; 00813 //angle = computeAngleRollOrientation (vfh_orientation_signature, vfh_o_signatureInput, nr_bins, &error); 00814 00816 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_xyz (new pcl::PointCloud<pcl::PointNormal> ()); 00817 getPointCloudFromId (*cloud_xyz, vfh_id); 00818 00819 if (cloud_xyz->points.size () == 0) 00820 break; 00821 00822 pcl::PointCloud<pcl::VFHSignature308>::Ptr 00823 vfh_o_signature_trash ( 00824 new pcl::PointCloud<pcl::VFHSignature308> ()); 00825 00826 std::vector<float> centroid_vfh_db (3, 0); 00827 getVFHCentroidFromVFHid (centroid_vfh_db, vfh_id); //centroids of the clusters in the database 00828 00829 Eigen::Vector3f ci3f (centroid_vfh_db[0], centroid_vfh_db[1], centroid_vfh_db[2]); 00830 cv::Mat frequency_domain_view; 00831 computeVFHRollOrientation (cloud_xyz, vfh_o_signature_trash, ci3f, frequency_domain_view); 00832 00833 /*std::stringstream path_vfh_orientation; 00834 path_vfh_orientation << "/u/aaldoma/data/vfhs_roll_orientation/vfh_orientation_view_" << i << ".pcd"; 00835 std::cout << path_vfh_orientation.str() << std::endl; 00836 pcl::io::savePCDFileBinary (path_vfh_orientation.str(), *vfh_o_signature_trash);*/ 00837 00838 /*std::stringstream path_vfh_orientation; 00839 path_vfh_orientation << "/u/aaldoma/data/vfhs_roll_orientation/vfh_orientation_frequency_domain:" << vfh_id << ".pcd"; 00840 //std::cout << path_vfh_orientation.str() << std::endl; 00841 pcl::io::savePCDFileBinary (path_vfh_orientation.str(), *vfh_o_signature_trash);*/ 00842 00843 //TODO: dirty stuff 00844 pcl::PointCloud < pcl::PointNormal > cloud_xyz_1; 00845 getPointCloudFromId (cloud_xyz_1, vfh_id); 00846 00847 std::cout << "Points in pointcloud:" << cloud_xyz_1.size () << std::endl; 00848 00849 std::vector<float> centroid_vfh_db_1 (3, 0); 00850 getVFHCentroidFromVFHid (centroid_vfh_db_1, vfh_id); //centroids of the clusters in the database 00851 Eigen::Vector4f 00852 centroidClusterInput ( 00853 centroids_dominant_orientations[roll_input_indices[index_scores.at (i).first]][0], 00854 centroids_dominant_orientations[roll_input_indices[index_scores.at (i).first]][1], 00855 centroids_dominant_orientations[roll_input_indices[index_scores.at (i).first]][2], 00856 0); 00857 00858 Eigen::Vector4f centroid_view (centroid_vfh_db_1[0], centroid_vfh_db_1[1], centroid_vfh_db_1[2], 0); 00859 00860 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_o_signatureInput_ptr; 00861 vfh_o_signatureInput_ptr = orientation_histogram_rolls_input[roll_input_indices[index_scores.at (i).first]]; //access the correct roll histogram 00862 angle 00863 = computeAngleRollOrientationFrequency ( 00864 frequency_domain_hists_input[roll_input_indices[index_scores.at ( 00865 i).first]], 00866 frequency_domain_view, nr_bins, centroid_view, 00867 centroidClusterInput, cloud_xyz_1, *cloud_normals, i, 00868 *vfh_o_signature_trash, *vfh_o_signatureInput_ptr); 00869 00870 roll_rotation_angles.push_back (angle); 00871 roll_histogram_errors.push_back (error); 00872 roll_histogram_errors_flipped.push_back (error_flipped); 00873 00874 if (use_cluster_centroids_) 00875 { 00876 getVFHCentroidFromVFHid (centroid_vfh_db, vfh_id); //centroids of the clusters in the database 00877 Eigen::Vector4f 00878 centroidClusterInput ( 00879 centroids_dominant_orientations[roll_input_indices[index_scores.at (i).first]][0], 00880 centroids_dominant_orientations[roll_input_indices[index_scores.at (i).first]][1], 00881 centroids_dominant_orientations[roll_input_indices[index_scores.at (i).first]][2], 00882 0); 00883 00884 centroidsInput.push_back (centroidClusterInput); 00885 } 00886 else 00887 { 00888 getViewCentroidFromVFHid (centroid_vfh_db, vfh_id); //centroids of the view... 00889 centroidsInput.push_back (centroidInput); 00890 } 00891 00892 Eigen::Vector4f centroid_vfh (centroid_vfh_db[0], centroid_vfh_db[1], centroid_vfh_db[2], 0); 00893 centroids.push_back (centroid_vfh); //get centroid from the VFH (cluster being used) or the view in the database... 00894 00895 if (use_fitness_score || perform_icp_) 00896 { 00897 pcl::PointCloud < pcl::PointNormal > cloud_xyz; 00898 getPointCloudFromId (cloud_xyz, vfh_id); 00899 00900 if (cloud_xyz.points.size () == 0) 00901 break; 00902 00903 pcl::PointCloud<pcl::PointNormal>::Ptr gridTransformed (new pcl::PointCloud<pcl::PointNormal> ()); 00904 00905 Eigen::Affine3f final_trans; 00906 computeRollTransform (centroidsInput[counter], centroids[counter], roll_rotation_angles.at (counter), 00907 final_trans); 00908 00909 //pcl::transformPointCloudWithNormals (cloud_xyz, *gridTransformed, transform); 00910 pcl::transformPointCloudWithNormals (cloud_xyz, *gridTransformed, final_trans); 00911 00912 //translate result point cloud so centroids match... 00913 Eigen::Vector3f centr (centroids[counter][0], centroids[counter][1], centroids[counter][2]); 00914 centr = final_trans * centr; 00915 Eigen::Vector4f diff = Eigen::Vector4f::Zero (); 00916 diff[0] = -centroidsInput[counter][0] + centr[0]; 00917 diff[1] = -centroidsInput[counter][1] + centr[1]; 00918 diff[2] = -centroidsInput[counter][2] + centr[2]; 00919 00920 cloud_xyz = *gridTransformed; 00921 00922 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_xyz_demean (new pcl::PointCloud<pcl::PointNormal> ()); 00923 pcl::demeanPointCloud (cloud_xyz, diff, *cloud_xyz_demean); 00924 00925 //Compute fitness score, we want the transformation from model to input 00926 if (perform_icp_) 00927 { 00928 00929 std::stringstream path_vfh_orientation; 00930 path_vfh_orientation << "/home/aitor/cloud_xyz_demean.pcd"; 00931 pcl::io::savePCDFileASCII (path_vfh_orientation.str(), *cloud_xyz_demean); 00932 00933 std::stringstream path_2; 00934 path_2 << "/home/aitor/cloud_normals.pcd"; 00935 pcl::io::savePCDFileASCII (path_2.str(), *cloud_normals); 00936 00937 std::cout << "Computing ICP" << std::endl; 00938 pcl::IterativeClosestPoint < pcl::PointNormal, pcl::PointNormal > reg; 00939 reg.setInputCloud (cloud_xyz_demean); //model aligned after VFH 00940 reg.setInputTarget (cloud_normals); //cluster in the camera coordinate system 00941 00942 //Perform ICP and save the final transformation, transformation will be appended later 00943 //after sorting... 00944 reg.setMaximumIterations (icp_iterations_); 00945 reg.setMaxCorrespondenceDistance (0.02); 00946 pcl::PointCloud<pcl::PointNormal>::Ptr output_ (new pcl::PointCloud<pcl::PointNormal> ()); 00947 reg.align (*output_); 00948 00949 Eigen::Matrix4f icp_trans = reg.getFinalTransformation (); 00950 icp_transformations.push_back (icp_trans); 00951 00952 if (use_fitness_score) 00953 { 00954 pcl::SegmentDifferences < pcl::PointNormal > seg; 00955 typedef pcl::KdTree<pcl::PointNormal>::Ptr KdTreePtr; 00956 KdTreePtr normals_tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointNormal> > (true); 00957 seg.setDistanceThreshold (0.005 * 0.005); //1cm 00958 seg.setSearchMethod (normals_tree); 00959 seg.setInputCloud (cloud_normals); 00960 //seg.setTargetCloud(cloud_xyz_demean); 00961 seg.setTargetCloud (output_); 00962 00963 pcl::PointCloud < pcl::PointNormal > difference; 00964 seg.segment (difference); 00965 //fscore = 1.0 / (cloud_normals->points.size() - difference.points.size()); //number of inliers 00966 std::cout << "difference size:" << difference.points.size () << " " << cloud_normals->points.size () 00967 << std::endl; 00968 fscore = difference.points.size (); 00969 } 00970 else 00971 { 00972 fscore = index_scores.at (i).second; 00973 } 00974 } 00975 else 00976 { 00977 pcl::SegmentDifferences < pcl::PointNormal > seg; 00978 typedef pcl::KdTree<pcl::PointNormal>::Ptr KdTreePtr; 00979 KdTreePtr normals_tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointNormal> > (true); 00980 seg.setDistanceThreshold (0.01 * 0.01); //1cm 00981 seg.setSearchMethod (normals_tree); 00982 seg.setInputCloud (cloud_normals); 00983 seg.setTargetCloud (cloud_xyz_demean); 00984 00985 pcl::PointCloud < pcl::PointNormal > difference; 00986 seg.segment (difference); 00987 00988 fscore = difference.points.size (); 00989 } 00990 } 00991 else 00992 { 00993 std::cout << "NOT USING FITNESS SCORE OR ICP" << std::endl; 00994 fscore = index_scores.at (i).second; 00995 } 00996 00997 std::cout << "fscore:" << fscore << std::endl; 00998 index_score is; 00999 is.first = counter; 01000 is.second = fscore; 01001 index_scores_short.push_back (is); 01002 counter++; 01003 } 01004 } //end of time scope, final step... 01005 01006 std::sort (index_scores_short.begin (), index_scores_short.end (), ICPredicate); 01007 01008 size_t result_size = (std::min) ((size_t) (nModels), index_scores_short.size ()); 01009 //otherwise its already sorted 01010 poses.resize (result_size); 01011 model_ids.resize (result_size); 01012 vfh_ids.resize (result_size); 01013 confidences.resize (result_size); 01014 roll_rotation_angles_.resize (result_size); 01015 roll_histogram_errors_.resize (result_size); 01016 roll_histogram_errors_flipped_.resize (result_size); 01017 01018 centroid_inputs_.resize (result_size); 01019 centroid_results_.resize (result_size); 01020 01021 if (perform_icp_) 01022 icp_transformations_.resize (result_size); 01023 01024 { 01025 pcl::ScopeTime t ("-------- computes poses, final step"); 01026 //Populate output structures 01027 for (size_t i = 0; i < result_size; ++i) 01028 { 01029 std::string vfh_id = models_.at (model_indices_short[index_scores_short.at (i).first]).first; 01030 geometry_msgs::Pose p; 01031 getPoseFromId (vfh_id, p); 01032 Eigen::Quaternion<double> pq = Eigen::Quaternion<double> (p.orientation.w, p.orientation.x, p.orientation.y, 01033 p.orientation.z); 01034 01035 //transform quaternion to matrix... 01036 Eigen::Matrix3d poseToRot = pq.toRotationMatrix (); 01037 Eigen::Matrix4f homMatrix = Eigen::Matrix4f (); 01038 homMatrix.setIdentity (4, 4); 01039 homMatrix.block (0, 0, 3, 3) = poseToRot.cast<float> (); 01040 01041 //roll 01042 Eigen::Affine3f rollToRot; 01043 computeRollTransform (centroidsInput[index_scores_short.at (i).first], 01044 centroids[index_scores_short.at (i).first], 01045 roll_rotation_angles.at (index_scores_short.at (i).first), rollToRot); 01046 Eigen::Matrix4f rollHomMatrix = Eigen::Matrix4f (); 01047 rollHomMatrix.setIdentity (4, 4); 01048 rollHomMatrix = rollToRot.matrix (); 01049 //std::cout << rollHomMatrix << std::endl; 01050 //rollHomMatrix.block (0, 0, 4, 3) = rollToRot.matrix(); 01051 01052 //translation matrix (1) - translates the mesh to the view 01053 Eigen::Matrix4f translation1; 01054 translation1.setIdentity (4, 4); 01055 translation1 (0, 3) = p.position.x; 01056 translation1 (1, 3) = p.position.y; 01057 translation1 (2, 3) = p.position.z; 01058 01059 Eigen::Vector4f cInput = centroidsInput[index_scores_short.at (i).first]; 01060 01061 //translation matrix (2) - center the view and the input 01062 Eigen::Vector4f centroidView = centroids[index_scores_short.at (i).first]; //contains the centroid of the rotated point cloud 01063 Eigen::Matrix4f translation2; 01064 translation2.setIdentity (4, 4); 01065 01066 Eigen::Vector3f centr (centroidView[0], centroidView[1], centroidView[2]); 01067 centr = rollToRot * centr; 01068 01069 translation2 (0, 3) = -centr[0] + cInput[0]; 01070 translation2 (1, 3) = -centr[1] + cInput[1]; 01071 translation2 (2, 3) = -centr[2] + cInput[2]; 01072 01073 //std::cout << "CentroidView:" << centroidView << std::endl; 01074 //std::cout << "CentroidInput:" << cInput << std::endl; 01075 01076 Eigen::Matrix4f resultHom = Eigen::Matrix4f (); 01077 Eigen::Matrix4f resultHom_1 = Eigen::Matrix4f (); 01078 resultHom_1.setIdentity (4, 4); 01079 01080 if (perform_icp_) 01081 //if (perform_icp_ && (i < ICP_SIZE)) 01082 { 01083 //append transformation 01084 //Eigen::Matrix4f icp_trans = icp_transformations.at (i); 01085 Eigen::Matrix4f icp_trans = icp_transformations.at (index_scores_short.at (i).first); 01086 //RESULT = TRANSLATION2 * (ROLL * (TRANSLATION1 * POSE_MATRIX)) * [p] 01087 resultHom = icp_trans * translation2 * (rollHomMatrix * translation1 * homMatrix); //result 01088 } 01089 else 01090 { 01091 //RESULT = TRANSLATION2 * (ROLL * (TRANSLATION1 * POSE_MATRIX)) * [p] 01092 resultHom = translation2 * (rollHomMatrix * translation1 * homMatrix); //result 01093 //resultHom = translation2 * (translation1 * homMatrix); //result 01094 } 01095 01096 //transform resultHom to pose 01097 p.position.x = resultHom (0, 3); 01098 p.position.y = resultHom (1, 3); 01099 p.position.z = resultHom (2, 3); 01100 01101 Eigen::Matrix3f rotFinal = resultHom.block (0, 0, 3, 3); 01102 Eigen::Quaternion<float> final = Eigen::Quaternion<float> (rotFinal); 01103 p.orientation.x = final.x (); 01104 p.orientation.y = final.y (); 01105 p.orientation.z = final.z (); 01106 p.orientation.w = final.w (); 01107 01108 poses[i] = p; 01109 model_ids[i] = getModelId (vfh_id); 01110 vfh_ids[i] = vfh_id; 01111 confidences[i] = index_scores_short.at (i).second; 01112 roll_rotation_angles_[i] = roll_rotation_angles.at (index_scores_short.at (i).first); 01113 roll_histogram_errors_[i] = roll_histogram_errors.at (index_scores_short.at (i).first); 01114 roll_histogram_errors_flipped_[i] = roll_histogram_errors_flipped.at (index_scores_short.at (i).first); 01115 01116 centroid_inputs_[i] = cInput; 01117 centroid_results_[i] = centroidView; 01118 01119 if (perform_icp_) 01120 icp_transformations_[i] = icp_transformations.at (index_scores_short.at (i).first); 01121 } 01122 } 01123 01124 return true; 01125 01126 } 01127 01128 template class VFHRecognizer<flann::ChiSquareDistance> ; 01129 template class VFHRecognizer<flann::L2> ; 01130 template class VFHRecognizer<flann::HistIntersectionDistance> ; 01131 template class VFHRecognizer<flann::HistIntersectionUnionDistance> ; 01132 }