寻找两个点云重叠部分

目录

*
方法1:
方法1实验效果:
方法2(c++):
方法2(python)
方法2实验效果:
结论:

网上大部分寻找重叠区域都是对一个点云建立kdtree,然后在r半径内搜索另外一个点云的点。这种方法适合两个点云完全一样。一般的点云数据并不完全一样,例如两条航带的点云,并不完全相同,如果应用这方法会损失很多点,造成特征计算的不准确性。下面介绍两种方法:

写在前面的结论:第二种方法速度和精度上均优于第一种方法(octree yyds!!!)

方法1:

(1)假设有两组点云A,B,计算A的OBB包围盒
(2)寻找点云A的OBB包围盒内的点云B,这样就得到点云B相对A的重叠区域
(3)反之计算,得到点云A相对于B的重叠区域
(4)综上可以得到一组重叠区域的点云,可用于后续分析。
show the codes


#include
#include
#include
#include

#include
#include
#include

void getOverlappedCloud(const pcl::PointCloud<pcl::PointXYZ> &cloud, const pcl::PointCloud<pcl::PointXYZ>&cloud2, pcl::PointCloud<pcl::PointXYZ>&overlapped_cloud2)
{
    pcl::MomentOfInertiaEstimation <pcl::PointXYZ> feature_extractor;
    feature_extractor.setInputCloud(cloud.makeShared());
    feature_extractor.compute();
    pcl::PointXYZ min_point_AABB;
    pcl::PointXYZ max_point_AABB;
    pcl::PointXYZ min_point_OBB;
    pcl::PointXYZ max_point_OBB;
    pcl::PointXYZ position_OBB;
    Eigen::Matrix3f rotational_matrix_OBB;
    feature_extractor.getAABB(min_point_AABB, max_point_AABB);
    feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);

    Eigen::Matrix4f tf = Eigen::Matrix4f::Identity();
    tf << (rotational_matrix_OBB.inverse());
    pcl::PointCloud<pcl::PointXYZ>cloud_tf, cloud2_tf;
    pcl::transformPointCloud(cloud, cloud_tf, tf);
    pcl::transformPointCloud(cloud2, cloud2_tf, tf);
    Eigen::Vector4f pmin, pmax;

    pcl::getMinMax3D(cloud_tf, pmin, pmax);
    pcl::PointCloud<pcl::PointXYZ> tf_overlapped_cloud2;
    std::vector<int> indices;

    pcl::getPointsInBox(cloud2_tf, pmin, pmax, indices);
    pcl::copyPointCloud(cloud2_tf, indices, tf_overlapped_cloud2);

    pcl::transformPointCloud(tf_overlapped_cloud2, overlapped_cloud2, tf.inverse());

    std::cout << tf << std::endl;
    std::cout << rotational_matrix_OBB << std::endl;
}
int main(int argc, char** argv)
{
    pcl::PointCloud<pcl::PointXYZ>cloud, overlapped_cloud;
    pcl::io::loadPCDFile("SHCSCloud.pcd", cloud);

    pcl::PointCloud<pcl::PointXYZ>cloud2,overlapped_cloud2;
    pcl::io::loadPCDFile("SHCSCloud副本.pcd", cloud2);

    getOverlappedCloud(cloud, cloud2, overlapped_cloud2);
    getOverlappedCloud(cloud2, cloud, overlapped_cloud);

    pcl::io::savePCDFile<pcl::PointXYZ>("重叠点云.pcd", overlapped_cloud);
    pcl::io::savePCDFile<pcl::PointXYZ>("重叠点云2.pcd", overlapped_cloud2);
}

方法1实验效果:

原始点云:

寻找两个点云重叠部分
图中白色点云为原始红色点云的重叠区域:
寻找两个点云重叠部分
绿色点云为蓝色原始点云的重叠区域:
寻找两个点云重叠部分

耗时:

寻找两个点云重叠部分

结论:从图上看,这种方法只能粗略点云重叠区域,提取的重叠区域与实际重叠区域存在一定偏差。

; 方法2(c++):

(1)假设有两组点云A,B,对A建立八叉树
(2)遍历B中所有点,查询其对应的A的体素是否存在点云(即同一体素中是否同时存在AB点云),若存在,则该点为B点云的重叠点云
(3)同理,得到A中重叠点云
show the codes


