Advertisement

D Point Cloud Registration Using Deformable Partitions

阅读量:

作者:禅与计算机程序设计艺术

1.简介

分形分解方法的主要思路是在现有点云数据的基础上构建一种层次化结构体系,在这种体系中采用树形布局来表征原始点云数据中的密集区域特征,并将层次间的过渡关系转化为稀疏区域分布的表现形式;其中树根节点对应于整体网格的空间分布特征;具体而言,在这一过程中我们主要利用局部变形操作(即通过局部空间位置调整实现形态转换)与全局几何变换手段相结合的方式来进行分割过程的设计;最终能够实现对复杂场景下的高精度点云配准目标的达成

本文将应用基于分形分解的技术来解决三维点云配准问题,并通过变分形式的优化方法实现配准过程的精确求解。

2.基本概念术语说明

2.1 点云配准

点云配准(Point Cloud Registration)旨在匹配两组不同点云之间的对应关系,并以此为基础帮助恢复或解读这些空间信息。该技术不仅适用于精确定位场景中的物体(如环境模型的建立和单目相机校准过程),还广泛应用于多个计算机视觉领域的关键任务。这些任务包括图像重建、对象跟踪、手势识别以及语义分割等。

2.2 分形分解

分形分解(Fractal decomposition)是一种通过分析原始点云的几何属性及其采样密度来构建类似规则形状(如正多边形或椭圆)的网格系统的方法。该系统能够根据网格内部区域的不同特性进行层次划分,并基于这些特征对点云进行细分。由于其内部区域具有光滑表面特性,在模拟真实世界的物理现象方面表现出良好的效果。该方法已在计算机图形学、数字动画、超分辨率成像以及生物信息学等多个领域得到广泛应用

2.3 概念

2.3.1 变分形式

变分方法(Variational method)是数值分析领域中的一种优化问题形式

2.3.2 特征选择

在机器学习领域中,特征选择被视为一个核心环节。在点云配准问题中,输入的数据通常是无序的三维点云,在直接作为特征使用方面存在挑战。为了有效提取有用的信息,在该过程的目标是从原始数据中提取关键信息,并以揭示数据集中的潜在模式和关系为目标。常用的解决方法包括标准化处理、线性降维技术、主成分分析以及核方法的应用等

2.4 符号说明

  • \mathbf{X}:待匹配的两个点云集合{\mathbf{X}_i}_{i=1}^{m}{\mathbf{Y}}_{j=1}^{n},其中\mathbf{X}_i为第i个点云,m为第一个点云集合的数量,\mathbf{Y}为第二个点云。
  • p_i,\cdots,p_{N_i}:第i个点云的N_i个点的坐标(x_i^k,y_i^k,z_i^k)构成的集合。k=1,\cdots,N_i
  • \Omega:一个封闭的超球面(hyper-sphere),中心为原点,半径为R
  • \mathcal{T}(\cdot):一个非线性变换,将输入坐标映射到输出坐标。
  • f(\cdot),g(\cdot):非线性函数。

3.核心算法原理和具体操作步骤

3.1 介绍

在点云配准任务中

  1. 去除外点:消除掉不参与配准的离群点。

  2. 范围缩减:将点云范围缩小至合适的大小。

  3. 数据归一化:使点云数据满足均值为零和方差为单位阵的分布。

  4. 特征提取:提取点云中有效的特征描述,例如法向量、颜色、距离等。

  5. 特征选择:选择特征中最具代表性的那些特征,舍弃其他无关的特征。

  6. 模板匹配:在模板数据库中匹配特征描述的点云。

  7. 对齐:使得每一个点云对齐到同一个坐标系下,便于后续的配准计算。

在预处理完成后,则可以通过转化将其视为一个优化问题,以便实现精确配准目标。近期研究则提出了基于分形分解的技术,将点云数据划分为层次结构形式,并通过局部变形(即局部移动)和全局变换相结合的方式来进行分割。

本文主要利用分形分解这一技术手段来进行3D点云配准,并通过变分法的形式对配准过程进行优化求解。其基本思想在于在现有数据基础上构建了一个层次分明的树状结构模型。其中叶子节点对应原始数据密集分布的区域,而内部节点则代表了分解后得到的各种稀疏区域特征。

