OpenCV 4.13.0
开源计算机视觉库 (Open Source Computer Vision)
正在加载...
正在搜索...
未找到匹配项
表面匹配

详细说明

关于许可证和专利的注意事项

本软件中体现的方法已获得以下专利:“使用几何点对描述符和广义霍夫变换识别和确定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匹配成为普遍的必需品。在此背景下,我将介绍OpenCV中利用3D特征实现3D物体识别和姿态估计算法。

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

为实现3D匹配任务的算法状态主要基于 [76],这是该领域最早也是主要的实用方法之一。该方法包括从深度图像或通用点云中随机提取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}\) 处的法线。在训练阶段,此向量被量化并索引。在测试阶段,从场景中提取相同的特征并与数据库进行比较。通过一些技巧,例如分离旋转分量,姿态估计部分也可以变得高效(有关更多详细信息,请查阅参考文献)。采用类似Hough的投票和聚类来估计物体姿态。为了聚类姿态,原始姿态假设按投票数量降序排列。从最高投票中创建一个新簇。如果下一个姿态假设与现有簇之一接近,则将该假设添加到该簇中,并将簇中心更新为簇内姿态假设的平均值。如果下一个假设不接近任何簇,则创建一个新簇。邻近性测试使用固定的平移和旋转阈值进行。平移的距离计算和平均在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\)。

类似Hough的投票方案

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

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 << "Poses: " << endl;
// 打印姿态
for (size_t i=0; i<results.size(); i++)
{
Pose3DPtr pose = results[i];
cout << "Pose Result " << 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 [327] 和 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}}\))。

对对进行拒绝

拒绝使用基于标准差的鲁棒估计的动态阈值。换句话说,在每次迭代中,我都会找到标准差的 MAD 估计值。我将其表示为 \(mad_i\)。我拒绝距离 \(d_i>\tau mad_i\) 的对。这里 \(\tau\) 是拒绝阈值,默认设置为 \(3\)。加权在 Picky 细化之前应用,如前一阶段所述。

误差度量

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

最小化

尽管提出了许多非线性优化器(例如 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中包含的每个姿态执行配准
// 执行配准
icp.registerModelToScene(pc, pcTest, results);
// results现在包含细化后的姿态

结果

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

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

下面展示了 Mian 数据集中不同模型的匹配结果。

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

您可以点击 此处 在 YouTube 上观看视频。

完整示例

参数调整

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

从模型中去除异常值并初步准备一个理想模型将是非常明智的。这是因为,异常值会直接影响相对计算并降低匹配精度。

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

\(RelativeDistanceStep\) 作为哈希表上的离散化步骤。点对特征被量化以映射到哈希表的桶中。这种离散化涉及乘法和转换为整数。理论上,调整 RelativeDistanceStep 控制碰撞率。请注意,哈希表上的碰撞越多,估计的准确性就越低。减小此参数会增加量化的影响,但会开始将不相似的点对分配到相同的桶中。然而,增加此参数会削弱对相似点对进行分组的能力。通常,由于在采样阶段,训练模型点以由 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
 类,允许存储姿态。数据结构存储四元数和矩阵形式。它支持IO功能以及各种辅助方法来处理姿态。 更多...
 
类  cv::ppf_match_3d::PoseCluster3D
 当多个姿态(参见 Pose3D)组合在一起(贡献于相同的变换)时,就会出现姿态簇。此类是此类姿态组的通用容器。可以存储、加载和对这些姿态执行 IO。更多...
 
类  cv::ppf_match_3d::PPF3DDetector
 类,允许加载和匹配 3D 模型。典型用法: 更多...
 
结构体  THash
 结构体,保存哈希表中的一个节点。 更多...
 

类型定义 (Typedefs)

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文件,法向量的尖端显示为可见的红点。
 

类型定义文档 (Typedef Documentation)

◆ KeyType

◆ Pose3DPtr

◆ PoseCluster3DPtr

函数文档 (Function Documentation)

◆ 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模型文件