Python点云处理(五)点云特征点/关键点提取算法(上)

目录

  • 0 简述
  • 1 基于密度的点云关键点提取
  • 2 基于曲率的点云关键点提取

0 简述

上一篇介绍了几种常见的点云下采样算法,这些算法得到的点云都不会强化特征,因为其计算原理要么是随机要么是根据格网或半径方式。

点云关键点提取是指从一个点云数据集中提取出一些重要的点,以便用于后续的点云分析和处理。
在点云处理中,关键点通常包括高曲率点、边缘点、拐角点等。这些点具有重要的特征信息,可以用于描述点云的局部形状和结构。
点云关键点提取的方法主要有两种:基于特征的方法和基于密度的方法。
基于特征的方法是利用点云中的曲率、表面法向量等特征来提取关键点,而基于密度的方法则是通过计算点云中每个点周围的密度来提取关键点。
在实际应用中,点云关键点提取通常是点云处理的第一步,它可以用于点云配准、建模、分割等各种应用场景。对于不同的应用场景和需求,需要选择适合的关键点提取方法和参数。

本篇先介绍基于曲率和密度的特征点提取实现方法,下一篇介绍比较经典的ISS关键点和harris关键点的实现方法

1 基于密度的点云关键点提取

首先根据点云k邻域范围内的邻域点间距来代表局部点云密度:

import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud(path)
point = np.asarray(pcd.points)
kdtree = o3d.geometry.KDTreeFlann(pcd)
point_size = point.shape[0]
density = np.zeros((point_size))
for i in range(point_size):
    [_, idx, dis] = kdtree.search_knn_vector_3d(point[i], 10)
    density[i] = np.mean(dis)

接着设置一个距离阈值,比如5cm。点的密度间距小于这个阈值的点被认为是特征明显的区域,其余的为不明显区域(或者根据需要相反)。
对特征明显区域和不明显区域分别采样,采样数分别为S * (1 – U),S * U。S为目标采样数,U为采样均匀性。

N = 5  # 自定义参数值(每N个点采样一次)
C = 10  # 自定义参数值(采样均匀性>N)
point_high = point[np.where(density <= dis_thre)]
point_low = point[np.where(density > dis_thre)]
pcd_high = o3d.geometry.PointCloud()
pcd_high.points = o3d.utility.Vector3dVector(point_high)
pcd_low = o3d.geometry.PointCloud()
pcd_low.points = o3d.utility.Vector3dVector(point_low)
pcd_high_down = o3d.geometry.PointCloud.uniform_down_sample(pcd_high, N)
pcd_low_down = o3d.geometry.PointCloud.uniform_down_sample(pcd_low, C)
pcd_finl = o3d.geometry.PointCloud()
pcd_finl.points = o3d.utility.Vector3dVector(np.concatenate((np.asarray(pcd_high_down.points),
							np.asarray(pcd_low_down.points))))

2 基于曲率的点云关键点提取

曲率下采样就是在点云曲率越大的地方,采样点个数越多。一种简单有效的曲率下采样实现方法如下:

  1. 通过该方法近似达到曲率的效果同时提高计算效率:计算每个点K邻域,然后计算点到邻域点的法线夹角值。曲率越大的地方,这个夹角值就越大。
  2. 设置一个角度阈值,比如5度。点的邻域夹角值大于这个阈值的点被认为是特征明显的区域,其余的为不明显区域。
  3. 均匀采样特征明显区域和不明显区域,采样数分别为S * (1 – U),S * U。S为目标采样数,U为采样均匀性。

该采样方法的特点:

  • 几何特征越明显的区域,采样点个数分布越多
  • 计算效率高
  • 采样点局部分布是均匀的
  • 稳定性高:通过几何特征区域的划分,使得采样结果抗噪性更强
def vector_angle(x, y):
	Lx = np.sqrt(x.dot(x))
	Ly = (np.sum(y ** 2, axis=1)) ** (0.5)
	cos_angle = np.sum(x * y, axis=1) / (Lx * Ly)
	angle = np.arccos(cos_angle)
	angle2 = angle * 360 / 2 / np.pi
	return angle2

knn_num = 10  # 自定义参数值(邻域点数)
angle_thre = 30  # 自定义参数值(角度值)
N = 5  # 自定义参数值(每N个点采样一次)
C = 10  # 自定义参数值(采样均匀性>N)

pcd = o3d.io.read_point_cloud(path)
point = np.asarray(pcd.points)
point_size = point.shape[0]
tree = o3d.geometry.KDTreeFlann(pcd)
o3d.geometry.PointCloud.estimate_normals(
	pcd, search_param=o3d.geometry.KDTreeSearchParamKNN(knn=knn_num))
normal = np.asarray(pcd.normals)
normal_angle = np.zeros((point_size))
for i in range(point_size):
	[_, idx, dis] = tree.search_knn_vector_3d(point[i], knn_num + 1)
	current_normal = normal[i]
	knn_normal = normal[idx[1:]]
	normal_angle[i] = np.mean(vector_angle(current_normal, knn_normal))
	
point_high = point[np.where(normal_angle >= angle_thre)]
point_low = point[np.where(normal_angle < angle_thre)]
pcd_high = o3d.geometry.PointCloud()
pcd_high.points = o3d.utility.Vector3dVector(point_high)
pcd_low = o3d.geometry.PointCloud()
pcd_low.points = o3d.utility.Vector3dVector(point_low)
pcd_high_down = o3d.geometry.PointCloud.uniform_down_sample(pcd_high, N)
pcd_low_down = o3d.geometry.PointCloud.uniform_down_sample(pcd_low, C)
pcd_finl = o3d.geometry.PointCloud()
pcd_finl.points = o3d.utility.Vector3dVector(np.concatenate((np.asarray(pcd_high_down.points),
							np.asarray(pcd_low_down.points))))

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年11月13日
下一篇 2023年11月13日

相关推荐