#include
#include
#include
#include
#include
#include
using point = pcl::PointXYZ;
using cloud = pcl::PointCloud<point>;
void getOverlappedCloud(const pcl::PointCloud<pcl::PointXYZ>& cloud1, const pcl::PointCloud<pcl::PointXYZ>& cloud2, pcl::PointCloud<pcl::PointXYZ>& overlapped_cloud2)
{
    double radius = 3.0;
    pcl::octree::OctreePointCloudSearch<point> octree(radius);
    octree.setInputCloud(cloud1.makeShared());
    octree.addPointsFromInputCloud();
    point min_pt, max_pt;
    pcl::getMinMax3D(cloud1, min_pt, max_pt);

    for (size_t i = 0; i < cloud2.size(); ++i)
    {

        if (cloud2.points[i].x>max_pt.x|| cloud2.points[i].y > max_pt.y || cloud2.points[i].z > max_pt.z ||
            cloud2.points[i].x < min_pt.x || cloud2.points[i].y < min_pt.y || cloud2.points[i].z < min_pt.z)
        {
            continue;
        }
        std::vector<int> indices;
        octree.voxelSearch(cloud2.points[i], indices);
        pcl::PointCloud<point> cloud_out;
        if (indices.size())
        {
            overlapped_cloud2.push_back(cloud2.points[i]);
        }

    }
}
int main()
{
    auto start = std::clock();
    pcl::PointCloud<point> cloud1, cloud2;
    pcl::io::loadPCDFile<point>("D:/1重叠.pcd", cloud1);
    pcl::io::loadPCDFile<point>("D:/2重叠.pcd", cloud2);
    cloud overlapped1, overlapped2;
    getOverlappedCloud(cloud1, cloud2, overlapped2);
    getOverlappedCloud(cloud2, cloud1, overlapped1);

    pcl::io::savePCDFile("D:/11重叠.pcd", overlapped1);
    pcl::io::savePCDFile("D:/22重叠.pcd", overlapped2);
    auto end = std::clock();
    std::cerr << "耗时" << std::difftime(end, start) << "ms" << std::endl;
    std::cout << "Hello World!\n";
}

方法2(python)

import open3d as o3d

def find_overlapped_cloud(cloud1, cloud2):
    overlapped_cloud_indices = []
    octree = o3d.geometry.Octree(max_depth=4)
    octree.convert_from_point_cloud(cloud1, size_expand=0.01)
    min_pt = octree.get_min_bound()
    max_pt = octree.get_max_bound()
    for point in cloud2.points:
        if point[0] < min_pt[0] or point[1] < min_pt[1] or point[2] < min_pt[2] or \
                point[0] > max_pt[0] or point[1] > max_pt[1] or point[2] > max_pt[2]:
            continue
        else:
            leaf_node, leaf_info = octree.locate_leaf_node(point)
            if leaf_info is not None:
                indices = leaf_node.indices
                for indice in indices:
                    overlapped_cloud_indices.append(indice)

    return cloud1.select_by_index(overlapped_cloud_indices)

if __name__ == '__main__':
    "read cloud"
    cloud1 = o3d.io.read_point_cloud("D:/1重叠.pcd")
    cloud2 = o3d.io.read_point_cloud("D:/2重叠.pcd")
    "find overlapped cloud"
    overlapped_cloud1 = find_overlapped_cloud(cloud2, cloud1)
    overlapped_cloud2 = find_overlapped_cloud(cloud1, cloud2)
    "save cloud"
    o3d.io.write_point_cloud("D:/o3d_overlapped1.pcd", overlapped_cloud1)
    o3d.io.write_point_cloud("D:/o3d_overlapped2.pcd", overlapped_cloud2)

方法2实验效果:

黄色为重叠区域

寻找两个点云重叠部分
棕色为重叠区域
寻找两个点云重叠部分
耗时:
寻找两个点云重叠部分

; 结论:

第二种方法速度和精度上均优于第一种方法
写在后面的参考资料:
寻找点云OBB
旋转点云

Original: https://blog.csdn.net/xinxiangwangzhi_/article/details/122517017
Author: xinxiangwangzhi_
Title: 寻找两个点云重叠部分

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/649956/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球