Laplace mesh editing

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Laplace mesh editing相关的知识,希望对你有一定的参考价值。

 

实现算法:简易的Laplace mesh editing。(2016年3月5日

$实现过程及原理

Laplace 坐标(算子)

这里的表示相对坐标,是某一点相对于其1-领域点的中心点的位置,也就是Laplace坐标。为什么这样表示呢?这样的坐标有两个特点:

1.它的方向与法相比较接近。

2.它的大小接近于曲率。

对于一些网格,我们进行拖动一些点,但是又要使得它的形状和原先的尽可能相似,怎么处理呢?假设为已知大概位置的点,其变换后的大概位置是。考虑这样的能量函数:

 

先来看看这个函数的意义,第一部分表示Laplace坐标变化大小,也就是原先的形状变化大小,第二部分表示对于固定点的位置变化大小。我们最小化这个能像函数就能得到一组点,既能使得形状变化小,又能使得与固定位置变化小。

$实验步骤

1.对能量函数进行求导,求其最小值相当于计算线性方程组

    ,

 ,

2.编写程序,测试。(参见附录)

3.测试结果及软件使用方法

(1)选择一些移动点

 

(2)计算一些必要的参数

 

(3)改变选中点的位置,这几个按钮都可以

 

(4)点击进行编辑

 

(5)效果如下

 

(6)对比原图。

 

$实验注意事项:

1.在对能能量函数进行求解事需要细心,转化成最小二乘法求解线性方程组时每一步都得耐心检查,否则一失足而成千古恨,以至于后面全都错。

2.在对方程组进行输入时,每进行一步都得测试,以防带入变量或者参数错误而得不到正确的结果

3.整合每一块的计算结果,需要对程序的操作流程非常熟悉,得知道第一步该干什么第二步该干什么,如果两个函数的操作顺序反了可能得不到想要的结果,比如如果先对点进行移动在计算Laplace坐标时就是不对的。

4.该清除的量必须清除,否则上一次变换的结果可能对下一次变换产生影响,结果导致只有第一次变换是对的,之后的变换全是错的。

总而言之,需要对实验的基本原理和程序的基本流程非常清楚才能进行编程,否则只会浪费更多的时间。

 

$主要程序代码:

void RenderingWidget::edit_()

{

    classfly();

    compute_matrix();

    get_b();

    solve_system();

    updateGL();

    triple_A.clear();

}

 

void RenderingWidget::compute_parameter()

{

    ptr_mesh_->laplace_position();//先计算laplace坐标

   

}

////////////分类/////////////

 

void RenderingWidget::classfly()

{

    int k =0;

    const std::vector<HE_vert*>& vertices = *(ptr_mesh_->get_vertex_list());

    for(int i = 0;i<vertices.size();i++)

    {

        vertices[i]->point_type = other;

    }

 

    for (int i = 0; i<vertices.size(); i++)

    {

        if (vertices[i]->boundary_flag_ == BOUNDARY) vertices[i]->point_type = boundary;

    }

    for (int i = 0; i < current_index_.size(); i++)

    {

        vertices[current_index_[i]]->point_type = drag;

    }

}

/////////////计算各种矩阵//////////////////

 

void RenderingWidget::compute_matrix()

{

    const std::vector<HE_vert*>& vertices = *(ptr_mesh_->get_vertex_list());

    float r1 = 1.0f / vertices.size();                 //所有点系数

    float r2 = 1.0f / current_index_.size();    //拖动点系数

    float r3 = 0;                         //边界点系数

    for (int i = 0; i < vertices.size(); i++)         //没错

    {

        if (vertices[i]->boundary_flag_==BOUNDARY)

        {

            r3++;

        }

    }

    if (r3>0)

    {

        r3 = 1.0f / r3;

    }

 

    int n = vertices.size();//点的个数

    float lambda = 0.01;

    float beta = 0.01;

    for (int i = 0; i < n; i++)

    {

        triple_A.push_back(Triplet<float>(i, i, 1.0f*r1));

       if (vertices[i]->point_type==boundary)//第二部分,边界点

       {

          triple_A.push_back(Triplet<float>(i, i, r3*beta));

       }

       if (vertices[i]->point_type == drag)

       {

           triple_A.push_back(Triplet<float>(i, i, r2*lambda));

       }

       for (int j = 0; j < vertices[i]->neighborIdx.size(); j++)

       {

           triple_A.push_back(Triplet<float>(i, vertices[i]->neighborIdx[j], -1.0f / vertices[i]->degree_*r1));

       }

 

       for (int j = 0; j < vertices[i]->degree_;j++)

       {

           int idx = vertices[i]->neighborIdx[j];

           int dk = vertices[vertices[i]->neighborIdx[j]]->degree_;

          triple_A.push_back(Triplet<float>(i, idx, -1.0f / dk*r1));

           for (int k = 0; k < dk; k++)

           {

              triple_A.push_back(Triplet<float>(i, vertices[idx]->neighborIdx[k], 1.0f / dk / dk*r1));

           }

       }

    }

    SparseMatrix<float> A(n, n);

    A.setFromTriplets(triple_A.begin(), triple_A.end());

    solver.compute(A);//对A进行预分解

 

}

 

 

void RenderingWidget::get_b()

{

    const std::vector<HE_vert*>& vertices = *(ptr_mesh_->get_vertex_list());

    float r1 = 1.0f / vertices.size();                 //没错

    float r2 = 1.0f / current_index_.size();    //没错

    float r3 = 0;                         //没错

    for (int i = 0; i < vertices.size(); i++)         //没错

    {

        if (vertices[i]->boundary_flag_==BOUNDARY)

        {

            r3++;

        }

    }

    if (r3>0)

    {

        r3 = 1.0f / r3;

    }

 

    int n = vertices.size();

    float lambda = 0.01;

    float beta = 0.01;

    VectorXf bx_(n), by_(n), bz_(n);

    bx_.fill(0);

    by_.fill(0);

    bz_.fill(0);

    for (int i = 0; i < n; i++)

    {

        if (vertices[i]->point_type == drag)//拖动点

        {

       

        bx_[i] += vertices[i]->position_[0] * r2*lambda;

        by_[i] += vertices[i]->position_[1] * r2*lambda;

        bz_[i] += vertices[i]->position_[2] * r2*lambda;

       }

        if (vertices[i]->boundary_flag_==BOUNDARY)//第二部分,边界点

        {

            bx_[i] += vertices[i]->position_[0] * r3*beta;

            by_[i] += vertices[i]->position_[1] * r3*beta;

            bz_[i] += vertices[i]->position_[2] * r3*beta;

        }

 

        bx_[i] += vertices[i]->ab_position[0] * r1;

        by_[i] += vertices[i]->ab_position[1] * r1;

        bz_[i] += vertices[i]->ab_position[2] * r1;

        for (int j = 0; j < vertices[i]->degree_; j++)

        {

            int idx = vertices[i]->neighborIdx[j];

            int dk = vertices[vertices[i]->neighborIdx[j]]->degree_;

            bx_[i] -= vertices[idx]->ab_position[0] / dk*r1;

            by_[i] -= vertices[idx]->ab_position[1] / dk*r1;

            bz_[i] -= vertices[idx]->ab_position[2] / dk*r1;

       

        }

    }

    SparseMatrix<float> A(n, n);

    A.setFromTriplets(triple_A.begin(), triple_A.end());

    bx.clear();

    by.clear();

    bz.clear();

    for (int i = 0; i < n; i++)

    {

        bx.push_back(bx_(i));

        by.push_back(by_(i));

        bz.push_back(bz_(i));

    }

   

}

 

void RenderingWidget::solve_system()

{

    const vector<HE_vert*>& vertices = *(ptr_mesh_->get_vertex_list());

    int n = vertices.size();

    VectorXf bx_(n), by_(n), bz_(n);

    bx_.fill(0);

    by_.fill(0);

    bz_.fill(0);

    for (int i = 0; i < n; i++)

    {

        bx_[i] = bx[i];

        by_[i] = by[i];

        bz_[i] = bz[i];

    }

    bx_ = solver.solve(bx_);

    by_ = solver.solve(by_);

    bz_ = solver.solve(bz_);

 

    for (int i = 0; i < vertices.size(); i++)

    {

        vertices[i]->position_[0] = bx_(i);

        vertices[i]->position_[1] = by_(i);

        vertices[i]->position_[2] = bz_(i);

    }

   

}

 

 

以上是关于Laplace mesh editing的主要内容,如果未能解决你的问题,请参考以下文章

关于p-Laplace的想法

Laplace变换要点

Laplace's equation

laplace transform 拉普拉斯变换

Opencv Laplace算子

[OpenCV] Samples 12: laplace