OpenCV 4.11.0
开源计算机视觉
加载中…
搜索中…
未找到匹配项
表面匹配

详细描述

关于许可证和专利的说明

本软件中包含的方法已获得以下专利:“使用几何点对描述符和广义霍夫变换在3D场景中识别和确定3D物体姿态”,Bertram Heinrich Drost,Markus Ulrich,欧洲专利2385483(2012年11月21日),受让人:MVTec Software GmbH,81675慕尼黑(德国);“3D场景中3D物体的识别和姿态确定”,Bertram Heinrich Drost,Markus Ulrich,美国专利8830229(2014年9月9日),受让人:MVTec Software GmbH,81675慕尼黑(德国)。其他专利正在申请中。更多详情,请联系MVTec Software GmbH (info@.nosp@m.mvte.nosp@m.c.com).

请注意,这些专利(以及可能的其他专利)施加的限制独立存在,并且可能与本许可证授予的自由相冲突,本许可证指的是程序的版权,而不是其实现的任何方法的专利。必须遵守版权法和专利法才能合法地使用和重新分发本程序,本许可证的目的并非诱使您侵犯任何专利或其他财产权利主张,或质疑任何此类主张的有效性。如果您重新分发或使用本程序,则本许可证仅保护您免受版权侵权。它不能保护您免受专利侵权。因此,在您使用本程序之前,请确保您不仅在版权方面,而且在专利法方面都拥有这样做的许可。

请注意,本许可证也不应被理解为一种保证。如果您根据本许可证使用本程序,但与专利法相冲突,这并不意味着许可方会因您因专利侵权而被起诉而造成的任何损失向您退款。

表面匹配简介

能够感知3D结构的相机和类似设备越来越普遍。因此,使用深度和强度信息来匹配3D物体(或部件)对于计算机视觉至关重要。应用范围从工业控制到为视障人士指导日常行动。范围图像中的识别和姿态估计任务旨在通过将查询的3D自由形状物体与其获取的数据库进行匹配来识别和定位该物体。

从工业角度来看,使机器人能够自动定位和拾取从料箱中随机放置和定向的物体是工厂自动化中的一个重要挑战,它可以取代繁琐和繁重的体力劳动。系统应该能够识别和定位具有预定义形状的物体,并以抓取机器人拾取所需的精度估计其位置。这就是视觉引导机器人技术发挥作用的地方。类似的工具也能够引导机器人(甚至人)穿过非结构化环境,从而实现自动化导航。这些特性使点云的3D匹配成为普遍的需求。在此背景下,我将描述使用3D特征的OpenCV 3D物体识别和姿态估计算法的实现。

通过3D特征的表面匹配算法

为了实现3D匹配任务,算法的状态很大程度上基于[72],这是该领域最早提出的主要实用方法之一。该方法由从深度图像或通用点云中随机提取3D特征点、索引它们以及随后在运行时有效地查询它们组成。只考虑3D结构,并使用简单的哈希表进行特征查询。

虽然完全意识到利用良好的CAD模型结构可以实现智能点采样,但我现在将将其搁置一边,以尊重方法的普遍性(通常,此类算法不需要在CAD模型上进行训练,点云就足够了)。以下是整个算法的概述

算法概述

如上所述,该算法依赖于点对特征的提取和索引,其定义如下

\[\bf{{F}}(\bf{{m1}}, \bf{{m2}}) = (||\bf{{d}}||_2, <(\bf{{n1}},\bf{{d}}), <(\bf{{n2}},\bf{{d}}), <(\bf{{n1}},\bf{{n2}}))\]

其中\(\bf{{m1}}\)和\(\bf{{m2}}\)是模型(或场景)上选择的两个特征点,\(\bf{{d}}\)是差向量,\(\bf{{n1}}\)和\(\bf{{n2}}\)分别是\(\bf{{m1}}\)和\(\bf{m2}\)处的法向量。在训练阶段,此向量被量化并索引。在测试阶段,从场景中提取相同的特征并与数据库进行比较。通过一些技巧,例如旋转分量的分离,姿态估计部分也可以高效地进行(查看参考文献了解更多详情)。采用霍夫变换样的投票和聚类来估计物体姿态。为了对姿态进行聚类,将原始姿态假设按投票数递减的顺序排序。从最高票数开始创建一个新的聚类。如果下一个姿态假设接近现有聚类中的一个,则将该假设添加到聚类中,并将聚类中心更新为聚类中姿态假设的平均值。如果下一个假设不接近任何聚类,则它会创建一个新的聚类。邻近性测试使用平移和旋转中的固定阈值进行。平移的距离计算和平均值在3D欧几里得空间中执行,而旋转的距离计算和平均值使用四元数表示进行。聚类后,按总投票数递减的顺序对聚类进行排序,这决定了估计姿态的置信度。

