[小汪学习日记02]pcl基于模型的球拟合方法

一、软件环境

        win10、pcl1.11.0、vs2019。

二、代码介绍

        刚学习完平面拟合,想自己试试根据算法写个球拟合的代码,另外不用更改pcl库的文件,放一个文件里,后续这样想加点约束条件来改进试试,其实就是RANSAC算法,利用mt19937来确定四个随机点,四点确定一个圆判断内外点。本人萌新,写的有些粗糙,请见谅。

三、算法介绍

算法参考链接:根据空间4点坐标求球心坐标 - 百度文库 (baidu.com)

四、详细代码

#include <pcl/io/pcd_io.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_sphere.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/point_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <boost/thread/thread.hpp>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/io/io.h>
#include <pcl/PolygonMesh.h>
#include <pcl/point_cloud.h>
#include <pcl/io/vtk_lib_io.h>
#include<pcl/features/normal_3d.h>
#include<pcl/features/principal_curvatures.h>
#include <vector>
#include <iostream>
#include <random>
using namespace std;
using namespace pcl;
int user_data;
void
viewerPsycho(pcl::visualization::PCLVisualizer& viewer)
{
    static unsigned count = 0;
    std::stringstream ss;
    ss << "Once per viewer loop: " << count++;
    viewer.removeShape("text", 0);
    viewer.addText(ss.str(), 200, 300, "text", 0);

    //FIXME: possible race condition here:
    user_data++;
}

