#include iostream#include vector#include string#include pclioply_ioh#include pclpoint_typesh#include pclvisualizationpcl_visualizerh#include opencv2opencvhpp#include pclpoint_cloudh#include pclpoint_t
#include <iostream>
#include <vector>
#include <string>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <opencv2/opencv.hpp>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
void stemDiameter(std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& inputPointClouds) {
// 导入点云文件
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::io::loadPLYFile<pcl::PointXYZRGB>("D:\\DIANYUNWENJIANJIA\\test_ply.ply", *cloud);
// 提取索引号为43的点的y值
float y = cloud->points[4].y;
// 将筛选后的切片点云存储在vector中
std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> slicedPointClouds;
std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> projectedPointClouds;
// 切片的厚度范围
float minThickness = 0.02;
float maxThickness = 0.1;
int numSlices = 8;
float thicknessStep = (maxThickness - minThickness) / numSlices;
// 创建每个切片的点云
for (int i = 0; i < numSlices; ++i) {
float sliceMin = y + (i * thicknessStep);
float sliceMax = y + ((i + 1) * thicknessStep);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr filteredCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
for (size_t j = 0; j < cloud->points.size(); ++j) {
if (cloud->points[j].y > sliceMin && cloud->points[j].y < sliceMax) {
filteredCloud->points.push_back(cloud->points[j]);
}
}
filteredCloud->width = filteredCloud->points.size();
filteredCloud->height = 1;
// 将切片点云投影到 XZ 平面
pcl::PointCloud<pcl::PointXYZRGB>::Ptr projectedCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
for (size_t j = 0; j < filteredCloud->points.size(); ++j) {
pcl::PointXYZRGB point;
point.x = filteredCloud->points[j].x;
point.y = 0; // 投影到 XZ 平面,y值设为0
point.z = filteredCloud->points[j].z;
point.r = 0;
point.g = 255;
point.b = 0; // 投影颜色为绿色
projectedCloud->points.push_back(point);
}
projectedCloud->width = projectedCloud->points.size();
projectedCloud->height = 1;
slicedPointClouds.push_back(filteredCloud);
projectedPointClouds.push_back(projectedCloud); // 注意修改此处
inputPointClouds.push_back(projectedPointClouds[i]); // 注意修改此处
}
// 创建PCL可视化对象
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("PointCloud Viewer"));
// 将原始点云显示为白色
pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> white_color(cloud);
viewer->addPointCloud<pcl::PointXYZRGB>(cloud, white_color, "original_cloud");
// 将每个切片的点云显示为不同颜色
std::vector<pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB>> colorHandlers;
for (int i = 0; i < numSlices; ++i) {
int red = 255 * (i + 1) / numSlices;
int green = 255 - (255 * (i + 1) / numSlices);
int blue = 0;
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> colorHandler(slicedPointClouds[i], red, green, blue);
colorHandlers.push_back(colorHandler);
viewer->addPointCloud<pcl::PointXYZRGB>(slicedPointClouds[i], colorHandler, "filtered_cloud_" + std::to_string(i));
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> projectedColorHandler(projectedPointClouds[i], 0, 255, 0);
viewer->addPointCloud<pcl::PointXYZRGB>(projectedPointClouds[i], projectedColorHandler, "projected_cloud_" + std::to_string(i));
}
// 设置点云可视化参数
viewer->setBackgroundColor(0, 0, 0);
viewer->initCameraParameters();
// 开始可视化循环
while (!viewer->wasStopped()) {
viewer->spinOnce();
}
// 保存每个切片的点云为PLY文件
for (int i = 0; i < numSlices; ++i) {
pcl::io::savePLYFileBinary("D:\\DIANYUNWENJIANJIA\\茎直径切片_" + std::to_string(i) + "_ply.ply", *slicedPointClouds[i]);
pcl::io::savePLYFileBinary("D:\\DIANYUNWENJIANJIA\\茎直径切片_" + std::to_string(i) + "_投影_ply.ply", *projectedPointClouds[i]);
}
}
void fitEllipses(const std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>& projectedPointClouds)
{
std::cout << "椭圆拟合结果:" << std::endl;
for (size_t i = 0; i < projectedPointClouds.size(); ++i) {
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = projectedPointClouds[i];
size_t numPoints = cloud->points.size();
// 检查点的数量是否满足椭圆拟合的最小要求
if (numPoints < 6)
{
std::cout << "切片 " << i << "不满足椭圆拟合要求。" << std::endl;
continue;
}
// 将pcl::PointCloud转换为cv::Mat
cv::Mat image(numPoints, 2, CV_32FC1);
for (size_t j = 0; j < numPoints; ++j) {
image.at<float>(j, 0) = cloud->points[j].x;
image.at<float>(j, 1) = cloud->points[j].z;
}
// 使用OpenCV进行椭圆拟合
cv::RotatedRect ellipse = cv::fitEllipse(image);
// 输出拟合椭圆的长轴长度
std::cout << "切片 " << i << ":长轴长度 = " << std::max(ellipse.size.width, ellipse.size.height) << std::endl;
// 可视化拟合的椭圆
cv::Mat imageVis;
cv::cvtColor(image, imageVis, cv::COLOR_BGR2RGB);
cv::ellipse(imageVis, ellipse, cv::Scalar(0, 255, 0), 2);
cv::imshow("拟合椭圆 (切片 " + std::to_string(i) + ")", imageVis);
cv::waitKey(0);
}
}
int main() {
std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> inputPointClouds;
stemDiameter(inputPointClouds);
fitEllipses(inputPointClouds);
return 0;
}
这段代码的注释已经是中文的了,不需要再翻译
原文地址: https://www.cveoy.top/t/topic/iytg 著作权归作者所有。请勿转载和采集!