? ? ? ? 本節我們來介紹PCA(主成分分析)算法進行點云配準,這是一種經典的統計降維與特征提取工具,在三維點云處理中常被用來完成“粗配準”。其核心思想是:先把兩個待對齊的點云各自進行主成分分解,獲得各自的“主軸”,然后只需把源點云的主軸旋轉-平移到與目標云的主軸重合,即可實現初步對齊。具體流程可概括為五步:
????????1. 計算質心:求出點云中所有點的幾何中心。 ?
2. 去質心:把每個點坐標減去質心,使點云以原點為中心。 ?
3. 協方差矩陣:在中心化后的點云上計算 3×3 協方差矩陣。 ?
4. 特征分解:對協方差矩陣做特征值分解,得到三個特征向量,即為點云的三個主方向(主軸)。 ?
5. 軸對齊:構造旋轉矩陣和平移向量,將源云的主軸依次對應到目標云的主軸,完成粗配準。
????????由于 PCA 只依賴一階矩和二階矩,計算量小、對噪聲有一定魯棒性,因此常被用作以下場景的“第一步”:
????????? 初始配準:在運行 ICP 等精細配準算法前,用 PCA 給出良好初值,可顯著減少迭代次數并避免局部極小。 ?
? 姿態估計:機器人或視覺系統可通過 PCA 快速估計物體或場景的大致朝向。 ?
? 多視角拼接:把不同視角拍到的點云先用 PCA 粗略對齊,為后續精細拼接提供初始解。
本次使用的數據依然我們的老朋友——兔砸!顯示如下:
一、PCA配準程序
from __future__ import annotationsimport copy
import logging
from typing import Tupleimport numpy as np
import open3d as o3dlogging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")# ------------------------------------------------------------------------------
# 工具函數
# ------------------------------------------------------------------------------
def estimate_covariances(pcd: o3d.geometry.PointCloud,search_param: o3d.geometry.KDTreeSearchParamHybrid,
) -> Tuple[np.ndarray, np.ndarray]:"""返回點云質心與 3×3 協方差矩陣"""center, cov = pcd.compute_mean_and_covariance()return np.asarray(center), np.asarray(cov)def pca_registration(source: o3d.geometry.PointCloud,target: o3d.geometry.PointCloud,
) -> o3d.geometry.PointCloud:"""使用 PCA 對齊兩個點云的主軸,再用 Kabsch 精細對齊返回 : 配準后的 source 點云(拷貝)"""# 1. 計算質心與主軸方向c_src, cov_src = estimate_covariances(source, o3d.geometry.KDTreeSearchParamHybrid(radius=0.01, max_nn=30))c_tgt, cov_tgt = estimate_covariances(target, o3d.geometry.KDTreeSearchParamHybrid(radius=0.01, max_nn=30))_, eig_src = np.linalg.eigh(cov_src)_, eig_tgt = np.linalg.eigh(cov_tgt)# 2. 粗略對齊:讓 source 的主軸與 target 對齊R0 = eig_tgt @ eig_src.Tt0 = c_tgt - R0 @ c_srcT0 = np.eye(4)T0[:3, :3] = R0T0[:3, 3] = t0# 3. 變換T_total = T0src_coarse = copy.deepcopy(source).transform(T0)logging.info("PCA配準矩陣:\n%s", T_total)return src_coarse# ------------------------------------------------------------------------------
# 主程序
# ------------------------------------------------------------------------------
def main() -> None:np.random.seed(42)# 1. 讀入源點云source = o3d.io.read_point_cloud("E:/CSDN/規則點云/bunny.pcd")# 2. 生成目標點云:平移 + 高斯噪聲target = copy.deepcopy(source)t_noise = np.array([0.10, 0.15, 0.20])target.translate(t_noise, relative=True)points = np.asarray(target.points)noise = np.random.normal(0, 0.001, points.shape)points += noisetarget.points = o3d.utility.Vector3dVector(points)# 3. 可視化原始source.paint_uniform_color([1, 0, 0])target.paint_uniform_color([0, 1, 0])o3d.visualization.draw_geometries([source, target],window_name="原始點云",width=1024,height=768,)# 4. 配準registered = pca_registration(source, target)# 5. 可視化結果o3d.visualization.draw_geometries([registered, target],window_name="PCA配準點云",width=1024,height=768,)if __name__ == "__main__":main()
二、PCA配準結果
????????可以看出,前兩次的兔砸數據也能很好的配準。但是此次有一點進行了改進,就是對原始點云和目標點云進行了KD-tree處理,所以運行起來會很快。總的來說此次配準還不錯,不過要說幾種配準方法的優劣,還需進一步結合數據分析。
就醬,下次見^-^