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

Python实现点云投影到直线、平面、柱面和球面

        本节我们分享点云的投影计算,按直线 → 平面 → 圆柱 → 球面顺序介绍。其实无论投影到哪种几何基元,都遵循“三步走”:① 读取或生成点云 → ② 计算每个点在目标几何体上的最近点 → ③ 用最近点坐标替换原坐标并可视化。
下面分别给出四种算法的具体做法。

1、投影到直线

目标
把点云 P = {pᵢ} 压到一条无限长直线上,得到新的点云 P′ = {p′ᵢ},其中 p′ᵢpᵢ 到直线的正交投影。

输入

  • 直线方向向量 d(单位化)

  • 直线上任意一点 o

算法

  1. 读取点云 P

  2. 对每个点 pᵢ 计算参数 tᵢ = (pᵢ − o)·d

  3. 投影点 p_{i}{}'= o + tᵢ d

  4. p_{i}{}'更新 P

  5. 使用 Open3D 的 draw_geometries 可视化。


2、投影到平面

目标
P 正交投影到给定平面。

输入

  • 平面法向量 n(单位化)

  • 平面上任意一点 o

算法

  1. 读取点云 P

  2. 对每个点 pᵢ 计算有符号距离 dᵢ = (pᵢ − o)·n

  3. 投影点 p_{i}{}'= pᵢ − dᵢ n

  4. p_{i}{}'更新 P

  5. 可视化。


3、投影到圆柱面

目标
P 投影到半径为 r、轴线已知的圆柱面上。

输入

  • 圆柱轴线方向向量 d(单位化)

  • 轴线上任意一点 o

  • 半径 r

算法

  1. 读取点云 P

  2. 对每个点 pᵢ
    ① 计算到轴线的最近点 qᵢ = o + ((pᵢ − o)·d) d
    ② 计算离轴距离向量 vᵢ = pᵢ − qᵢ
    ③ 归一化 uᵢ = vᵢ / ‖vᵢ‖(若 ‖vᵢ‖ = 0 可任取正交于 d 的单位向量);
    ④ 圆柱表面点 p_{i}{}'= qᵢ + r uᵢ

  3. p_{i}{}'更新 P

  4. 可视化。


4、投影到球面

目标
P 投影到以 c 为中心、半径 R 的球面上。

输入

  • 球心 c

  • 半径 R

算法

  1. 读取点云 P

  2. 对每个点 pᵢ
    ① 计算方向向量 vᵢ = pᵢ − c
    ② 归一化 uᵢ = vᵢ / ‖vᵢ‖
    ③ 球面点 p′ᵢ = c + R uᵢ

  3. p′ᵢ 更新 P

  4. 可视化。

当然,本次使用的数据依然是兔砸,闪亮登场:

一、四种投影程序

