4PCS点云配准算法实现

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4PCS点云配准算法的C++实现如下:

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/common.h>
#include <pcl/common/distances.h>
#include <pcl/common/transforms.h>
#include <pcl/search/kdtree.h> struct Points4
{pcl::PointXYZ p1;pcl::PointXYZ p2;pcl::PointXYZ p3;pcl::PointXYZ p4;
};int compute_LCP(const pcl::PointCloud<pcl::PointXYZ>& cloud, pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree, float radius)
{std::vector<int>index(1);std::vector<float>distance(1);int count = 0;for (size_t i = 0; i < cloud.size(); i++){kdtree->nearestKSearch(cloud.points[i], 1, index, distance);if (distance[0] < radius)count = count + 1;}return count;
}int main(int argc, char** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ>::Ptr pcs_cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile("bunny1.pcd", *source_cloud);pcl::io::loadPCDFile("bunny2.pcd", *target_cloud);pcl::PointXYZ min_pt, max_pt;pcl::getMinMax3D(*source_cloud, min_pt, max_pt);float d_max = pcl::euclideanDistance(min_pt, max_pt);//srand(time(0));int iters = 100;float s_max = 0;float f = 0.5;float ff = 0.1;float delta = 0.0001;int index1 = -1, index2 = -1, index3 = -1, index4 = -1;for (size_t i = 0; i < iters; i++){int n1 = rand() % source_cloud->size(), n2 = rand() % source_cloud->size(), n3 = rand() % source_cloud->size();pcl::PointXYZ p1 = source_cloud->points[n1], p2 = source_cloud->points[n2], p3 = source_cloud->points[n3];Eigen::Vector3f a(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z);Eigen::Vector3f b(p1.x - p3.x, p1.y - p3.y, p1.z - p3.z);float s = 0.5 * sqrt(pow(a.y() * b.z() - b.y() * a.z(), 2) + pow(a.x() * b.z() - b.x() * a.z(), 2) + pow(a.x() * b.y() - b.x() * a.y(), 2));if (s > s_max && pcl::euclideanDistance(source_cloud->points[n1], source_cloud->points[n2]) < f* d_max &&	pcl::euclideanDistance(source_cloud->points[n1], source_cloud->points[n3]) < f * d_max){index1 = n1;index2 = n2;index3 = n3;}}if (index1 == -1 || index2 == -1 || index3 == -1){std::cout << "find three points error!" << std::endl;return -1;}pcl::PointXYZ p1 = source_cloud->points[index1], p2 = source_cloud->points[index2], p3 = source_cloud->points[index3];float A = (p2.y - p1.y) * (p3.z - p1.z) - (p2.z - p1.z) * (p3.y - p1.y);	float B = (p2.z - p1.z) * (p3.x - p1.x) - (p2.x - p1.x) * (p3.z - p1.z);float C = (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);float D = -(A * p1.x + B * p1.y + C * p1.z);for (size_t i = 0; i < source_cloud->size(); i++){pcl::PointXYZ p = source_cloud->points[i];float d = fabs(A * p.x + B * p.y + C * p.z + D) / sqrt(A * A + B * B + C * C);bool flag = (pcl::euclideanDistance(p, p1) < f * d_max && pcl::euclideanDistance(p, p2) < f * d_max && pcl::euclideanDistance(p, p3) < f * d_max&& pcl::euclideanDistance(p, p1) > ff * d_max && pcl::euclideanDistance(p, p2) > ff * d_max && pcl::euclideanDistance(p, p3) > ff * d_max);if (d < delta * d_max && flag){index4 = i;}}if (index4 == -1){std::cout << "find fouth point error!" << std::endl;return -1;}pcl::PointXYZ p4 = source_cloud->points[index4];pcl::PointCloud<pcl::PointXYZ>::Ptr four_points(new pcl::PointCloud<pcl::PointXYZ>);four_points->push_back(p1);four_points->push_back(p2);four_points->push_back(p3);four_points->push_back(p4);pcl::io::savePCDFile("four_points.pcd", *four_points);Eigen::VectorXf line_a(6), line_b(6);line_a << p1.x, p1.y, p1.z, p1.x - p2.x, p1.y - p2.y, p1.z - p2.z;line_b << p3.x, p3.y, p3.z, p3.x - p4.x, p3.y - p4.y, p3.z - p4.z;Eigen::Vector4f pt1_seg, pt2_seg;pcl::lineToLineSegment(line_a, line_b, pt1_seg, pt2_seg);pcl::PointXYZ p5((pt1_seg[0]+ pt2_seg[0])/2, (pt1_seg[1] + pt2_seg[1]) / 2, (pt1_seg[2] + pt2_seg[2]) / 2);float d1 = pcl::euclideanDistance(p1, p2);	//d1=|b1-b2|float d2 = pcl::euclideanDistance(p3, p4);	//d2=|b3-b4|float r1 = pcl::euclideanDistance(p1, p5) / d1;	//r1=|b1-e| / |b1-b2|float r2 = pcl::euclideanDistance(p3, p5) / d2;	//r2=|b3-e| / |b3-b4|std::cout << d1 << " " << d2 << " " << r1 << " " << r2 <<  std::endl;std::vector<std::pair<pcl::PointXYZ, pcl::PointXYZ>> R1, R2;for (size_t i = 0; i < target_cloud->size(); i++){pcl::PointXYZ pt1 = target_cloud->points[i];for (size_t j = i + 1; j < target_cloud->size(); j++){pcl::PointXYZ pt2 = target_cloud->points[j];if (pcl::euclideanDistance(pt1, pt2) > d1 * (1 - delta) && pcl::euclideanDistance(pt1, pt2) < d1 * (1 + delta)){R1.push_back(std::pair<pcl::PointXYZ, pcl::PointXYZ>(pt1, pt2));}else if (pcl::euclideanDistance(pt1, pt2) > d2 * (1 - delta) && pcl::euclideanDistance(pt1, pt2) < d2 * (1 + delta)){R2.push_back(std::pair<pcl::PointXYZ, pcl::PointXYZ>(pt1, pt2));}}}std::cout << R1.size() << " " << R2.size() << std::endl;std::vector<std::pair<float, std::vector<pcl::PointXYZ>>> Map1, Map2;pcl::PointCloud<pcl::PointXYZ>::Ptr pts1(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ>::Ptr pts2(new pcl::PointCloud<pcl::PointXYZ>);for (auto r : R1){pcl::PointXYZ p1, p2; p3;p1 = r.first;p2 = r.second;p3 = pcl::PointXYZ(p1.x + r1 * (p2.x - p1.x), p1.y + r1 * (p2.y - p1.y), p1.z + r1 * (p2.z - p1.z));Map1.push_back(std::pair<float, std::vector<pcl::PointXYZ>>(r1, { p1, p2, p3 }));pts1->push_back(p3);}for (auto r : R2){pcl::PointXYZ p1, p2; p3;p1 = r.first;p2 = r.second;p3 = pcl::PointXYZ(p1.x + r2 * (p2.x - p1.x), p1.y + r2 * (p2.y - p1.y), p1.z + r2 * (p2.z - p1.z));Map2.push_back(std::pair<float, std::vector<pcl::PointXYZ>>(r2, { p1, p2, p3 }));pts2->push_back(p3);}pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);kdtree->setInputCloud(pts1);std::vector<Points4> Uvec;for (size_t i = 0; i < pts2->size(); i++){std::vector<int> indices;std::vector<float> distance;if (kdtree->radiusSearch(pts2->points[i], 0.001 * d_max, indices, distance) > 0){for (int indice: indices){Points4 points4;points4.p1 = Map1[indice].second[0];points4.p2 = Map1[indice].second[1];points4.p3 = Map2[i].second[0];points4.p4 = Map2[i].second[1];Uvec.push_back(points4);//points4.p1 = Map1[indice].second[1];//points4.p2 = Map1[indice].second[0];//points4.p3 = Map2[i].second[0];//points4.p4 = Map2[i].second[1];//Uvec.push_back(points4);//points4.p1 = Map1[indice].second[0];//points4.p2 = Map1[indice].second[1];//points4.p3 = Map2[i].second[1];//points4.p4 = Map2[i].second[0];//Uvec.push_back(points4);//points4.p1 = Map1[indice].second[1];//points4.p2 = Map1[indice].second[0];//points4.p3 = Map2[i].second[1];//points4.p4 = Map2[i].second[0];//Uvec.push_back(points4);}}}std::cout << Uvec.size() << std::endl;int max_count = 0;Eigen::Matrix4f transformation;kdtree->setInputCloud(target_cloud);for (int i = 0; i < Uvec.size(); i++){//if (i % 1000 == 0 && i> 0)	//std::cout << i << std::endl;pcl::PointCloud<pcl::PointXYZ>::Ptr temp(new pcl::PointCloud<pcl::PointXYZ>);temp->resize(4);temp->points[0] = Uvec[i].p1;temp->points[1] = Uvec[i].p2;temp->points[2] = Uvec[i].p3;temp->points[3] = Uvec[i].p4;Eigen::Vector4f pts1_centroid, pts2_centroid;pcl::compute3DCentroid(*four_points, pts1_centroid);pcl::compute3DCentroid(*temp, pts2_centroid);Eigen::MatrixXf pts1_cloud, pts2_cloud;pcl::demeanPointCloud(*four_points, pts1_centroid, pts1_cloud);pcl::demeanPointCloud(*temp, pts2_centroid, pts2_cloud);Eigen::MatrixXf W = (pts1_cloud * pts2_cloud.transpose()).topLeftCorner(3, 3);Eigen::JacobiSVD<Eigen::MatrixXf> svd(W, Eigen::ComputeFullU | Eigen::ComputeFullV);Eigen::Matrix3f V = svd.matrixV(), U = svd.matrixU();if (U.determinant() * V.determinant() < 0){for (int x = 0; x < 3; ++x)V(x, 2) *= -1;}Eigen::Matrix3f R = V * U.transpose();Eigen::Vector3f T = pts2_centroid.head(3) - R * pts1_centroid.head(3);Eigen::Matrix4f H;H << R, T, 0, 0, 0, 1;//std::cout << H << std::endl;pcl::transformPointCloud(*source_cloud, *pcs_cloud, H);int count = compute_LCP(*pcs_cloud, kdtree, 0.0001 * d_max);if (count > max_count){std::cout << count << std::endl;std::cout << H << std::endl;max_count = count;transformation = H;}}pcl::transformPointCloud(*source_cloud, *pcs_cloud, transformation);pcl::io::savePCDFile("result.pcd", *pcs_cloud);return 0;
}

