拉普拉斯算子网格形变

Posted toomanywaytobe

tags:

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

  网格顶点的拉普拉斯坐标定义为 技术分享图片 ,公式中di代表顶点Vi的一环邻域顶点数量

  网格的拉普拉斯坐标用矩阵表示技术分享图片技术分享图片,  然后通过网格的拉普拉斯坐标求解为稀疏线性方程组便可以得到形变后的网格顶点

 

  技术分享图片

  初始化拉普拉斯矩阵

 1 void mainNode::InitLpls()
 2 {
 3     int vertexNumber = m_vecAllVertex.size();
 4     //计算拉普拉斯坐标。方式一
 5     for (int i = 0; i < vertexNumber; i++)
 6     {
 7         pVERTEX pVertex = m_vecAllVertex.at(i);
 8         osg::Vec3 neighborPos(0.0, 0.0, 0.0);
 9         for (int j = 0; j < pVertex->vecNeighborVertex.size(); j++)
10         {
11             neighborPos += pVertex->vecNeighborVertex.at(j)->pos;
12         }
13         pVertex->lplsPos = pVertex->pos - neighborPos / pVertex->vecNeighborVertex.size();
14     }
15 
16     //计算顶点一阶临接顶点的权值
17     for (int i = 0; i < vertexNumber; i++)
18     {
19         pVERTEX pVertex = m_vecAllVertex.at(i);
20         int neighborNumber = pVertex->vecNeighborVertex.size();
21         for (int j = 0; j < neighborNumber; j++)
22         {
23             pVERTEX pNeighbor = pVertex->vecNeighborVertex.at(j);
24             float weight = float(1) / float(neighborNumber);
25             pVertex->mapWeightForOther.insert(std::pair<int, float>(pNeighbor->id, weight) );
26             pVertex->fTotalWeight = 1.0;
27         }
28     }
29 
30     //构建拉普拉斯矩阵
31     int count = 0;
32     std::vector<int> beginNumber(vertexNumber);
33     for (int i = 0; i < vertexNumber; i++)
34     {
35         beginNumber[i] = count;
36         count += m_vecAllVertex[i]->vecNeighborVertex.size() + 1;
37     }
38 
39     std::vector<Eigen::Triplet<float> > vectorTriplet(count);
40     for (int i = 0; i < vertexNumber; i++)
41     {
42         pVERTEX pVertex = m_vecAllVertex.at(i);
43         vectorTriplet[beginNumber[i]] = Eigen::Triplet<float>(i, i, pVertex->fTotalWeight);
44 
45         int j = 0;
46         std::map<int, float>::iterator itor;
47         for(itor = pVertex->mapWeightForOther.begin(); itor != pVertex->mapWeightForOther.end(); itor++)
48         {
49             int neighborID = itor->first;
50             float weight = itor->second;
51             vectorTriplet[beginNumber[i] + j + 1] = Eigen::Triplet<float>(i, neighborID, -weight);
52             j++;
53         }
54     }
55 
56     //加入移动点以及不动点,这里便是调参的地方
57     for (int i = 0; i < 2; i++)
58     {
59         pVERTEX pVertex;
60         if (i == 0)
61         {
62             pVertex = m_vecAllVertex.at(i);
63         }
64         else
65         {
66             pVertex = m_vecAllVertex.at(vertexNumber - 1);
67         }
68 
69         int row = i + vertexNumber;
70         vectorTriplet.push_back(Eigen::Triplet<float>(row, pVertex->id, pVertex->fTotalWeight));
71     }
72     
73     m_vectorTriplet = vectorTriplet;
74     m_Matrix.resize(vertexNumber + 2, vertexNumber);
75     m_Matrix.setFromTriplets(vectorTriplet.begin(), vectorTriplet.end());
76 }

  求解稀疏线性方程组

 1 void mainNode::CalculateMaitrxLpls()
 2 {
 3     Eigen::SparseMatrix<float> Matrix = m_Matrix;
 4     Eigen::SparseMatrix<float> MatrixTranspose = Matrix.transpose();
 5     Eigen::SparseMatrix<float> MatrixLpls = MatrixTranspose * Matrix;
 6 
 7     Eigen::VectorXf targetX, targetY, targetZ;
 8     int vertexNumber = m_vecAllVertex.size();
 9     
10     targetX.resize(vertexNumber + 2);
11     targetY.resize(vertexNumber + 2);
12     targetZ.resize(vertexNumber + 2);
13     
14     for (int i = 0; i < vertexNumber + 2; i++)
15     {
16         if (i < vertexNumber)
17         {
18             targetX[i] = m_vecAllVertex.at(i)->lplsPos.x();
19             targetY[i] = m_vecAllVertex.at(i)->lplsPos.y();
20             targetZ[i] = m_vecAllVertex.at(i)->lplsPos.z();
21         }
22         else if (i < vertexNumber + 1)
23         {
24             //第一个的顶点坐标分量
25             targetX[i] = m_vecAllVertex.at(i - vertexNumber)->pos.x();
26             targetY[i] = m_vecAllVertex.at(i - vertexNumber)->pos.y();
27             targetZ[i] = m_vecAllVertex.at(i - vertexNumber)->pos.z();
28         }
29         else
30         {
31             //最后一个的顶点坐标分量
32             targetX[i] = m_vecAllVertex.at(vertexNumber - 1)->pos.x();
33             targetY[i] = m_vecAllVertex.at(vertexNumber - 1)->pos.y();
34             targetZ[i] = m_vecAllVertex.at(vertexNumber - 1)->pos.z();
35         }
36     }
37     
38     Eigen::SimplicialCholesky<Eigen::SparseMatrix<float> > MatrixCholesky(MatrixLpls);
39     Eigen::VectorXf resX, resY, resZ;
40     resX = MatrixTranspose * targetX;
41     resY = MatrixTranspose * targetY;
42     resZ = MatrixTranspose * targetZ;
43 
44     Eigen::VectorXf X, Y, Z;
45     X = MatrixCholesky.solve(resX);
46     //std::cout << X << std::endl;
47     Y = MatrixCholesky.solve(resY);
48     //std::cout << Y << std::endl;
49     Z = MatrixCholesky.solve(resZ);
50     //std::cout << Z << std::endl;
51     for (int i = 0; i < m_vecAllVertex.size(); i++)
52     {
53         pVERTEX pVertex = m_vecAllVertex.at(i);
54         float x, y, z;
55         x = X[i];
56         y = Y[i];
57         z = Z[i];
58 
59         pVertex->pos = osg::Vec3(X[i], Y[i], Z[i]);
60     }
61 }

 

  参考论文:

  Differential Coordinates for Interactive Mesh Editing

  基于微分坐标的网格morphing

 

以上是关于拉普拉斯算子网格形变的主要内容,如果未能解决你的问题,请参考以下文章

Laplacian Mesh Editing 拉普拉斯形变(待回学校更新)

python坎尼算子索贝尔算子和拉普拉斯算子实现边缘检测

OpenCV之图像梯度 – 拉普拉斯算子(二阶导数算子)

OpenCV之图像梯度 – 拉普拉斯算子(二阶导数算子)

三维人脸模型贴图算法基于离散拉普拉斯-贝尔特拉米算子的三维人脸模型贴图算法的MATLAB仿真

请教高手,关于拉普拉斯算子做图像锐化