当前位置:   article > 正文

ICP配准_o3d.pipelines.registration.registration_icp

o3d.pipelines.registration.registration_icp

 

点云配准可以分为粗配准(Coarse Registration)和精配准(Fine Registration)两步。粗配准指的是在两幅点云之间的变换完全未知的情况下进行较为粗糙的配准,目的主要是为精配准提供较好的变换初值;精配准则是给定一个初始变换,进一步优化得到更精确的变换。

整体上来看,ICP 把点云配准问题拆分成了两个子问题:

  • 找最近点
  • 找最优变换

首先把图片转为pcd格式的文件

  1. import open3d as o3d
  2. import numpy as np
  3. import copy
  4. #输入是两个点云和一个初始转换,该转换将源点云和目标点云大致对齐,输出是精确的变换,使两点云紧密对齐。
  5. #可视化帮助函数
  6. #将目标点云和源点云可视化,并通过对齐变换对其进行转换。
  7. #目标点云和源点云分别用青色和黄色绘制。两点云重叠的越紧密,对齐的结果就越好。
  8. def draw_registration_result(source, target, transformation):
  9. source_temp = copy.deepcopy(source)
  10. target_temp = copy.deepcopy(target)
  11. source_temp.paint_uniform_color([1, 0.706, 0])
  12. target_temp.paint_uniform_color([0, 0.651, 0.929])
  13. source_temp.transform(transformation)
  14. o3d.visualization.draw_geometries([source_temp, target_temp],
  15. zoom=0.4459,
  16. front=[0.9288, -0.2951, -0.2242],
  17. lookat=[1.6784, 2.0612, 1.4451],
  18. up=[-0.3402, -0.9189, -0.1996])
  19. #输入
  20. source = o3d.io.read_point_cloud("/cloud/cloud_disk/users/huh/pcb/shuixin_11_26/pcd/temp.pcd")
  21. target = o3d.io.read_point_cloud("/cloud/cloud_disk/users/huh/pcb/shuixin_11_26/pcd/test_aug.pcd")
  22. threshold = 0.02
  23. trans_init = np.asarray([[0.862, 0.011, -0.507, 0.5],
  24. [-0.139, 0.967, -0.215, 0.7],
  25. [0.487, 0.255, 0.835, -1.4],
  26. [0.0, 0.0, 0.0, 1.0]])
  27. draw_registration_result(source, target, trans_init)
  28. #该函数evaluate_registration计算两个主要指标。fitness计算重叠区域(内点对应关系/目标点数)。越高越好。inlier_rmse计算所有内在对应关系的均方根误差RMSE。越低越好。
  29. reg_p2p = o3d.pipelines.registration.registration_icp(source, target, threshold, trans_init,
  30. o3d.pipelines.registration.TransformationEstimationPointToPoint(),
  31. o3d.pipelines.registration.ICPConvergenceCriteria(max_iteration = 2000))
  32. print(reg_p2p)
  33. print("Transformation is:")
  34. print(reg_p2p.transformation)
  35. draw_registration_result(source, target, reg_p2p.transformation)

二维 ICP 配准算法具体步骤

① ICP算法简单来说就是对源点云,B点云,不停进行矩阵变换,把它变换到和目标点云,A点云,很接近就停止。

② 算法步骤:

1) 点云归一化。

2) 找到两片点云中的对应点对。

3) 根据对应点对的信息,计算得到这次的变换矩阵。

4) 变换点云。

5) 计算当前的损失。

6) 是否决定继续迭代,如果损失小于设定阈值或者达到最大迭代数停止,否则返回第1步。

