首页 > 其他分享 >RANSAC(提取FPFH特征)+ICP配准

RANSAC(提取FPFH特征)+ICP配准

时间:2024-03-30 13:31:04浏览次数:24  
标签:RANSAC 配准 target sac FPFH icp pcl include

        RANSAC(Random Sample Consensus)和ICP(Iterative Closest Point)是点云配准中常用的两个算法,可以使用RANSAC进行粗配准结合ICP进行精配准。

1.FPFH特征

  1. FPFH特征

    • 定义:FPFH是一种点云特征描述子,用于表示点云中每个点的局部特征。
    • 计算过程
      1. 对于每个点,计算其法向量(通常使用最近邻点法)。
      2. 选择一个半径内的邻域(例如,以该点为中心的球体)。
      3. 对于每个邻域中的点,计算其与中心点的相对位置和法向量之间的关系。
      4. 构建直方图,将这些相对位置和法向量的关系编码为特征向量。
    • 特点
      • FPFH保留了PFH(Point Feature Histogram)的信息,但计算效率更高。
      • 它对点云的旋转、平移和尺度变换具有一定的不变性。
  2. 核心思想

    • FPFH的核心思想是将每个点的局部几何信息编码为一个紧凑的特征向量,以便在点云匹配和配准中使用。
    • 通过计算点与其邻域中其他点的关系,FPFH能够捕捉到点云的表面形状、曲率和法向量信息。
  3. 应用

    • FPFH特征通常用于点云配准的初始阶段,例如RANSAC中的粗配准。
    • 它可以帮助识别具有相似局部几何特征的点,从而估计初始的变换矩阵。

2.整体流程

  1. FPFH特征计算

    • 对于每个点,选择一个半径内的邻域(例如,以该点为中心的球体)。
    • 对于邻域中的每个点,计算其与中心点的相对位置和法向量之间的关系。
    • 在RANSAC中,我们使用FPFH特征来识别具有相似局部几何特征的点对。
    • 通过匹配FPFH特征,我们可以估计初始的变换矩阵,将源点云变换到目标点云的坐标系中。
  2. RANSAC算法(粗配准):

    • 随机选择源点云中的一组点作为初始匹配点对。
    • 在目标点云中查找与这组点最接近的点。
    • 计算两个三角形之间的变换矩阵(通常使用最小二乘法)。
    • 重复上述步骤,维护并返回重合度最高的变换。
  3. ICP算法(精配准):

    • 使用RANSAC得到的初始变换矩阵。
    • 迭代优化变换矩阵,使点云对齐。
    • ICP通过最小化点云之间的距离来优化变换矩阵。
  4. 迭代

    • 如果匹配的阈值不满足要求,继续迭代RANSAC和ICP。
    • 在每次迭代中,更新匹配点对和变换矩阵。

3.相关程序

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/ply_io.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/keypoints/iss_3d.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/search/kdtree.h> 
#include <pcl/features/3dsc.h>
#include <pcl/search/kdtree.h>
#include <pcl/filters/random_sample.h> 
#include <pcl/registration/ia_ransac.h>
#include <pcl/registration/icp.h>     
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h> 
#include <time.h> 
#include <vector>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/features/fpfh_omp.h>
#include <pcl/registration/sample_consensus_prerejective.h>
#include <Eigen/Dense>
#include<cmath>
#include <pcl/registration/registration.h>
# define pcl_isfinite(x) std::isfinite(x)
using namespace std;

typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<pcl::PointXYZ> pointcloud;
typedef pcl::PointCloud<pcl::Normal> pointnormal;
typedef pcl::PointCloud<pcl::PointXYZ> pointcloud;
typedef pcl::PointCloud<pcl::FPFHSignature33> fpfhFeature;



