首页 > 其他分享 >点云学习笔记19——RANSAC拟合点云轮廓的外接圆

点云学习笔记19——RANSAC拟合点云轮廓的外接圆

时间:2024-11-18 10:46:46浏览次数:3  
标签:RANSAC std pt float 外接圆 points pcl 点云 circle

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/surface/convex_hull.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <iostream>
#include <vector>
#include <cmath>

// 定义一个结构体 Circle 表示圆,包含圆心坐标 (x, y) 和半径 r
struct Circle 
{
    // 圆心 (x, y) 和半径 r
    float x, y, r;  
};

// 计算点到圆的距离
float distanceToCircle(float x, float y, Circle& circle)
{
    // 使用勾股定理计算点到圆心的距离,并减去半径,欧几里得距离公式tt
    return std::sqrt(std::pow(x - circle.x, 2) + std::pow(y - circle.y, 2)) - circle.r;
}

// 最小二乘法拟合圆
Circle fitCircle(const std::vector<pcl::PointXYZ>& points) 
{
    // 初始化用于计算的变量
    float A = 0, B = 0, C = 0, D = 0, E = 0, F = 0;

    // 构造矩阵方程 Ax + By + C = 0 和 x^2 + y^2的方程
    for (const auto& pt : points) 
    {
        float x = pt.x;
        float y = pt.y;
        A += x;
        B += y;
        C += 1;
        D += x * x;
        E += x * y;
        F += y * y;
    }

    // 计算分母,避免分母为零的情况
    float denom = points.size() * D - A * A;
    if (denom == 0)
    {
        std::cerr << "Denominator is zero; cannot fit a circle." << std::endl;
        return { 0, 0, 0 };// 返回空的圆
    }

    // 计算圆心坐标
    float cx = (B * D - A * E) / denom;
    float cy = (A * E - B * D) / denom;

    // 计算半径
    float r = 0;
    for (const auto& pt : points) 
    {
        r += std::sqrt(std::pow(pt.x - cx, 2) + std::pow(pt.y - cy, 2));
    }
    r /= points.size();// 求平均半径

    return { cx, cy, r };// 返回拟合的圆
}

int main(int argc, char** argv) 
{
    // 读取点云文件
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    std::string file_path = "F:\\convex.pcd";  // 替换为你的点云文件路径

    if (pcl::io::loadPCDFile<pcl::PointXYZ>(file_path, *cloud) == -1) 
    {
        PCL_ERROR("Couldn't read PCD file \n");
        return (-1);
    }

    std::cout << "Loaded point cloud with " << cloud->points.size() << " points.\n";

    //  使用凸包算法提取二维点云的凸多边形边界
    pcl::ConvexHull<pcl::PointXYZ> chull;// 创建凸包对象
    pcl::PointCloud<pcl::PointXYZ>::Ptr hull_points(new pcl::PointCloud<pcl::PointXYZ>);// 用于存储凸包点云
    chull.setInputCloud(cloud);// 设置输入点云
    chull.reconstruct(*hull_points);// 计算凸包并保存结果

    std::cout << "Convex hull points: " << hull_points->points.size() << std::endl;

    // 提取二维点云坐标(x, y)
    std::vector<pcl::PointXYZ> points_2d;
    for (const auto& pt : hull_points->points) 
    {
        points_2d.push_back(pt);// 将凸包点存入二维坐标向量
    }

    // 2. 拟合外接圆
    Circle circle = fitCircle(points_2d);// 拟合外接圆
    std::cout << "Fitted Circle: Center = (" << circle.x << ", " << circle.y << "), Radius = " << circle.r << std::endl;

    // 3. 可视化凸包点云和拟合的外接圆
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Convex Hull Viewer"));

    // 添加拟合圆的可视化(通过画多个圆周上的点来表示)
    pcl::PointCloud<pcl::PointXYZ>::Ptr circle_points(new pcl::PointCloud<pcl::PointXYZ>);
    int num_points = 100;
    for (int i = 0; i < num_points; ++i) 
    {
        float theta = 2 * M_PI * i / num_points;// 均匀分布的角度
        pcl::PointXYZ pt;
        pt.x = circle.x + circle.r * std::cos(theta);// 计算圆周点的 x 坐标
        pt.y = circle.y + circle.r * std::sin(theta);// 计算圆周点的 y 坐标
        pt.z = 0;
        circle_points->points.push_back(pt);// 添加圆周点到点云
    }
    viewer->addPointCloud<pcl::PointXYZ>(circle_points, "fitted circle");// 添加圆的点云到可视化器

    // 4. 保存拟合圆的点云到PCD文件
    //std::string output_file = "F:\\fitted_circle_points.pcd";  // 输出文件路径
    //if (pcl::io::savePCDFileASCII(output_file, *circle_points) == -1) {
    //    std::cerr << "Failed to save fitted circle points." << std::endl;
    //    return (-1);
    //}
    //std::cout << "Saved fitted circle points to '" << output_file << "'." << std::endl;

    // 启动可视化器
    while (!viewer->wasStopped()) 
    {
        viewer->spinOnce(100);
    }

    return 0;
}

