alpha-shape计算二维点云边界--c++实现

25 篇文章 17 订阅

alpha-shape原理看过很久了,今天花点时间实现一下:
原理参考:
博客
平面点云边界提取算法研究[D].长沙理工大学,2017.
《综合机载与车载LiDAR数据的建筑物三维重建》
《基于体元的机载LiDAR建筑物提取》
注意个人原创,转载注明出处,如果感觉有帮助,点个赞,有疑问,欢迎留言交流。

show the codes:

// ashape.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<pcl\common\common.h>
#include <iostream>
#include<pcl/point_cloud.h>
#include<pcl/kdtree/kdtree_flann.h>
#include<pcl/io/pcd_io.h>

double get2DDist(pcl::PointXYZ p1, pcl::PointXYZ p2)
{
    double dist = std::pow(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)), 0.5);
    return dist;
}
int main()
{
    std::string file_name("Plane_0002.pcd");
    pcl::PointCloud<pcl::PointXYZ> ::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::io::loadPCDFile<pcl::PointXYZ>(file_name, *cloud_in);
    //投影到二维平面
    for (auto& point : *cloud_in)
    {
        point.z = 0.0;
    }
    pcl::io::savePCDFile<pcl::PointXYZ>("二维平面.pcd", *cloud_in);
    std::vector<int> boundary_bool(cloud_in->size(), 0);
    double r = 1.8;
    pcl::KdTreeFLANN<pcl::PointXYZ>kdtree;
    kdtree.setInputCloud(cloud_in);
    std::vector<int> indices(0,0);
    std::vector<float>dist(0, 0.0);
    for (size_t i = 0; i < cloud_in->size(); ++i)
    {
        pcl::PointXYZ p = cloud_in->points[i];
        kdtree.radiusSearch(cloud_in->points[i], 2*r, indices,dist ,100);
        //indices[0]对应的点云即为查询点本身
        for (size_t j = 1; j < indices.size(); ++j)
        {
            pcl::PointXYZ p1 = cloud_in->points[indices[j]];
            double s_2 = std::pow((p.x - p1.x), 2) +
                std::pow((p.y - p1.y), 2);
            double h = std::pow((r * r / s_2 - 0.25), 0.5);
            double x2 = p.x + 0.5 * (p1.x - p.x) - h * (p1.y - p.y);
            double y2 = p.y + 0.5 * (p1.y - p.y) - h * (p.x - p1.x);
            double x3 = p.x + 0.5 * (p1.x - p.x) + h * (p1.y - p.y);
            double y3 = p.y + 0.5 * (p1.y - p.y) + h * (p.x - p1.x);
            pcl::PointXYZ p2(x2, y2, 0.0);
            pcl::PointXYZ p3(x3, y3, 0.0);
            //计算邻域内除了p1之外的点到p2,p3的距离
            std::vector<double>distp2,distp3;
            std::vector<int>distp2_bool(0, 0), distp3_bool(0, 0);
            int count = 0;
            for (size_t k = 1; k < indices.size(); ++k)
            {
                pcl::PointXYZ p_other = cloud_in->points[indices[k]];
                if (k != j)
                {
                    ++count;
                    double distance_p2 = get2DDist(p_other, p2);
                    double distance_p3 = get2DDist(p_other, p3);
                    //比较距离与r的大小
                    if (distance_p2 > r)
                    {
                        distp2_bool.push_back(1);
                    }
                    if (distance_p3 > r)
                    {
                        distp3_bool.push_back(1);
                    }
                }
            }
            //如果邻域内所有点到p2,或者p3的距离均大于r,则有distp2_bool.size()==count
            //则表明p是边界点,退出循环,不用再计算邻域内点距离了
            if (count == distp2_bool.size() || count == distp3_bool.size())
            {
                boundary_bool[i] = 1;
                break;
            }
        }      
    }
    pcl::PointCloud<pcl::PointXYZ> boundary_cloud;
    for (size_t it=0;it< boundary_bool.size();++it)
    {
        if (boundary_bool[it] == 1)
        {
            boundary_cloud.push_back(cloud_in->points[it]);
        }
    }
    boundary_cloud.height = boundary_cloud.size();
    boundary_cloud.width = 1;
    boundary_cloud.resize(boundary_cloud.height * boundary_cloud.width);
    if (boundary_cloud.size())
    {
        pcl::io::savePCDFile<pcl::PointXYZ>("边界点云.pcd", boundary_cloud);

    }

    std::cout << "Hello World!\n";
}

实验效果:(红色为提取的边界点)
在这里插入图片描述
结论:该方法提取边界效率较慢(可以看出来三层循环,速度慢),效果还行(中间有一部分错误边界点)

  • 1
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面是使用Python实现alpha shape算法对二维点云进行边界提取的代码: ```python from scipy.spatial import Delaunay import numpy as np from matplotlib import pyplot as plt def alpha_shape(points, alpha): """ Compute the alpha shape (concave hull) of a set of points. """ # Delaunay triangulation tri = Delaunay(points) # Filter triangles by alpha value edges = set() edge_points = [] for j, tri in enumerate(tri.simplices): # Calculate circumcenter and radius of circumcircle x, y = np.mean(points[tri], axis=0) r = np.sqrt((points[tri[0]][0] - x)**2 + (points[tri[0]][1] - y)**2) # Check if triangle is within alpha value if r < alpha: for i in range(3): edge = (tri[i], tri[(i+1)%3]) if edge not in edges and (edge[1], edge[0]) not in edges: edges.add(edge) edge_points.append(points[tri[i]]) edge_points.append(points[tri[(i+1)%3]]) # Compute boundary vertices and edges boundary_vertices = set() boundary_edges = [] for i, point in enumerate(points): for edge in edges: if i in edge: boundary_vertices.add(i) boundary_edges.append(edge) # Plot alpha shape plt.triplot(points[:,0], points[:,1], tri.simplices.copy()) plt.plot(edge_points[:,0], edge_points[:,1], 'r.') plt.plot(points[list(boundary_vertices),0], points[list(boundary_vertices),1], 'b.') plt.show() return boundary_vertices, boundary_edges ``` 在这个代码中,我们使用了`scipy.spatial`库中的`Delaunay`函数来进行Delaunay三角剖分,然后根据alpha值筛选出在范围内的三角形,并提取出边界。 下面是一个使用示例: ```python # Generate random points points = np.random.rand(30, 2) # Compute alpha shape alpha = 0.3 boundary_vertices, boundary_edges = alpha_shape(points, alpha) # Print boundary vertices and edges print("Boundary vertices:", boundary_vertices) print("Boundary edges:", boundary_edges) ``` 这个例子中,我们先生成了30个随机,然后使用`alpha_shape`函数计算alpha shape,并输出边界和边。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值