目录
- 一、算法原理
- 二、代码实现
- 1、python
- 2、matlab
- 三、算法效果
一、算法原理
设拟合出的平面方程为:
a
x
+
b
y
+
c
z
+
d
=
0
(1)
ax+by+cz+d=0\tag{1}
ax+by+cz+d=0(1)
约束条件为:
a
2
+
b
2
+
c
2
=
1
(2)
a^2+b^2+c^2=1\tag{2}
a2+b2+c2=1(2)
可以得到平面参数
a
、
b
、
c
、
d
a、b、c、d
a、b、c、d。此时,要使获得的拟合平面是最佳的,就是使点到该平面的距离的平方和最小,即满足:
e
=
∑
i
=
1
n
d
i
2
→
m
i
n
(3)
e=\sum_{i=1}^nd_i^2\rightarrow min\tag{3}
e=i=1∑ndi2→min(3)
式中,
d
i
=
∣
a
x
i
+
b
y
i
+
c
z
i
+
d
∣
d_i=|ax_i+by_i+cz_i+d|
di=∣axi+byi+czi+d∣,是点云数据中的任一点
p
i
(
x
i
,
y
i
,
z
i
)
p_i(x_i,y_i,z_i)
pi(xi,yi,zi)到这个平面的距离。要使
e
→
m
i
n
e\rightarrow min
e→min,可以利用拉格朗日乘子法求解极值,得到函数:
f
=
e
−
λ
(
a
2
+
b
2
+
c
2
−
1
)
=
∑
i
=
1
n
d
i
2
−
λ
(
a
2
+
b
2
+
c
2
−
1
)
(4)
f = e - λ(a^2 + b^2 + c^2 - 1) =\sum_{i=1}^nd_i^2 - λ(a^2 + b^2 + c^2 - 1) \tag{4}
f=e−λ(a2+b2+c2−1)=i=1∑ndi2−λ(a2+b2+c2−1)(4)
先将式(2-4)两边对
d
d
d求偏导,并且令偏导数为零,得到:
d
=
1
n
(
a
∑
i
=
1
n
x
i
2
+
b
∑
i
=
1
n
y
i
2
+
c
∑
i
=
1
n
z
i
2
)
(5)
d=\frac{1}{n}(a\sum_{i=1}^nx_i^2+b\sum_{i=1}^ny_i^2+c\sum_{i=1}^nz_i^2)\tag{5}
d=n1(ai=1∑nxi2+bi=1∑nyi2+ci=1∑nzi2)(5)
令
x
ˉ
=
∑
i
=
1
n
x
i
n
\bar{x}=\sum_{i=1}^n\frac{x_i}{n}
xˉ=∑i=1nnxi、
y
ˉ
=
∑
i
=
1
n
y
i
n
\bar{y}=\sum_{i=1}^n\frac{y_i}{n}
yˉ=∑i=1nnyi、
z
ˉ
=
∑
i
=
1
n
z
i
n
\bar{z}=\sum_{i=1}^n\frac{z_i}{n}
zˉ=∑i=1nnzi,质心为
P
ˉ
=
(
x
ˉ
,
y
ˉ
,
z
ˉ
)
\bar{P}=(\bar{x},\bar{y},\bar{z})
Pˉ=(xˉ,yˉ,zˉ),
Δ
x
i
=
x
i
−
x
ˉ
\Delta x_i=x_i-\bar{x}
Δxi=xi−xˉ,
Δ
y
i
=
y
i
−
y
ˉ
\Delta y_i=y_i-\bar{y}
Δyi=yi−yˉ,
Δ
z
i
=
z
i
−
z
ˉ
\Delta z_i=z_i-\bar{z}
Δzi=zi−zˉ则:
d
i
=
∣
a
Δ
x
i
+
b
Δ
y
i
+
c
Δ
z
i
∣
(6)
d_i=|a\Delta x_i+b\Delta y_i+c\Delta z_i|\tag{6}
di=∣aΔxi+bΔyi+cΔzi∣(6)
再对式(2-4)两边求对
a
、
b
、
c
a 、b 、c
a、b、c 的偏导数,得
{
2
∑
i
=
1
n
(
a
Δ
x
i
+
b
Δ
y
i
+
c
Δ
z
i
)
Δ
x
i
−
2
λ
a
=
0
2
∑
i
=
1
n
(
a
Δ
x
i
+
b
Δ
y
i
+
c
Δ
z
i
)
Δ
y
i
−
2
λ
b
=
0
2
∑
i
=
1
n
(
a
Δ
x
i
+
b
Δ
y
i
+
c
Δ
z
i
)
Δ
z
i
−
2
λ
c
=
0
\begin{cases} 2\sum_{i=1}^n(a\Delta x_i+b\Delta y_i+c\Delta z_i)\Delta x_i-2λa=0\\ 2\sum_{i=1}^n(a\Delta x_i+b\Delta y_i+c\Delta z_i)\Delta y_i-2λb=0\\ 2\sum_{i=1}^n(a\Delta x_i+b\Delta y_i+c\Delta z_i)\Delta z_i-2λc=0 \end{cases}
⎩
⎨
⎧2∑i=1n(aΔxi+bΔyi+cΔzi)Δxi−2λa=02∑i=1n(aΔxi+bΔyi+cΔzi)Δyi−2λb=02∑i=1n(aΔxi+bΔyi+cΔzi)Δzi−2λc=0
将上述方程组构成特征值方程:
A
x
=
λ
x
(7)
Ax = λx \tag{7}
Ax=λx(7)
式中,
A
=
[
∑
i
=
1
n
Δ
x
i
2
∑
i
=
1
n
Δ
x
i
Δ
y
i
∑
i
=
1
n
Δ
x
i
Δ
z
i
∑
i
=
1
n
Δ
x
i
Δ
y
i
∑
i
=
1
n
Δ
y
i
2
∑
i
=
1
n
Δ
y
i
Δ
z
i
∑
i
=
1
n
Δ
x
i
Δ
z
i
∑
i
=
1
n
Δ
y
i
Δ
z
i
∑
i
=
1
n
Δ
z
i
2
]
A= \left[ \begin{matrix} \sum_{i=1}^n\Delta x_{i}^{2}&\sum_{i=1}^n\Delta x_{i}\Delta y_{i}&\sum_{i=1}^n\Delta x_{i}\Delta z_{i} \\ \sum_{i=1}^n\Delta x_{i}\Delta y_{i}&\sum_{i=1}^n\Delta y_{i}^{2}&\sum_{i=1}^n\Delta y_{i}\Delta z_{i} \\ \sum_{i=1}^n\Delta x_{i}\Delta z_{i} &\sum_{i=1}^n\Delta y_{i}\Delta z_{i} &\sum_{i=1}^n\Delta z_{i}^{2}\\ \end{matrix} \right]
A=
∑i=1nΔxi2∑i=1nΔxiΔyi∑i=1nΔxiΔzi∑i=1nΔxiΔyi∑i=1nΔyi2∑i=1nΔyiΔzi∑i=1nΔxiΔzi∑i=1nΔyiΔzi∑i=1nΔzi2
x
=
[
a
b
c
]
x= \left[ \begin{matrix} a\\ b\\ c\\ \end{matrix} \right]
x=
abc
那么,求解平面参数
a
、
b
、
c
a 、b 、c
a、b、c ,就是求解矩阵的特征值和特征向量。又因为
A
A
A 是3 阶实对称矩阵,其特征值求解公式为:
λ
=
(
A
x
)
T
x
x
T
x
,
x
≠
0
(8)
λ=\frac{(Ax)^Tx}{x^Tx},x\neq0\tag{8}
λ=xTx(Ax)Tx,x=0(8)
在约束条件
a
2
+
b
2
+
c
2
=
1
a^2 + b^2 + c^2 = 1
a2+b2+c2=1 下,得
λ
=
∑
i
=
1
n
(
a
Δ
x
i
+
b
Δ
y
i
+
c
Δ
z
i
)
2
=
∑
i
=
1
n
d
i
2
=
e
λ=\sum_{i=1}^n(a\Delta x_i+b\Delta y_i+c\Delta z_i)^2=\sum_{i=1}^nd_i^2=e
λ=∑i=1n(aΔxi+bΔyi+cΔzi)2=∑i=1ndi2=e。 所以,
e
e
e最小值就是矩阵
A
A
A的最小特征值,对应特征向量为平面参数
a
、
b
、
c
a 、b 、c
a、b、c ,利用质心可求得
d
d
d。
二、代码实现
1、python
import numpy as np
# 创建函数,用于生成不同属于一个平面的100个离散点
def not_all_in_plane(a, b, c):
x = np.random.uniform(-10, 10, size=100)
y = np.random.uniform(-10, 10, size=100)
z = (a * x + b * y + c) + np.random.normal(-1, 1, size=100)
return x, y, z
# 调用函数,生成离散点
x, y, z = not_all_in_plane(2, 5, 6)
# 计算质心
x0 = np.mean(x)
y0 = np.mean(y)
z0 = np.mean(z)
# 去质心
x = x - x0
y = y - y0
z = z - z0
# ------------------------构建系数矩阵-----------------------------
A = np.array([[sum(x * x), sum(x * y), sum(x * z)],
[sum(x * y), sum(y * y), sum(y * z)],
[sum(x * z), sum(y * z), sum(z * z)]])
[D, X] = np.linalg.eig(A)
print('平面拟合结果为:z = %.3f * x + %.3f * y + %.3f' % (X[0, 2], X[1, 2], X[2, 2]))
2、matlab
clc;clear;
%% -------------------------------读取点云---------------------------------
pc = ReadPointCloud('plane1.pcd');
%% -----------------------------获取点云信息-------------------------------
n ; % 点的个数
x ; % 点的x坐标
y ; % 点的y坐标
z ; % 点的z坐标
% 1、计算点云质心
centroid = pcmean(pc);
% 2、去质心化
deMean=pcdemean(pc.Location,centroid);
%% -------------------------------拟合平面---------------------------------
% 3、矩阵A
A = [sumXX sumXY sumXZ;
sumXY sumYY sumYZ;
sumXZ sumYZ sumZZ];
% 4、矩阵A分解求特征值特征向量
[V,D]=eig(A);
a = V(1,1);b = V(2,1);c = V(3,1);
% 5、计算原点到拟合平面的距离
d = -dot([a b c],centroid);
%% ---------------------------可视化拟合结果-------------------------------
figure
% 图形绘制
scatter3(x,y,z,'filled')
hold on;
[XFit,YFit]= meshgrid (xfit,yfit);
mesh(XFit,YFit,ZFit);
title('拉格朗日乘子法拟合平面');