此姿态将使用\(ICP\)进一步细化,以获得最终姿态。

上面介绍的PPF很大程度上取决于对3D向量之间角度的鲁棒计算。即使论文中没有报告,这样做的方法(\(\theta = cos^{-1}({\bf{a}}\cdot{\bf{b}})\)仍然在数值上不稳定。更好的方法是使用反切函数,例如

\[<(\bf{n1},\bf{n2})=tan^{-1}(||{\bf{n1} \wedge \bf{n2}}||_2, \bf{n1} \cdot \bf{n2})\]

给定PPF的物体姿态粗略计算

让我总结一下以下符号

点对特征中的变换是首先找到来自第一点的变换\(T_{m\rightarrow g}\),然后将相同的变换应用于第二个点来计算的。将每个点及其法向量变换到地面平面,使我们在与新的点对进行比较时,只需要找到一个角度。

我们现在可以简单地开始写

\[(p^i_m)^{'} = T_{m\rightarrow g} p^i_m\]

其中

\[T_{m\rightarrow g} = -t_{m\rightarrow g}R_{m\rightarrow g}\]

注意,这只是一个堆叠变换。平移分量\(t_{m\rightarrow g}\)表示为

\[t_{m\rightarrow g} = -R_{m\rightarrow g}p^i_m\]

旋转分量为

\[\theta_{m\rightarrow g} = \cos^{-1}(n^i_m \cdot {\bf{x}})\\ {\bf{R_{m\rightarrow g}}} = n^i_m \wedge {\bf{x}}\]

采用轴角表示法。注意,粗体表示向量形式。变换后,模型的特征向量被注册到地面平面X上,相对于\(x=0\)的角度称为\(\alpha_m\)。类似地,对于场景,称为\(\alpha_s\)。

类霍夫投票方案

如概述所示,在训练阶段,从模型中提取PPF(点对特征),进行量化,存储在哈希表中并建立索引。然而,在运行时,对输入场景执行类似的操作,不同之处在于这次执行的是对哈希表的相似性查找,而不是插入操作。此查找还允许我们计算场景对到地面平面的变换。在此之后,位姿的旋转分量计算简化为计算差值\(\alpha=\alpha_m-\alpha_s\)。此分量携带有关物体位姿的线索。对局部模型坐标向量和\(\alpha\)执行类霍夫投票方案。每个场景点获得的最高位姿使我们能够恢复物体位姿。

PPF匹配的源代码

// pc是加载的模型点云
// (Nx6),pcTest是加载的场景点云
// (Mx6)
ppf_match_3d::PPF3DDetector detector(0.03, 0.05);
detector.trainModel(pc);
vector<Pose3DPtr> results;
detector.match(pcTest, results, 1.0/10.0, 0.05);
cout << "位姿:" << endl;
// 打印位姿
for (size_t i=0; i<results.size(); i++)
{
Pose3DPtr pose = results[i];
cout << "位姿结果 " << i << endl;
pose->printPose();
}
Ptr< Pose3D > Pose3DPtr
定义 pose_3d.hpp:59
@ pc
定义 container_avi.private.hpp:138

通过ICP进行位姿配准

匹配过程以获得位姿而结束。然而,由于存在多个匹配点、错误假设、位姿平均等因素,这种位姿非常容易受到噪声的影响,并且很多时候都远非完美。虽然在这个阶段获得的视觉结果令人满意,但定量评估显示存在约\(~10\)度的偏差(误差),这是一个可以接受的匹配水平。很多时候,要求可能会远高于此范围,并且需要改进计算出的位姿。

此外,在典型的RGBD场景和点云中,由于场景中的可见性,3D结构只能捕获不到模型一半的内容。因此,一种能够快速准确地配准遮挡和部分可见形状的鲁棒位姿细化算法并非不切实际的愿望。

此时,一个简单的选择是使用众所周知的迭代最近点算法。然而,使用基本的ICP会导致收敛速度慢、配准不良、对离群值敏感以及无法配准部分形状。因此,它肯定不适合这个问题。出于这个原因,许多变体已被提出。不同的变体有助于位姿估计过程的不同阶段。

ICP由\(6\)个阶段组成,我对每个阶段的改进总结如下。

采样

为了提高收敛速度和计算时间,通常使用少于模型实际拥有的点数。然而,对要配准的点进行正确的采样本身就是一个问题。简单的方法是均匀采样并希望得到一个合理的子集。更智能的方法试图识别关键点,这些点被发现对配准过程有很大贡献。Gelfand等人利用协方差矩阵来约束特征空间,以便使用影响平移和旋转的一组点。这是一种巧妙的子采样方法,我将在实现中选择性地使用它。

对应点搜索

顾名思义,此步骤实际上是以最近点的方式分配数据和模型中的点。正确的分配将导致正确的位姿,而错误的分配会严重降低结果。通常,在最近邻搜索中使用KD树来提高速度。但这并非最优保证,并且很多时候会导致错误的点匹配。幸运的是,这些分配会在迭代中得到纠正。

为了克服一些局限性,Picky ICP [322]和BC-ICP(使用双唯一对应关系的ICP)是两种众所周知的方法。Picky ICP首先以传统方式找到对应关系,然后在生成的对应对中,如果多个场景点\(p_i\)被分配给同一个模型点\(m_j\),则选择对应于最小距离的\(p_i\)。另一方面,BC-ICP首先允许多个对应关系,然后通过建立双唯一对应关系来解决分配问题。它还定义了一种新的无对应关系离群值,这从本质上简化了识别离群值的流程。

作为参考,这两种方法都使用。因为P-ICP速度更快,性能损失不那么显著,所以它将成为细化对应关系的首选方法。

点对加权

在我的实现中,我目前不使用加权方案。但常见的方法包括法线兼容性*(\(w_i=n^1_i\cdot n^2_j\))或为距离更大的点对分配较低的权重(\(w=1-\frac{||dist(m_i,s_i)||_2}{dist_{max}}\))。

点对剔除

剔除是使用基于标准差的稳健估计的动态阈值进行的。换句话说,在每次迭代中,我找到Std. Dev.的MAD估计。我将其表示为\(mad_i\)。我剔除距离\(d_i>\tau mad_i\)的点对。这里\(\tau\)是剔除阈值,默认设置为\(3\)。加权在前面解释的Picky细化之前应用。

误差度量

如所述,使用点到面的线性化,如[172]中的误差度量。这既加快了配准过程又提高了收敛速度。

最小化

尽管提出了许多非线性优化器(例如 Levenberg-Marquardt),但由于上一步的线性化,位姿估计简化为求解线性方程组。我正是使用 cv::solve 以及 DECOMP_SVD 选项来实现这一点。

ICP 算法

在描述了上述步骤之后,这里我总结一下 ICP 算法的布局。

通过点云金字塔实现高效 ICP

虽然迄今为止提出的各种方法能够很好地处理一些异常值和较差的初始值,但它们需要大量的迭代次数。然而,多分辨率方案可以通过允许配准从粗略级别开始并传播到较低和更精细的级别来帮助减少迭代次数。这种方法既提高了性能,又增强了运行时间。

搜索以分层的方式通过多个级别进行。配准从模型的非常粗略的样本集开始。迭代地,点被稠密化并被搜索。在每次迭代之后,先前估计的位姿被用作初始位姿,并使用 ICP 进行细化。

可视化结果

合成数据结果

在所有结果中,位姿由 PPF 初始化,其余部分保持为:\([\theta_x, \theta_y, \theta_z, t_x, t_y, t_z]=[0]\)

使用 ICP 进行位姿细化的源代码

ICP icp(200, 0.001f, 2.5f, 8);
// 使用先前声明的 pc 和 pcTest
// 这将对 results 中包含的每个位姿进行配准
// contained in results
icp.registerModelToScene(pc, pcTest, results);
// results 现在包含细化后的位姿

结果

本节专门介绍表面匹配的结果(点对特征匹配和后续的 ICP 细化)

使用 ppf + icp 的单个青蛙模型的多个匹配

下面显示了 Mian 数据集中不同模型的匹配

Mian 数据集中不同模型的匹配

您可以在 YouTube 上查看视频

一个完整的示例

参数调整

表面匹配模块尽可能将其参数处理为相对于模型直径(轴平行边界框的直径),这使得参数独立于模型大小。这就是为什么模型和场景点云都被二次采样,以使所有点之间的最小距离为 \(RelativeSamplingStep*DimensionRange\),其中 \(DimensionRange\) 是给定维度上的距离。所有三个维度都以类似的方式进行采样。例如,如果 \(RelativeSamplingStep\) 设置为 0.05,而模型直径为 1m(1000mm),则从物体表面采样的点之间的距离大约为 50 mm。从另一个角度来看,如果采样 \(RelativeSamplingStep\) 设置为 0.05,则最多会生成 \(20x20x20 = 8000\) 个模型点(取决于模型填充体积的方式)。因此,这最多会导致 8000x8000 对。实际上,由于模型不是均匀分布在矩形棱柱体上,因此预计点要少得多。减小此值会导致更多模型点,从而产生更精确的表示。但是,请注意,现在要计算的点对特征的数量呈二次方增加,因为复杂度为 O(N^2)。这对于 32 位系统尤其是一个问题,在 32 位系统中,大型模型很容易超过可用内存。通常,对于大多数应用程序而言,0.025-0.05 范围内的值似乎足够,默认值为 0.03。(请注意,此参数与 [72] 中提出的参数有所不同。[72] 使用均匀长方体进行量化,并使用模型直径作为采样的参考。在我的实现中,长方体是矩形棱柱体,每个维度都独立量化。我不以直径为参考,而是沿各个维度进行。)

最好先去除模型中的异常值并准备一个理想的模型。这是因为异常值会直接影响相对计算并降低匹配精度。

在运行时阶段,场景再次通过 \(RelativeSamplingStep\) 进行采样,如上所述。但是这次,只有一部分场景点用作参考。这部分由参数 \(RelativeSceneSampleStep\) 控制,其中 \(SceneSampleStep = (int)(1.0/RelativeSceneSampleStep)\)。换句话说,如果 \(RelativeSceneSampleStep = 1.0/5.0\),则二次采样的场景将再次均匀采样到点数的 1/5。此参数的最大值为 1,增加此参数也会提高稳定性,但会降低速度。同样,由于初始场景无关的相对采样,微调此参数并不是一个很大的问题。只有当模型形状均匀地占据一个体积,或者当模型形状在一个量化体积内的很小空间内被压缩时(例如,八叉树表示将有太多空单元格),这才会成为一个问题。

\(RelativeDistanceStep\) 用作散列表上离散化的步长。点对特征被量化以映射到散列表的桶中。这种离散化涉及乘法和强制类型转换为整数。理论上调整 RelativeDistanceStep 可以控制碰撞率。请注意,散列表上的更多碰撞会导致不太精确的估计。减小此参数会增加量化的影响,但会开始将不相似的点对分配到相同的 bin 中。然而,增加它会削弱对相似对进行分组的能力。通常,因为在采样阶段,训练模型点以由 RelativeSamplingStep 控制的距离均匀选择,所以 RelativeDistanceStep 预计等于此值。然而,在 0.025-0.05 范围内的值仍然是合理的。但是这一次,当模型密集时,不建议减小此值。对于噪声场景,可以增加该值以提高匹配对噪声点的鲁棒性。

结构体  hashnode_i
 
结构体  hashtable_int
 
类  cv::ppf_match_3d::ICP
 此类实现了一种非常高效且鲁棒的迭代最近点 (ICP) 算法变体。其任务是将 3D 模型(或点云)与一组噪声目标数据配准。这些变体是在经过某些测试后由我本人整合的。其目标是能够快速匹配杂乱场景中部分的、含噪声的点云。您会发现,我的重点在于性能,同时保持精度。此实现基于 Tolga Birdal 在此处的 MATLAB 实现:http://www.mathworks.com/matlabcentral/fileexchange/47152-icp-registration-using-efficient-variants-and-multi-resolution-scheme 主要贡献来自:更多...
 
类  cv::ppf_match_3d::Pose3D
 类,允许存储姿态。数据结构同时存储四元数和矩阵形式。它支持 I/O 功能以及各种辅助方法来处理姿态。更多...
 
类  cv::ppf_match_3d::PoseCluster3D
 当多个姿态(参见 Pose3D)组合在一起(贡献于相同的变换)时,就会出现姿态聚类。此类是此类姿态组的通用容器。可以存储、加载和执行这些姿态的 I/O 操作。更多...
 
类  cv::ppf_match_3d::PPF3DDetector
 类,允许加载和匹配 3D 模型。典型用法:更多...
 
结构体  THash
 结构体,保存哈希表中的一个节点。更多...
 

类型定义

typedef uint cv::ppf_match_3d::KeyType
 
typedef Ptr< Pose3Dcv::ppf_match_3d::Pose3DPtr
 
typedef Ptr< PoseCluster3Dcv::ppf_match_3d::PoseCluster3DPtr
 

函数

Mat cv::ppf_match_3d::addNoisePC (Mat pc, double scale)
 
void cv::ppf_match_3d::computeBboxStd (Mat pc, Vec2f &xRange, Vec2f &yRange, Vec2f &zRange)
 
int cv::ppf_match_3d::computeNormalsPC3d (const Mat &PC, Mat &PCNormals, const int NumNeighbors, const bool FlipViewpoint, const Vec3f &viewpoint)
 计算任意点云的法线 computeNormalsPC3d 使用平面拟合方法平滑地计算局部法线。法线通过协方差矩阵的特征向量获得,对应于最小特征值。如果提供 PCNormals 为 Nx6 矩阵,则不会进行新的分配,而是覆盖现有内存。
 
void cv::ppf_match_3d::destroyFlann (void *flannIndex)
 
void cv::ppf_match_3d::getRandomPose (Matx44d &Pose)
 
hashtable_intcv::ppf_match_3d::hashtable_int_clone (hashtable_int *hashtbl)
 
hashtable_intcv::ppf_match_3d::hashtableCreate (size_t size, size_t(*hashfunc)(uint))
 
void cv::ppf_match_3d::hashtableDestroy (hashtable_int *hashtbl)
 
void * cv::ppf_match_3d::hashtableGet (hashtable_int *hashtbl, KeyType key)
 
hashnode_icv::ppf_match_3d::hashtableGetBucketHashed (hashtable_int *hashtbl, KeyType key)
 
int cv::ppf_match_3d::hashtableInsert (hashtable_int *hashtbl, KeyType key, void *data)
 
int cv::ppf_match_3d::hashtableInsertHashed (hashtable_int *hashtbl, KeyType key, void *data)
 
void cv::ppf_match_3d::hashtablePrint (hashtable_int *hashtbl)
 
hashtable_intcv::ppf_match_3d::hashtableRead (FILE *f)
 
int cv::ppf_match_3d::hashtableRemove (hashtable_int *hashtbl, KeyType key)
 
int cv::ppf_match_3d::hashtableResize (hashtable_int *hashtbl, size_t size)
 
int cv::ppf_match_3d::hashtableWrite (const hashtable_int *hashtbl, const size_t dataSize, FILE *f)
 
void * cv::ppf_match_3d::indexPCFlann (Mat pc)
 
Mat cv::ppf_match_3d::loadPLYSimple (const char *fileName, int withNormals=0)
 加载 PLY 文件。
 
static uint cv::ppf_match_3d::next_power_of_two (uint value)
 向上舍入到下一个 2 的幂。
 
Mat cv::ppf_match_3d::normalizePCCoeff (Mat pc, float scale, float *Cx, float *Cy, float *Cz, float *MinVal, float *MaxVal)
 
void cv::ppf_match_3d::queryPCFlann (void *flannIndex, Mat &pc, Mat &indices, Mat &distances)
 
void cv::ppf_match_3d::queryPCFlann (void *flannIndex, Mat &pc, Mat &indices, Mat &distances, const int numNeighbors)
 
Mat cv::ppf_match_3d::samplePCByQuantization (Mat pc, Vec2f &xrange, Vec2f &yrange, Vec2f &zrange, float sample_step_relative, int weightByCenter=0)
 
Mat cv::ppf_match_3d::samplePCUniform (Mat PC, int sampleStep)
 
Mat cv::ppf_match_3d::samplePCUniformInd (Mat PC, int sampleStep, std::vector< int > &indices)
 
Mat cv::ppf_match_3d::transformPCPose (Mat pc, const Matx44d &Pose)
 
Mat cv::ppf_match_3d::transPCCoeff (Mat pc, float scale, float Cx, float Cy, float Cz, float MinVal, float MaxVal)
 
void cv::ppf_match_3d::writePLY (Mat PC, const char *fileName)
 将点云写入PLY文件。
 
void cv::ppf_match_3d::writePLYVisibleNormals (Mat PC, const char *fileName)
 用于调试目的,将点云及其法向量顶点(以红色显示)写入PLY文件。
 

类型定义文档

◆ KeyType

◆ Pose3DPtr

◆ PoseCluster3DPtr

函数文档

◆ addNoisePC()

Mat cv::ppf_match_3d::addNoisePC ( Mat pc,
double scale )
Python
cv.ppf_match_3d.addNoisePC(pc, scale) -> retval

#include <opencv2/surface_matching/ppf_helpers.hpp>

向输入点云添加给定比例的均匀噪声。

参数
[in]pc输入点云 (CV_32F 类型)。
[in]scale输入噪声比例。比例越大,输出越噪。

◆ computeBboxStd()

void cv::ppf_match_3d::computeBboxStd ( Mat pc,
Vec2f & xRange,
Vec2f & yRange,
Vec2f & zRange )

◆ computeNormalsPC3d()

int cv::ppf_match_3d::computeNormalsPC3d ( const Mat & PC,
Mat & PCNormals,
const int NumNeighbors,
const bool FlipViewpoint,
const Vec3f & viewpoint )
Python
cv.ppf_match_3d.computeNormalsPC3d(PC, NumNeighbors, FlipViewpoint, viewpoint[, PCNormals]) -> retval, PCNormals

#include <opencv2/surface_matching/ppf_helpers.hpp>

计算任意点云的法线 computeNormalsPC3d 使用平面拟合方法平滑地计算局部法线。法线通过协方差矩阵的特征向量获得,对应于最小特征值。如果提供 PCNormals 为 Nx6 矩阵,则不会进行新的分配,而是覆盖现有内存。

参数
[in]PC要计算法向量的输入点云。
[out]PCNormals输出点云
[in]NumNeighbors要考虑的局部区域中的邻居数量
[in]FlipViewpoint是否应将法线翻转到观察方向?
[in]viewpoint
返回值
成功返回 0

◆ destroyFlann()

void cv::ppf_match_3d::destroyFlann ( void * flannIndex)

◆ getRandomPose()

void cv::ppf_match_3d::getRandomPose ( Matx44d & Pose)
Python
cv.ppf_match_3d.getRandomPose(Pose) -> None

#include <opencv2/surface_matching/ppf_helpers.hpp>

生成一个随机的 4x4 姿态矩阵。

参数
[out]Pose随机姿态

◆ hashtable_int_clone()

hashtable_int * cv::ppf_match_3d::hashtable_int_clone ( hashtable_int * hashtbl)

◆ hashtableCreate()

hashtable_int * cv::ppf_match_3d::hashtableCreate ( size_t size,
size_t(* hashfunc )(uint) )

◆ hashtableDestroy()

void cv::ppf_match_3d::hashtableDestroy ( hashtable_int * hashtbl)

◆ hashtableGet()

void * cv::ppf_match_3d::hashtableGet ( hashtable_int * hashtbl,
KeyType key )

◆ hashtableGetBucketHashed()

hashnode_i * cv::ppf_match_3d::hashtableGetBucketHashed ( hashtable_int * hashtbl,
KeyType key )

◆ hashtableInsert()

int cv::ppf_match_3d::hashtableInsert ( hashtable_int * hashtbl,
KeyType key,
void * data )

◆ hashtableInsertHashed()

int cv::ppf_match_3d::hashtableInsertHashed ( hashtable_int * hashtbl,
KeyType key,
void * data )

◆ hashtablePrint()

void cv::ppf_match_3d::hashtablePrint ( hashtable_int * hashtbl)

◆ hashtableRead()

hashtable_int * cv::ppf_match_3d::hashtableRead ( FILE * f)

◆ hashtableRemove()

int cv::ppf_match_3d::hashtableRemove ( hashtable_int * hashtbl,
KeyType key )

◆ hashtableResize()

int cv::ppf_match_3d::hashtableResize ( hashtable_int * hashtbl,
size_t size )

◆ hashtableWrite()

int cv::ppf_match_3d::hashtableWrite ( const hashtable_int * hashtbl,
const size_t dataSize,
FILE * f )

◆ indexPCFlann()

void * cv::ppf_match_3d::indexPCFlann ( Mat pc)

◆ loadPLYSimple()

Mat cv::ppf_match_3d::loadPLYSimple ( const char * fileName,
int withNormals = 0 )
Python
cv.ppf_match_3d.loadPLYSimple(fileName[, withNormals]) -> retval

#include <opencv2/surface_matching/ppf_helpers.hpp>

加载 PLY 文件。

参数
[in]fileName要读取的PLY模型。
[in]withNormals输入PLY是否包含法线信息,以及是否应该加载法线信息的标志。
返回值
加载成功返回矩阵。

◆ next_power_of_two()

static uint cv::ppf_match_3d::next_power_of_two ( uint value)
inlinestatic

◆ normalizePCCoeff()

Mat cv::ppf_match_3d::normalizePCCoeff ( Mat pc,
float scale,
float * Cx,
float * Cy,
float * Cz,
float * MinVal,
float * MaxVal )

◆ queryPCFlann() [1/2]

void cv::ppf_match_3d::queryPCFlann ( void * flannIndex,
Mat & pc,
Mat & indices,
Mat & distances )

◆ queryPCFlann() [2/2]

void cv::ppf_match_3d::queryPCFlann ( void * flannIndex,
Mat & pc,
Mat & indices,
Mat & distances,
const int numNeighbors )

◆ samplePCByQuantization()

Mat cv::ppf_match_3d::samplePCByQuantization ( Mat pc,
Vec2f & xrange,
Vec2f & yrange,
Vec2f & zrange,
float sample_step_relative,
int weightByCenter = 0 )
Python
cv.ppf_match_3d.samplePCByQuantization(pc, xrange, yrange, zrange, sample_step_relative[, weightByCenter]) -> retval

#include <opencv2/surface_matching/ppf_helpers.hpp>

使用均匀步长对点云进行采样

参数
[in]pc输入点云
[in]xrange模型边界框的X分量(最小值和最大值)
[in]yrange模型边界框的Y分量(最小值和最大值)
[in]zrange模型边界框的Z分量(最小值和最大值)
[in]sample_step_relative对点云进行采样,使得所有点都具有某个最小距离。此最小距离使用参数sample_step_relative相对确定。
[in]weightByCenter量化数据点的贡献可以按到原点的距离加权。此参数启用/禁用权重的使用。
返回值
采样后的点云

◆ samplePCUniform()

Mat cv::ppf_match_3d::samplePCUniform ( Mat PC,
int sampleStep )

◆ samplePCUniformInd()

Mat cv::ppf_match_3d::samplePCUniformInd ( Mat PC,
int sampleStep,
std::vector< int > & indices )

◆ transformPCPose()

Mat cv::ppf_match_3d::transformPCPose ( Mat pc,
const Matx44d & Pose )
Python
cv.ppf_match_3d.transformPCPose(pc, Pose) -> retval

#include <opencv2/surface_matching/ppf_helpers.hpp>

使用给定的4x4齐次位姿矩阵(双精度)变换点云

参数
[in]pc输入点云 (CV_32F 系列)。预期每行具有 3 或 6 个元素的点云。如果提供了法线,则它们也会旋转以与整个变换兼容。
[in]Pose4x4 位姿矩阵,但以行主序形式线性化。
返回值
变换后的点云

◆ transPCCoeff()

Mat cv::ppf_match_3d::transPCCoeff ( Mat pc,
float scale,
float Cx,
float Cy,
float Cz,
float MinVal,
float MaxVal )

◆ writePLY()

void cv::ppf_match_3d::writePLY ( Mat PC,
const char * fileName )
Python
cv.ppf_match_3d.writePLY(PC, fileName) -> None

#include <opencv2/surface_matching/ppf_helpers.hpp>

将点云写入PLY文件。

参数
[in]PC输入点云
[in]fileName要写入的PLY模型文件

◆ writePLYVisibleNormals()

void cv::ppf_match_3d::writePLYVisibleNormals ( Mat PC,
const char * fileName )
Python
cv.ppf_match_3d.writePLYVisibleNormals(PC, fileName) -> None

#include <opencv2/surface_matching/ppf_helpers.hpp>

用于调试目的,将点云及其法向量顶点(以红色显示)写入PLY文件。

参数
[in]PC输入点云
[in]fileName要写入的PLY模型文件