#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;
}

这段代码的注释已经是中文的了,不需要再翻译

#include iostream#include vector#include string#include pclioply_ioh#include pclpoint_typesh#include pclvisualizationpcl_visualizerh#include opencv2opencvhpp#include pclpoint_cloudh#include pclpoint_t

原文地址: https://www.cveoy.top/t/topic/iytg 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录