使用PCA 计算点云平面法向量,并旋转至二维XoY坐标系

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


下面调用上面的函数,生成平面点和参数model,其中红色的就是随机生成的法向量:

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]]
对比上下两组蓝色数据,的确是一样的。

你可能感兴趣的:(使用PCA 计算点云平面法向量,并旋转至二维XoY坐标系)