标签:RANSAC,std,pt,float,外接圆,points,pcl,点云,circle
From: https://blog.csdn.net/qq_64095888/article/details/143848231

相关文章

  • @Transactional事务注解与函数内多线程并发编程出现的问题
    @Transactional当@Transactional注解写在函数上之后,就表示这个函数开启了事务。事务是基于数据库连接的connect。parallelStream这是针对List进行多线程Stream的操作。//对list集合开启多线程操作list.parallelStream().forEach(item->{//业务代码})@Transactional和pa......
  • Spring注解@Transactional事务使用问题
    同步数据需要分批操作,每次同步1000条,都需要提交事务@ServicepublicclassMyService{@AutowiredprivateMyServiceself;//注意使用自身代理对象来触发事务//循环调用此方法@Transactional(propagation=Propagation.REQUIRES_NEW)publicvoid......
  • PCL 点云拟合 Ransac拟合圆柱
    目录一、概述1.1原理1.2实现步骤1.3应用场景二、关键函数2.1头文件2.2加载点云数据2.3计算法线2.4拟合圆柱2.5可视化三、完整代码四、结果展示内容抄自CSDN点云侠:【2024最新版】PCL点云处理算法汇总(C++长期更新版)。质量无忧,永久免费,可放心复制粘贴。一、概......
  • 点云学习笔记17——PCL保存提取到的二维点云边界(即凸包边界)
    #include<pcl/io/pcd_io.h>#include<pcl/io/ply_io.h>#include<pcl/point_types.h>#include<pcl/features/normal_3d.h>#include<pcl/filters/project_inliers.h>#include<pcl/segmentation/sac_segmentation.h>#include<......
  • 点云学习笔记16——提取点云的边界,填充边界
    #include<iostream>#include<algorithm>#include<pcl/io/pcd_io.h>#include<pcl/point_types.h>#include<pcl/visualization/pcl_visualizer.h>voidBoundaryExtraction(pcl::PointCloud<pcl::PointXYZ>::Ptrcloud,pcl::Poi......
  • 21天教你学会PCIe专栏(5)--事务层(Transaction Layer)
    目录第5天:事务层(TransactionLayer)课程目标课程内容1.事务层概述2.事务类型3.请求和响应机制4.事务层的配置和管理5.实际应用示例课后练习结语第5天:事务层(TransactionLayer)课程目标理解PCIe事务层的基本概念和功能掌握事务类型及其工作原理了解请求和响应......
  • PCL 点云分割 分割多个平面
    目录一、概述1.1原理1.2实现步骤1.3应用场景二、代码实现2.1关键函数2.1.1RANSAC平面分割2.1.2剔除已分割的平面2.1.3可视化点云2.2完整代码三、实现效果PCL点云算法汇总及实战案例汇总的目录地址链接:PCL点云算法与项目实战案例汇总(长期更新)一、概述  ......
  • PCL 点云分割 Ransac分割3D球体
    目录一、概述1.1原理1.2实现步骤1.3应用场景二、代码实现2.1关键函数2.1.1球体拟合2.1.2可视化2.2完整代码三、实现效果PCL点云算法汇总及实战案例汇总的目录地址链接:PCL点云算法与项目实战案例汇总(长期更新)一、概述        在点云数据处理中,RANSAC(随......
  • 理解@Transactional
    在SpringBoot中,@Transactional注解仍然是Spring框架提供的一个核心注解,用于声明式事务管理。SpringBoot通过自动配置和简化配置,使得在SpringBoot应用程序中使用@Transactional注解变得更加方便。本文将深入探讨@Transactional注解在SpringBoot中的使用方法、......
  • Spring学习笔记_30——事务接口PlatformTransactionManager
    PlatformTransactionManager是Spring框架中事务管理的核心接口,它负责管理事务的创建、提交和回滚等操作。源码/**Copyright2002-2020theoriginalauthororauthors.**LicensedundertheApacheLicense,Version2.0(the"License");*youmaynotusethis......