[PCL]点云渐进形态学滤波
PCL支持点云的形态学滤波,四种操作:侵蚀、膨胀、开(先侵蚀后膨胀)、闭(先膨胀后侵蚀)
关于渐进的策略,在初始cell_size_ 的基础上逐渐变大。满足如下公式:
$$window\_size =cell\_size *(2*base^{k}+1)$$
$$window\_size =cell\_size *(2*base*(k+1)+1)$$
1 // Compute the series of window sizes and height thresholds 2 std::vector<float> height_thresholds; 3 std::vector<float> window_sizes; 4 int iteration = 0; 5 float window_size = 0.0f; 6 float height_threshold = 0.0f; 7 8 while (window_size < max_window_size_) 9 { 10 // Determine the initial window size. 11 if (exponential_) 12 window_size = cell_size_ * (2.0f * std::pow (base_, iteration) + 1.0f); 13 else 14 window_size = cell_size_ * (2.0f * (iteration+1) * base_ + 1.0f); 15 16 // Calculate the height threshold to be used in the next iteration. 17 if (iteration == 0) 18 height_threshold = initial_distance_; 19 else 20 height_threshold = slope_ * (window_size - window_sizes[iteration-1]) * cell_size_ + initial_distance_; 21 22 // Enforce max distance on height threshold 23 if (height_threshold > max_distance_) 24 height_threshold = max_distance_; 25 26 window_sizes.push_back (window_size); 27 height_thresholds.push_back (height_threshold); 28 29 iteration++; 30 }
在#include <pcl/filters/morphological_filter.h>中定义了枚举类型
1 enum MorphologicalOperators 2 { 3 MORPH_OPEN, 4 MORPH_CLOSE, 5 MORPH_DILATE, 6 MORPH_ERODE 7 };
具体实现:
1 template <typename PointT> void 2 pcl::applyMorphologicalOperator (const typename pcl::PointCloud<PointT>::ConstPtr &cloud_in, 3 float resolution, const int morphological_operator, 4 pcl::PointCloud<PointT> &cloud_out) 5 { 6 if (cloud_in->empty ()) 7 return; 8 9 pcl::copyPointCloud<PointT, PointT> (*cloud_in, cloud_out); 10 11 pcl::octree::OctreePointCloudSearch<PointT> tree (resolution); 12 13 tree.setInputCloud (cloud_in); 14 tree.addPointsFromInputCloud (); 15 16 float half_res = resolution / 2.0f; 17 18 switch (morphological_operator) 19 { 20 case MORPH_DILATE: 21 case MORPH_ERODE: 22 { 23 for (size_t p_idx = 0; p_idx < cloud_in->points.size (); ++p_idx) 24 { 25 Eigen::Vector3f bbox_min, bbox_max; 26 std::vector<int> pt_indices; 27 float minx = cloud_in->points[p_idx].x - half_res; 28 float miny = cloud_in->points[p_idx].y - half_res; 29 float minz = -std::numeric_limits<float>::max (); 30 float maxx = cloud_in->points[p_idx].x + half_res; 31 float maxy = cloud_in->points[p_idx].y + half_res; 32 float maxz = std::numeric_limits<float>::max (); 33 bbox_min = Eigen::Vector3f (minx, miny, minz); 34 bbox_max = Eigen::Vector3f (maxx, maxy, maxz); 35 tree.boxSearch (bbox_min, bbox_max, pt_indices); 36 37 if (pt_indices.size () > 0) 38 { 39 Eigen::Vector4f min_pt, max_pt; 40 pcl::getMinMax3D<PointT> (*cloud_in, pt_indices, min_pt, max_pt); 41 42 switch (morphological_operator) 43 { 44 case MORPH_DILATE: 45 { 46 cloud_out.points[p_idx].z = max_pt.z (); 47 break; 48 } 49 case MORPH_ERODE: 50 { 51 cloud_out.points[p_idx].z = min_pt.z (); 52 break; 53 } 54 } 55 } 56 } 57 break; 58 } 59 case MORPH_OPEN: 60 case MORPH_CLOSE: 61 { 62 pcl::PointCloud<PointT> cloud_temp; 63 64 pcl::copyPointCloud<PointT, PointT> (*cloud_in, cloud_temp); 65 66 for (size_t p_idx = 0; p_idx < cloud_temp.points.size (); ++p_idx) 67 { 68 Eigen::Vector3f bbox_min, bbox_max; 69 std::vector<int> pt_indices; 70 float minx = cloud_temp.points[p_idx].x - half_res; 71 float miny = cloud_temp.points[p_idx].y - half_res; 72 float minz = -std::numeric_limits<float>::max (); 73 float maxx = cloud_temp.points[p_idx].x + half_res; 74 float maxy = cloud_temp.points[p_idx].y + half_res; 75 float maxz = std::numeric_limits<float>::max (); 76 bbox_min = Eigen::Vector3f (minx, miny, minz); 77 bbox_max = Eigen::Vector3f (maxx, maxy, maxz); 78 tree.boxSearch (bbox_min, bbox_max, pt_indices); 79 80 if (pt_indices.size () > 0) 81 { 82 Eigen::Vector4f min_pt, max_pt; 83 pcl::getMinMax3D<PointT> (cloud_temp, pt_indices, min_pt, max_pt); 84 85 switch (morphological_operator) 86 { 87 case MORPH_OPEN: 88 { 89 cloud_out.points[p_idx].z = min_pt.z (); 90 break; 91 } 92 case MORPH_CLOSE: 93 { 94 cloud_out.points[p_idx].z = max_pt.z (); 95 break; 96 } 97 } 98 } 99 } 100 101 cloud_temp.swap (cloud_out); 102 103 for (size_t p_idx = 0; p_idx < cloud_temp.points.size (); ++p_idx) 104 { 105 Eigen::Vector3f bbox_min, bbox_max; 106 std::vector<int> pt_indices; 107 float minx = cloud_temp.points[p_idx].x - half_res; 108 float miny = cloud_temp.points[p_idx].y - half_res; 109 float minz = -std::numeric_limits<float>::max (); 110 float maxx = cloud_temp.points[p_idx].x + half_res; 111 float maxy = cloud_temp.points[p_idx].y + half_res; 112 float maxz = std::numeric_limits<float>::max (); 113 bbox_min = Eigen::Vector3f (minx, miny, minz); 114 bbox_max = Eigen::Vector3f (maxx, maxy, maxz); 115 tree.boxSearch (bbox_min, bbox_max, pt_indices); 116 117 if (pt_indices.size () > 0) 118 { 119 Eigen::Vector4f min_pt, max_pt; 120 pcl::getMinMax3D<PointT> (cloud_temp, pt_indices, min_pt, max_pt); 121 122 switch (morphological_operator) 123 { 124 case MORPH_OPEN: 125 default: 126 { 127 cloud_out.points[p_idx].z = max_pt.z (); 128 break; 129 } 130 case MORPH_CLOSE: 131 { 132 cloud_out.points[p_idx].z = min_pt.z (); 133 break; 134 } 135 } 136 } 137 } 138 break; 139 } 140 default: 141 { 142 PCL_ERROR ("Morphological operator is not supported!\n"); 143 break; 144 } 145 } 146 147 return; 148 }
而渐进形态学滤波则是逐渐增大窗口,循环进行开操作
template <typename PointT> void pcl::ProgressiveMorphologicalFilter<PointT>::extract (std::vector<int>& ground) { bool segmentation_is_possible = initCompute (); if (!segmentation_is_possible) { deinitCompute (); return; } // Compute the series of window sizes and height thresholds std::vector<float> height_thresholds; std::vector<float> window_sizes; int iteration = 0; float window_size = 0.0f; float height_threshold = 0.0f; while (window_size < max_window_size_) { // Determine the initial window size. if (exponential_) window_size = cell_size_ * (2.0f * std::pow (base_, iteration) + 1.0f); else window_size = cell_size_ * (2.0f * (iteration+1) * base_ + 1.0f); // Calculate the height threshold to be used in the next iteration. if (iteration == 0) height_threshold = initial_distance_; else height_threshold = slope_ * (window_size - window_sizes[iteration-1]) * cell_size_ + initial_distance_; // Enforce max distance on height threshold if (height_threshold > max_distance_) height_threshold = max_distance_; window_sizes.push_back (window_size); height_thresholds.push_back (height_threshold); iteration++; } // Ground indices are initially limited to those points in the input cloud we // wish to process ground = *indices_; // Progressively filter ground returns using morphological open for (size_t i = 0; i < window_sizes.size (); ++i) { PCL_DEBUG (" Iteration %d (height threshold = %f, window size = %f)...", i, height_thresholds[i], window_sizes[i]); // Limit filtering to those points currently considered ground returns typename pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>); pcl::copyPointCloud<PointT> (*input_, ground, *cloud); // Create new cloud to hold the filtered results. Apply the morphological // opening operation at the current window size. typename pcl::PointCloud<PointT>::Ptr cloud_f (new pcl::PointCloud<PointT>); pcl::applyMorphologicalOperator<PointT> (cloud, window_sizes[i], MORPH_OPEN, *cloud_f); // Find indices of the points whose difference between the source and // filtered point clouds is less than the current height threshold. std::vector<int> pt_indices; for (size_t p_idx = 0; p_idx < ground.size (); ++p_idx) { float diff = cloud->points[p_idx].z - cloud_f->points[p_idx].z; if (diff < height_thresholds[i]) pt_indices.push_back (ground[p_idx]); } // Ground is now limited to pt_indices ground.swap (pt_indices); PCL_DEBUG ("ground now has %d points\n", ground.size ()); } deinitCompute (); }
作者:太一吾鱼水
文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。
欢迎大家留言交流,转载请注明出处。