算法的流程基本上和原理能对得上,但是实现过程中发现该算法结果不太稳定。可能实现有些问题吧,希望有懂的大神指出来(逃~)

参考:
3D点云配准算法-4PCS(4点全等集配准算法)
点云配准–4PCS原理与应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/38844.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php 通过vendor文件 生成还原最新的composer.json

起因&#xff1a;因为历史原因&#xff0c;在本项目中composer.json基本算废了&#xff0c;没法直接使用composer管理扩展&#xff0c;今天尝试修复一下composer.json。 历史文件&#xff0c;可以看出来已经很久没有维护了&#xff0c;我们主要是恢复require的信息 {"na…

基于CNN的股票预测方法【卷积神经网络】

基于机器学习方法的股票预测系列文章目录 一、基于强化学习DQN的股票预测【股票交易】 二、基于CNN的股票预测方法【卷积神经网络】 文章目录 基于机器学习方法的股票预测系列文章目录一、CNN建模原理二、模型搭建三、模型参数的选择&#xff08;1&#xff09;探究window_size…

下代iPhone或回归可拆卸电池,苹果这操作把我看傻了

刚度过一个愉快的周末&#xff0c;苹果又双叒叕摊上事儿了。 iPhone13 系列被曝扎堆电池鼓包了。 早在去年&#xff0c;就有 iPhone13 和 iPhone14 用户反馈过类似的问题&#xff0c;表示在手机仅仅使用了一年多的时间就出现了电池鼓包的情况&#xff0c;而且还把屏幕给撑起来了…