\begin{equation} \min_{u(\theta)} \left( \int_\Omega \left( |\nabla u(\theta) - \frac{1}{2}\epsilon^{-1}\nabla^2 u(\theta)\nabla f(a)|^2 + \frac{1}{2}|A_i|^2 \right) du(\theta) \right) \end{equation} \end{split}

复制代码
    通过对拉普拉斯方程(Laplace equation)的变分形式的推导,得到了一个新的损失函数,称作拉普拉斯损失(Laplace loss)。在实际训练过程中,对数似然损失和拉普拉斯损失可以同时使用,以提高模型的性能。
    
    
    代码解读

在处理过程中,在输入数据的基础上(input data),我们对两组点云数据分别进行了预处理步骤(preprocessing steps)。计算得出了两组相应的点集(point sets),分别为X_i=(x_i^1,\cdots,x_i^{N_i}), Y=(y_1,\cdots,y_{N_j})。随后,在进一步的数据分析阶段(data analysis stage),我们通过分形分解技术(fractal decomposition technique),将这些复杂的三维形状划分成层次结构(hierarchical structures)。

定义一个由多个基底向量构成的集合β={β_ki | k=1,2,…,K;i=1,2,…,n}。具体来说,每个符号β_ki表示第k个集合中的第i个基本向量,并且其形式为β_ki=(b_ki¹,…,b_kin¹)。

设某一点索引为i且归属第k组,则可将其视为具有位置属性x_i\in X_i以及方向向量\xi_{ik}\in \mathbb{R}^n. 并满足以下限制条件: 其中\gamma_{jk}=t(k,\vec x_i)被视为一种基函数, 构成一个权重体系. 考虑至此, 将基于上述约束关系对所有样本进行分类处理: 最终形成了一个基础矢量集合.

通过递归的方式对各点进行分组分类,并层层构建树结构,在每一层中将当前组的所有点与上一层分解所得的部分点进行结合,生成新的局部点集合。同时基于所有组的距离矩阵以及相对基矢量进行计算处理,得出权重矩阵和基矢量的更新值。这一过程持续进行直至满足终止条件:当每个子树仅包含单个节点或所有节点最终聚集成一棵完整的树时,则完成整个过程并得到整体的树型结构。最终形成的根部节点即为包含全部数据特征的关键节点位置信息...]

将树的所有叶子节点被看作一个独立的局部点集,在平面L上采用相应的局部坐标系统来表示这些局部点。这里L是一个超球面(hyper-sphere),其中c代表了该超球面的中心位置,而r则表示其半径值。在选择基矢量的过程中(或者当需要选择基矢量时),我们可以应用贪心算法以确定最优解:具体而言,在满足条件的情况下使用贪心算法来选择使得整体损失最小化的基矢量选项;这种策略能够最大限度地实现将各个数据点分配到各自对应的子区域内

在所有点都分配到局部区域之后,就可以应用变分形式的方法对整个树进行优化。首先,对于某个局部坐标\xi_{ki},设计一个表示其导数的变分形式:

