[Open3d系列]--點雲曲線擬合

汗牛充栋發表於2024-03-11

Open3d: 點雲曲線擬合

因為專案需要分析點雲資料, 此文總結其中擬合點雲的部分。

擬合

首先定一個曲線方程:

def func(x, a, b, c):
    return a * x**2 + b * x + c

然後將點雲資料結構轉換為numpy陣列:

points = np.asarray(pcd.points)

讀取點陣列中,x軸、y軸的陣列:

xy_points = points[:, :2]
x = xy_points[:,x_axis_idx]
y = xy_points[:,y_axis_idx]

呼叫scipy.optimize中的curve_fit進行點擬合, 得到各項係數:

popt, pcov = curve_fit(func,x, y)

以上結果係數在返回值popt中, 為一個元組

為了評估其擬合的好壞, 此處計算了殘差, 然後分析其分佈情況:

residuals = y - func(x, *popt)

# 透過標準差, 判斷其離散程度
np.sqrt(np.sum(residuals**2)/x.shape[0]) < std_threshold

視覺化

import matplotlib.pyplot as plt
import matplotlib
# 保證中文顯示正常
matplotlib.rcParams['axes.unicode_minus'] = False
matplotlib.rcParams['font.family'] = 'SimHei'

x_fit = np.linspace(np.min(x), np.max(x), x.shape[0])
y_fit = func(x_fit, a_fit, b_fit, c_fit)
# 建立兩個子圖
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
ax1.scatter(x,y, color='blue', label='Point Cloud')
ax1.plot(x_fit,y_fit, color='red', linewidth=2, label='Fitted Curve')
ax1.legend()
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
ax1.set_title(f"曲線擬合(Fitted Curve)\n$y={a_fit:.3f}*x^2+{b_fit:.3f}*x+{c_fit:.3f}$")

# 繪製殘差圖
ax2.scatter(x, residuals)
ax2.axhline(y=0, color='r', linestyle='--')
ax2.set_xlabel('X')
ax2.set_ylabel('Residuals')
ax2.set_title('殘差(Residuals)')

# 計算R-squared
mean_y = np.mean(y)
ss_total = np.sum((y - mean_y) ** 2)
ss_residual = np.sum(residuals ** 2)
r_squared = 1 - (ss_residual / ss_total)

# 值越大擬合效果越好
ax2.text(0.02, 0.95, f"R平方:{r_squared:.3f},殘差的標準差:{np.sqrt(np.sum(residuals**2)/x.shape[0]):.3f}", transform=ax2.transAxes, fontsize=14,verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))

# 0.06為觀測閾值
fig.suptitle("點雲擬合分析", fontsize=20) 
plt.tight_layout()
plt.show()

最終效果:
點雲擬合分析

相關文章