import open3d as o3d
import numpy as np
import os# -------------------------------------------------
# 基础工具
# -------------------------------------------------
def load_pcd(name):pcd = o3d.io.read_point_cloud(name)if pcd.is_empty():raise RuntimeError(f"找不到或无法读取 {name}")return pcddef save_pcd(pcd, src_name, suffix):out = src_name.replace(".pcd", f"_proj_{suffix}.pcd")o3d.io.write_point_cloud(out, pcd, print_progress=False)print(f"已保存:{out}")def view(pcd, title):o3d.visualization.draw_geometries([pcd], window_name=title, width=900, height=700, left=50, top=50)# -------------------------------------------------
# 四种投影实现
# -------------------------------------------------
def proj_line(pcd, line_p, line_d):pts = np.asarray(pcd.points)d = line_d / np.linalg.norm(line_d)t = ((pts - line_p) @ d)[:, None]proj = line_p + t * dnew = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(proj))if pcd.has_colors():new.colors = pcd.colorsreturn newdef proj_plane(pcd, coeffs):A, B, C, D = coeffsn = np.array([A, B, C], dtype=float)n = n / np.linalg.norm(n)pts = np.asarray(pcd.points)dist = (pts @ n + D)[:, None]proj = pts - dist * nnew = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(proj))if pcd.has_colors():new.colors = pcd.colorsreturn newdef proj_cylinder(pcd, axis_p, axis_d, radius):pts = np.asarray(pcd.points)d = axis_d / np.linalg.norm(axis_d)vec = pts - axis_pt = (vec @ d)[:, None]axis_proj = axis_p + t * dradial = pts - axis_projnorms = np.linalg.norm(radial, axis=1, keepdims=True)norms[norms == 0] = 1surf = axis_proj + radius * radial / normsnew = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(surf))if pcd.has_colors():new.colors = pcd.colorsreturn newdef proj_sphere(pcd, center, radius):pts = np.asarray(pcd.points)vec = pts - centernorms = np.linalg.norm(vec, axis=1, keepdims=True)norms[norms == 0] = 1surf = center + radius * vec / normsnew = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(surf))if pcd.has_colors():new.colors = pcd.colorsreturn new# -------------------------------------------------
# 主流程
# -------------------------------------------------
def main():src_file = "E:/CSDN/规则点云/bunny.pcd"if not os.path.isfile(src_file):print("请确保点云存在!")returnpcd = load_pcd(src_file)print(f"已加载 {src_file},共 {len(pcd.points)} 点")# 1) 直线line_p = np.array([0., 0., 0.])line_d = np.array([1., 1., 1.])line_proj = proj_line(pcd, line_p, line_d)# save_pcd(line_proj, src_file, "line")view(line_proj, "投影到直线")# 2) 平面(示例:x+2y+3z+4=0)plane_coeff = [1, 2, 3, 4]plane_proj = proj_plane(pcd, plane_coeff)# save_pcd(plane_proj, src_file, "plane")view(plane_proj, "投影到平面")# 3) 圆柱(Z轴,半径 2.5)axis_p = np.array([0., 0., 0.])axis_d = np.array([0., 0., 1.])radius = 2.5cyl_proj = proj_cylinder(pcd, axis_p, axis_d, radius)# save_pcd(cyl_proj, src_file, "cylinder")view(cyl_proj, "投影到圆柱")# 4) 球(原点,半径 1)center = np.array([0., 0., 0.])sphere_r = 1.0sphere_proj = proj_sphere(pcd, center, sphere_r)# save_pcd(sphere_proj, src_file, "sphere")view(sphere_proj, "投影到球面")print("全部完成!")if __name__ == "__main__":main()

二、四种投影结果

        可以看到,兔砸分别被投影到了直线、平面、圆柱和球面上。当然,根据参数的不同,最后显示的不同,有兴趣的同学可以调节参数试一试。

就酱,下次见^-^

http://www.xdnf.cn/news/18881.html

相关文章:

  • ComfyUI AI一键换装工作流无私分享
  • 《分布式系统跨服务数据一致性Bug深度复盘:从现象到本质的排查与破局》
  • 从“数据孤岛”到“业财融合”,外贸订单管理ERP重构一体化逻辑
  • 电气工程及其自动化的课程笔记
  • 接口自动化测试:测试用例也能自动生成
  • Vue3 + Golang Gin 实现客服实时聊天系统(WebSocket + Socket.IO 详解)
  • 【工具安装使用-Jetson】Jetson Orin Nano 刷机和踩坑总结
  • 从人工巡检到AI预警:智慧工地如何用技术重构施工安全体系
  • Flink 状态 RocksDBListState(写入时的Merge优化)
  • 《C++哈希表:高效数据存储与检索的核心技术》
  • 正则表达式 —— \s*
  • C# 相机内存复用(减少图像采集耗时)以及行数复用
  • HTB赛季8靶场 - Previous
  • 无障碍辅助模块|Highcharts引领可访问数据可视化的交流
  • 《李沐读论文》系列笔记:论文读写与研究方法【更新中】
  • 【每天一个知识点】大模型训推一体机
  • linux的conda配置与应用阶段的简单指令备注
  • Hadoop(四)
  • Rust爬虫实战:用reqwest+select打造高效网页抓取工具
  • HIVE创建UDF函数全流程
  • nowcoder刷题--反转链表
  • MCP 协议原理与系统架构详解—从 Server 配置到 Client 应用
  • SSM从入门到实战:3.1 SpringMVC框架概述与工作原理
  • AI 应用开发:从 Prompt 工程到实战应用开发
  • 基于Flask和AI的智能简历分析系统开发全流程
  • golang 基础类 八股文400题
  • 数据赋能(406)——大数据——数据系统安全性原则
  • k8s笔记04-常用部署命令
  • Matlab高光谱遥感、数据处理与混合像元分解实践技术应用
  • 从Java全栈到前端框架的深度探索