fpfhFeature::Ptr compute_fpfh_feature(pointcloud::Ptr input_cloud)
{
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
	//-------------------------法向量估计-----------------------
	pointnormal::Ptr normals(new pointnormal);
	pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> n;
	n.setInputCloud(input_cloud);
	n.setNumberOfThreads(8);        
	n.setSearchMethod(tree);      
	n.setKSearch(10);               
	//n.setRadiusSearch(0.01);      
	n.compute(*normals);            
	//-------------------------FPFH估计-------------------------
	fpfhFeature::Ptr fpfh(new fpfhFeature);
	pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fest;
	fest.setNumberOfThreads(8);   
	fest.setInputCloud(input_cloud);
	fest.setInputNormals(normals);  
	fest.setSearchMethod(tree);     
	fest.setKSearch(10);            
	//fest.setRadiusSearch(0.025); 
	fest.compute(*fpfh);            

	return fpfh;
}

int main(int argc, char** argv)
{

	pcl::PointCloud<PointT>::Ptr source(new pcl::PointCloud<PointT>);
	pcl::io::loadPLYFile("C:/Users/17927/Desktop/QYQ/D1-2.ply", *source);
	pcl::PointCloud<PointT>::Ptr target(new pcl::PointCloud<PointT>);
	pcl::io::loadPLYFile("C:/Users/17927/Desktop/QYQ/D1-1.ply", *target);

	clock_t start = clock();
	
	//---------------计算源点云和目标点云的FPFH----------------------
	fpfhFeature::Ptr source_fpfh = compute_fpfh_feature(source);
	fpfhFeature::Ptr target_fpfh = compute_fpfh_feature(target);

	//-------------------------SAC配准--------------------------------------------------
	pcl::SampleConsensusPrerejective<PointT, PointT, pcl::FPFHSignature33> r_sac;
	r_sac.setInputSource(source);            
	r_sac.setInputTarget(target);           
	r_sac.setSourceFeatures(source_fpfh);    
	r_sac.setTargetFeatures(target_fpfh);   
	r_sac.setCorrespondenceRandomness(5);  
	r_sac.setInlierFraction(0.5f);        
	r_sac.setNumberOfSamples(3);          
	r_sac.setSimilarityThreshold(0.1f);    
	r_sac.setMaxCorrespondenceDistance(1.0f);
	r_sac.setMaximumIterations(100);        
	pointcloud::Ptr align(new pointcloud);
	r_sac.align(*align);

	Eigen::Matrix4f sac_trans;
	sac_trans = r_sac.getFinalTransformation();
	std::cout << sac_trans << endl;
	clock_t sac_time = clock();

	//-----------------------icp配准-------------------------------------------
	pcl::PointCloud<PointT>::Ptr icp_result(new pcl::PointCloud<PointT>);
	pcl::IterativeClosestPoint<PointT, PointT> icp;
	icp.setInputSource(source);
	icp.setInputTarget(target);

	icp.setMaxCorrespondenceDistance(100);
	icp.setMaximumIterations(35);        
	icp.setTransformationEpsilon(1e-10);
	icp.setEuclideanFitnessEpsilon(0.01);
	icp.align(*icp_result, sac_trans);
	clock_t end = clock();
	cout << "total time: " << (double)(end - start) / (double)CLOCKS_PER_SEC << " s" << endl;
	cout << "sac time: " << (double)(sac_time - start) / (double)CLOCKS_PER_SEC << " s" << endl;
	cout << "icp time: " << (double)(end - sac_time) / (double)CLOCKS_PER_SEC << " s" << endl;

	cout << "ICP has converged:" << icp.hasConverged() << " score: " << icp.getFitnessScore() << endl;
	Eigen::Matrix4f icp_trans;
	icp_trans = icp.getFinalTransformation();
	cout << icp_trans << endl;
	pcl::transformPointCloud(*source, *sac_icp, icp_trans);
	pcl::io::savePLYFileASCII("sac_icp.ply", *sac_icp);

	 // -----------------点云可视化--------------------------
	boost::shared_ptr<pcl::visualization::PCLVisualizer>
		viewer_final(new pcl::visualization::PCLVisualizer("配准结果"));
	viewer_final->setBackgroundColor(0, 0, 0);  

	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>
		target_color(target, 255, 0, 0);
	viewer_final->addPointCloud<pcl::PointXYZ>(target, target_color, "target cloud");
	viewer_final->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,
		1, "target cloud");
	
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>
		output_color(sac_icp, 0, 0, 255);
	viewer_final->addPointCloud<pcl::PointXYZ>(icp_result, output_color, "output cloud");
	viewer_final->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,
		1, "output cloud");

	while (!viewer_final->wasStopped())
	{
		viewer_final->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}

	return (0);
}






