Skip to content

ISS 关键点检测

本教程展示如何检测三维形状的 ISS 关键点(keypoints)。其实现基于 Yu Zhong 在 2009 年论文《Intrinsic Shape Signatures: A Shape Descriptor for 3D Object Recognition》中提出的关键点检测模块。

ISS 显著性度量(saliency measure)基于点 pp 支撑域内各点的散布矩阵(scatter matrix)Σ(p)\boldsymbol{\Sigma}(\mathbf{p}) 的特征值分解(Eigenvalue Decomposition, EVD),即:

Σ(p)=1N∑q∈N(p)(q−μp)(q−μp)T with μp=1N∑q∈N(p)q\begin{array}{l} \boldsymbol{\Sigma}(\mathbf{p})=\frac{1}{N} \sum_{\mathbf{q} \in \mathcal{N}(\mathbf{p})}\left(\mathbf{q}-\mu_{\mathbf{p}}\right)\left(\mathbf{q}-\mu_{\mathbf{p}}\right)^{T} \quad \text { with } \\ \mu_{\mathbf{p}}=\frac{1}{N} \sum_{\mathbf{q} \in \mathcal{N}(\mathbf{p})} \mathbf{q} \end{array}

给定 Σ(p)\boldsymbol{\Sigma}(\mathbf{p}),其特征值按从大到小的顺序记为 λ1\lambda_1、λ2\lambda_2、λ3\lambda_3。在剪枝(pruning)阶段,会保留相邻两个特征值之比低于某阈值的点:

λ2(p)λ1(p)<γ12∧λ3(p)λ2(p)<γ23\frac{\lambda_{2}(\mathbf{p})}{\lambda_{1}(\mathbf{p})}<\gamma_{12} \wedge \frac{\lambda_{3}(\mathbf{p})}{\lambda_{2}(\mathbf{p})}<\gamma_{23}

这样做的理由是:避免在沿各主方向具有相似展布的点上检测关键点——在这些点上无法建立可重复的规范参考系(canonical reference frame),因此随后的描述阶段很难取得好的效果。在剩余的点中,显著性由最小特征值的大小决定:

ρ(p)≐λ3(p)\rho(\mathbf{p}) \doteq \lambda_{3}(\mathbf{p})

从而只保留沿每个主方向都有较大变化的点。检测之后,如果某点在给定邻域内具有最大的显著性值,则被视为关键点。

# Compute ISS Keypoints on ArmadilloMesh
armadillo = o3d.data.ArmadilloMesh()
mesh = o3d.io.read_triangle_mesh(armadillo.path)
mesh.compute_vertex_normals()
pcd = o3d.geometry.PointCloud()
pcd.points = mesh.vertices
tic = time.time()
keypoints = o3d.geometry.keypoint.compute_iss_keypoints(pcd)
toc = 1000 * (time.time() - tic)
print("ISS Computation took {:.0f} [ms]".format(toc))
mesh.compute_vertex_normals()
mesh.paint_uniform_color([0.5, 0.5, 0.5])
keypoints.paint_uniform_color([1.0, 0.75, 0.0])
o3d.visualization.draw_geometries([keypoints, mesh], front=[0, 0, -1.0])

tutorial_geometry_iss_keypoint_detector_2_1.png

输出:

ISS Computation took 666 [ms]
# This function is only used to make the keypoints look better on the rendering
def keypoints_to_spheres(keypoints):
spheres = o3d.geometry.TriangleMesh()
for keypoint in keypoints.points:
sphere = o3d.geometry.TriangleMesh.create_sphere(radius=0.001)
sphere.translate(keypoint)
spheres += sphere
spheres.paint_uniform_color([1.0, 0.75, 0.0])
return spheres
# Compute ISS Keypoints on Standford BunnyMesh, changing the default parameters
bunny = o3d.data.BunnyMesh()
mesh = o3d.io.read_triangle_mesh(bunny.path)
mesh.compute_vertex_normals()
pcd = o3d.geometry.PointCloud()
pcd.points = mesh.vertices
tic = time.time()
keypoints = o3d.geometry.keypoint.compute_iss_keypoints(pcd,
salient_radius=0.005,
non_max_radius=0.005,
gamma_21=0.5,
gamma_32=0.5)
toc = 1000 * (time.time() - tic)
print("ISS Computation took {:.0f} [ms]".format(toc))
mesh.compute_vertex_normals()
mesh.paint_uniform_color([0.5, 0.5, 0.5])
o3d.visualization.draw_geometries([keypoints_to_spheres(keypoints), mesh])

tutorial_geometry_iss_keypoint_detector_4_1.png

输出:

ISS Computation took 57 [ms]