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.pswp.cn/diannao/38844.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/38844.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/38844.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

唯一ID:UUID 介紹與 google/uuid 庫生成 UUID

UUID 即通用唯一識別碼&#xff0c;是一種用于計算機系統中以確保全局唯一性的標識符。其標準定義于 RFC 4122 文檔中。標準形式包含 32 個 16 進制數字&#xff0c;以連字符切割為五組&#xff0c;格式為 8-4-4-4-12&#xff0c;總共 36 個字符。&#xff08;形如, d169aa7f-4…

php 通過vendor文件 生成還原最新的composer.json

起因&#xff1a;因為歷史原因&#xff0c;在本項目中composer.json基本算廢了&#xff0c;沒法直接使用composer管理擴展&#xff0c;今天嘗試修復一下composer.json。 歷史文件&#xff0c;可以看出來已經很久沒有維護了&#xff0c;我們主要是恢復require的信息 {"na…

K8s節點維護流程

用途 用于下線異常節點、集群縮容等 操作步驟 1. 查看節點名稱 先確認節點的名稱 kubectl get node -o wide2. 設置節點不可調度 設置節點不可調度狀態&#xff0c;禁止新的pod調度到該節點上 kubectl cordon ${node_name}3. 剔除節點上運行的pod&#xff08;生產環境慎…

Spring Boot中集成Redis實現緩存功能

Spring Boot中集成Redis實現緩存功能 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天我們將深入探討如何在Spring Boot應用程序中集成Redis&#xff0c;實現…

AP無法上線原因分析及排障

一、AP未分配到IP地址 如果遇到AP無法上線問題&#xff0c;可以檢查下AP是否分配到IP地址。AP獲取IP地址有兩種方式&#xff1a;靜態方式&#xff1a;登錄到AP設備&#xff0c;手工配置IP地址&#xff0c;該方式操作起來比較麻煩&#xff0c;不推薦使用&#xff1b;DHCP方式&am…

基于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; 下載并打開對應運營商的…

C++ 指針介紹

指針是C編程語言中的一個強大且重要的特性。它允許程序員直接操作內存地址&#xff0c;從而提供了對低級別內存的訪問和控制。雖然指針在使用時可能比較復雜且容易出錯&#xff0c;但它們在提高程序效率和靈活性方面有著不可替代的作用。本文將介紹C指針的基本概念、用法及其應…

Docker 中 MySQL 遷移策略(單節點)

目錄 一、 簡介二、操作流程2.1 進入mysql容器2.2 導出 MySQL 數據2.3. 將導出的文件復制到宿主機2.4 創建 Docker Compose 配置2.5 啟動新的 Docker 容器2.6 導入數據到新的容器2.7 驗證數據2.8 刪除舊的容器&#xff08;刪除操作需慎重&#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多家國內外工業裝備制造名企將云集…

C++中的RAII(資源獲取即初始化)原則

C中的RAII&#xff08;Resource Acquisition Is Initialization&#xff0c;資源獲取即初始化&#xff09;原則是一種管理資源、避免資源泄漏的慣用法。RAII是C之父Bjarne Stroustrup提出的設計理念&#xff0c;其核心思想是將資源的獲取&#xff08;如動態內存分配、文件句柄、…

最細最有條理解析:事件循環(消息循環)是什么?進程與線程的定義、關系與差異

目錄 事件循環&#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服務器的架構需求、架構分析兩方面入手&…