特征匹配-NNDR策略,kd树,BBF算法

本文介绍了特征匹配中的NNDR策略、最近邻和最近邻距离比率,探讨了它们在提高匹配效果上的作用。接着,详细讲解了k-d树的构建过程及其在高效匹配中的应用,特别是k-d树的最近邻搜索算法。最后,提到了BBF算法,这是一种针对k-d树回溯问题的改进方法,通过优先级队列和运行超时限定提高搜索性能。
摘要由CSDN通过智能技术生成

特征匹配需要考虑匹配策略和如何更快的完成匹配。


一:以欧式距离为度量,有三种匹配策略:固定阈值、最近邻、最近邻距离比率(NNDR)

固定阈值:就是设定一个阈值,当距离大于阈值,判为不匹配,否则判为匹配。但是一个问题是,阈值很难设定。随着移动到特征空间的不同部分时,阈值的有效范围会变化很大,即没有通用的阈值。

最近邻:找最近的那个。

最近邻距离比率:定义为最近邻距离和次近邻距离的比值。


        最近邻和NNDR策略改善了匹配效果。

——————————————————————————————————————

————————————更详细的介绍————————————————————

参考:结合NNDR与霍夫变换的匹配方法。

在建立两幅图像之间局部特征的匹配关系时,需要满唯一性、相似性、连续性三个基本约束条件,即物体表面任意一点到观察点距离是唯一的,因此其视差是唯一的,给定一副图像中的一点,其在另一幅图像中对应的匹配点最多只有一个;对应的特征应有相同的属性,在某种度量下,同一物理特征在两幅图像中具有相似的描述符;与观测点的距离相比,物体表面因凹凸不平引起的深度变化是缓慢的,因而视差变化是缓慢的,或者说视差具有连续性。


目前常用的目标匹配策略有两种:1、是距离阈值法,即待匹配目标与模型之间的距离小于某个阈值,则认为匹配上了,改方法非常简单,但是阈值的确定非常困难,而且目标很容易匹配上多个模型,从而产生大量的误匹配;2、最小距离法,即目标只匹配与其距离最近的模型,实际应用中一般还需要满足距离小于某个阈值的条件,该方法只有一个最佳的匹配结果,相对于距离阈值法来说,正确率要高。

由于图像的内容千差万别,加上场景中运动物体,不重叠内容以及图像质量等因素的存在,一副图像中的局部特征并不一定能够在另一幅图像中找到相似的特征,这就需要采取措施剔除那些产生干扰的噪声点。


3、通过对SIFT特征的研究表明,可以通过比较最近邻特征和次近邻特征的距离有效的甄别局部特征是否正确匹配。这就是最近邻距离比值法。该方法的理论来源是,如果一个特征在一副图像中与两个特征的距离都很相似,那么该特征的区分度较低,会对图像相似度的判断产生干扰。


——————————————————————————————————————

——————————————————————————————————————

二:高效完成匹配

选定匹配策略,下面要做的就是在潜在的候选中高效地进行搜索。

在PCL中,NNDR特征匹配可以使用`pcl::registration::CorrespondenceEstimation`类和`pcl::registration::CorrespondenceRejectorOneToOne`类实现。下面是一个示例代码,用于在两个点云中匹配SURF特征: ```cpp #include <pcl/registration/correspondence_estimation.h> #include <pcl/registration/correspondence_rejection_one_to_one.h> #include <pcl/features/normal_3d.h> #include <pcl/features/shot_omp.h> #include <pcl/features/board.h> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/visualization/pcl_visualizer.h> typedef pcl::PointXYZ PointT; typedef pcl::Normal NormalT; typedef pcl::SHOT352 DescriptorT; int main(int argc, char **argv) { // 加载两个点云 pcl::PointCloud<PointT>::Ptr cloud1(new pcl::PointCloud<PointT>); pcl::PointCloud<PointT>::Ptr cloud2(new pcl::PointCloud<PointT>); pcl::io::loadPCDFile<PointT>("cloud1.pcd", *cloud1); pcl::io::loadPCDFile<PointT>("cloud2.pcd", *cloud2); // 计算法线 pcl::PointCloud<NormalT>::Ptr normals1(new pcl::PointCloud<NormalT>); pcl::PointCloud<NormalT>::Ptr normals2(new pcl::PointCloud<NormalT>); pcl::NormalEstimation<PointT, NormalT> normalEstimator; normalEstimator.setInputCloud(cloud1); normalEstimator.setRadiusSearch(0.01); normalEstimator.compute(*normals1); normalEstimator.setInputCloud(cloud2); normalEstimator.compute(*normals2); // 计算SHOT特征 pcl::PointCloud<DescriptorT>::Ptr features1(new pcl::PointCloud<DescriptorT>); pcl::PointCloud<DescriptorT>::Ptr features2(new pcl::PointCloud<DescriptorT>); pcl::SHOTEstimationOMP<PointT, NormalT, DescriptorT> shotEstimator; shotEstimator.setInputCloud(cloud1); shotEstimator.setInputNormals(normals1); shotEstimator.setRadiusSearch(0.01); shotEstimator.compute(*features1); shotEstimator.setInputCloud(cloud2); shotEstimator.setInputNormals(normals2); shotEstimator.compute(*features2); // 特征匹配 pcl::registration::CorrespondenceEstimation<DescriptorT, DescriptorT> correspondenceEstimator; correspondenceEstimator.setInputSource(features1); correspondenceEstimator.setInputTarget(features2); pcl::CorrespondencesPtr correspondences(new pcl::Correspondences); correspondenceEstimator.determineCorrespondences(*correspondences); // NNDR匹配 pcl::registration::CorrespondenceRejectorOneToOne correspondenceRejector; correspondenceRejector.setInputCorrespondences(correspondences); correspondenceRejector.setThreshold(0.8); // 设置NNDR阈值 pcl::CorrespondencesPtr filteredCorrespondences(new pcl::Correspondences); correspondenceRejector.getCorrespondences(*filteredCorrespondences); // 可视化匹配结果 pcl::visualization::PCLVisualizer viewer("Correspondences"); viewer.addPointCloud(cloud1, "cloud1"); viewer.addPointCloud(cloud2, "cloud2"); viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "cloud1"); viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1, 0, "cloud2"); for (int i = 0; i < filteredCorrespondences->size(); i++) { int index1 = filteredCorrespondences->at(i).index_query; int index2 = filteredCorrespondences->at(i).index_match; std::stringstream ss; ss << "correspondence_" << i; viewer.addCorrespondence<PointT>(cloud1, cloud2, index1, index2, ss.str()); } viewer.spin(); return 0; } ``` 该代码中,我们首先加载了两个点云,然后计算了它们的法线和SHOT特征。接着,使用`CorrespondenceEstimation`类对两个点云的特征进行匹配,并得到了一组初始的匹配对。然后,使用`CorrespondenceRejectorOneToOne`类对这些匹配对进行NNDR匹配,并得到了一组筛选后的匹配对。最后,我们可以使用PCL可视化工具对匹配结果进行可视化。 需要注意的是,在进行NNDR匹配时,需要根据实际应用场景来调整阈值的取值。如果阈值过大,会导致匹配成功的对数较少;如果阈值过小,会导致误匹配的对数较多。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值