python 上的迭代最近点 (ICP) 实现

新手上路,请多包涵

我最近一直在寻找 python 中 ICP 算法的实现,但没有结果。

根据维基百科文章 http://en.wikipedia.org/wiki/Iterative_closest_point ,算法步骤是:

  • 通过最近邻标准关联点(对于一个点云中的每个点,找到第二个点云中的最近点)。

  • 使用均方成本函数估计转换参数(旋转和平移)(转换会将每个点与其在上一步中找到的匹配项最佳对齐)。

  • 使用估计的参数转换点。

  • 迭代(重新关联点等)。

好吧,我知道 ICP 是一种非常有用的算法,它被用于各种应用程序。但是我找不到任何内置的 Python 解决方案。是吗,我在这里遗漏了什么?

原文由 Harry R. 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
1 个回答

最后,我设法使用 sklearn 和 opencv 库在 Python 中编写了自己的 ICP 实现。

该函数采用两个数据集,一个初始相对姿态估计和所需的迭代次数。它返回将第一个数据集转换为第二个数据集的转换矩阵。

享受!

  import cv2
 import numpy as np
 import matplotlib.pyplot as plt
 from sklearn.neighbors import NearestNeighbors

def icp(a, b, init_pose=(0,0,0), no_iterations = 13):
    '''
    The Iterative Closest Point estimator.
    Takes two cloudpoints a[x,y], b[x,y], an initial estimation of
    their relative pose and the number of iterations
    Returns the affine transform that transforms
    the cloudpoint a to the cloudpoint b.
    Note:
        (1) This method works for cloudpoints with minor
        transformations. Thus, the result depents greatly on
        the initial pose estimation.
        (2) A large number of iterations does not necessarily
        ensure convergence. Contrarily, most of the time it
        produces worse results.
    '''

    src = np.array([a.T], copy=True).astype(np.float32)
    dst = np.array([b.T], copy=True).astype(np.float32)

    #Initialise with the initial pose estimation
    Tr = np.array([[np.cos(init_pose[2]),-np.sin(init_pose[2]),init_pose[0]],
                   [np.sin(init_pose[2]), np.cos(init_pose[2]),init_pose[1]],
                   [0,                    0,                   1          ]])

    src = cv2.transform(src, Tr[0:2])

    for i in range(no_iterations):
        #Find the nearest neighbours between the current source and the
        #destination cloudpoint
        nbrs = NearestNeighbors(n_neighbors=1, algorithm='auto',
                                warn_on_equidistant=False).fit(dst[0])
        distances, indices = nbrs.kneighbors(src[0])

        #Compute the transformation between the current source
        #and destination cloudpoint
        T = cv2.estimateRigidTransform(src, dst[0, indices.T], False)
        #Transform the previous source and update the
        #current source cloudpoint
        src = cv2.transform(src, T)
        #Save the transformation from the actual source cloudpoint
        #to the destination
        Tr = np.dot(Tr, np.vstack((T,[0,0,1])))
    return Tr[0:2]

像这样称呼它:

 #Create the datasets
ang = np.linspace(-np.pi/2, np.pi/2, 320)
a = np.array([ang, np.sin(ang)])
th = np.pi/2
rot = np.array([[np.cos(th), -np.sin(th)],[np.sin(th), np.cos(th)]])
b = np.dot(rot, a) + np.array([[0.2], [0.3]])

#Run the icp
M2 = icp(a, b, [0.1,  0.33, np.pi/2.2], 30)

#Plot the result
src = np.array([a.T]).astype(np.float32)
res = cv2.transform(src, M2)
plt.figure()
plt.plot(b[0],b[1])
plt.plot(res[0].T[0], res[0].T[1], 'r.')
plt.plot(a[0], a[1])
plt.show()

原文由 Harry R. 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题