1、背景
点云数据只是一种基本的、对物理目标三维结构的理解形式,一般无法直接使用。从点云重建网格模型的关键是从离散点构造出拓扑连接关系。
对于点云来说,法线是很重要的一个属性。
- 点云渲染:在进行光照渲染时需要发现信息才能正常进行。
- 点云重建:用于计算点到隐式曲面的有符号几何距离,从而构建隐式曲面。
- 其他:区分正反面。
2、法线计算原理
确定表面一点法线的问题近似于估计表面的一个相切面法线的问题,因此转换过来以后就变成一个最小二乘法平面拟合估计问题。
对一个平面来说,可以使用法线方式表示一个平面, a x + b y + c z = d ( d > = 0 ) , a 2 + b 2 + c 2 = 1 ax+by+cz=d(d>=0),a^2+b^2+c^2=1 ax+by+cz=d(d>=0),a2+b2+c2=1。为了使得平面最准确,则使用最小二乘法构造代价函数:
d i = ∣ a x + b y + c z − d ∣ d_i=\lvert ax+by+cz-d \rvert di=∣ax+by+cz−d∣
则目标是求 m i n ∑ i = 1 n d i 2 min\sum_{i=1}^nd_i^2 min∑i=1ndi2, a 2 + b 2 + c 2 = 1 a^2+b^2+c^2=1 a2+b2+c2=1
- 构造拉格朗日:
f = ∑ i = 1 n d i 2 − λ ( a 2 + b 2 + c 2 − 1 ) f=\sum_{i=1}^nd_i^2-\lambda(a^2+b^2+c^2-1) f=∑i=1ndi2−λ(a2+b2+c2−1)
f对d求导则,
d
=
1
n
(
a
∑
i
=
1
n
x
i
+
b
∑
i
=
1
n
y
i
+
c
∑
i
=
1
n
z
i
)
=
a
x
‾
+
b
y
‾
+
c
z
‾
d=\frac{1}{n}(a\sum_{i=1}^{n}x_i+b\sum_{i=1}^{n}y_i+c\sum_{i=1}^{n}z_i)=a\overline x+b\overline y+c\overline z
d=n1(a∑i=1nxi+b∑i=1nyi+c∑i=1nzi)=ax+by+cz
d i = ∣ a x i + b y i + c z i − a x ‾ + b y ‾ + c z ‾ ∣ = ∣ a Δ x i + b Δ b i + c Δ z i ∣ d_i=\lvert ax_i+by_i+cz_i-a\overline x+b\overline y+c\overline z \rvert=\lvert a\Delta x_i+b\Delta b_i+c\Delta z_i \rvert di=∣axi+byi+czi−ax+by+cz∣=∣aΔxi+bΔbi+cΔzi∣
令 Δ x i = x i − x ˉ , Δ y i = y i − y ˉ , Δ z i = z i − z ˉ \Delta x_i=x_i-\bar x,\Delta y_i=y_i-\bar y,\Delta z_i=z_i-\bar z Δxi=xi−xˉ,Δyi=yi−yˉ,Δzi=zi−zˉ则 d i = ∣ a Δ x i + b Δ b i + c Δ z i ∣ d_i=\lvert a\Delta x_i+b\Delta b_i+c\Delta z_i \rvert di=∣aΔxi+bΔbi+cΔzi∣
- 另一边,f分别对a、b、c求导:
∂ f ∂ a = 2 ∑ i = 1 n ( a Δ x i + b Δ b i + c Δ z i ) Δ x i − 2 λ a \frac{\partial f}{\partial a}=2\sum_{i=1}^n(a\Delta x_i+b\Delta b_i+c\Delta z_i)\Delta x_i-2\lambda a ∂a∂f=2∑i=1n(aΔxi+bΔbi+cΔzi)Δxi−2λa
∂ f ∂ b = 2 ∑ i = 1 n ( a Δ x i + b Δ b i + c Δ z i ) Δ y i − 2 λ b \frac{\partial f}{\partial b}=2\sum_{i=1}^n(a\Delta x_i+b\Delta b_i+c\Delta z_i)\Delta y_i-2\lambda b ∂b∂f=2∑i=1n(aΔxi+bΔbi+cΔzi)Δyi−2λb
∂ f ∂ c = 2 ∑ i = 1 n ( a Δ x i + b Δ b i + c Δ z i ) Δ z i − 2 λ c \frac{\partial f}{\partial c}=2\sum_{i=1}^n(a\Delta x_i+b\Delta b_i+c\Delta z_i)\Delta z_i-2\lambda c ∂c∂f=2∑i=1n(aΔxi+bΔbi+cΔzi)Δzi−2λc
则
[
∑
Δ
x
i
2
∑
Δ
x
i
Δ
y
i
∑
Δ
x
i
Δ
z
i
∑
Δ
x
i
Δ
y
i
∑
Δ
y
i
2
∑
Δ
y
i
Δ
z
i
∑
Δ
x
i
Δ
z
i
∑
Δ
y
i
Δ
z
i
∑
Δ
z
i
2
]
[
a
b
c
]
=
λ
[
a
b
c
]
\left[\begin{matrix} \sum \Delta x_i^2 & \sum \Delta x_i\Delta y_i & \sum \Delta x_i\Delta z_i \\ \sum \Delta x_i\Delta y_i & \sum \Delta y_i^2 & \sum \Delta y_i\Delta z_i \\ \sum \Delta x_i\Delta z_i & \sum \Delta y_i\Delta z_i & \sum \Delta z_i^2 \end{matrix}\right] \left[\begin{matrix} a \\ b \\ c \end{matrix}\right]= \lambda \left[\begin{matrix} a \\ b \\ c \end{matrix}\right]
∑Δxi2∑ΔxiΔyi∑ΔxiΔzi∑ΔxiΔyi∑Δyi2∑ΔyiΔzi∑ΔxiΔzi∑ΔyiΔzi∑Δzi2
abc
=λ
abc
则需要求的
(
a
,
b
,
c
)
(a,b,c)
(a,b,c)即为
λ
\lambda
λ特征值对应的特征向量。
对于上面左右同时乘
[
a
b
c
]
\left[\begin{matrix}a & b & c \end{matrix}\right]
[abc],即
λ
=
∑
i
=
1
n
(
a
Δ
x
i
+
b
Δ
b
i
+
c
Δ
z
i
)
2
=
∑
i
=
1
n
d
i
2
\lambda=\sum_{i=1}^{n}(a\Delta x_i+b\Delta b_i+c\Delta z_i)^2=\sum_{i=1}^nd_i^2
λ=∑i=1n(aΔxi+bΔbi+cΔzi)2=∑i=1ndi2.
则我们的目标就是求最小特征值对应的特征向量。
3、pcl库计算法向量
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;//创建法向估计对象
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//创建法向数据指针
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);//创建kdtree用于法向计算时近邻搜索
tree->setInputCloud(cloud);//为kdtree输入点云
n.setInputCloud(cloud);//为法向估计对象输入点云
n.setSearchMethod(tree);//设置法向估计时采用的搜索方式为kdtree
n.setKSearch(20);//设置法向估计时,k近邻搜索的点数
n.compute(*normals); //进行法向估计