PCA对点云平面处理后,返回三个特征向量,分别是平面自身坐标系的X轴,Y轴和Z轴在点云全局坐标系中的向量。其中Z轴信息最少,就是平面的法向量。要想把点云从全局坐标系下转化到XoY的二维平面,只需把点按照旋转矩阵R变换后,PCA返回的三个向量就组成了3X3的旋转矩阵R。
换句话说,PCA对平面点云的变换,就是把点转换到三个特征向量组成的新的XYZ坐标系下,新坐标系的原点和全局原点是相同的。
首先import相关库:
from sklearn.decomposition import PCA
from sklearn import preprocessing
import numpy as np
平面方程为 aX + bY + cZ + d = 0
下面我们自己随机生成一个平面的4个参数(3维法向量[a,b,c]和平面离原点的距离d),并生成1000点:
def create_plain_data():
model = np.random.randint(1,100,4).astype('float64')
model[:3] = preprocessing.normalize(np.array([model[:3]]), norm='l2')
x_range = (100,110)
y_range = (1000, 1010)
data = np.zeros((1000,3), dtype='float64')
data[:,0] = np.random.randint(x_range[0],x_range[1],data.shape[0])
data[:,1] = np.random.randint(y_range[0],y_range[1],data.shape[0])
data[:,2] = -( data[:,0] * model[0] + data[:,1] * model[1] + model[3] ) / model[2]
return model, data
if __name__ == '__main__':
model, data = create_plain_data()
print "model: ", model
print "data:"
print data
>
model: [ 0.59223344 0.41456341 0.69093902 92. ]
data:
[[ 103. 1007. -825.63784149]
[ 101. 1004. -822.12355578]
[ 107. 1001. -825.46641292]
...,
[ 107. 1007. -829.06641292]
[ 108. 1004. -828.12355578]
[ 109. 1006. -830.18069863]]
接下来我们用PCA分析出3个特征向量(pca.components_), 并打印旋转后的平面点
pca = PCA(n_components=3)
pca.fit(data)
print "variance_ratio: ", pca.explained_variance_ratio_
print "components_", pca.components_
print "Transformed points in 3 components' coordinate"
print pca.fit_transform(data)
>
variance_ratio: [ 6.84766389e-01 3.15233611e-01 1.19653080e-26]
components_ [[ 0.55240657 0.4153701 -0.7227134 ]
[ 0.58660594 -0.8096943 -0.01698851]
[-0.59223344 -0.41456341 -0.69093902]]
Transformed points in 3 components' coordinate
[[ 6.16324398e-01 -2.80846397e+00 6.11165344e-13]
[ -4.27442042e+00 -1.61229542e+00 6.22402823e-13]
[ 2.09836384e-01 4.39321328e+00 4.99872091e-13]
...,
[ 5.30382521e+00 -4.03793897e-01 5.06568841e-13]
[ 3.92870600e+00 2.59587721e+00 6.45553024e-13]
[ 6.79857748e+00 1.59804234e+00 4.62417997e-13]]
可以看到最后一个特征向量的信息量(variance_ratio[2])非常少1.19653080e-26,说明点的坐标在这个特征向量的方向上计划是没有区分度的,所以它
pca.components_[2]就是点平面的法向量。我们对比前面的model输出(红色的)发现它们的确是相等的。而且,转换后点的Z值都为0.
那pca.fit_transform(data)这样的PCA变换具体做的什么事情呢,它就是把所有点旋转到 pca.components_[0]和pca.components_[1]组成的坐标平面,然后把原点移动到点云的中心点。下面我们验证一下:
rotated_data = np.dot(data, pca.components_.T)
mean_data = rotated_data - np.mean(rotated_data, axis=0)
print "manual transformed ponts"
print mean_data
>
manual transformed ponts
[[ 6.16324398e-01 -2.80846397e+00 -4.68958206e-13]
[ -4.27442042e+00 -1.61229542e+00 -5.68434189e-13]
[ 2.09836384e-01 4.39321328e+00 -5.96855898e-13]
...,
[ 5.30382521e+00 -4.03793897e-01 -6.25277607e-13]
[ 3.92870600e+00 2.59587721e+00 -4.68958206e-13]
[ 6.79857748e+00 1.59804234e+00 -6.53699317e-13]]
对比上下两组蓝色数据,的确是一样的。