MeshCoordinates l1_ls_inpainting(CMesh& mesh, const std::vector<int>& missing_idx, ParaL1LsInpainting& para) { const int totalVertCount = mesh.vertCount(); MeshLaplacian graphLaplacian; graphLaplacian.constructUmbrella(&mesh); int eigenCount = para.eigen_count; // -1 means full decomposition if (eigenCount == -1) eigenCount = totalVertCount - 1; ZGeom::EigenSystem es; graphLaplacian.meshEigenDecompose(eigenCount, &g_engineWrapper, es); ZGeom::Dictionary dictMHB; computeDictionary(DT_Fourier, es, dictMHB); ZGeom::DenseMatrixd matCoordOld = mesh.getVertCoordinates().toDenseMatrix(); ZGeom::DenseMatrixd matDict = dictMHB.toDenseMatrix(); CStopWatch timer; timer.startTimer(); ZGeom::DenseMatrixd matCoordInpainted = matlab_inpaintL1LS(matCoordOld, matDict, missing_idx, para.lambda, para.tol); timer.stopTimer("-- L1_Ls inpainting time: "); MeshCoordinates coordInpainted; coordInpainted.fromDenseMatrix(matCoordInpainted); return coordInpainted; }
MeshCoordinates thin_plate_energy_hole_inpainting(CMesh& mesh, const ZGeom::MeshRegion& hole_region, int nIter, double eps) { const vector<int> anchor_verts = ZGeom::vertSurroundingVerts(mesh, hole_region.vert_inside, 2); vector<int> submesh_verts; int inside_vert_count = (int)hole_region.vert_inside.size(); int anchor_vert_count = (int)anchor_verts.size(); vector<int> newVert2oldVert(inside_vert_count); for (int i = 0; i < inside_vert_count; ++i) { int vi = hole_region.vert_inside[i]; submesh_verts.push_back(vi); newVert2oldVert[i] = vi; } for (int vi : anchor_verts) submesh_verts.push_back(vi); CMesh submesh; mesh.getSubMesh(submesh_verts, "hole_mesh", submesh); MeshCoordinates faired_sub_coord = thin_plate_energy_fairing(submesh, inside_vert_count); MeshCoordinates result(mesh.getVertCoordinates()); for (int sub_vIdx = 0; sub_vIdx < inside_vert_count; ++sub_vIdx) { result.setVertCoord(newVert2oldVert[sub_vIdx], faired_sub_coord[sub_vIdx]); } return result; }
////////////////////////////////////////////////////////////////////////// // format: zmesh_operator [mesh_file_name] // currently, just output three types of Laplacian operator in .mat Matlab file int main(int argc, char *argv[]) { using namespace std; using namespace ZGeom; using namespace std::tr2::sys; if (argc < 2) { std::cerr << "Lack argument!" << std::endl; std::exit(-1); } string meshfile = argv[1]; if (!fileExist(meshfile)) { std::cerr << "Mesh file not existent!" << std::endl; std::exit(-1); } CMesh mesh; mesh.load(meshfile); mesh.scaleToUnitBox(); int N = mesh.vertCount(); mesh.scaleAndTranslate(-mesh.calMeshCenter(), 1.0); Laplacian umbrella, goemUmbrella, cotformula; umbrella.constructUmbrella(&mesh); cotformula.constructCotFormula(&mesh); auto coord = mesh.getVertCoordinates(); DenseMatrixd matCoord = coord.toDenseMatrix(); ZGeom::calMeshAttrVertNormals(mesh, ZGeom::VN_AREA_WEIGHT); auto normals = ZGeom::getMeshVertNormals(mesh); DenseMatrixd matNormal(N, 3); for (int i = 0; i < N; ++i) { for (int j = 0; j < 3; ++j) matNormal(i, j) = normals[i][j]; } calMeshAttrMixedVertAreas(mesh); ZGeom::computeMeshCurvatures(mesh, true); Laplacian anisoLap; anisoLap.constructAniso(&mesh); MatlabEngineWrapper eng; eng.open(); auto pwd = initial_path<path>(); eng.eval("cd " + pwd.string()); eng.addDenseMat(matCoord, "mat_coord"); eng.addDenseMat(matNormal, "mat_normal"); eng.addSparseMat(umbrella.getLS(), "mat_umbrella"); eng.addSparseMat(cotformula.getW(), "mat_weight"); eng.addSparseMat(cotformula.getLS(), "mat_cot"); eng.addSparseMat(anisoLap.getLS(), "mat_aniso"); eng.eval("save meshlaplace.mat mat_coord mat_normal mat_umbrella mat_weight mat_cot mat_aniso"); eng.close(); cout << "Mesh and Laplace .mat file saved!" << endl; exit(0); }
MeshCoordinates meshDLRS(CMesh& mesh, double lambda) { int totalVertCount = mesh.vertCount(); MeshCoordinates coordCurrent = mesh.getVertCoordinates(); MeshLaplacian graphLaplacian; graphLaplacian.constructUmbrella(&mesh); vector<VecNd> vDenoisedCoord = DLRS(graphLaplacian.getLS(), lambda, coordCurrent.to3Vec()); MeshCoordinates coordDenoised(totalVertCount, vDenoisedCoord); return coordDenoised; }
MeshCoordinates thin_plate_energy_fairing(CMesh& mesh, int free_vert_count) { const int totalVertCount = mesh.vertCount(); const MeshCoordinates coordOld = mesh.getVertCoordinates(); vector<VecNd> vOriginalCoords = coordOld.to3Vec(); MeshLaplacian mesh_laplacian; mesh_laplacian.constructCotFormula(&mesh); SparseMatrixd matL = mesh_laplacian.getSparseMatrix(); SparseMatrixd matL2; mulMatMat(matL, matL, matL2); vector<int> rowIdxL2, colIdxL2; vector<double> valsL2; matL2.convertToCOO(rowIdxL2, colIdxL2, valsL2, ZGeom::MAT_FULL); vector<int> rowIdxA, colIdxA; vector<double> valsA; for (int i = 0; i < (int)rowIdxL2.size(); ++i) { if (rowIdxL2[i] < free_vert_count && colIdxL2[i] < free_vert_count) { rowIdxA.push_back(rowIdxL2[i]); colIdxA.push_back(colIdxL2[i]); valsA.push_back(valsL2[i]); } } SparseMatrixd matA; matA.convertFromCOO(free_vert_count, free_vert_count, rowIdxA, colIdxA, valsA); DenseMatrixd matB(free_vert_count, 3); for (int m = 0; m < 3; ++m) { for (int i = 0; i < free_vert_count; ++i) { for (int j = free_vert_count; j < totalVertCount; ++j) matB(i, m) -= matL2(i, j) * vOriginalCoords[m][j]; } } g_engineWrapper.addSparseMat(matA, "matA"); g_engineWrapper.addDenseMat(matB, "matB"); g_engineWrapper.eval("matX=matA\\matB;"); DenseMatrixd matX = g_engineWrapper.getDenseMat("matX"); vector<VecNd> vNewCoord = vOriginalCoords; for (int m = 0; m < 3; ++m) for (int i = 0; i < free_vert_count; ++i) vNewCoord[m][i] = matX(i, m); MeshCoordinates result(totalVertCount, vNewCoord); return result; }
MeshCoordinates least_square_hole_inpainting(CMesh& mesh, const std::vector<ZGeom::MeshRegion>& hole_regions, int anchor_ring, double anchor_weight) { ZGeom::logic_assert(anchor_weight >= 0, "Illegal parameter!"); MeshCoordinates result(mesh.getVertCoordinates()); if (anchor_ring <= 0) { vector<int> hole_verts = getMeshRegionsInsideVerts(hole_regions); set<int> set_hole_verts(hole_verts.begin(), hole_verts.end()); set<int> anchor_verts; for (int vi = 0; vi < (int)mesh.vertCount(); ++vi) { if (!setHas(set_hole_verts, vi)) anchor_verts.insert(vi); } MeshCoordinates faired_coord = least_square_inpainting(mesh, vector<int>(anchor_verts.begin(),anchor_verts.end()), anchor_weight); for (int vi : hole_verts) result.setVertCoord(vi, faired_coord[vi]); return result; } for (const MeshRegion& mr : hole_regions) { const vector<int> anchor_verts = ZGeom::vertSurroundingVerts(mesh, mr.vert_inside, anchor_ring); vector<int> submesh_verts; int inside_vert_count = (int)mr.vert_inside.size(); int anchor_vert_count = (int)anchor_verts.size(); vector<int> newVert2oldVert(inside_vert_count); int newVertIdx(0); for (int vi : mr.vert_inside) { submesh_verts.push_back(vi); newVert2oldVert[newVertIdx++] = vi; } for (int vi : anchor_verts) submesh_verts.push_back(vi); CMesh submesh; mesh.getSubMesh(submesh_verts, "hole_mesh", submesh); vector<int> control_verts; for (int i = inside_vert_count; i < (int)submesh_verts.size(); ++i) control_verts.push_back(i); MeshCoordinates faired_sub_coord = least_square_inpainting(submesh, control_verts, anchor_weight); for (int sub_vIdx = 0; sub_vIdx < inside_vert_count; ++sub_vIdx) { result.setVertCoord(newVert2oldVert[sub_vIdx], faired_sub_coord[sub_vIdx]); } } return result; }
MeshCoordinates l1_ls_hole_inpainting(CMesh& mesh, const std::vector<ZGeom::MeshRegion>& hole_regions, ParaL1LsInpainting& para) { MeshCoordinates result(mesh.getVertCoordinates()); if (para.fitting_ring <= 0) { vector<int> hole_verts = getMeshRegionsInsideVerts(hole_regions); MeshCoordinates faired_coord = l1_ls_inpainting(mesh, hole_verts, para); for (int vi : hole_verts) result.setVertCoord(vi, faired_coord[vi]); return result; } for (const ZGeom::MeshRegion& mr : hole_regions) { const vector<int> anchor_verts = ZGeom::vertSurroundingVerts(mesh, mr.vert_inside, para.fitting_ring); vector<int> submesh_verts; int inside_vert_count = (int)mr.vert_inside.size(); int anchor_vert_count = (int)anchor_verts.size(); vector<int> newVert2oldVert(inside_vert_count); vector<int> missing_verts; int newVertIdx(0); for (int vi : mr.vert_inside) { submesh_verts.push_back(vi); missing_verts.push_back(newVertIdx); newVert2oldVert[newVertIdx++] = vi; } for (int vi : anchor_verts) submesh_verts.push_back(vi); CMesh submesh; mesh.getSubMesh(submesh_verts, "hole_mesh", submesh); MeshCoordinates faired_sub_coord = l1_ls_inpainting(submesh, missing_verts, para); for (int sub_vIdx = 0; sub_vIdx < inside_vert_count; ++sub_vIdx) { result.setVertCoord(newVert2oldVert[sub_vIdx], faired_sub_coord[sub_vIdx]); } } return result; }
MeshCoordinates least_square_inpainting(CMesh& mesh, const std::vector<int>& anchor_verts, double anchor_weight) { const int totalVertCount = mesh.vertCount(); const MeshCoordinates coordOld = mesh.getVertCoordinates(); vector<VecNd> vOriginalCoords = coordOld.to3Vec(); MeshLaplacian matLaplacian; matLaplacian.constructTutte(&mesh); const vector<int> &vControlVerts = anchor_verts; set<int> setControlVerts{ anchor_verts.begin(), anchor_verts.end() }; int controlVertCount = (int)anchor_verts.size(); double controlWeight = anchor_weight; vector<int> rowIdxA, colIdxA; vector<double> valsA; matLaplacian.getSparseMatrix().convertToCOO(rowIdxA, colIdxA, valsA, ZGeom::MAT_FULL); for (int i = 0; i < controlVertCount; ++i) { rowIdxA.push_back(totalVertCount + i + 1); colIdxA.push_back(vControlVerts[i] + 1); valsA.push_back(controlWeight); } SparseMatrixd matA(totalVertCount + controlVertCount, totalVertCount); matA.convertFromCOO(totalVertCount + controlVertCount, totalVertCount, rowIdxA, colIdxA, valsA); DenseMatrixd matB(totalVertCount + controlVertCount, 3); for (int i = 0; i < controlVertCount; ++i) { for (int j = 0; j < 3; ++j) matB(totalVertCount + i, j) = controlWeight * vOriginalCoords[j][vControlVerts[i]]; } g_engineWrapper.addSparseMat(matA, "matA"); g_engineWrapper.addDenseMat(matB, "matB"); g_engineWrapper.eval("matX=matA\\matB;"); DenseMatrixd matX = g_engineWrapper.getDenseMat("matX"); MeshCoordinates result; result.fromDenseMatrix(matX); return result; }
MeshCoordinates meshHoleDLRS(CMesh& mesh, const std::vector<MeshRegion>& hole_regions, double lambda, int anchor_ring) { MeshCoordinates result(mesh.getVertCoordinates()); if (anchor_ring <= 0) { vector<int> hole_verts = getMeshRegionsInsideVerts(hole_regions); MeshCoordinates faired_coord = meshDLRS(mesh, lambda); for (int vi : hole_verts) result.setVertCoord(vi, faired_coord[vi]); return result; } for (const MeshRegion& mr : hole_regions) { const vector<int> anchor_verts = ZGeom::vertSurroundingVerts(mesh, mr.vert_inside, anchor_ring); vector<int> submesh_verts; int inside_vert_count = (int)mr.vert_inside.size(); vector<int> newVert2oldVert(inside_vert_count); int newVertIdx(0); for (int vi : mr.vert_inside) { submesh_verts.push_back(vi); newVert2oldVert[newVertIdx++] = vi; } for (int vi : anchor_verts) submesh_verts.push_back(vi); CMesh submesh; mesh.getSubMesh(submesh_verts, "hole_mesh", submesh); MeshCoordinates faired_sub_coord = meshDLRS(submesh, lambda); for (int sub_vIdx = 0; sub_vIdx < inside_vert_count; ++sub_vIdx) { result.setVertCoord(newVert2oldVert[sub_vIdx], faired_sub_coord[sub_vIdx]); } } return result; }