Energy-based formulation
u
∗
=
a
r
g
m
i
n
u
E
(
u
)
=
a
g
r
m
i
n
u
1
2
∫
S
(
f
−
u
)
2
+
λ
∣
∣
∣
▽
∣
∣
2
d
A
u^{*}=argmin_{u}E(u)=agrmin_{u}\frac{1}{2}\int_{S}(f-u)^{2}+\lambda|||\triangledown||^{2}dA
u∗=argminuE(u)=agrminu21∫S(f−u)2+λ∣∣∣▽∣∣2dA
f
:
n
o
i
s
y
s
i
g
n
a
l
f:noisy\space signal
f:noisy signal
λ
:
c
o
n
t
r
o
l
s
t
h
e
r
a
t
e
o
f
s
m
o
o
t
h
i
n
g
\space \lambda:controls \space the\space rate\space of \space smoothing
λ:controls the rate of smoothing
u
u
u是我们最终要求解的,其中
(
f
−
u
)
2
(f-u)^{2}
(f−u)2项尽量减少result和noisy signal之间的差距,项
λ
∣
∣
∣
▽
∣
∣
2
\lambda|||\triangledown||^{2}
λ∣∣∣▽∣∣2则尽量控制结果更加的圆滑
注意:
1.当noisy signal为vertex’s position时,我们对顶点的position进行了平滑。除此之外我们还可以选择其他signal平滑,比如vertex’s normal。
2.energy-based formulation 和下文提到的flow-based formulation是等价的。
Flow-based formulation
∂
u
∂
t
=
λ
Δ
u
\frac{\partial u}{\partial t}=\lambda\Delta u
∂t∂u=λΔu
Δ
u
:
\Delta u:
Δu:the laplacian of signal u
λ
:
\lambda :
λ:controls the rate of smooth
显式表达:
u
t
+
1
=
u
t
+
λ
Δ
u
t
u^{t+1}=u^{t}+\lambda \Delta u^{t}
ut+1=ut+λΔut
隐式表达:
u
t
+
1
=
u
t
+
λ
Δ
u
t
+
1
→
u
t
=
(
I
−
λ
Δ
u
)
u
t
+
1
u^{t+1}=u^{t}+\lambda \Delta u^{t+1} \rightarrow u^{t}=(I-\lambda \Delta u)u^{t+1}
ut+1=ut+λΔut+1→ut=(I−λΔu)ut+1
Discrete Laplacian
离散拉普拉斯算子的推导有很多种方式,由于式子太多,敲起来比较麻烦,这里省略了,直接给出结果:
Δ
f
(
v
i
)
=
1
2
A
i
Σ
j
∈
Ω
i
(
c
o
t
α
i
j
+
c
o
t
β
i
j
)
(
f
j
−
f
i
)
\Delta f(v_{i})=\frac{1}{2A_{i}}\Sigma_{j\in \Omega_{i}}(cot\alpha_{ij}+cot\beta_{ij})(f_{j}-f_{i})
Δf(vi)=2Ai1Σj∈Ωi(cotαij+cotβij)(fj−fi)
Δ f ( v i ) = 1 2 A i [ − Σ j ∈ Ω i ( c o t α i j + c o t β i j ) f i + Σ j ∈ Ω i ( c o t α i j + c o t β i j ) f j ] \Delta f(v_{i})=\frac{1}{2A_{i}}[-\Sigma_{j\in \Omega_{i}}(cot\alpha_{ij}+cot\beta_{ij})f_{i}+\Sigma_{j\in \Omega_{i}}(cot\alpha_{ij}+cot\beta_{ij})f_{j}] Δf(vi)=2Ai1[−Σj∈Ωi(cotαij+cotβij)fi+Σj∈Ωi(cotαij+cotβij)fj]
Δ f ( v i ) = [ − Σ j ∈ Ω i ( c o t α i j + c o t β i j ) f i Σ j ∈ Ω i ( c o t α i j + c o t β i j ) f j ] [ f i f j ] \Delta f(v_{i})=\begin{bmatrix} -\Sigma_{j\in \Omega_{i}}(cot\alpha_{ij}+cot\beta_{ij})f_{i}&\Sigma_{j\in \Omega_{i}}(cot\alpha_{ij}+cot\beta_{ij})f_{j} \\ \end{bmatrix}\begin{bmatrix} f_{i}\\f_{j} \end{bmatrix} Δf(vi)=[−Σj∈Ωi(cotαij+cotβij)fiΣj∈Ωi(cotαij+cotβij)fj][fifj]
[
Δ
f
i
Δ
f
j
Δ
f
k
⋮
]
=
[
1
A
i
⋯
1
A
j
⋯
1
A
k
⋯
⋮
⋮
⋮
⋱
]
[
−
Σ
l
∈
Ω
i
(
c
o
t
α
i
l
+
c
o
t
β
i
l
)
c
o
t
α
i
j
+
c
o
t
β
i
j
c
o
t
α
i
k
+
c
o
t
β
i
k
⋯
⋯
⋯
⋮
⋮
⋮
⋱
]
[
f
i
f
j
f
k
⋮
]
\begin{bmatrix}\Delta f_{i}\\ \Delta f_{j}\\ \Delta f_{k}\\ \vdots \end{bmatrix}=\begin{bmatrix}\frac{1}{A_{i}}& & & \cdots \\ & \frac{1}{A_{j}}& &\cdots \\ && \frac{1}{A_{k}}& \cdots \\ \vdots &\vdots &\vdots &\ddots \end{bmatrix}\begin{bmatrix}-\Sigma_{l\in \Omega_{i}}(cot\alpha_{il}+cot\beta_{il})&cot\alpha_{ij}+cot\beta_{ij} & cot\alpha_{ik}+cot\beta_{ik}& \cdots \\ && &\cdots \\ &&& \cdots \\ \vdots &\vdots &\vdots &\ddots \end{bmatrix}\begin{bmatrix} f_{i}\\ f_{j}\\ f_{k}\\ \vdots \end{bmatrix}
⎣⎢⎢⎢⎡ΔfiΔfjΔfk⋮⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎡Ai1⋮Aj1⋮Ak1⋮⋯⋯⋯⋱⎦⎥⎥⎥⎤⎣⎢⎢⎢⎡−Σl∈Ωi(cotαil+cotβil)⋮cotαij+cotβij⋮cotαik+cotβik⋮⋯⋯⋯⋱⎦⎥⎥⎥⎤⎣⎢⎢⎢⎡fifjfk⋮⎦⎥⎥⎥⎤
上面右边的式子中第一个矩阵为
M
−
1
M^{-1}
M−1,其中M为mass matrix,第二个矩阵为cotangent matrix,最后一个矩阵为signal matrix。
求解
隐式表示的矩阵形式:
u
t
=
(
I
−
λ
M
−
1
L
)
u
t
+
1
u^{t} = (I - λM^{-1} L)u^{t+1}
ut=(I−λM−1L)ut+1
M
u
t
=
(
M
−
λ
L
)
u
t
+
1
.
M u^{t} = (M - λL)u^{t+1}.
Mut=(M−λL)ut+1.
A
=
M
−
λ
L
A=M - λL
A=M−λL
b
=
M
u
t
b=M u^{t}
b=Mut
源码
#include "massmatrix.h"
#include "doublearea.h"
void cgpl::massmatrix(
const Eigen::MatrixXd & l,
const Eigen::MatrixXi & F,
Eigen::DiagonalMatrix<double,Eigen::Dynamic> & M)
{
Eigen::VectorXd dblA(F.rows());
cgpl::doublearea(l, dblA);
Eigen::VectorXd areas = Eigen::VectorXd::Zero(F.maxCoeff() + 1);
for (int i = 0; i < F.rows(); i++)
{
Eigen::Vector3i f = F.row(i);
double area = dblA[i];
for (int j = 0; j < f.size(); j++)
{
int v = f[j];
areas[v] += area;
}
}
M.resize(F.maxCoeff() + 1);
M.diagonal() = 1 / (double)6 * areas;
}
计算mass matrix,每个顶点的Local average region近似为周围三角形的面积除以3
#include "cotmatrix.h"
#include <iostream>
#include <vector>
#include <cmath>
typedef Eigen::Triplet<double> T;
// Given edge lengths of a triangle ABC
// Return the cotan of angle A
double my_cot(double a, double b, double c) {
// Heron's Formula
double s = (a + b + c) / 2.0;
double area = sqrt(s * (s - a) * (s - b) * (s - c));
// Law of Sine and Cosine
double sinA = 2.0 * area / (b * c);
double cosA = (a*a - b*b - c*c) / (-2.0 * b * c);
return cosA / sinA;
}
void cgpl::cotmatrix(
const Eigen::MatrixXd & l,
const Eigen::MatrixXi & F,
Eigen::SparseMatrix<double> & L)
{
int nV = F.maxCoeff() + 1;
std::vector<T> tripletList;
for(int fi = 0; fi < F.rows(); fi++) {
for(int e = 0; e < 3; e++) {
int i = F(fi, e);
int j = F(fi, (e + 1) % 3);
double a = l(fi, (e + 2) % 3);
double b = l(fi, (e + 0) % 3);
double c = l(fi, (e + 1) % 3);
double cotA = my_cot(a, b, c);
double Lij = 0.5 * cotA;
tripletList.push_back(T(i, j, Lij));
tripletList.push_back(T(j, i, Lij));
// Diagonal
tripletList.push_back(T(i, i, -Lij));
tripletList.push_back(T(j, j, -Lij));
}
}
L.resize(nV, nV);
L.setFromTriplets(tripletList.begin(), tripletList.end());
}
计算L矩阵
#include "smooth.h"
#include "cotmatrix.h"
#include "massmatrix.h"
#include "edge_lengths.h"
void cgpl::smooth(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const Eigen::MatrixXd & G,
double lambda,
Eigen::MatrixXd & U)
{
Eigen::MatrixXd l;
cgpl::edge_lengths(V, F, l);
Eigen::SparseMatrix<double> L;
cotmatrix(l, F, L);
Eigen::DiagonalMatrix<double,Eigen::Dynamic> M;
massmatrix(l, F, M);
// M * G = (M - lambda * L) * U
Eigen::SparseMatrix<double> A = -lambda * L;
for(int i = 0; i < M.rows(); i++) {
A.coeffRef(i, i) += M.diagonal()[i];
}
Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver(A);
U = solver.solve(M * G);
}
求解方程组
结果
没有smooth
smooth 3次