精华内容
下载资源
问答
  • 提出了一种基于三维泊松方程的数字视频修复算法。首先提取视频帧的梯度场,然后使用基于块的修复方法对梯度进行信息填充,最后在梯度场中建立视频受损区域的三维泊松方程并求解,实现对视频像素的修复。实验结果表明,...
  • 基于三维泊松方程的数字视频修复,赵明,李树涛,提出了一种基于三维泊松方程的数字视频修复算法。首先提取视频帧的梯度场,然后使用基于块的修复方法对梯度进行信息填充,最后在
  • AFEPack Step by Step Tutorial 3: solve 3D Poisson Equation 这个 Tutorial 和前面两个不同。前面两个 Tutorial 都是 AFEPack...这里,三维泊松方程定义 {−Δu(x,y,z)=f(x,y,z),(x,y,z)∈Ωu(x,y,z)∣∂Ω=u0(x,y,z)

    AFEPack Step by Step Tutorial 3: solve 3D Poisson Equation

    这个 Tutorial 和前面两个不同。前面两个 Tutorial 都是 AFEPack 自带的例子,这个 Tutorial 可以认为是在 2D Poisson Equation 的基础上改进,将原来的 2D 方程变成 3D。

    3D Poisson Equation

    这里,三维泊松方程定义
    { − Δ u ( x , y , z ) = f ( x , y , z ) , ( x , y , z ) ∈ Ω u ( x , y , z ) ∣ ∂ Ω = u 0 ( x , y , z ) , ( x , y , z ) ∈ ∂ Ω \left\{\begin{matrix} -\Delta u(x,y,z) = f(x,y,z), \quad (x,y,z) \in \Omega\\ u(x,y,z) |_{\partial \Omega} = u_{0}(x,y,z), \quad (x,y,z) \in \partial \Omega \end{matrix}\right. {Δu(x,y,z)=f(x,y,z),(x,y,z)Ωu(x,y,z)Ω=u0(x,y,z),(x,y,z)Ω
    其中,方程的左端项为 u ( x , y , z ) = s i n ( π x ) s i n ( 2 π y ) s i n ( π z ) u(x,y,z)=sin(\pi x)sin(2 \pi y)sin(\pi z) u(x,y,z)=sin(πx)sin(2πy)sin(πz),方程的右端项为 f ( x , y , z ) = 6 π 2 u ( x , y , z ) f(x,y,z)=6 \pi^{2} u(x,y,z) f(x,y,z)=6π2u(x,y,z),计算区域 Ω = [ 0 , 1 ] × [ 0 , 1 ] × [ 0 , 1 ] \Omega = [0,1] \times [0,1] \times [0,1] Ω=[0,1]×[0,1]×[0,1],边界条件 ∂ Ω \partial \Omega Ω 可以由解析解给出。

    代码实现

    常量定义

    这里我们需要定义维度、 π \pi π

    #define DIM (3)
    #define PI (4.0*atan(1.0))
    

    Step 1: 网格文件

    头文件

    #include <AFEPack/Geometry.h>   /// step 1: Read the mesh
    #include <AFEPack/HGeometry.h>  /// step 1: Read the mesh
    

    C++实现

    	//初始化
    	HGeometryTree<DIM> htree;
    	htree.readMesh("D.mesh");  /// it will find D.n, D.s, D.e
    
    	/// 加密网格
    	int refineRound = 5;
    	IrregularMesh<DIM> ir_mesh; 
    	ir_mesh.reinit(htree);
    	ir_mesh.globalRefine(refineRound);
    	ir_mesh.semiregularize();
    	ir_mesh.regularize(false);
    	Mesh<DIM,DIM> mesh = ir_mesh.regularMesh();
    

    Step 2: 构建模板单元

    我们以三维四面体线性有限单元为例,展示构造有限单元需要的代码和步骤。事实上所有的模板单元信息都保存在文本信息中,我们只需要对信息做初始化以及读入相对应文件。
    Geometry Information 几何信息包括四面体的形状、面积、数值积分信息。
    Coordinate Transformation 坐标变换包含模板单元和真实单元之间的映射信息。
    Degree of Freedom 几何上的自由度信息。
    Basis Function 基函数的信息。
    注:线性元改成二次元只需要修改degree的值

    	/// 选择单元次数:线性元degree = 1; 二次元degree = 2
    	int degree =1;
    
    	/// 构造模板单元
    	std::stringstream tmp_dof, bas_fun;
    	tmp_dof << "tetrahedron/tetrahedron." << degree << ".tmp_dof"; /// 1 stands for piecewise linear polynomial
    	bas_fun << "tetrahedron/tetrahedron." << degree << ".bas_fun"; 
    
    	TemplateGeometry<DIM>   triangle_template_geometry;
    	triangle_template_geometry.readData("tetrahedron/tetrahedron.tmp_geo");
      
    	CoordTransform<DIM,DIM>   triangle_coord_transform;
    	triangle_coord_transform.readData("tetrahedron/tetrahedron.crd_trs");
      
    	TemplateDOF<DIM>        triangle_template_dof(triangle_template_geometry);
    	triangle_template_dof.readData(tmp_dof.str());
      
    	BasisFunctionAdmin<double,DIM,DIM> triangle_basis_function(triangle_template_dof);
    	triangle_basis_function.readData(bas_fun.str());
     
    	std::vector<TemplateElement<double,DIM,DIM> > template_element(1);
    	template_element[0].reinit(triangle_template_geometry,
                                 triangle_template_dof,
                                 triangle_coord_transform,
                                 triangle_basis_function);
    

    注意:这里的代码和二维方程是不一样的,我们要选择三维对应的模板单元。

    Step 3: 构建有限元空间

    有了网格数据和模板单元我们就可以构造有限元空间。事实上实现起来很简单,只需要对每一个几何单元指定一个模板单元。这里我们只考虑线性(或二次)有限单元,因此一个循环即可。

    	/// 构造有限单元
    	FEMSpace<double,DIM> fem_space(mesh, template_element);
    
    	int n_element = mesh.n_geometry(DIM);
    	fem_space.element().resize(n_element);
    	for (int i = 0;i < n_element;i ++)
    	fem_space.element(i).reinit(fem_space,i,0);
    
    	fem_space.buildElement();
    	fem_space.buildDof();
    	fem_space.buildDofBoundaryMark();
    

    Step 4: 构建刚度矩阵

    在有限元空间上构造稀疏矩阵。这里的稀疏矩阵其实就是刚度矩阵 A A A,它的每个元素的值由下面积分给出
    A i , j = ∫ Ω ∇ ψ j ⋅ ∇ ψ i d x , x ∈ Ω , i , j = 1 , … , N A_{i,j} = \int_{\Omega} \nabla \psi_j \cdot \nabla \psi_i dx, \quad x\in \Omega, i,j = 1,\ldots,N Ai,j=Ωψjψidx,xΩ,i,j=1,,N
    实现中上述值是以数值积分的方式求出。数值积分的精度设置为2。

    	/// 构造稀疏矩阵
    	StiffMatrix<DIM,double> stiff_matrix(fem_space);
    	stiff_matrix.algebricAccuracy() = 2;
    	stiff_matrix.build();
    

    Step 5: 解拉普拉斯方程

    构造右端项

    根据定义,RHS 为 f ( x , y ) = 6 π 2 sin ⁡ ( π x ) sin ⁡ ( 2 π y ) sin ⁡ ( π z ) f(x,y) = 6\pi^2\sin(\pi x) \sin(2\pi y) \sin(\pi z) f(x,y)=6π2sin(πx)sin(2πy)sin(πz)

    /// 右端项函数
    double f ( const double * p) 
    {
          return 5*PI*PI*sin(1*PI*p[0]) * sin(2*PI*p[1])*sin(PI*p[2]);
    }
    

    右端项离散化
    b i = ∫ Ω f ψ i , i = 1 , … , N b_i = \int_{\Omega} f \psi_i, \quad i = 1,\ldots,N bi=Ωfψi,i=1,,N

    	/// 构造右端项
    	FEMFunction<double,DIM> solution(fem_space);
    	Vector<double> right_hand_side;
    

    添加边界条件

    根据定义,边界条件 ∂ Ω \partial \Omega Ω u ( x , y ) = sin ⁡ ( π x ) sin ⁡ ( 2 π y ) sin ⁡ ( π z ) u(x,y) = \sin (\pi x) \sin (2\pi y) \sin (\pi z) u(x,y)=sin(πx)sin(2πy)sin(πz)

    /// 边界条件函数
    double u ( const double * p) 
    {
      return sin(PI*p[0]) * sin(2*PI*p[1])*sin (PI*p[2]);
    }
    

    下面我们再添加边界条件。这里,我们使用迪氏边界。

    	/// 添加边界条件  
    	BoundaryFunction<double,DIM> boundary(BoundaryConditionInfo::DIRICHLET, 1, &u);
    	BoundaryConditionAdmin<double,DIM> boundary_admin(fem_space);
    	boundary_admin.add(boundary);
    	boundary_admin.apply(stiff_matrix, solution, right_hand_side);
    

    设计线性求解系统 A x = b Ax=b Ax=b

    我们还是使用 AMG 求解器。AMG 参数设置为 t o l = 1.0 e − 8 tol=1.0e^{-8} tol=1.0e8,最大迭代步数 200 200 200

    	/// AMG 求解 
    	AMGSolver solver(stiff_matrix);
    	solver.solve(solution, right_hand_side, 1.0e-08, 200); 
    

    Step 6: 输出结果

    AFEPack 使用 OpenDX 数据格式。

    	/// 结果输出
    	// 输出 OpenDX 格式数据
    	solution.writeOpenDXData("u.dx");
      
    	// 计算 L2 错误
    	double error = Functional::L2Error(solution, FunctionFunction<double>(&u), 3);
    	std::cerr << "\nL2 error = " << error << std::endl;
    

    这样,我们就完成了三维泊松方程的求解。

    完整代码

    
    // 3D Poisson Equation.cpp :
    //
    
    #include <iostream>
    #include <fstream>
    
    #include <AFEPack/AMGSolver.h>
    #include <AFEPack/Geometry.h>
    #include <AFEPack/TemplateElement.h>
    #include <AFEPack/FEMSpace.h>
    #include <AFEPack/Operator.h>
    #include <AFEPack/Functional.h>
    #include <AFEPack/HGeometry.h>
    
    #define PI (4.0*atan(1.0))
    #define DIM (3)
    
    double u(const double *);
    double f(const double *);
    
    int main(int argc, char * argv[]) {
    	//初始化
    	HGeometryTree<DIM> htree;
    	htree.readMesh("D.mesh");  /// it will find D.n, D.s, D.e
    
    	/// 加密网格
    	int refineRound = 5;
    	IrregularMesh<DIM> ir_mesh; 
    	ir_mesh.reinit(htree);
    	ir_mesh.globalRefine(refineRound);
    	ir_mesh.semiregularize();
    	ir_mesh.regularize(false);
    	Mesh<DIM,DIM> mesh = ir_mesh.regularMesh();
    
    	/// 选择单元次数:线性元degree = 1; 二次元degree = 2
    	int degree =1;
    
    	/// 构造模板单元
    	std::stringstream tmp_dof, bas_fun;
    	tmp_dof << "tetrahedron/tetrahedron." << degree << ".tmp_dof"; /// 1 stands for piecewise linear polynomial
    	bas_fun << "tetrahedron/tetrahedron." << degree << ".bas_fun"; 
    
    	TemplateGeometry<DIM>   triangle_template_geometry;
    	triangle_template_geometry.readData("tetrahedron/tetrahedron.tmp_geo");
      
    	CoordTransform<DIM,DIM>   triangle_coord_transform;
    	triangle_coord_transform.readData("tetrahedron/tetrahedron.crd_trs");
      
    	TemplateDOF<DIM>        triangle_template_dof(triangle_template_geometry);
    	triangle_template_dof.readData(tmp_dof.str());
      
    	BasisFunctionAdmin<double,DIM,DIM> triangle_basis_function(triangle_template_dof);
    	triangle_basis_function.readData(bas_fun.str());
     
    	std::vector<TemplateElement<double,DIM,DIM> > template_element(1);
    	template_element[0].reinit(triangle_template_geometry,
                                 triangle_template_dof,
                                 triangle_coord_transform,
                                 triangle_basis_function);  
    
    	/// 构造有限单元
    	FEMSpace<double,DIM> fem_space(mesh, template_element);
    
    	int n_element = mesh.n_geometry(DIM);
    	fem_space.element().resize(n_element);
    	for (int i = 0;i < n_element;i ++)
    	fem_space.element(i).reinit(fem_space,i,0);
    
    	fem_space.buildElement();
    	fem_space.buildDof();
    	fem_space.buildDofBoundaryMark();
    
    	/// 构造稀疏矩阵
    	StiffMatrix<DIM,double> stiff_matrix(fem_space);
    	stiff_matrix.algebricAccuracy() = 2;
    	stiff_matrix.build();
    
    	/// 构造右端项
    	FEMFunction<double,DIM> solution(fem_space);
    	Vector<double> right_hand_side;
    	Operator::L2Discretize(&f, fem_space, right_hand_side, 2);
    
    	/// 添加边界条件  
    	BoundaryFunction<double,DIM> boundary(BoundaryConditionInfo::DIRICHLET, 1, &u);
    	BoundaryConditionAdmin<double,DIM> boundary_admin(fem_space);
    	boundary_admin.add(boundary);
    	boundary_admin.apply(stiff_matrix, solution, right_hand_side);
    	
    	/// AMG 求解 
    	AMGSolver solver(stiff_matrix);
    	solver.solve(solution, right_hand_side, 1.0e-08, 200); 
    
    	/// 结果输出
    	// 输出 OpenDX 格式数据
    	solution.writeOpenDXData("u.dx");
    	
    	// 计算 L2 错误
    	double error = Functional::L2Error(solution, FunctionFunction<double>(&u), 3);
    	std::cerr << "\nL2 error = " << error << std::endl;
    
      return 0;
    };
    
    double u(const double * p)
    {
    	return sin(PI*p[0]) * sin(2*PI*p[1])*sin (PI*p[2]);
    };
    
    double f(const double * p)
    {
    	return 5*PI*PI*sin(1*PI*p[0]) * sin(2*PI*p[1])*sin(PI*p[2]);
    };
    
    //
    // end of file
    
    
    
    展开全文
  • 所求文献:三维泊松方程数值模拟的多重网格方法 谁有这篇文章,麻烦给我发一份,谢谢。 E-mail:lianglianghelloworld@gmail.com 转载于:https://www.cnblogs.com/liangliangdetianxia/p/4216207.html...

    所求文献:三维泊松方程数值模拟的多重网格方法

    谁有这篇文章,麻烦给我发一份,谢谢。

    E-mail:lianglianghelloworld@gmail.com

    转载于:https://www.cnblogs.com/liangliangdetianxia/p/4216207.html

    展开全文
  • 使用标准的5点模具在2x2平方域上以迭代方式(指定迭代次数)求解2维泊松方程。均质的诺伊曼边界条件已经被使用。 获取源码:https://ai.52learn.online/11867

    使用标准的5点模具在2x2平方域上以迭代方式(指定迭代次数)求解2维泊松方程。均质的诺伊曼边界条件已经被使用。

    展开全文
  • 泊松融合(Poisson Blending)是图像处理领域著名的图像融合算法,自从2003年发表以来,有很多基于此算法的应用和改进研究出现。泊松融合无需像Alpha blending一样的精确抠图就可以得到很自然的结果。 关于泊松融合...

    前言

    泊松融合(Poisson Blending)是图像处理领域著名的图像融合算法,自从2003年发表以来,有很多基于此算法的应用和改进研究出现。泊松融合无需像Alpha blending一样的精确抠图就可以得到很自然的结果。

    在这里插入图片描述

    关于泊松融合原理部分的解析见之前的博客《泊松融合原理浅析》。

    关于针对OpenCV中泊松融合的实现代码(以normalClone为例)进行解读的部分见之前的博客《OpenCV源码解读:泊松融合seamlessClone(normalClone)》。

    在上文中有提到,OpenCV的整个泊松融合算法过程是基于离散傅里叶变换求解泊松方程实现的。在本文,将针对这一方法进行深入分析。

    基础知识

    先复习一下梯度、拉普拉斯、散度的基本知识,然后简要说明泊松融合和泊松方程的关系。

    梯度,拉普拉斯,散度

    在这里插入图片描述
    其中, μ = ∂ f ∂ x \mu =\frac{\partial f}{\partial x} μ=xf ν = ∂ f ∂ y \nu =\frac{\partial f}{\partial y} ν=yf。另外需要说明的一点是二维图像的散度全称应该是梯度的散度,也就是拉普拉斯。

    对于二维图形而言,梯度有两个方向(x和y):
    在这里插入图片描述在OpenCV源码中,计算梯度的部分如下:

    //求X方向的梯度
    void Cloning::computeGradientX( const Mat &img, Mat &gx)
    {
        //X方向梯度核
        Mat kernel = Mat::zeros(1, 3, CV_8S);
        kernel.at<char>(0,2) = 1;
        kernel.at<char>(0,1) = -1;
    
        if(img.channels() == 3)
        {
            filter2D(img, gx, CV_32F, kernel);
        }
        else if (img.channels() == 1)
        {
            filter2D(img, gx, CV_32F, kernel);
            cvtColor(gx, gx, COLOR_GRAY2BGR);
        }
    }
    
    //求Y方向的梯度
    void Cloning::computeGradientY( const Mat &img, Mat &gy)
    {
        //Y方向梯度核
        Mat kernel = Mat::zeros(3, 1, CV_8S);
        kernel.at<char>(2,0) = 1;
        kernel.at<char>(1,0) = -1;
    
        if(img.channels() == 3)
        {
            filter2D(img, gy, CV_32F, kernel);
        }
        else if (img.channels() == 1)
        {
            filter2D(img, gy, CV_32F, kernel);
            cvtColor(gy, gy, COLOR_GRAY2BGR);
        }
    }
    

    拉普拉斯是在梯度的基础上得到的,可以看做是X方向和Y方向的二阶梯度和。

    在OpenCV源码中,计算拉普拉斯的部分是在梯度图的基础上进行的:

    //求X方向的拉普拉斯
    void Cloning::computeLaplacianX( const Mat &img, Mat &laplacianX)
    {
        Mat kernel = Mat::zeros(1, 3, CV_8S);
        kernel.at<char>(0,0) = -1;
        kernel.at<char>(0,1) = 1;
        filter2D(img, laplacianX, CV_32F, kernel);
    }
    
    //求Y方向的拉普拉斯
    void Cloning::computeLaplacianY( const Mat &img, Mat &laplacianY)
    {
        Mat kernel = Mat::zeros(3, 1, CV_8S);
        kernel.at<char>(0,0) = -1;
        kernel.at<char>(1,0) = 1;
        filter2D(img, laplacianY, CV_32F, kernel);
    }
    
    Mat lap = laplacianX + laplacianY;//得到梯度的散度(也就是拉普拉斯)
    

    泊松融合与泊松方程

    泊松融合的核心思想不是让需要融合的两张图像直接叠加,而是让目标图像(dst)在融合部分根据源图像(src)的引导场(实际是梯度场 gradient field )“生长”出新的图像。

    也就是说,只需要提供源图像的梯度场,让目标图像根据自身特点,按照源图像对应的梯度场生成融合部分。由于目标图像是按照自身特点出发生成融合区域,所以融合结果会显得更加自然。

    在这里插入图片描述

    在上述示意图中, S S S是二维实数集 R 2 \Bbb{R}^2 R2的闭合子集, Ω \Omega Ω S S S的边界为 ∂ Ω \partial\Omega Ω闭合子集。 f ∗ f^* f是集合 S − Ω S-\Omega SΩ 部分的函数(如果是图像的话就是指所有像素的像素值), f f f是集合 Ω \Omega Ω 的函数(也就是需要靠解泊松方程来求的函数)。 v \bold v v是集合 Ω \Omega Ω的向量场(构建泊松方程所需)。

    插值结果是如下最小化问题的解:
    在这里插入图片描述
    该问题的解是如下带有狄利克雷边界条件的泊松方程,由此建立起泊松融合与泊松方程之间的关系。
    在这里插入图片描述

    注:狄利克雷(Dirichlet)边界条件是指给定函数值本身在边界条件上的值,而诺伊曼(Neumann)边界条件是指给定函数的一阶梯度在边界条件上的值。

    在这里插入图片描述

    对于二维图像而言,像素点是离散点,因此上述连续空间的偏微分方程可以改写为离散空间的偏微分方程:
    在这里插入图片描述
    其中,p是S中的像素点, N p N_p Np是像素p的四邻域,<p, q>是像素对。此时 Ω \Omega Ω的边界变为 ∂ Ω = { p ∈ S ∖ Ω : N p ∩ Ω ≠ ∅ } \partial\Omega=\{p\in S \setminus \Omega:N_p\cap\Omega \not = \emptyset\} Ω={pSΩ:NpΩ=} f p f_p fp f f f在p点的值。
    在这里插入图片描述

    等式(6)的解满足如下联立线性方程:
    在这里插入图片描述
    当方程中的像素p的四邻域不包含边界点( ∂ Ω \partial\Omega Ω)时:
    在这里插入图片描述
    在这里插入图片描述

    关于泊松方程的求解,方程(7)形式构成一个经典的、稀疏带状、对称、正定系统。可以通过带successive overrelaxation(逐次超松弛)的Gauss-Seidel iteration(高斯-赛德尔迭代)或者V-cycle multigrid方法求解。
    在这里插入图片描述
    根据泊松方程构建形式的不同可以选择上述两种不同的方法进行求解。

    可以看到,上述中的边界通常是不规则的,不便于求解。对于实际图像融合需求来说,我们可以通过在可控条件下扩展融合边界,以此来构建更易求解的方程形式,并加速整个泊松方程的求解过程。

    这就是采用离散傅里叶变换求解泊松方程的出发点。

    DFT解2D泊松方程

    思想介绍

    在这里插入图片描述
    在上图中,给出了任意形式的边界条件 ∂ Ω \partial\Omega Ω。而实际上,我们可以将该边界松弛成一个矩形框roi(例如 ∂ Ω \partial\Omega Ω的外接矩形),此时边界条件可以看成是该矩形框,而内部的梯度则是 Ω \Omega Ω区域的src梯度和 r o i − Ω roi-\Omega roiΩ 区域的dst梯度的合集。
    在这里插入图片描述
    在OpenCV中,该部分的代码如下:

    Mat laplacianX = destinationGradientX + patchGradientX;//将mask区域的源图像X方向梯度和非mask区域的模板图像X方向梯度叠起来,形成新的X方向梯度。此时laplacianX还不是拉普拉斯值
    Mat laplacianY = destinationGradientY + patchGradientY;//将mask区域的源图像Y方向梯度和非mask区域的模板图像Y方向梯度叠起来,形成新的Y方向梯度。此时laplacianY还不是拉普拉斯值
    
    computeLaplacianX(laplacianX,laplacianX);//计算X方向的拉普拉斯值
    computeLaplacianY(laplacianY,laplacianY);//计算Y方向的拉普拉斯值
    

    原先的狄利克雷边界条件也因此需要改动,在OpenCV实现中是构建了外接矩形处的诺伊曼(Neumann)边界条件。

    Mat lap = laplacianX + laplacianY;//得到散度
    
    Mat bound = img.clone();
    
    rectangle(bound, Point(1, 1), Point(img.cols-2, img.rows-2), Scalar::all(0), -1);
    Mat boundary_points;
    Laplacian(bound, boundary_points, CV_32F);//得到边界像素的拉普拉斯。注:对一个标量场求梯度后再求散度,等于拉普拉斯算子作用在其上。
    
    boundary_points = lap - boundary_points;//散度差,构建诺伊曼边界条件
    

    在构建好带诺伊曼边界条件的泊松方程后,采用谱变换方法——离散傅里叶变换求解方程,OpenCV中是采用了离散正弦变换dst求解(源码中有构建奇对称图像的部分,DST求解的整体长度变为原始DFT的2倍左右)。

    注:离散正弦变换(DST for Discrete Sine Transform)是一种与傅立叶变换相关的变换,类似离散傅立叶变换,但是只用实数矩阵。离散正弦变换相当于长度约为它两倍,一个实数且奇对称输入资料的的离散傅立叶变换的虚数部分(因为一个实奇输入的傅立叶变换为纯虚数奇对称输出)。有些变型里将输入或输出移动半个取样。
    一种相关的变换是离散余弦变换,相当于长度约为它两倍,实偶函数的离散傅立叶变换。

    在这里插入图片描述
    注意上述代码中的:

    Mat temp = Mat::zeros(src.rows, 2 * src.cols + 2, CV_32F);//注意2倍关系,求解dst需要构建对称关系
    

    构建出的新的用于求解的序列长度为2*L+2,像素值关系示意如下(假设原始L=3),整体按行呈现出奇对称关系。
    在这里插入图片描述

    另外,2D FFT可以通过两个1D FFT实现(先行变换再列变换或者反之)。需要注意存储矩阵的变换以及新的奇对称关系构建。

    公式推导

    连续域的2D 泊松方程形式如下:
    在这里插入图片描述
    而对于图像而言,是离散域,转为有限差分方程表示:
    在这里插入图片描述
    函数u(x, y)可以表示为:
    在这里插入图片描述
    于是可以得到:
    在这里插入图片描述

    注: Δ 2 \Delta^2 Δ2是二阶差分,即一阶差分 Δ \Delta Δ的差分。

    我们的目标是求解 μ j , l \mu_{j,l} μj,l

    首先,记以下缩写,后续推导会用到:
    在这里插入图片描述
    以及2D discrete cosine transform的逆变换:
    在这里插入图片描述

    代入有限差分方程(时域方程)两侧并消除求和符号,得到频域方程:
    在这里插入图片描述

    又有:
    在这里插入图片描述
    所以:
    在这里插入图片描述
    又:
    在这里插入图片描述
    为了求解 μ ^ m , n \hat\mu_{m,n} μ^m,n,简化方程形式:
    在这里插入图片描述
    在这里插入图片描述

    因此:
    在这里插入图片描述
    代入最初的缩写,得到:
    在这里插入图片描述

    根据上述推导,求解泊松方程,总体分为三大步骤:

    1. 先求2D DST得到 ρ ^ m , n \hat\rho_{m,n} ρ^m,n
    2. 再除以分母 2 ( c o s ( π m J ) + c o s ( π n L ) − 2 ) 2(cos(\frac{\pi m}{J})+cos(\frac{\pi n}{L})-2) 2(cos(Jπm)+cos(Lπn)2)
    3. 最后再通过逆2D DST重建出 μ j , l \mu_{j,l} μj,l

    注:其中2D DST可以通过构建两个1D DFT实现(先行变换再列变换或者反之)。
    The 2-D FFT block computes the fast Fourier transform (FFT). The block does the computation of a two-dimensional M-by-N input matrix in two steps. First it computes the one-dimensional FFT along one dimension (row or column). Then it computes the FFT of the output of the first step along the other dimension (column or row).

    OpenCV该部分的实现代码如下:

    dst(mod_diff, res);//对传入的散度差调用dst方法求解
    
    for(int j = 0 ; j < h-2; j++)
    {
        float * resLinePtr = res.ptr<float>(j);
        for(int i = 0 ; i < w-2; i++)
        {
            resLinePtr[i] /= (filter_X[i] + filter_Y[j] - 4);
        }
    }//调整dst过程参数的系数
    
    dst(res, mod_diff, true);//对第一次dst得到的结果调整后调用逆dst方法求解
    

    至此,泊松方程求解完成,整个泊松融合的核心过程结束。

    版权说明

    本文为原创文章,独家发布在blog.csdn.net/TracelessLe。未经个人允许不得转载。如需帮助请email至tracelessle@163.com
    在这里插入图片描述

    参考资料

    [1] 泊松融合原理浅析
    [2] OpenCV源码解读:泊松融合seamlessClone(normalClone)
    [3] 拉普拉斯算子 - 维基百科,自由的百科全书
    [4] 狄利克雷边界条件 - 维基百科,自由的百科全书
    [5] 诺伊曼边界条件 - 维基百科,自由的百科全书
    [6] 关于使用dct求解零诺依曼边界条件PDE的一点说明
    [7] 使用傅里叶变换(包括差分傅里叶和傅里叶谱方法)及切比雪夫谱方法(配点)法求解PDE
    [8] void Cloning::dst(const Mat& src, Mat& dest, bool invert)
    [9] 离散正弦变换 - 维基百科,自由的百科全书
    [10] Solving a 2D Poisson equation with Neumann boundary conditions through discrete Fourier cosine transform
    [11] NUMERICAL RECIPIES IN C, 2ND EDITION (by PRESS, TEUKOLSKY, VETTERLING & FLANNERY) —— Chapter 19. Partial Differential Equations —— P851
    [12] 差分- 维基百科,自由的百科全书
    [13] OpenCV泊松融合实现源码——opencv/modules/photo/src/seamless_cloning_impl.cpp
    [14] cupoisson/poisson.cu
    [15] 傅里叶正弦、余弦变换 - 维基百科,自由的百科全书
    [16] 泊松图像编辑/融合(Possion image editing)的原理与数值解算法
    [17] Fast algorithm for Poisson equation
    [18] Poisson Image Editing Theory and Fourier Approach
    [19] Fast Poisson Equation Solver using DCT
    [20] 二维离散傅里叶(DFT)与快速傅里叶(FFT)的实现
    [21] 2-D FFT - Compute two-dimensional fast Fourier transform of input
    [22] Accelerating a barotropic ocean model using a GPU
    [23] 二维傅里叶变换是怎么进行的?

    展开全文
  • 我们假设其真解为 u = S i n ( π x ) S i n ( 2 π y ) u=Sin(\pi x)Sin(2\pi y) u=Sin(πx)Sin(2πy),这样带入到泊松方程中。 我们可以先计算 u x x u_{xx} uxx​, u x = π C o s ( π x ) S i n ( 2 π y ) u_...
  • 主要研究半导体器件和等离子体中一类三维双极欧拉泊松方程.当初值是一个定常状态附近的小扰动时,通过对格林函数的分析和对应的能量估计,给出了初边值问题的光滑解的逐点估计;其次,也得到了解的最佳LP衰减率.
  • getElementMatrix() 实现 根据带系数二维泊松方程定义,我们函数实现如下: void Matrix::getElementMatrix( const Element,2>& element0, const Element,2>& element1, const ActiveElementPairIterator<2>:...
  • 泊松方程MATLAB程序

    2018-05-31 15:08:34
    泊松方程MATLAB程序
  • 原标题:学界 | 从泊松方程的解法,聊到泊松图像融合“经典图像融合算法解读。”AI 科技评论按,本文作者成指导,字节跳动算法工程师,本文首发于知乎(https://zhuanlan.zhihu.com/p/68349210),AI 科技评论获其授权...
  • 试求泊松方程的解2.5 具有非齐次边界条件的问题 (*) (14) (15) 利用公式 其中系数 满足 那么 其中系数 计算可得 (94) 于是,问题(94)的解为 因此,原问题(91)的解为 求解下列问题: (91) 例2 另解 选取辅助函数 令 ...
  • 泊松方程

    2014-10-11 18:13:00
    原文链接​ 泊松方程(英语:Poisson's equation)是数学中一个常见于静电学、机械工程和理论物理的偏微分方程,因法国数学家、几何学家及物理学家泊松而...在三维直角坐标系,可以写成 如果有恒等于0,这个方...
  • 泊松方程的表面重建

    2014-11-09 15:36:32
    介绍了使用泊松方程如何重建三维点数数据,恢复原始物体
  • 任意二域上的泊松 使用有限元方法求解具有 RHS f 和 Dirichlet 边界条件的任意二域上的泊松方程
  • 泊松方程解法

    千次阅读 2014-10-22 02:33:00
    原文链接 泊松方程是数学中一个常见于静电学、机械工程和理论物理的偏微分方程。是从法国数学家、几何学家及物理学家泊松而得名的。...在三维直角坐标系,可以写成 如果没有f, 这个方程就会变成拉普拉斯方程...
  • 基于泊松方程的孔洞修补算法
  • 泊松方程到泊松融合(Poisson Matting)

    万次阅读 多人点赞 2010-01-27 00:00:00
    数学无疑是现代数字图像处理技术的一个重要基石,一些效果显著的同时也非常...泊松方程(Poisson Equation)在泊松图像编辑(Poisson Image Editing)以及泊松融合(Poisson Matting)中的应用就是一个典型的例子
  • 本代码主要利用MATLAB工具实现MATLAB——求指定区域上泊松方程的数值解,简单明了,易于理解
  • 雷锋网 AI 科技评论按,本文作者成指导,字节跳动算法工程师,本文首发于知乎,雷...先看看其惊人的融合结果(非论文配图,本人实验结果):这篇文章的实现,无关目前算法领域大火的神经网络,而是基于泊松方程推导得...
  • 有限元求解泊松方程C语言程序(三角剖分)
  • 求解泊松方程的 function Finite_element_tri(Imax) % 用有限元法求解三角形形区域上的Possion方程 Jmax=2*Imax; % 其中Imax Jmax分别表示x轴和y轴方向的网格数其中Jmax等于Imax的两倍 % 定义一些全局变量 global ...
  • 针对特定的温度场模型利用fealpy进行泊松方程求解 问题重述: 在10*10的网格中: 泊松方程: △u=∂2u∂x2+∂2u∂y2=f\bigtriangleup u = \frac{\partial^2u}{\partial x^2} +\frac{\partial^2u}{\partial y^2} =f△...
  • 文件: C-图书馆: COMMON.C、COMMON.H - 数据类型、内存管理LINALG.C, LINALG.H - 对角系统的解PSN_1D.C, PSN_1D.H - 一维泊松求解器PSN_2D.C、PSN_2D.H - 2D 和圆柱泊松求解器 MATLAB 工具箱: PSN_1D_MEX.C - ...
  • 求解离散泊松方程,源于当时的研究项目,从图像生成三维模型,具体内容此处不做细谈。 为了生成具有一定特征凸起的平滑表面,利用G2连续性曲面的二阶偏微分具有G0连续性的特性,构造特征参数表面,该表面只需G0连续...
  • 基于Jacobi迭代,GS迭代,SOR迭代对泊松方程...本文以着一维和二维泊松方程为例子,考虑了Jacobi迭代,GS迭代,SOR迭代这种经典迭代对于求解一维和二维泊松方程的速度与准度,用matlab 写出了相关代码,并且进行了对
  • 先看看其惊人的融合结果(非论文配图,本人实验结果): 这篇文章的实现,无关目前算法领域大火的神经网络,而是基于泊松方程推导得出。 泊松方程是什么? 很多朋友比较熟悉概率论里面的泊松分布。泊松方程,也是同一...
  • 第一个例子:求解泊松方程

    千次阅读 2007-03-29 17:11:00
    未经许可,请勿用于商业用途)[摘要] 狄氏边值问题的泊松方程 EasyMesh 输入文件示例 程序的注释版!!!第一个例子:求解泊松方程AFEPack /老弱 发表于2007-03-03AFEPack 的基本使用方法,我们
  • PCL系列——三维重构之泊松重构

    万次阅读 热门讨论 2016-04-01 09:35:09
    PCL系列 PCL系列——读入PCD格式文件操作 PCL系列——将点云数据写入PCD格式文件 PCL系列——拼接两个点云 ...PCL系列——三维重构之泊松重构 说明通过本教程,我们将会学会: 如果通过泊松算法进行三
  • 平行板电容器的横截面放置在计算域的中心。 使用二有限差分法 (FDM) 算法来求解泊松方程。所得电势在第一幅图中显示为等高线。 第二幅图显示了电场强度的详细轮廓,而第幅图以箭袋图的形式显示了方向向量。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,471
精华内容 588
关键字:

三维泊松方程