bool isPointDuplicate(const pcl::PointXYZ& point, const std::vector<pcl::PointXYZ>& selectedPoints)
{
    for (const auto& selectedPoint : selectedPoints)
    {
        if (point.x == selectedPoint.x && point.y == selectedPoint.y && point.z == selectedPoint.z)
        {
            return true;
        }
    }
    return false;
}
int main()
{
    pcl::PointCloud<pcl::PointNormal>::Ptr cloud_inputsb(new pcl::PointCloud<pcl::PointNormal>);
    if (pcl::io::loadPCDFile("D://code//Project5//normal_with_cur.pcd", *cloud_inputsb) < 0)
    {
        PCL_ERROR("点云读取失败!\n");
        return -1;
    }
    cout << "加载点云点数:" << cloud_inputsb->points.size() << endl;
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_input(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile("D://code//Project5//1.pcd", *cloud_input) < 0)
    {
        PCL_ERROR("点云读取失败!\n");
        return -1;
    }
    cout << "加载点云点数:" << cloud_input->points.size() << endl;

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dist(0, cloud_input->size() - 1);
    double jieshou_x = 0;
    double jieshou_y = 0;
    double jieshou_z = 0;
    double banjing = 0;
    double zuijia_x = 0;
    double zuijia_y = 0;
    double zuijia_z = 0;
    double zuijia_banjing = 0;
    double zuijia_neidianlv;
    double distance = 0;
    double neidianlv_indices = 0;
    double neidianlv_index = 0;
    int diedaicishu = 10000;
    double x_centre = 0;
    double y_centre = 0;
    double z_centre = 0;
    for (int i = 0; i < diedaicishu; i++)
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr neidianji(new pcl::PointCloud<pcl::PointXYZ>);
        pcl::PointCloud<pcl::PointXYZ>::Ptr waidianji(new pcl::PointCloud<pcl::PointXYZ>);
        neidianji->resize(cloud_input->size());
        waidianji->resize(cloud_input->size());
        double neidianjishu = 0;
        double waidianjishu = 0;

        std::vector<pcl::PointXYZ> selectedPoints;
        while (selectedPoints.size() < 4)
        {
            int index = dist(gen);
            pcl::PointXYZ selectedPoint = cloud_input->points[index];
            if (!isPointDuplicate(selectedPoint, selectedPoints))
            {
                selectedPoints.push_back(selectedPoint);
                std::cout << "Selected point: (" << selectedPoint.x << ", " << selectedPoint.y << ", " << selectedPoint.z << ")" << std::endl;
            }
        }
        double p1x = selectedPoints[0].x;
        double p1y = selectedPoints[0].y;
        double p1z = selectedPoints[0].z;
        double p2x = selectedPoints[1].x;
        double p2y = selectedPoints[1].y;
        double p2z = selectedPoints[1].z;
        double p3x = selectedPoints[2].x;
        double p3y = selectedPoints[2].y;
        double p3z = selectedPoints[2].z;
        double p4x = selectedPoints[3].x;
        double p4y = selectedPoints[3].y;
        double p4z = selectedPoints[3].z;
        double a = p1x - p2x, b = p1y - p2y, c = p1z - p2z;
        double a1 = p3x - p4x, b1 = p3y - p4y, c1 = p3z - p4z;
        double a2 = p2x - p3x, b2 = p2y - p3y, c2 = p2z - p3z;
        double A = p1x * p1x - p2x * p2x;
        double B = p1y * p1y - p2y * p2y;
        double C = p1z * p1z - p2z * p2z;
        double A1 = p3x * p3x - p4x * p4x;
        double B1 = p3y * p3y - p4y * p4y;
        double C1 = p3z * p3z - p4z * p4z;
        double A2 = p2x * p2x - p3x * p3x;
        double B2 = p2y * p2y - p3y * p3y;
        double C2 = p2z * p2z - p3z * p3z;
        double P = (A + B + C) / 2;
        double Q = (A1 + B1 + C1) / 2;
        double R = (A2 + B2 + C2) / 2;
        double D = a * b1 * c2 + a2 * b * c1 + c * a1 * b2 - (a2 * b1 * c + a1 * b * c2 + a * b2 * c1);
        double Dx = P * b1 * c2 + b * c1 * R + c * Q * b2 - (c * b1 * R + P * c1 * b2 + Q * b * c2);
        double Dy = a * Q * c2 + P * c1 * a2 + c * a1 * R - (c * Q * a2 + a * c1 * R + c2 * P * a1);
        double Dz = a * b1 * R + b * Q * a2 + P * a1 * b2 - (a2 * b1 * P + a * Q * b2 + R * b * a1);
        if (D == 0) {
            cerr << "四点共面" << endl;
        }
        else {
            x_centre = Dx / D;
            y_centre = Dy / D;
            z_centre = Dz / D;
            banjing = sqrt((p1x - x_centre) * (p1x - x_centre) +
                (p1y - y_centre) * (p1y - y_centre) +
                (p1z - z_centre) * (p1z - z_centre));

        }
        std::cout << "x坐标" << x_centre << "y坐标" << y_centre << "z坐标" << z_centre << "半径为" << banjing << std::endl;
        double array01[629];
        for (int j = 0; j < cloud_input->size(); j++)
        {
            distance = sqrt(((cloud_input->points[j].x - x_centre) * (cloud_input->points[j].x - x_centre) +
                (cloud_input->points[j].y - y_centre) * (cloud_input->points[j].y - y_centre) +
                (cloud_input->points[j].z - z_centre) * (cloud_input->points[j].z - z_centre))) - banjing;
            array01[j] = distance;
            if (distance <= 0.1 && distance >= -0.1)
            {
                neidianji->points[neidianjishu].x = cloud_input->points[j].x;
                neidianji->points[neidianjishu].y = cloud_input->points[j].y;
                neidianji->points[neidianjishu].z = cloud_input->points[j].z;
                neidianjishu = neidianjishu + 1;
            }
            else
            {
                waidianji->points[waidianjishu].x = cloud_input->points[j].x;
                waidianji->points[waidianjishu].y = cloud_input->points[j].y;
                waidianji->points[waidianjishu].z = cloud_input->points[j].z;
                waidianjishu = waidianjishu + 1;
            }
        }

        std::cout << "内点数为:" << neidianjishu << std::endl;
        std::cout << "外点数为:" << waidianjishu << std::endl;
        float neidianlv = 100 * neidianjishu / (neidianjishu + waidianjishu);
        std::cout << neidianlv << std::endl;
        neidianlv_indices = neidianlv;
        jieshou_x = x_centre;
        jieshou_y = y_centre;
        jieshou_z = z_centre;
        if (neidianlv >= 70)
        {
            zuijia_x = x_centre;
            zuijia_y = y_centre;
            zuijia_z = z_centre;
            zuijia_banjing = banjing;
            zuijia_neidianlv = neidianlv_indices;

            pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("拟合结果"));
            viewer->addPointCloud<pcl::PointXYZ>(neidianji, "cloud");
            viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 1, 1, "cloud");
            viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud");
            viewer->addPointCloud<pcl::PointXYZ>(waidianji, "sphere");
            viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "sphere");
            viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sphere");
            while (!viewer->wasStopped())
            {
                viewer->spinOnce(100);
            }
            break;
        }
        if (neidianlv_indices >= neidianlv_index)
        {
            zuijia_x = jieshou_x;
            zuijia_y = jieshou_y;
            zuijia_z = jieshou_z;
            zuijia_banjing = banjing;
            zuijia_neidianlv = neidianlv_indices;
            neidianlv_index = neidianlv_indices;
            zuijia_x = jieshou_x;
            jieshou_x = 0;
        }
        std::cout << "hhhhhh" << std::endl;
    }
    std::cout << "最佳拟合球参数:" << "球心坐标x" << zuijia_x << "球心坐标y" << zuijia_y << "球心坐标z" << zuijia_z << "球半径" << zuijia_banjing << std::endl;
    std::cout << "内点率为" << zuijia_neidianlv << std::endl;





    pcl::PointCloud<pcl::PointXYZ>::Ptr neidian(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr waidian(new pcl::PointCloud<pcl::PointXYZ>);
    neidian->resize(cloud_input->size());
    waidian->resize(cloud_input->size());
    double neidian02 = 0;
    double waidian02 = 0;
    double array02[629];
    for (int k = 0; k < cloud_input->size(); k++)
    {
        distance = sqrt(((cloud_input->points[k].x - zuijia_x) * (cloud_input->points[k].x - zuijia_x) +
            (cloud_input->points[k].y - zuijia_y) * (cloud_input->points[k].y - zuijia_y) +
            (cloud_input->points[k].z - zuijia_z) * (cloud_input->points[k].z - zuijia_z))) - zuijia_banjing;
        array02[k] = distance;
        if (distance <= 0.1 && distance >= -0.1)
        {
            neidian->points[neidian02].x = cloud_input->points[k].x;
            neidian->points[neidian02].y = cloud_input->points[k].y;
            neidian->points[neidian02].z = cloud_input->points[k].z;
            neidian02 = neidian02 + 1;
        }
        else
        {
            waidian->points[waidian02].x = cloud_input->points[k].x;
            waidian->points[waidian02].y = cloud_input->points[k].y;
            waidian->points[waidian02].z = cloud_input->points[k].z;
            waidian02 = waidian02 + 1;
        }
    }

    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("拟合结果"));
    viewer->addPointCloud<pcl::PointXYZ>(neidian, "cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 1, 1, "cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud");
    viewer->addPointCloud<pcl::PointXYZ>(waidian, "sphere");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "sphere");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sphere");
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
    }

    return 0;
}

最后的效果如下,白色为拟合的球体。

最佳拟合球参数:球心坐标x86.8652球心坐标y60.0072球心坐标z86.8682球半径9.96032
内点率为27.9809

五、pcd文件链接

链接:https://pan.baidu.com/s/13IJMh6ALlqAMAngaKVc80g 
提取码:acdl 
--来自百度网盘超级会员V4的分享

六、总结

        如有不足,请各位大佬批评指正。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值