4.实验结果

标签:RANSAC,配准,target,sac,FPFH,icp,pcl,include
From: https://blog.csdn.net/m0_71596228/article/details/137079328

相关文章

  • ViewPager2 FragmentManager is already executing transactions
    一、概述双层Fragment+ViewPager2嵌套来回切换导致如下异常ViewPager2FragmentManagerisalreadyexecutingtransactions 二、解决办法FragmentStateAdapter的默认构造函数使用的是:publicFragmentStateAdapter(@NonNullFragmentActivityfragmentActivity......
  • ArcGIS Desktop使用入门(二)常用工具条——地理配准
    系列文章目录ArcGISDesktop使用入门(一)软件初认识ArcGISDesktop使用入门(二)常用工具条——标准工具ArcGISDesktop使用入门(二)常用工具条——编辑器ArcGISDesktop使用入门(二)常用工具条——数据驱动页面ArcGISDesktop使用入门(二)常用工具条——基础工具ArcGISDesktop......
  • 【IT老齐070】@Transactional注意
    【IT老齐070】@Transactional注意场景原因经过对比排查,在支付数据原始数据报文中,由于X行上报数据中的存在备选日期(字符串类型)字段,上报后包含隐藏字符,导致生成任务时无法按预期解析,抛出ParseException导致批处理流程中断@Transactional注解的特性是方法执行成功自动......
  • 安装图形化界面时候报错 Transaction check error: file /boot/efi/EFI/centos from
    报错Transactioncheckerror:file/boot/efi/EFI/centosfrominstalloffwupdate-efi-12-5.el7.centos.x86_64conflictswithfilefrompackagegrub2-common-1:2.02-0.65.el7.centos.2.noarch如果在安装过程出现类似这种错误:Transactioncheckerror:file/boot/efi/EFI......
  • @Transactional注解失效场景以及解决方法
    该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点面试官:说一说@Transactional注解失效的场景以及解决方法@Transactional是Spring框架提供的一个注解,用于声明事务的边界。它可以应用于类、方法或接口上,用于指定......
  • 关于并发编程一些问题与解决--事务回滚@Transactional
    先贴一下代码吧@Transactional@OverridepublicintupSunp(Integera_id){//查询数据库QueryWrapper<Animal>animalQueryWrapper=newQueryWrapper<>();animalQueryWrapper.eq("a_id",a_id);Animalanima......
  • @Transactional底层实现和失效场景
    本文介绍下@Transactional底层实现和哪些场景会导致其失效当使用@Transactional注解标注一个方法时,springboot会在运行时生成一个代理对象,该代理对象拦截被注解的方法调用,并在方法调用前后进行事务管理。事务管理包括开启事务、提交事务或者回滚事务等操作。@Transactional实现......
  • ENVI CLASSIC进行几何配准
        遥感图像的几何纠正是指消除影像中的几何形变,产生一幅符合某种地图投影或图形表达要求的新影像。一般常见的几何纠正有从影像到地图的纠正,以及从影像到影像的纠正,后者也称为影像的配准。遥感影像中需要改正的几何形变主要来自相机系统误差、地形起伏、地球曲率以及......
  • service层设置手动事务回滚,原因@Transactional事务与try{}catch(){}会失效,导事务不回
     1、原因是这样的,在service层的方法中,需要执行多条update或insert的数据操作,service的方法上是加@Transactional(rollbackFor=Exception.class)注解,然后方法体中又用了try{}catch(){}操作,导致在update多个执行时,其中有一条sql报错,本应该执行事务回滚操作报错前的update都不应......
  • UVM - 6 (Transaction Modeling)
    内容uvm_sequence_item是transaction的基类可以使用uvm_sequence_item和uvm_transaction对数据进行建模什么是事务(transaction)?总线协议可以认为是一个事务UVM数据流testcase一般不产生数据,通常进行configsequencer会产生激励给到driver,传递的就是transaction......