首先PCL定義了搜索的基類pcl::search::Search<PointInT>ide
template<typename PointT>
class Search
其子類包括:KD樹,八叉樹,FLANN快速搜索,暴力搜索(brute force),有序點雲搜索。ui
The pcl_search library provides methods for searching for nearest neighbors using different data structures, including:雲計算
|
search類都定義了兩種最多見的近鄰搜索模式:k近鄰搜索,球狀固定距離半徑近鄰搜索。spa
virtual int nearestKSearch (const PointT &point, int k, std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const = 0; virtual int radiusSearch (const PointT& point, double radius, std::vector<int>& k_indices, std::vector<float>& k_sqr_distances, unsigned int max_nn = 0) const = 0;
還有一種比較有用的方式是:圓柱固定距離半徑搜索,即在XOY平面的投影距離,目前沒有看到PCL中的專門的實現方式,能夠經過一種折中的方法解決octree。rest
還有就是經過累積地圖實現的投影到XOY平面內的簡單搜索。code
Weinmann, M., et al. (2015). "Semantic point cloud interpretation based on optimal neighborhoods, relevant features and efficient classifiers." ISPRS Journal of Photogrammetry and Remote Sensing 105: 286-304.
orm
在feature模塊中大量使用了近鄰搜索的東西。近鄰搜索是不少點雲計算的基礎功能。blog
以下調用了點雲KD樹近鄰搜索實現了8個基於特徵值的點雲特徵計算:索引
1 QString filePly = dlg.txtPath->text(); 2 std::wstring pszRoomFile1 = filePly.toStdWString(); 3 char buffer[256]; 4 size_t ret = wcstombs(buffer, pszRoomFile1.c_str(), sizeof(buffer)); 5 const char * pszShapeFile = buffer; 6 char * file_name = (char*)pszShapeFile; 7 pcl::PointCloud<pcl::PointXYZ>::Ptr input_(new pcl::PointCloud<pcl::PointXYZ>); 8 /*------------讀取PLY文件-------------*/ 9 if (pcl::io::loadPLYFile<pcl::PointXYZ>(file_name, *input_) == -1) //* load the file 10 { 11 PCL_ERROR("Couldn't read file test_pcd.pcd \n"); 12 QMessageBox::information(NULL, "Title", "Content", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); 13 } 14 double search_radius_ = dlg.sb_scale2->value(); 15 int k_=10; 16 double search_parameter_ = 0.0; 17 /*------------構造索引-------------*/ 18 boost::shared_ptr <std::vector<int> > indices_; 19 if (!indices_) 20 { 21 indices_.reset(new std::vector<int>); 22 try 23 { 24 indices_->resize(input_->points.size()); 25 } 26 catch (const std::bad_alloc&) 27 { 28 PCL_ERROR("[initCompute] Failed to allocate %lu indices.\n", input_->points.size()); 29 } 30 for (size_t i = 0; i < indices_->size(); ++i) { (*indices_)[i] = static_cast<int>(i); } 31 } 32 std::vector<int> nn_indices(k_); 33 std::vector<float> nn_dists(k_); 34 /*---------------構造KD樹-------------*/ 35 //pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ> >(new pcl::search::KdTree<pcl::PointXYZ>); 36 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>); 37 tree->setInputCloud(input_); 38 SearchMethodSurface search_method_surface_; 39 if (search_radius_ != 0.0) 40 { 41 search_parameter_ = search_radius_; 42 int (pcl::search::Search<pcl::PointXYZ>::*radiusSearchSurface)(const PointCloudIn &cloud, int index, double radius, 43 std::vector<int> &k_indices, std::vector<float> &k_distances, 44 unsigned int max_nn) const = &pcl::search::Search<pcl::PointXYZ>::radiusSearch; 45 search_method_surface_ = boost::bind(radiusSearchSurface, boost::ref(tree), _1, _2, _3, _4, _5, 0); 46 } 47 else 48 { 49 search_parameter_ = k_; 50 int (pcl::search::Search<pcl::PointXYZ>::*nearestKSearchSurface)(const PointCloudIn &cloud, int index, int k, std::vector<int> &k_indices, 51 std::vector<float> &k_distances) const = &pcl::search::Search<pcl::PointXYZ>::nearestKSearch; 52 search_method_surface_ = boost::bind(nearestKSearchSurface, boost::ref(tree), _1, _2, _3, _4, _5); 53 } 54 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>); 55 PointCloudOut& output = *cloud_normals; 56 AxPointCloudOut output_pts; 57 if (input_->size() < 3) 58 { 59 return; 60 } 61 else/*--------------計算特徵值和特徵向量-------------*/ 62 { 63 output_pts.resize(input_->size()); 64 //output_pts.reserve(input_->size(), (new AxPoint())); 65 #ifdef _OPENMP 66 #pragma omp parallel for shared (output_pts) private (nn_indices, nn_dists) num_threads(threads_) 67 #endif 68 // Iterating over the entire index vector 69 for (int idx = 0; idx < static_cast<int> (indices_->size()); ++idx) 70 { 71 if (search_method_surface_(*input_, (*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 72 { 73 output.points[idx].normal[0] = output.points[idx].normal[1] = output.points[idx].normal[2] = output.points[idx].curvature = std::numeric_limits<float>::quiet_NaN(); 74 75 output.is_dense = false; 76 continue; 77 } 78 79 EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; 80 // 16-bytes aligned placeholder for the XYZ centroid of a surface patch 81 Eigen::Vector4f xyz_centroid; 82 83 if (pcl::computeMeanAndCovarianceMatrix(*input_, nn_indices, covariance_matrix, xyz_centroid) == 0) 84 { 85 continue; 86 } 87 88 EIGEN_ALIGN16 Eigen::Matrix3f eigen_vector3; 89 EIGEN_ALIGN16 Eigen::Vector3f eigen_values; 90 //計算特徵值和特徵向量 91 pcl::eigen33(covariance_matrix, eigen_vector3, eigen_values); 92 double eig_val1 = eigen_values[0]; 93 double eig_val2 = eigen_values[1]; 94 double eig_val3 = eigen_values[2]; 95 96 output_pts[idx].x = input_->at((*indices_)[idx]).x; 97 output_pts[idx].y = input_->at((*indices_)[idx]).y; 98 output_pts[idx].z = input_->at((*indices_)[idx]).z; 99 output_pts[idx].eig_val1 = eig_val1; 100 output_pts[idx].eig_val2 = eig_val2; 101 output_pts[idx].eig_val3 = eig_val3; 102 } 103 QString savefilePly = filePly.replace(".ply",".txt"); 104 std::wstring psaveFile1 = savefilePly.toStdWString(); 105 char buffer[256]; 106 size_t ret = wcstombs(buffer, psaveFile1.c_str(), sizeof(buffer)); 107 const char * psavetxtFile = buffer; 108 char * file_name_2 = (char*)psavetxtFile; 109 FILE* saveFeaturePointCloud = fopen(file_name_2, "w"); 110 for (int i = 0; i < output_pts.size(); i++) 111 { 112 float x = output_pts[i].x; 113 float y = output_pts[i].y; 114 float z = output_pts[i].z; 115 116 //注意:eig_val1最小 117 float eig_val1 = output_pts[i].eig_val1; 118 float eig_val2 = output_pts[i].eig_val2; 119 float eig_val3 = output_pts[i].eig_val3; 120 float eig_sum = eig_val1 + eig_val2 + eig_val3; 121 122 float e1 = 0, e2 = 0, e3 = 0; 123 float Linearity = 0; 124 float Planarity = 0; 125 float Scattering = 0; 126 float Omnivariance = 0; 127 float Anisotropy = 0; 128 float EigenEntropy = 0; 129 float changeOfcurvature = 0; 130 if (eig_sum != 0) 131 { 132 e1 = eig_val3 / eig_sum; 133 e2 = eig_val2 / eig_sum; 134 e3 = eig_val1 / eig_sum; 135 Linearity = (e1 - e2) / e1; 136 Planarity = (e2 - e3) / e1; 137 Scattering = e3 / e1; 138 Omnivariance = pow(e1*e2*e3, 1 / 3); 139 Anisotropy = (e1 - e3) / e1; 140 EigenEntropy = -(e1*log(e1) + e2*log(e2) + e3*log(e3)); 141 //計算曲率變化 142 changeOfcurvature = fabsf(e1 / (e1 + e2 + e3)); 143 } 144 else 145 changeOfcurvature = 0; 146 //x,y,z,e1,e2,e3, 147 //Linearity,Planarity,Scattering,Omnivariance,Anisotropy, 148 //Eigenentropy,Sum of eigenvalues,Change of curvature 149 fprintf(saveFeaturePointCloud, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", x, y, z, eig_val1, eig_val2, eig_val3, 150 Linearity, Planarity, Scattering, Omnivariance, Anisotropy, EigenEntropy, eig_sum, changeOfcurvature); 151 } 152 fclose(saveFeaturePointCloud); 153 }