news 2026/4/24 15:01:17

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python实现点云投影到直线、平面、柱面和球面

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

1、投影到直线

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

输入

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

  • 直线上任意一点o

算法

  1. 读取点云P

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

  3. 投影点= o + tᵢ d

  4. 更新P

  5. 使用 Open3D 的draw_geometries可视化。


2、投影到平面

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

输入

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

  • 平面上任意一点o

算法

  1. 读取点云P

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

  3. 投影点= pᵢ − dᵢ n

  4. 更新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的单位向量);
    ④ 圆柱表面点= qᵢ + r uᵢ

  3. 更新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 pcd def 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 * d new = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(proj)) if pcd.has_colors(): new.colors = pcd.colors return new def proj_plane(pcd, coeffs): A, B, C, D = coeffs n = 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 * n new = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(proj)) if pcd.has_colors(): new.colors = pcd.colors return new def proj_cylinder(pcd, axis_p, axis_d, radius): pts = np.asarray(pcd.points) d = axis_d / np.linalg.norm(axis_d) vec = pts - axis_p t = (vec @ d)[:, None] axis_proj = axis_p + t * d radial = pts - axis_proj norms = np.linalg.norm(radial, axis=1, keepdims=True) norms[norms == 0] = 1 surf = axis_proj + radius * radial / norms new = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(surf)) if pcd.has_colors(): new.colors = pcd.colors return new def proj_sphere(pcd, center, radius): pts = np.asarray(pcd.points) vec = pts - center norms = np.linalg.norm(vec, axis=1, keepdims=True) norms[norms == 0] = 1 surf = center + radius * vec / norms new = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(surf)) if pcd.has_colors(): new.colors = pcd.colors return new # ------------------------------------------------- # 主流程 # ------------------------------------------------- def main(): src_file = "E:/CSDN/规则点云/bunny.pcd" if not os.path.isfile(src_file): print("请确保点云存在!") return pcd = 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.5 cyl_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.0 sphere_proj = proj_sphere(pcd, center, sphere_r) # save_pcd(sphere_proj, src_file, "sphere") view(sphere_proj, "投影到球面") print("全部完成!") if __name__ == "__main__": main()

二、四种投影结果

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

就酱,下次见^-^

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 15:00:19

2025届学术党必备的六大降AI率神器推荐榜单

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 于学术写作的全程之中,恰当地运用AI工具可显著地提高效率,论文AI工具…

作者头像 李华
网站建设 2026/4/24 14:59:21

Verilog FFT仿真与Matlab结果对比:手把手教你分析定点运算误差

Verilog FFT仿真与Matlab结果对比:定点运算误差分析与优化实战 当我们在FPGA上实现FFT算法时,定点运算带来的误差常常成为工程师面临的主要挑战之一。最近在调试一个8点FFT核时,我发现Verilog仿真结果与Matlab的理想计算结果之间存在明显差异…

作者头像 李华
网站建设 2026/4/24 14:55:46

金融新闻AI生成技术:架构设计与实战优化

1. 金融新闻AI生成的核心价值金融新闻生成这个需求在业内已经存在多年,但直到最近两年才真正具备落地条件。我去年为三家金融机构部署过类似的系统,最深的体会是:传统人工撰写金融新闻最大的痛点不是速度慢,而是难以保持客观中立。…

作者头像 李华
网站建设 2026/4/24 14:55:27

告别手机小屏幕:在Windows电脑上玩转酷安社区的完整指南

告别手机小屏幕:在Windows电脑上玩转酷安社区的完整指南 【免费下载链接】Coolapk-UWP 一个基于 UWP 平台的第三方酷安客户端 项目地址: https://gitcode.com/gh_mirrors/co/Coolapk-UWP 还在为刷酷安时眼睛酸痛而烦恼吗?想在大屏幕上舒适地浏览数…

作者头像 李华
网站建设 2026/4/24 14:53:20

YAJL错误处理最佳实践:如何优雅地处理解析异常

YAJL错误处理最佳实践:如何优雅地处理解析异常 【免费下载链接】yajl A fast streaming JSON parsing library in C. 项目地址: https://gitcode.com/gh_mirrors/ya/yajl YAJL(Yet Another JSON Library)作为一款高效的C语言JSON解析库…

作者头像 李华