【点云上采样】最近邻插值上采样算法 增加点云密度
创作时间:
作者:
@小白创作中心
【点云上采样】最近邻插值上采样算法 增加点云密度
引用
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效果
加点前:
加点后:
热门推荐
装修必看:14种常见家用电器额定功率参考
思瑶女孩名字的寓意解析
2025年2月金价及黄金ETF资产管理规模均创历史新高
股价早盘涨逾5%!小鹏汇天“陆地航母”预订超3000台
详解电感的关键参数
如何区分URL和API
利用LLMs自动寻找量化投资策略
十部80年代国产刑侦悬疑片,全部看过的,才是骨灰级侦探迷
两台电脑如何建立共享磁盘网络连接
你过度清洁了吗?真正该清洁的地方可别被忽略了!
原神神瞳有必要全捡吗?攻略详解
南京鼓楼医院:从患者需求出发 在细节里彰显医者初心
老外最爱的前十名中国菜
什么是国债逆回购?有哪些规则?
北交所上市规则
新疆美食探秘:炒米粉与拌面的独特魅力
劳务合同签订指南:注意事项与风险防范
结膜炎症状和表现
增值税网上申报流程是怎样的
如何分析货币供应量的变化趋势?这种趋势对经济运行有何影响?
主序星是什么意思 恒星的主要演化阶段具体如下
通俗科普:我们的地球和太阳是如何诞生的?
在古代,嫁女儿比现在娶媳妇还难?
六大茶类的前世今生:从工艺到文化的传承
宽窄巷子:穿越历史,探寻成都的古老记忆
中国八大著名烧饼
如何提升非急救转运服务的质量
职场社交礼仪:如何在职场中展现自信和专业?
职场需要“界限感”
养老院收费标准全解析:从一线城市到三线城市,不同需求下的选择指南