【点云上采样】最近邻插值上采样算法 增加点云密度
创作时间:
作者:
@小白创作中心
【点云上采样】最近邻插值上采样算法 增加点云密度
引用
CSDN
1.
https://blog.csdn.net/weixin_43798721/article/details/143818219
看了很多文章都是用CGAL去做的,又是下载安装CGAL的贼麻烦,关键弄好还不能用,气死了。
前言
传感器采集到的点云比较稀疏,毕竟价位在那,好的太贵,买便宜的点又太稀,需要增加点云数据。
一、最近邻插值上采样算法
1、原理:
最近邻插值上采样算法的核心思想是在每个点与其最近邻点之间插入一个新点。具体来说,对于点云中的每个点 Pi,找到其最近邻点 Pj,然后在这两个点之间插入一个新点 Pnew,使得 Pnew 的坐标是 Pi和Pj坐标的平均值。
2、步骤:
- 读取点云数据:从文件中读取点云数据,将其加载到内存中。
pcl::PointCloud<PointType>::Ptr cloud(new pcl::PointCloud<PointType>);
if (pcl::io::loadPCDFile<PointType>("rabbit.pcd", *cloud) == -1) {
std::cerr << "Error: cannot read file rabbit.pcd" << std::endl;
return EXIT_FAILURE;
}
- 构建KD树:使用 KD 树(K-Dimensional Tree)来加速最近邻搜索。【KD 树是一种高效的空间分割数据结构,适用于多维空间中的快速最近邻查询。】
pcl::search::KdTree<PointType>::Ptr kdtree(new pcl::search::KdTree<PointType>);
kdtree->setInputCloud(cloud);
- 最近邻搜索:对点云中的每个点Pi ,使用 KD 树查找其最近邻点 Pj 。
for (size_t i = 0; i < cloud->points.size(); ++i) {
std::vector<int> pointIdxNKNSearch(1);
std::vector<float> pointNKNSquaredDistance(1);
// 寻找最近邻点
if (kdtree->nearestKSearch(cloud->points[i], 2, pointIdxNKNSearch, pointNKNSquaredDistance) > 0) {
// 在原始点和其最近邻点之间插入一个点
PointType newPoint;
newPoint.x = (cloud->points[i].x + cloud->points[pointIdxNKNSearch[1]].x) / 2.0;
newPoint.y = (cloud->points[i].y + cloud->points[pointIdxNKNSearch[1]].y) / 2.0;
newPoint.z = (cloud->points[i].z + cloud->points[pointIdxNKNSearch[1]].z) / 2.0;
outputCloud->push_back(newPoint);
}
}
- 插值新点:计算 Pi 和 Pj 之间的中点 Pnew ,并将 Pnew 添加到新的点云中。
PointType newPoint;
newPoint.x = (cloud->points[i].x + cloud->points[pointIdxNKNSearch[1]].x) / 2.0;
newPoint.y = (cloud->points[i].y + cloud->points[pointIdxNKNSearch[1]].y) / 2.0;
newPoint.z = (cloud->points[i].z + cloud->points[pointIdxNKNSearch[1]].z) / 2.0;
outputCloud->push_back(newPoint);
- 合并点云:将插值后的新点云与原始点云合并。
*cloud += *outputCloud;
- 保存点云:将合并后的点云保存到文件中。
if (pcl::io::savePCDFileBinary("output.pcd", *cloud) == -1) {
std::cerr << "Error: cannot write file output.pcd" << std::endl;
return EXIT_FAILURE;
}
二、完整代码
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/search/kdtree.h>
#include <iostream>
#include <vector>
// 类型定义
typedef pcl::PointXYZ PointType;
// 最近邻插值函数实现
pcl::PointCloud<PointType>::Ptr nearestNeighborInterpolation(pcl::PointCloud<PointType>::Ptr inputCloud)
{
// 创建KdTree对象进行最近邻搜索
pcl::search::KdTree<PointType>::Ptr kdtree(new pcl::search::KdTree<PointType>);
kdtree->setInputCloud(inputCloud);
// 新点云,用于存储插值后的点
pcl::PointCloud<PointType>::Ptr outputCloud(new pcl::PointCloud<PointType>);
// 对每个点进行最近邻搜索并插值
for (size_t i = 0; i < inputCloud->points.size(); ++i) {
std::vector<int> pointIdxNKNSearch(1);
std::vector<float> pointNKNSquaredDistance(1);
// 寻找最近邻点
if (kdtree->nearestKSearch(inputCloud->points[i], 2, pointIdxNKNSearch, pointNKNSquaredDistance) > 0) {
// 在原始点和其最近邻点之间插入一个点
PointType newPoint;
newPoint.x = (inputCloud->points[i].x + inputCloud->points[pointIdxNKNSearch[1]].x) / 2.0;
newPoint.y = (inputCloud->points[i].y + inputCloud->points[pointIdxNKNSearch[1]].y) / 2.0;
newPoint.z = (inputCloud->points[i].z + inputCloud->points[pointIdxNKNSearch[1]].z) / 2.0;
outputCloud->push_back(newPoint);
}
}
return outputCloud;
}
int main()
{
// 输入文件路径
const std::string input_file = "rabbit.pcd";
// 输出文件路径
const std::string output_file = "output.pcd";
// 读取 PCD 文件
pcl::PointCloud<PointType>::Ptr cloud(new pcl::PointCloud<PointType>);
if (pcl::io::loadPCDFile<PointType>(input_file, *cloud) == -1) {
std::cerr << "Error: cannot read file " << input_file << std::endl;
return EXIT_FAILURE;
}
// 进行最近邻插值
pcl::PointCloud<PointType>::Ptr interpolatedCloud = nearestNeighborInterpolation(cloud);
// 将插值后的点云合并到原始点云中
*cloud += *interpolatedCloud;
// 保存点云为 PCD 文件
if (pcl::io::savePCDFileBinary(output_file, *cloud) == -1) {
std::cerr << "Error: cannot write file " << output_file << std::endl;
return EXIT_FAILURE;
}
std::cout << "Interpolation completed and saved to " << output_file << std::endl;
return EXIT_SUCCESS;
}
三、效果对比
cloudcompare效果
加点前:
加点后:
热门推荐
专家解读:绿茶的过量饮用是否对肝肾有损害
宅基地流转合同高清图片:法律依据与注意事项
梦见追逐的梦
低颅压怎么检查出来的
报警人会有什么后果
梦见已故老人的多重象征意义
如何在 Windows 上恢复不在回收站中的已删除文件
硬盘接口及协议详解:SATA、PCI-E与NVMe的区别
硬件开发工程师需要学哪些
如何利用技术分析来进行外汇交易决策?
整体治疗:21世纪的养生之道,让身心灵焕发健康光彩
掼蛋进贡还贡规则详解
房屋继承律师费用收取方式详解
四川麻辣烫的多种配料配方和制作方法
恩施土家族苗族自治州景点推荐
胎儿出生体重小是否会影响未来身高
郑学宝:湿热不除,全身受苦!这三招帮你清热祛湿,横扫一身湿热
江苏镇江最有名的七大特色美食,尤其是第一种,早已名扬海内外
数学错题本:建立方法、使用技巧及重要作用
1050ti和750ti性能差多少
怎么治疗急性胆囊炎
宝宝呛奶后家庭紧急处理方法,收藏学习希望你永远用不上
经常梦见发洪水是什么征兆
决定素食前必知的6个问题
如何申请公租房补助?申请补助有哪些条件?
公租房申请流程及所需材料
中医怎么治胃病
Vue应用中的会话管理:防劫持与超时设置
革兰氏阳性菌的详细分类及特征
晚上睡觉出汗全身湿透是什么原因