如何求取叶片点云前后缘与叶盆叶背的分界点(c++)
时间: 2024-01-27 20:04:51 浏览: 67
求取叶片点云前后缘与叶盆叶背的分界点需要进行以下步骤:
1. 对点云进行预处理,包括去除离群点、降采样等操作。
2. 确定叶片的主轴方向,可以采用PCA等方法求解。
3. 将点云沿主轴方向进行投影,得到一维的点云分布。
4. 对点云分布进行平滑滤波,得到分布的拐点。
5. 将点云沿法向方向进行投影,得到叶片截面的点云。
6. 对叶片截面的点云进行聚类,得到叶片前后两侧点云。
7. 对前后两侧点云进行分别拟合,得到拟合曲线。
8. 拟合曲线的交点即为前后缘的分界点,拟合曲线与点云的交点即为叶盆叶背的分界点。
以下是C++代码的示例:
```c++
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/visualization/cloud_viewer.h>
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
int main(int argc, char** argv)
{
// Load point cloud
PointCloudT::Ptr cloud(new PointCloudT);
pcl::io::loadPCDFile<PointT>("leaf.pcd", *cloud);
// Voxel grid filtering
pcl::VoxelGrid<PointT> vg;
vg.setInputCloud(cloud);
vg.setLeafSize(0.01f, 0.01f, 0.01f);
PointCloudT::Ptr cloud_filtered(new PointCloudT);
vg.filter(*cloud_filtered);
// Statistical outlier removal
pcl::StatisticalOutlierRemoval<PointT> sor;
sor.setInputCloud(cloud_filtered);
sor.setMeanK(50);
sor.setStddevMulThresh(1.0);
PointCloudT::Ptr cloud_sor(new PointCloudT);
sor.filter(*cloud_sor);
// Estimate normals
pcl::NormalEstimation<PointT, pcl::Normal> ne;
ne.setInputCloud(cloud_sor);
pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>());
ne.setSearchMethod(tree);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
ne.setRadiusSearch(0.03);
ne.compute(*normals);
// Segment plane
pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_NORMAL_PLANE);
seg.setNormalDistanceWeight(0.1);
seg.setMethodType(pcl::SAC_RANSAC);
seg.setMaxIterations(100);
seg.setDistanceThreshold(0.02);
seg.setInputCloud(cloud_sor);
seg.setInputNormals(normals);
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
seg.segment(*inliers, *coefficients);
// Extract inliers
pcl::ExtractIndices<PointT> extract;
extract.setInputCloud(cloud_sor);
extract.setIndices(inliers);
extract.setNegative(false);
PointCloudT::Ptr cloud_plane(new PointCloudT);
extract.filter(*cloud_plane);
// Project to axis
Eigen::Vector4f centroid;
pcl::compute3DCentroid(*cloud_plane, centroid);
Eigen::Matrix3f covariance_matrix;
pcl::computeCovarianceMatrixNormalized(*cloud_plane, centroid, covariance_matrix);
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance_matrix, Eigen::ComputeEigenvectors);
Eigen::Matrix3f eigD = eigen_solver.eigenvalues().asDiagonal();
Eigen::Matrix3f eigV = eigen_solver.eigenvectors();
int idx = 0;
if (eigD(1, 1) > eigD(0, 0))
idx = 1;
if (eigD(2, 2) > eigD(idx, idx))
idx = 2;
Eigen::Vector3f axis = eigV.col(idx);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ProjectInliers<PointT> proj;
proj.setModelType(pcl::SACMODEL_PLANE);
proj.setInputCloud(cloud_plane);
proj.setModelCoefficients(coefficients);
proj.setInputCloud(cloud_plane);
proj.filter(*cloud_projected);
// Smooth filtering
std::vector<float> data(cloud_projected->points.size());
for (int i = 0; i < cloud_projected->points.size(); i++)
data[i] = cloud_projected->points[i].x;
std::vector<float> kernel = { 1, 5, 8, 5, 1 };
std::vector<float> data_smooth(cloud_projected->points.size());
for (int i = 2; i < cloud_projected->points.size() - 2; i++)
{
for (int j = -2; j <= 2; j++)
data_smooth[i] += data[i + j] * kernel[j + 2];
data_smooth[i] /= 20;
}
// Find inflection points
std::vector<int> inflections;
for (int i = 2; i < cloud_projected->points.size() - 2; i++)
{
if (data_smooth[i] > data_smooth[i - 1] && data_smooth[i] > data_smooth[i + 1])
inflections.push_back(i);
if (data_smooth[i] < data_smooth[i - 1] && data_smooth[i] < data_smooth[i + 1])
inflections.push_back(i);
}
// Extract cross section
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_section(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ExtractIndices<PointT> extract_indices;
extract_indices.setInputCloud(cloud);
pcl::PointIndices::Ptr section_indices(new pcl::PointIndices);
for (int i = 0; i < cloud_projected->points.size(); i++)
{
if (abs(cloud_projected->points[i].x - data_smooth[inflections[0]]) < 0.002)
section_indices->indices.push_back(i);
}
extract_indices.setIndices(section_indices);
extract_indices.setNegative(false);
extract_indices.filter(*cloud_section);
// Cluster front and back sides
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree_section(new pcl::search::KdTree<pcl::PointXYZ>);
tree_section->setInputCloud(cloud_section);
std::vector<pcl::PointIndices> cluster_indices;
pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
ec.setClusterTolerance(0.02);
ec.setMinClusterSize(100);
ec.setMaxClusterSize(10000);
ec.setSearchMethod(tree_section);
ec.setInputCloud(cloud_section);
ec.extract(cluster_indices);
// Fit curves
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_front(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_back(new pcl::PointCloud<pcl::PointXYZ>);
for (int i = 0; i < cluster_indices.size(); i++)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointIndices::Ptr cluster_indices_ptr(new pcl::PointIndices(cluster_indices[i]));
extract_indices.setInputCloud(cloud_section);
extract_indices.setIndices(cluster_indices_ptr);
extract_indices.setNegative(false);
extract_indices.filter(*cloud_cluster);
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
pcl::SACSegmentation<pcl::PointXYZ> seg;
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_LINE);
seg.setMethodType(pcl::SAC_RANSAC);
seg.setMaxIterations(1000);
seg.setDistanceThreshold(0.02);
seg.setInputCloud(cloud_cluster);
seg.segment(*inliers, *coefficients);
if (coefficients->values[3] > 0)
*cloud_front += *cloud_cluster;
else
*cloud_back += *cloud_cluster;
}
// Show results
pcl::visualization::PCLVisualizer viewer("Leaf");
viewer.setBackgroundColor(0.0, 0.0, 0.0);
viewer.addPointCloud(cloud, "cloud");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud");
viewer.addPointCloud(cloud_projected, "projected");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 0.0, 0.0, "projected");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "projected");
viewer.addPointCloud(cloud_section, "section");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0.0, 1.0, 0.0, "section");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "section");
viewer.addPointCloud(cloud_front, "front");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0.0, 0.0, 1.0, "front");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "front");
viewer.addPointCloud(cloud_back, "back");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1.0, 1.0, 0.0, "back");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "back");
viewer.spin();
return 0;
}
```
阅读全文