当前位置: 首页 > news >正文

Python实现点云基于法向量、曲率和ISS提取特征点

        今天我们分享点云的特征点提取,这是三维数据处理中的关键步骤,它有助于识别和提取点云中具有显著几何特征的关键点。以下是点云基于法向量、曲率和ISS(Intrinsic Shape Signatures)提取特征点的方法总结:

1) 法向量夹角法(Edge-Aware)
1.1核心思想  
把“表面朝向变化剧烈”当成特征。对每个点求法向量,再算它与邻域法向量的夹角 θ;θ 大即为潜在边缘或角点。

        1.2流程  
1. 读点云 → 2. K 近邻求法向量 → 3. 计算 θ 并取平均/最大值 → 4. 设阈值挑出大 θ 点 → 5. 放大并着色 → 6. 可视化。  

        1.3用途  
边缘检测、跨视角粗配准、三维重建轮廓增强。

2) 曲率法(Curvature-Saliency)
2.1核心思想  
把“局部弯曲程度高”当成特征。对每个点构造协方差矩阵 C,特征值 λ₁≥λ₂≥λ₃,曲率 κ = λ₃ /(λ₁+λ₂+λ₃);κ 大即是棱角、脊或谷。

        2.2流程  
1. 读点云 → 2. K 近邻求法向量 → 3. 算 κ → 4. 设阈值取高 κ 点 → 5. 放大着色 → 6. 可视化。  

        2.3用途  
精细三维重建、物体识别、多视角精配准。

3) ISS(Intrinsic Shape Signatures)
3.1核心思想  
在“形状固有”尺度上寻找跨视角稳定的显著点。结合局部协方差矩阵特征值差异与多尺度非极大值抑制,保证既显著又鲁棒。

        3.2流程  
1. 对每个点计算邻域协方差矩阵 → 2. 特征值分解得 λ₁,λ₂,λ₃ → 3. 设定比率阈值筛显著点 → 4. 多尺度重复 → 5. NMS 去冗余 → 6. 保留 ISS 关键点。  

        3.3用途  
三维物体识别与匹配、SLAM 定位建图、机器人导航、医学影像比对。

        一句话总结就是:法向量法看“朝向突变”,曲率法看“弯曲剧烈”,ISS 法看“跨尺度稳定”,三者互补,共同构成点云几何特征提取的“三驾马车”。

本次使用的数据依然是——————兔砸!

一、各种特征点提取程序

