寻找两个点云重叠部分

25 篇文章 17 订阅
16 篇文章 7 订阅

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

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

方法1:

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

// 提取点云重叠区域.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <pcl/features/moment_of_inertia_estimation.h>
#include <vector>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

#include<pcl/filters/crop_box.h>
#include <pcl/common/transforms.h>
#include<pcl/common/common.h>
//获取第二个点云相对第一个点云的重叠区域
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);
   //将点云旋转,使得第一个点云的OBB=AABB,以此获得第一个点云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

// 提取点云重叠区域2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_cloud.h>
#include<pcl/point_types.h>
#include<pcl/octree/octree.h>
#include<ctime>
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);

	//pcl::PointCloud<point> overlapped_2;
	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
旋转点云

  • 17
    点赞
  • 119
    收藏
    觉得还不错? 一键收藏
  • 39
    评论
点云是由一系列离散的三维点组成的数据集,用于表示物体的形状和表面信息。在点云处理中,经常需要找到不同点云之间的重叠部分,以便进行特征匹配、配准、形状对齐等应用。而提取点云重叠部分的关键是通过对应点估计(correspondence estimation)。 对应点估计是指在两个或多个点云之间建立点之间的对应关系。通常通过特征描述子进行点云间的特征匹配,找到相似的特征点对应关系,从而建立点云的对应关系。常用的特征描述子包括SIFT、SURF和SHOT等。 在点云重叠部分提取的过程中,首先需要对每个点云进行特征提取,计算每个点的特征描述子。然后,通过比较两个点云的特征描述子,找到最匹配的特征点对应关系。 在找到对应点之后,可以通过计算点云之间的变换矩阵,将重叠部分点云进行配准或形状对齐。配准是将点云投影到同一坐标系下,并使之尽可能重合;而形状对齐则是通过调整点云的姿态和尺度,使得它们的形状相似。 对应点估计在计算机视觉和三维重建领域有广泛的应用。例如,在目标识别中,可以通过对应点估计将3D模型与场景中的点云进行匹配,从而实现目标的识别与定位。此外,在虚拟现实和增强现实中,对应点估计也被用于生成虚拟物体与真实场景之间的精准对应关系。 综上所述,通过对应点估计可以提取点云重叠部分,为后续的点云处理任务提供必要的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值