【数字几何处理】 Laplacian Smooth 源码+介绍

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)=agrminu21S(fu)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} (fu)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 tu=λΔ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+1ut=(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)(fjfi)

Δ 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=Ai1Aj1Ak1ΣlΩi(cotαil+cotβil)cotαij+cotβijcotαik+cotβikfifjfk
上面右边的式子中第一个矩阵为 M − 1 M^{-1} M1,其中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λM1L)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次
在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值