????????本節我們分享上節提到的不填充點云。在點云處理、計算機視覺與工業檢測中,幾何輪廓(邊框/環)點云比實心點云更能反映物體的邊緣特征、結構骨架與形貌突變區域。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,好看又好用。關于圖形邊界的寬度,同學們可以自己動動小手調節嘗試下。就醬,下次見^-^