icp.py

  1. import numpy as np
  2. from sklearn.neighbors import NearestNeighbors
  3. def best_fit_transform(A, B):
  4. '''
  5. Calculates the least-squares best-fit transform that maps corresponding points A to B in m spatial dimensions
  6. Input:
  7. A: Nxm numpy array of corresponding points
  8. B: Nxm numpy array of corresponding points
  9. Returns:
  10. T: (m+1)x(m+1) homogeneous transformation matrix that maps A on to B
  11. R: mxm rotation matrix
  12. t: mx1 translation vector
  13. '''
  14. assert A.shape == B.shape
  15. # get number of dimensions
  16. m = A.shape[1]
  17. # translate points to their centroids
  18. centroid_A = np.mean(A, axis=0)
  19. centroid_B = np.mean(B, axis=0)
  20. AA = A - centroid_A
  21. BB = B - centroid_B
  22. # rotation matrix
  23. H = np.dot(AA.T, BB)
  24. U, S, Vt = np.linalg.svd(H)
  25. R = np.dot(Vt.T, U.T)
  26. # special reflection case
  27. if np.linalg.det(R) < 0:
  28. Vt[m-1,:] *= -1
  29. R = np.dot(Vt.T, U.T)
  30. # translation
  31. t = centroid_B.T - np.dot(R,centroid_A.T)
  32. # homogeneous transformation
  33. T = np.identity(m+1)
  34. T[:m, :m] = R
  35. T[:m, m] = t
  36. return T, R, t
  37. def nearest_neighbor(src, dst):
  38. '''
  39. Find the nearest (Euclidean) neighbor in dst for each point in src
  40. Input:
  41. src: Nxm array of points
  42. dst: Nxm array of points
  43. Output:
  44. distances: Euclidean distances of the nearest neighbor
  45. indices: dst indices of the nearest neighbor
  46. '''
  47. assert src.shape == dst.shape
  48. neigh = NearestNeighbors(n_neighbors=1)
  49. neigh.fit(dst)
  50. distances, indices = neigh.kneighbors(src, return_distance=True)
  51. return distances.ravel(), indices.ravel()
  52. def icp(A, B, init_pose=None, max_iterations=20, tolerance=0.001):
  53. '''
  54. The Iterative Closest Point method: finds best-fit transform that maps points A on to points B
  55. Input:
  56. A: Nxm numpy array of source mD points
  57. B: Nxm numpy array of destination mD point
  58. init_pose: (m+1)x(m+1) homogeneous transformation
  59. max_iterations: exit algorithm after max_iterations
  60. tolerance: convergence criteria
  61. Output:
  62. T: final homogeneous transformation that maps A on to B
  63. distances: Euclidean distances (errors) of the nearest neighbor
  64. i: number of iterations to converge
  65. '''
  66. assert A.shape == B.shape
  67. # get number of dimensions
  68. m = A.shape[1]
  69. # make points homogeneous, copy them to maintain the originals
  70. src = np.ones((m+1,A.shape[0]))
  71. dst = np.ones((m+1,B.shape[0]))
  72. src[:m,:] = np.copy(A.T)
  73. dst[:m,:] = np.copy(B.T)
  74. # apply the initial pose estimation
  75. if init_pose is not None:
  76. src = np.dot(init_pose, src)
  77. prev_error = 0
  78. for i in range(max_iterations):
  79. # find the nearest neighbors between the current source and destination points
  80. distances, indices = nearest_neighbor(src[:m,:].T, dst[:m,:].T)
  81. # compute the transformation between the current source and nearest destination points
  82. T,_,_ = best_fit_transform(src[:m,:].T, dst[:m,indices].T)
  83. # update the current source
  84. src = np.dot(T, src)
  85. # check error
  86. mean_error = np.mean(distances)
  87. if np.abs(prev_error - mean_error) < tolerance:
  88. break
  89. prev_error = mean_error
  90. # calculate final transformation
  91. T,_,_ = best_fit_transform(A, src[:m,:].T)
  92. return T, distances, i

main.py

  1. import numpy as np
  2. import time
  3. import icp
  4. import cv2
  5. from skimage import io
  6. # Constants
  7. N = 640 # number of random points in the dataset
  8. num_tests = 100 # number of test iterations
  9. dim = 3 # number of dimensions of the points
  10. noise_sigma = .01 # standard deviation error to be added
  11. translation = .1 # max translation of the test set
  12. rotation = .1 # max rotation (radians) of the test set
  13. def rotation_matrix(axis, theta):
  14. axis = axis/np.sqrt(np.dot(axis, axis))
  15. a = np.cos(theta/2.)
  16. b, c, d = -axis*np.sin(theta/2.)
  17. return np.array([[a*a+b*b-c*c-d*d, 2*(b*c-a*d), 2*(b*d+a*c)],
  18. [2*(b*c+a*d), a*a+c*c-b*b-d*d, 2*(c*d-a*b)],
  19. [2*(b*d-a*c), 2*(c*d+a*b), a*a+d*d-b*b-c*c]])
  20. def test_best_fit():
  21. # Generate a random dataset
  22. A = np.random.rand(N, dim)
  23. total_time = 0
  24. for i in range(num_tests):
  25. B = np.copy(A)
  26. # Translate
  27. t = np.random.rand(dim)*translation
  28. B += t
  29. # Rotate
  30. R = rotation_matrix(np.random.rand(dim), np.random.rand()*rotation)
  31. B = np.dot(R, B.T).T
  32. # Add noise
  33. B += np.random.randn(N, dim) * noise_sigma
  34. # Find best fit transform
  35. start = time.time()
  36. T, R1, t1 = icp.best_fit_transform(B, A)
  37. total_time += time.time() - start
  38. # Make C a homogeneous representation of B
  39. C = np.ones((N, 4))
  40. C[:,0:3] = B
  41. # Transform C
  42. C = np.dot(T, C.T).T
  43. assert np.allclose(C[:,0:3], A, atol=6*noise_sigma) # T should transform B (or C) to A
  44. assert np.allclose(-t1, t, atol=6*noise_sigma) # t and t1 should be inverses
  45. assert np.allclose(R1.T, R, atol=6*noise_sigma) # R and R1 should be inverses
  46. print('best fit time: {:.3}'.format(total_time/num_tests))
  47. return
  48. def test_icp():
  49. temp_path = 'temp.jpg'
  50. temp_img = io.imread(temp_path)
  51. A = np.uint8(temp_img)
  52. test_aug_img_path = 'test_aug.jpg'
  53. test_aug_img = io.imread(test_aug_img_path)
  54. B = np.uint8(test_aug_img)
  55. T, distances, iterations = icp.icp(B, A, tolerance=0.000001)
  56. # T: (m+1)x(m+1) homogeneous transformation matrix that maps A on to B
  57. # R: mxm rotation matrix
  58. # t: mx1 translation vector
  59. T, R1, t1 = icp.best_fit_transform(B, A)
  60. print(T.shape)
  61. print(R1.shape)
  62. print(t1.shape)
  63. return
  64. if __name__ == "__main__":
  65. #test_best_fit()
  66. test_icp()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/122607
推荐阅读
相关标签
  

闽ICP备14008679号