import open3d as o3d
import numpy as np
import time# ---------------- 工具函数 ----------------
def keypoints_to_spheres(keypoints, radius=1.0, color=[1, 0, 0]):mesh = o3d.geometry.TriangleMesh()for p in keypoints.points:sp = o3d.geometry.TriangleMesh.create_sphere(radius).translate(p)sp.paint_uniform_color(color)mesh += spreturn mesh# ---------------- KDTree 加速版本 ----------------
def extract_by_normal_fast(pcd, angle_th_deg=30, radius=0.1, max_nn=30):"""Open3D 自带 KDTree + 批量法向量夹角"""if not pcd.has_normals():pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn))# 构建 KDTree(C++ 实现)kdtree = o3d.geometry.KDTreeFlann(pcd)pts = np.asarray(pcd.points)normals = np.asarray(pcd.normals)angle_th = np.radians(angle_th_deg)mask = np.zeros(len(pts), dtype=bool)for i in range(len(pts)):[_, idx, _] = kdtree.search_radius_vector_3d(pts[i], radius)if len(idx) < 2:continuenbr_normals = normals[idx]cos_vals = np.clip(np.dot(nbr_normals, normals[i]), -1.0, 1.0)angles = np.arccos(cos_vals)if angles.mean() > angle_th:mask[i] = Truereturn pcd.select_by_index(np.where(mask)[0])def extract_by_curvature_fast(pcd, curv_th=0.1, radius=0.1, max_nn=30):"""KDTree + 批量协方差/曲率"""if not pcd.has_normals():pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn))kdtree = o3d.geometry.KDTreeFlann(pcd)pts = np.asarray(pcd.points)curvatures = np.zeros(len(pts))for i in range(len(pts)):[_, idx, _] = kdtree.search_radius_vector_3d(pts[i], radius)if len(idx) < 3:continuecov = np.cov(pts[idx].T)eigvals = np.linalg.eigh(cov)[0]curvatures[i] = eigvals[0] / (eigvals.sum() + 1e-12)return pcd.select_by_index(np.where(curvatures > curv_th)[0])def extract_by_iss(pcd, salient_radius=5, non_max_radius=5,gamma_21=0.5, gamma_32=0.5):tic = time.time()kpts = o3d.geometry.keypoint.compute_iss_keypoints(pcd, salient_radius, non_max_radius, gamma_21, gamma_32)toc = 1000 * (time.time() - tic)print(f"ISS {len(kpts.points)} keypoints, {toc:.1f} ms")return kpts# ---------------- 主菜单 ----------------
def main():file_path = "E:/CSDN/规则点云/bunny.pcd"pcd = o3d.io.read_point_cloud(file_path)if not pcd.has_points():print("加载失败!")returnprint(f"Loaded {len(pcd.points)} points")o3d.visualization.draw_geometries([pcd], window_name="Original",width = 768, height = 768,left = 150, top = 150)while True:choice = input("\n1) 法向量夹角  2) 曲率  3) ISS  4) 退出\n选择:").strip()if choice == "1":th = float(input("夹角阈值(°) 默认30:") or 30)r = float(input("搜索半径 默认0.005:") or 0.005)feature = extract_by_normal_fast(pcd, th, radius=r)elif choice == "2":th = float(input("曲率阈值 默认0.1:") or 0.1)r = float(input("搜索半径 默认0.005:") or 0.005)feature = extract_by_curvature_fast(pcd, th, radius=r)elif choice == "3":sr = float(input("salient_radius 默认0.005:") or 0.005)nr = float(input("non_max_radius 默认0.005:") or 0.005)feature = extract_by_iss(pcd, sr, nr)elif choice == "4":breakelse:print("无效选项")continueif len(feature.points) == 0:print("未提取到特征点!")continuepcd.paint_uniform_color([1, 0, 0])if choice == "3":spheres = keypoints_to_spheres(feature, radius=0.005)o3d.visualization.draw_geometries([pcd, spheres])else:feature.paint_uniform_color([0, 1, 0])pts = np.asarray(feature.points) * 1.02feature.points = o3d.utility.Vector3dVector(pts)o3d.visualization.draw_geometries([pcd, feature], window_name="特征点提取结果",width=768, height=768,left=150, top=150)if __name__ == "__main__":main()

二、各种特征点提取结果

        可以看到,点云的法向量特征被顺利的提取出来了(时长原因,其他两个没显示出来)。通过改变参数,特征点的提取会出现非常明显的变化,感兴趣的同学们可以试试。

就酱,下次见^-^

http://www.dtcms.com/a/354796.html

相关文章:

  • 【GM3568JHF】FPGA+ARM异构开发板 使用指南:显示与触摸
  • 第二章:Cesium 视图控制与相机操作
  • Java集合操作:Apache Commons Collections4启示录
  • React中优雅管理CSS变量的最佳实践
  • iOS文件管理在uni-app开发中的实战应用,多工具解决
  • 三、计算机网络与分布式系统(上)
  • Subdev与Media子系统的数据结构
  • 线程池及线程池单例模式
  • 图数据库neo4j的安装
  • Go语言数组完全指南
  • 基于Springboot的酒店房间预订系统源码
  • More Effective C++ 条款13:以by reference方式捕捉exceptions
  • [Mysql数据库] 知识点总结5
  • 【C++游记】物种多样——谓之多态
  • 49个Docker自动化脚本:覆盖全场景运维,构建高可用容器体系
  • 【C初阶】文件操作
  • Claude Code 流畅使用指南
  • java中sleep与wait的区别
  • ES基础知识
  • PostgreSQL15——常用函数
  • docker一键部署!强大的本地音乐服务器NAS-Music
  • labelme的安装
  • 数据库服务-主从同步-高可用架构MHA
  • vue的动态组件keep-alive实现组件缓存和状态保留
  • 解锁制造业增长密码:MES如何适配行业特性?
  • Linux04:
  • Electron解压缩文件
  • 【实战笔记】OCI Ubuntu 24.04 + TigerVNC + XFCE + Chrome 开机自启全记录
  • [吾爱出品] windows桌面课程表
  • Kafka 4.0 五大 API 选型指南、依赖坐标、上手示例与最佳实践