Python实现生成矩形框、三角形框、六边形框和圆环点云
本节我们分享上节提到的不填充点云。在点云处理、计算机视觉与工业检测中,几何轮廓(边框/环)点云比实心点云更能反映物体的边缘特征、结构骨架与形貌突变区域。Python 借助 NumPy 即可快速生成矩形边框、三角形边框、六边形边框与圆环点云,并可按需附加噪声、局部加密或升维到 3-D。
下文给出统一范式:
① 参数定义 → ② 边界方程 → ③ 等距/随机采样 → ④ 可视化/保存 → ⑤ 典型应用。
一、共性流程
步骤 关键操作 常用 API ① 几何参数 边长、顶点、线宽、采样密度 `np.array` ② 边界方程 参数方程 / 隐式方程 `np.linspace` + 方向向量 ③ 采样策略 等距采样、随机扰动、局部加密 `np.random.rand` ④ 可视化 2-D 散点或 3-D 点云 `matplotlib`, `Open3D` ⑤ 保存格式 `.xyz`, `.ply`, `.pcd` `np.savetxt`, `open3d.io` 二、矩形边框点云
1. 生成步骤
- 输入:中心`(cx,cy)`、边长`L,W`、线宽`w`、单点平均密度`ρ`
- 计算四条骨架线 → 对每条边按长度×ρ采样 → 在线宽方向±w/2 加随机偏移
- (可选)加高程`z=0` 或挤出成“框柱”3-D 点云2. 核心代码
import numpy as np def rectangle_frame(cx=0, cy=0, L=10, W=5, w=0.2, rho=200):seg = [L, W, L, W]dir = [np.array([1,0]), np.array([0,1]), np.array([-1,0]), np.array([0,-1])]pts = []start = np.array([cx-L/2, cy-W/2])for k in range(4):n = int(seg[k]*rho)t = np.linspace(0, 1, n)line = start[:,None] + t[None,:]*dir[k][:,None]*seg[k]noise = np.random.uniform(-w/2, w/2, (2, n))pts.append(line + noise)start = start + dir[k]*seg[k]return np.hstack(pts).Tframe = rectangle_frame() import matplotlib.pyplot as plt plt.figure(figsize=(5,3)) plt.scatter(frame[:,0], frame[:,1], s=1) plt.title("Rectangle Frame Point Cloud") plt.gca().set_aspect('equal'); plt.show()
3. 典型应用
- 建筑平面图提取——仅保留墙体轮廓,用于 BIM 逆向
- PCB 焊盘边缘定位——快速验证 2-D 视觉测量算法
- 文档扫描纠偏——检测纸张四边,估计倾斜角三、三角形边框点云
1. 生成步骤
- 输入:三顶点`A,B,C`、线宽`w`、密度`ρ`
- 对三条边分别参数化:`P = (1-t)Vi + tVj`
- 每条边按长度×ρ采样,横向±w/2 扰动;顶点处做圆弧过渡防止断裂2. 核心代码
def triangle_frame(A, B, C, w=0.15, rho=300):vert = [A, B, C, A] # 闭合pts = []for i in range(3):v1, v2 = np.array(vert[i]), np.array(vert[i+1])L = np.linalg.norm(v2-v1)n = int(L*rho)t = np.linspace(0, 1, n)line = (1-t)[:,None]*v1 + t[:,None]*v2norm = np.array([-(v2-v1)[1], (v2-v1)[0]])); norm /= np.linalg.norm(norm)noise = np.random.uniform(-w/2, w/2, n)pts.append(line + noise[:,None]*norm)return np.vstack(pts)tri = triangle_frame([0,0], [8,2], [4,7]) plt.scatter(tri[:,0], tri[:,1], s=1) plt.title("Triangle Frame Point Cloud") plt.gca().set_aspect('equal'); plt.show()
3. 典型应用
- 结构光标定板——三角形镂空靶标边缘提取
- 三角面片质量检测——扫描网格后对比设计边框
- 有限元边界条件可视化——仅显示壳单元外轮廓四、六边形边框点云
1. 生成步骤
- 输入:中心`C`、外接圆半径`R`、线宽`w`、密度`ρ`
- 计算六顶点 → 六条边等距采样 → 径向噪声±w/2
- 可做成“蜂窝环”用于拼接测试2. 核心代码
def hexagon_frame(C, R, w=0.2, rho=250):ang = np.linspace(0, 2*np.pi, 7)[:-1]verts = np.array([C + R*np.array([np.cos(a), np.sin(a)]) for a in ang])pts = []for i in range(6):v1, v2 = verts[i], verts[(i+1)%6]L = R # 正六边形边长=Rn = int(L*rho)t = np.linspace(0, 1, n)line = (1-t)[:,None]*v1 + t[:,None]*v2norm = verts[i] - C; norm /= np.linalg.norm(norm) # 径向noise = np.random.uniform(-w/2, w/2, n)pts.append(line + noise[:,None]*norm)return np.vstack(pts)hex = hexagon_frame([0,0], 5) plt.scatter(hex[:,0], hex[:,1], s=1) plt.title("Hexagon Frame Point Cloud") plt.gca().set_aspect('equal'); plt.show()
3. 典型应用
- 蜂窝夹芯板缺陷检测——仅扫描蜂窝壁
- 无人机集群区域围栏——生成六边形边界用于路径规划
- 游戏六边形地图编辑器——快速生成可交互边界点云五、圆环(Ring)点云
1. 生成步骤
- 输入:圆心`C`、内半径`r`、外半径`R`、环宽`w=R-r`、点数`N`
- 极坐标随机采样:半径`rho = sqrt(rand*(R^2-r^2)+r^2)`,角度`theta = rand*2pi`
- 若仅需“环”而非实心圆,则限制`r>0`;若只要细环,可令`w`很小且加高斯径向噪声2. 核心代码
def ring_point_cloud(C, r, R, N):theta = np.random.uniform(0, 2*np.pi, N)rad = np.sqrt(np.random.uniform(r**2, R**2, N))x = C[0] + rad*np.cos(theta)y = C[1] + rad*np.sin(theta)z = np.zeros(N)return np.vstack((x,y,z)).Tring = ring_point_cloud([0,0], 4, 5, 2000) plt.scatter(ring[:,0], ring[:,1], s=1) plt.title("Ring Point Cloud"); plt.show()
3. 典型应用
- 管道焊缝扫描——仅保留管壁环带
- 激光雷达标定靶——黑白环形靶点云提取
- 轴承磨损测量——对比设计环带与实测点云偏差六、综合对比表
轮廓类型 采样关键 线宽/环宽控制 主要应用场景 矩形边框 四边独立参数化 横向噪声 建筑墙体、文档边界 三角边框 三边+顶点过渡 法向噪声 标定板、面片质检 六边形框 六边+径向噪声 径向噪声 蜂窝夹芯、无人机围栏 圆环 极坐标+半径限幅 内外半径差 管道、轴承、环形靶 七、进阶技巧
1. 3-D 挤出:给边框点云加`z=height` 或沿`z`随机拉伸,生成“框柱”“环柱”
2. 局部加密:在拐角/焊缝区域提高`rho` 2×–5×,模拟人工扫描重点区
3. 噪声模型:径向高斯噪声模拟激光光斑扩散;切向均匀噪声模拟手持抖动八、总结
利用 Python + NumPy,可在 30 行内完成**矩形边框、三角形边框、六边形边框与圆环点云的生成;通过调节线宽/环宽、密度与噪声,可直接服务于**工业检测、机器人导航、虚拟现实与测绘建模**等多个下游任务。掌握“轮廓点云”生成技术,为后续**边缘配准、缺陷测量与骨架提取**提供了高信噪比的输入数据。
一、总体程序
# tk_edge_shapes.py
import tkinter as tk
from tkinter import messagebox
import open3d as o3d
import numpy as np
import os
import threading# -------------------------------------------------
# 1. 通用工具
# -------------------------------------------------
def random_colors(n):return np.random.rand(n, 3)def save_and_show(pc, name):o3d.visualization.draw_geometries([pc])# os.makedirs("output", exist_ok=True)# path = os.path.join("output", name)# o3d.io.write_point_cloud(path, pc)# messagebox.showinfo("完成", f"已保存边缘点云:{path}")# -------------------------------------------------
# 2. 边缘采样生成器
# -------------------------------------------------
def generate_circle(center, r, n):"""圆环边缘"""theta = np.linspace(0, 2*np.pi, n, endpoint=False)x = center[0] + r * np.cos(theta)y = center[1] + r * np.sin(theta)return np.column_stack((x, y, np.zeros(n)))def generate_rectangle(center, w, h, n):"""矩形边框"""w2, h2 = w/2, h/2n4 = n // 4# 下→右→上→左x1 = np.linspace(-w2, w2, n4, endpoint=False) + center[0]y1 = np.full(n4, -h2) + center[1]y2 = np.linspace(-h2, h2, n4, endpoint=False) + center[1]x2 = np.full(n4, w2) + center[0]x3 = np.linspace(w2, -w2, n4, endpoint=False) + center[0]y3 = np.full(n4, h2) + center[1]y4 = np.linspace(h2, -h2, n - 3*n4, endpoint=False) + center[1]x4 = np.full_like(y4, -w2) + center[0]return np.column_stack((np.hstack((x1, x2, x3, x4)),np.hstack((y1, y2, y3, y4)),np.zeros(n)))def generate_triangle(v0, v1, v2, n):"""三角形边框"""n3 = n // 3def edge(p, q, cnt):t = np.linspace(0, 1, cnt, endpoint=False).reshape(-1, 1)return p + t * (q - p)return np.vstack([edge(v0, v1, n3),edge(v1, v2, n3),edge(v2, v0, n - 2*n3)])def generate_hexagon(center, r, n):"""六边形边框"""angles = np.linspace(0, 2*np.pi, 7, endpoint=False)[:-1]verts = np.array([[r*np.cos(a), r*np.sin(a), 0] for a in angles])n6 = n // 6pts = []for i in range(6):p, q = verts[i], verts[(i+1)%6]t = np.linspace(0, 1, n6, endpoint=False).reshape(-1, 1)pts.append(p + t * (q - p))return np.vstack(pts)# -------------------------------------------------
# 3. 按钮回调
# -------------------------------------------------
def _build_pc(points, name):pc = o3d.geometry.PointCloud()pc.points = o3d.utility.Vector3dVector(points)pc.colors = o3d.utility.Vector3dVector(random_colors(len(points)))threading.Thread(target=save_and_show, args=(pc, name), daemon=True).start()def on_rect():pts = generate_rectangle([0, 0], 2, 1, 10000)_build_pc(pts, "rectangle_edge.pcd")def on_circle():pts = generate_circle([0, 0], 1, 10000)_build_pc(pts, "circle_edge.pcd")def on_triangle():v0 = np.array([0, 0.5, 0])v1 = np.array([-0.5, -0.5, 0])v2 = np.array([0.5, -0.5, 0])pts = generate_triangle(v0, v1, v2, 10000)_build_pc(pts, "triangle_edge.pcd")def on_hexagon():pts = generate_hexagon([0, 0], 1, 12000)_build_pc(pts, "hexagon_edge.pcd")def on_exit():root.destroy()# -------------------------------------------------
# 4. GUI
# -------------------------------------------------
root = tk.Tk()
root.title("Open3D 边缘点云生成器")
root.resizable(False, False)tk.Label(root, text="选择要生成的形状(仅边缘):", font=("微软雅黑", 14)).grid(row=0, column=0, columnspan=2, pady=10)btn_style = {"width": 15, "font": ("微软雅黑", 12)}
tk.Button(root, text="矩形", command=on_rect, **btn_style).grid(row=1, column=0, padx=15, pady=8)
tk.Button(root, text="三角形", command=on_triangle, **btn_style).grid(row=1, column=1, padx=15, pady=8)
tk.Button(root, text="六边形", command=on_hexagon, **btn_style).grid(row=2, column=0, padx=15, pady=8)
tk.Button(root, text="圆形", command=on_circle, **btn_style).grid(row=2, column=1, padx=15, pady=8)
tk.Button(root, text="退出", command=on_exit, **btn_style).grid(row=3, column=0, columnspan=2, pady=15)root.mainloop()
二、结果运行显示
喏,不填充版本依旧使用上节的GUI,好看又好用。关于图形边界的宽度,同学们可以自己动动小手调节尝试下。就酱,下次见^-^