舞会无领导:一种树形动态规划的视角

没有上司的舞会 Ural 大学有 &#x1d441; 名职员&#xff0c;编号为1∼&#x1d441;。 他们的关系就像一棵以校长为根的树&#xff0c;父节点就是子节点的直接上司。 每个职员有一个快乐指数&#xff0c;用整数 &#x1d43b;&#x1d456; 给出&#xff0c;其中1≤&…

校园卡手机卡怎么注销?

校园手机卡的注销流程可以根据不同的运营商和具体情况有所不同&#xff0c;但一般来说&#xff0c;以下是注销校园手机卡的几种常见方式&#xff0c;我将以分点的方式详细解释&#xff1a; 一、线上注销&#xff08;通过手机APP或官方网站&#xff09; 下载并打开对应运营商的…

当年很多跑到美加澳写代码的人现在又移回香港?什么原因?

当年很多跑到美加澳写代码的人现在又移回香港&#xff1f;什么原因&#xff1f; 近年来&#xff0c;确实有部分曾经移民到美国、加拿大、澳大利亚等地的香港居民选择移回香港。这一现象与多种因素相关&#xff0c;主要可以归结为以下几点&#xff1a; 疫情后的环境变化&#…

【STM32】温湿度采集与OLED显示

一、任务要求 1. 学习I2C总线通信协议&#xff0c;使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集&#xff0c;并将采集的温度-湿度值通过串口输出。 任务要求&#xff1a; 1&#xff09;解释什么是“软件I2C”和“硬件I2C”&#xff1f;&#xff08;阅读野火配…

2025第13届常州国际工业装备博览会招商全面启动

常州智造 装备中国|2025第13届常州国际工业装备博览会招商全面启动 2025第13届常州国际工业装备博览会将于2025年4月11-13日在常州西太湖国际博览中心盛大举行&#xff01;目前&#xff0c;各项筹备工作正稳步推进。 60000平米的超大规模、800多家国内外工业装备制造名企将云集…