\delta \xi_{ki}=\frac{d}{dt}(x_i-\sum_{l=1}^nb_{kl}\xi_{il}-\sum_{j=1}^{K-1}w_{ij}\gamma_{jk})(x_i'-\sum_{l=1}^nb_{kl}'\xi_{il}'-\sum_{j=1}^{K-1}w_{ij}'\gamma_{jk}')\ \delta\gamma_{jk}=\frac{d}{dt}(x_i-\sum_{l=1}^nb_{kl}\xi_{il}-\sum_{j=1}^{K-1}w_{ij}\gamma_{jk})(x_i'\sum_{l=1}^nb_{kl}'\xi_{il}'-\sum_{l=1}^nb_{kl}'\xi_{il}'-\sum_{j

这里,\delta表示导数,\beta表示基矢量,n表示第i个点的权重,r表示超球面L的半径。对于每个基矢量\beta_{kl},我们希望它对应于一个权重函数t(k,\vec x_i),这可以通过最小化它的负值来实现。注意,上述表达式中乘号的优先级较低,故要加括号。

除了上面给出的变分形式之外,另外一种方法就是利用马尔可夫链蒙特卡洛方法来计算上述变分形式的近似值。

随后,在对每个局部坐标进行处理时(其中每个局部坐标都被视为一个独立的控制变量),我们将其作为输入参数代入目标函数进行最小化运算(从而求得最优控制变量的估计值)。针对每一批节点数据(即每一批独立存在的节点集合),我们分别展开优化计算(逐一求解其最优点)。最后通过整体变换算法将各组优化结果汇总(并整合各组数据以形成整体解决方案),从而确定出最终的最佳配准方案。

3.2 数学原理与算法细节

3.2.1 拉普拉斯插值

拉普拉斯插值法(Lagrange interpolation)是一种较为基础的插值技术。当面对确定的一组离散点P=\{(x_i,y_i)\}_{i=1}^n时,拉普拉斯插值法能够有效重构其对应的Lagrange插值公式,即

其中,在点x处的第i阶多项式基函数为L_i(x)。即对于任何点x, 当且仅当x=x_i, L_i(x)=1, 否则为零。由此可见,在n=1时, L_i(x)=1. 而在n=2时, L_i(x) = \frac{(x - x_1)(x - x_2)}{(x_i - x_1)(x_i - x_2)}. 由此可知, 拉普拉斯插值方法存在以下缺陷:它无法完美满足邻近区域的插值要求。

3.2.2 分形分解

该方法(Fractal decomposition)通过研究原始点云的空间几何特性和采样密度分布特点,在此基础上构建类似于规则多边形或椭圆型的空间网格结构,并按照形状特征和生成顺序将点云数据划分为层次结构。由于空间单元内部呈现光滑曲面特性,从而能够较为准确地模拟真实世界中的物理现象。该方法已在多个领域得到广泛应用

3.2.3 分形分解中的局部坐标

在分形分解的过程中,在将点集分配至若干局部区域时,则可基于平面L上建立的局部坐标系来进行划分操作。对于任意一点x∈X,则其在其局部坐标系中的位置表示为ξ(x),并需满足以下约束条件:

在这里,我们采用测地线坐标系来表征区域几何特性。具体而言,在空间中任意一点x'处引入一个局部坐标\xi(x')= (\xi_1, \xi_2, \cdots, \xi_{K-1})^T(其中总共有K-1个独立变量),该变量组被用来唯一确定该点的位置关系。当所需的局部坐标的数量较少时,在L\subset M^{N}上选定一个固定基矢量,并对每个点赋予相应的局部坐标参数;而当所需的局域参数较多时,则可选取多个基矢量,并使每个基矢量对应一个权重函数f_k(k=1,2,\cdots,K);随后通过这组权重函数对点云进行分解分析。

在二维空间中通常会选择两个作为基准向量,并在此基础上引入一定变化。这种变化通常表现为相对于原基准向量有一定的旋转角度或缩放比例等参数调整。具体而言,在水平和垂直方向上设置一定角度的变化即可满足需求。此外,在二维情况下也可以考虑采用水平和垂直两个基准方向作为新的基准系统。而对于三维空间,则可以选择三个基准向量(例如,在α、β、γ三个轴的方向上设置相应的基准向量)。

确定了基矢量集合之后, 从而能够得到该点的局部坐标表达式. 取定一个点 C 其在其切平面上, 则对于空间中任意一点 x, 其局部坐标表示为

\xi(x)=\xi^C(x)=e^{\alpha \phi(x)},\quad \phi(x)=\tan^{-1}(x^TC)

在本研究中,符号\alpha代表基本矢量的模,在该研究中定义了点x相对于该切平面上的位置关系。对于任意给定的函数\phi(x)而言,在该切平面上的位置参数被定义为其方位角。而符号C则代表该切平面的交汇点位置。

我们可以采用拉普拉斯插值法来将点分配至特定区域。
每个局部坐标的处理均通过一次拉普拉斯插值完成。
给定点x及其对应的局部坐标,则该点所在的位置由这些坐标决定。
具体位置则可通过在两个基矢量端点之间的简单线性插值来确定。
当该点的局部坐标位于两个基矢量所界定的区间时,则可将其赋以对应区间内各端点处的平均局

3.2.4 计算量度

假设在以下情况下对一张具有宽度W和高度H的图片进行配准,并使用K个基矢量进行处理,则该过程的时间复杂度大致为

3.2.5 基于变分形式的优化算法

基于给定的一组基矢量,我们可以通过将优化问题描述为一个非线性泛函的变分问题来求解。

这里,\theta表示参数,a表示源点云的值,\nabla u(\theta)表示变形场,f(x+\nabla u(\theta))表示变形后的点云的值,\epsilon表示噪声级别,n_i表示点云的权重,L(x',\psi_{\mu}(A_i),\epsilon,n_i,\sigma)表示局部损失,\sigma表示局部损失的截断阈值,b_{ki}表示基矢量。

为了解决优化问题的解满足实际需求而受限的问题,在变分形式中应施加进一步约束于积分区域上的行为特性。

其中,\rho>0表示各点云的点数比例,\omega_i是噪声强度,由局部损失来保证。

为了对上述优化问题进行求解, 可以采用基于梯度下降法的迭代算法, 或者采用其他基于概率的优化方法。

3.3 代码示例

复制代码
    import numpy as np
    from scipy import optimize
    
    class DeformableRegistration():
    
    def __init__(self):
        pass
    
    def _weight_matrix(self, xi, psi_list, epsilon, sigma):
    
        N = len(psi_list)
        W = np.zeros((N,len(xi)))
    
        for i in range(N):
            W[i,:] = self._local_loss(xi, psi_list[i], epsilon, sigma)**(-1)*np.sqrt(np.linalg.norm(xi-psi_list[i]))
    
        return W
    
    def _local_loss(self, xi, psi, epsilon, sigma):
    
        r_sqr = (xi - psi).dot(xi - psi)
        phi_sqr = np.arctan(r_sqr*epsilon**-1)/np.pi
    
        if phi_sqr < sigma:
    
            res = -(np.log(1-phi_sqr/sigma)+np.log(1-phi_sqr/(sigma*(1+epsilon**-1))))
    
        else:
    
            res = np.inf
    
        return res
    
    def _spline_coeff(self, xi, psi, teta):
    
        tx,ty,tz = xi
        px,py,pz = psi
        c0 = 1
        c1 = 0
        c2 = 0
        c3 = tz+(px-tx)*(tx-px)+(py-ty)*(ty-py)-(pz-tz)
        c4 = ty-(ty-py)*(ty-py)/(px-tx)-(tz-pz)*(py-ty)/(px-tx)
        c5 = pz-(py-ty)*(tz-pz)/(px-tx)-(pz-pz)*(px-tx)/(px-tx)
        c6 = -tx*(ty-py)*(tz-pz)/(px-tx)+ty*(tx-px)*(tz-pz)/(px-tx)+pz*(tx-px)*(ty-py)/(px-tx)
    
        cx = c3*((teta-np.arccos(tz/np.sqrt(tx**2+ty**2+tz**2))*np.sign(tz))/np.sin(np.arccos(tz/np.sqrt(tx**2+ty**2+tz**2))))**3
        cy = ((cx-tx)*c1-c2*(c0-cy))/(cz-c6)
        cz = (cz-c6-cy*c4-cx*c5)/(c0-cy*c1-cx*c2)
    
        return np.array([cx,cy,cz])
    
    def train(self, X, Y):
    
        # Preprocess input data
    
        # Initialize parameters
    
        while True:
    
            # Update control variables and split the point cloud into subsets based on local coordinates
    
            # Optimize each subset
    
            break
    
    def main():
    
    reg = DeformableRegistration()
    
    # Generate sample data
    m = 1000 # number of points in first cloud
    n = 1000 # number of points in second cloud
    dim = 3 # dimensionality of points
    
    mu1 = np.random.normal(size=(dim,))
    cov1 = np.eye(dim) * 0.1
    X1 = np.random.multivariate_normal(mean=mu1, cov=cov1, size=m)
    X1 += 0.1*np.random.randn(*X1.shape)
    
    mu2 = np.random.normal(size=(dim,))
    cov2 = np.eye(dim) * 0.1
    X2 = np.random.multivariate_normal(mean=mu2, cov=cov2, size=n)
    X2 += 0.1*np.random.randn(*X2.shape)
    
    # Train the model using non-linear least squares algorithm to find best transform
    params, cost = optimize.nnls(X1@X2.T, X1@Y[:,None].ravel())
    
    # Apply the trained transformation to both clouds
    Y_pred = X1@(params[:dim]).reshape((-1,1))+params[-1]*np.ones((n,1)).T
    
    if __name__ == '__main__':
    main()    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

全部评论 (0)

还没有任何评论哟~