最细最有条理解析:事件循环(消息循环)是什么?进程与线程的定义、关系与差异

目录 事件循环&#xff1a;引入 一、浏览器的进程模型 1.1、什么是进程&#xff08;Process&#xff09; 1.2、什么是线程&#xff08;Thread&#xff09; 1.3、进程与线程之间的关系联系与区别 二、浏览器有哪些进程和线程 2.1、浏览器的主要进程 ①浏览器进程 ②网络…

ctfshow sqli-libs web561--web568

web561 ?id-1 or 1--?id-1 union select 1,2,3--?id-1 union select 1,(select group_concat(column_name) from information_schema.columns where table_nameflags),3-- Your Username is : id,flag4s?id-1 union select 1,(select group_concat(flag4s) from ctfshow.f…

扩展学习|风险评估和风险管理:回顾其基础上的最新进展

文献来源&#xff1a;[1]Aven, T. (2016). Risk assessment and risk management: Review of recent advances on their foundation. European journal of operational research, 253(1), 1-13. 文章简介&#xff1a;大约30-40年前&#xff0c;风险评估和管理被确立为一个科学领…

数据结构 - C/C++ - 链表

目录 结构特性 内存布局 结构样式 结构拓展 单链表 结构定义 节点关联 插入节点 删除节点 常见操作 双链表 环链表 结构容器 结构设计 结构特性 线性结构的存储方式 顺序存储 - 数组 链式存储 - 链表 线性结构的链式存储是通过任意的存储单元来存储线性…

技术分享:分布式数据库DNS服务器的架构思路

DNS是企业数字化转型的基石。伴随微服务或单元化部署的推广&#xff0c;许多用户也开始采用分布式数据库将原来的单体数据库集群服务架构拆分为大量分布式子服务集群&#xff0c;对应不同的微服务或服务单元。本文将从分布式数据库DNS服务器的架构需求、架构分析两方面入手&…

湖北大学2024年成人高考函授报名专升本市场营销专业介绍

在璀璨的学术殿堂中&#xff0c;湖北大学如同一颗璀璨的明珠&#xff0c;熠熠生辉。为了满足广大社会人士对于继续深造、提升自我、实现职业梦想的渴望&#xff0c;湖北大学特别开设了成人高等继续教育项目&#xff0c;为广大有志之士敞开了一扇通往知识殿堂的大门。 而今&…

【FFmpeg】av_write_frame函数

目录 1.av_write_frame1.1 写入pkt&#xff08;write_packets_common&#xff09;1.1.1 检查pkt的信息&#xff08;check_packet&#xff09;1.1.2 准备输入的pkt&#xff08;prepare_input_packet&#xff09;1.1.3 检查码流&#xff08;check_bitstream&#xff09;1.1.4 写入…

【创建者模式-建造者模式】

概要 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 建造者模式包含以下角色 抽象建造者类&#xff08;Builder&#xff09;&#xff1a;这个接口规定要实现复杂对象的那些部分的创建&#xff0c;并不涉及具体的部件对象的创建。具体建…

在WSL Ubuntu中启用root用户的SSH服务

在 Ubuntu 中&#xff0c;默认情况下 root 用户是禁用 SSH 登录的&#xff0c;这是为了增加系统安全性。 一、修改配置 找到 PermitRootLogin 行&#xff1a;在文件中找到 PermitRootLogin 配置项。默认情况下&#xff0c;它通常被设置为 PermitRootLogin prohibit-password 或…

一篇文章学会【node.js安装以及Vue-Cli脚手架搭建】

一.为什么搭建Vue-Cli (1).传统的前端项目结构&#xff1a; 一个项目中有许多html文件&#xff0c;每一个html文件都是相互独立的&#xff0c; 如果需要在页面中导入一些外部依赖的组件&#xff0c;就需要在每一个html文件中都需要导入&#xff0c;非常麻烦 (2).现在的前端…

A股低开高走,近3000点,行情要启动了吗?

A股低开高走&#xff0c;近3000点&#xff0c;行情要启动了吗&#xff1f; 今天的A股&#xff0c;让人瞪目结舌了&#xff0c;你们知道是为什么吗&#xff1f;盘面上出现2个重要信号&#xff0c;一起来看看&#xff1a; 1、今天两市低开高走&#xff0c;银行板块护盘指数&…

盘古5.0,靠什么去解最难的题?

文&#xff5c;周效敬 编&#xff5c;王一粟 当大模型的竞争开始拼落地&#xff0c;商业化在B端和C端都展开了自由生长。 在B端&#xff0c;借助云计算向千行万业扎根&#xff1b;在C端&#xff0c;通过软件App和智能终端快速迭代。 在华为&#xff0c;这家曾经以通信行业起…