From 90f3d8b738b90b27fb3c49870ac59ea1b91ad18c Mon Sep 17 00:00:00 2001 From: Bharath Kumar Date: Thu, 4 Apr 2024 16:18:38 -0700 Subject: [PATCH 1/5] [Mesh] Copy UV coordinates from a reference mesh --- cpp/open3d/geometry/TriangleMesh.cpp | 62 ++++++++++++++++++++++++++++ cpp/open3d/geometry/TriangleMesh.h | 7 ++++ 2 files changed, 69 insertions(+) diff --git a/cpp/open3d/geometry/TriangleMesh.cpp b/cpp/open3d/geometry/TriangleMesh.cpp index 88f602770cb..8d7d52d8a77 100644 --- a/cpp/open3d/geometry/TriangleMesh.cpp +++ b/cpp/open3d/geometry/TriangleMesh.cpp @@ -153,6 +153,68 @@ TriangleMesh &TriangleMesh::ComputeAdjacencyList() { return *this; } +TriangleMesh TriangleMesh::InterpolateTextureCoordinatesFrom(const TriangleMesh &input_mesh){ + KDTreeFlann kdtree(input_mesh); + + // Custom equality function for Eigen::Vector2d + struct Vector2dEqual { + bool operator()(const Eigen::Vector2d& v1, const Eigen::Vector2d& v2) const { + return v1.isApprox(v2); + } + }; + using vector2d_set = std::unordered_set, Vector2dEqual>; + + // Maps vertex index to set of uvs in input mesh + std::unordered_map vertex_to_uvs; + for (size_t i = 0; i < input_mesh.triangles_.size(); i++) { + const Eigen::Vector3i &triangle = input_mesh.triangles_[i]; + for (int j = 0; j < 3; j++) { + int vertex_idx = triangle[j]; + auto uv = input_mesh.triangle_uvs_[i * 3 + j]; + if(vertex_to_uvs[vertex_idx].find(uv) == vertex_to_uvs[vertex_idx].end()){ + vertex_to_uvs[vertex_idx].insert(uv); + } + } + } + + + auto distance = [](const Eigen::Vector2d &v1, const Eigen::Vector2d &v2) { + return (v1 - v2).norm(); + }; + + // Gets the uvs coordinates that are closest to each other, given 3 sets of uvs corresponding to each vertex + // of a triangle + auto get_best_uvs = [&distance](const vector2d_set &uvs1, const vector2d_set &uvs2, const vector2d_set &uvs3){ + std::vector best_uvs{Eigen::Vector2d(0, 0), Eigen::Vector2d(0, 0), Eigen::Vector2d(0, 0)}; + if (uvs1.size() == 0 || uvs2.size() == 0 || uvs3.size() == 0) return best_uvs; + + double minimum_distance = std::numeric_limits::max(); + for(auto &uv1 : uvs1){ + for(auto &uv2 : uvs2){ + for(auto &uv3 : uvs3){ + auto aggregate_distance = distance(uv1, uv2) + distance(uv2, uv3) + distance(uv3, uv1); + if (aggregate_distance < minimum_distance){ + minimum_distance = aggregate_distance; + best_uvs = {uv1, uv2, uv3}; + } + } + } + } + return best_uvs; + }; + + // Writes the uvs to the triangle mesh + for(const auto &triangle: triangles_){ + auto best_uvs = get_best_uvs(vertex_to_uvs[triangle(0)], vertex_to_uvs[triangle(1)], vertex_to_uvs[triangle(2)]); + for(auto &uv : best_uvs){ + triangle_uvs_.push_back(uv); + } + } + + return *this; +} + + std::shared_ptr TriangleMesh::FilterSharpen( int number_of_iterations, double strength, FilterScope scope) const { bool filter_vertex = diff --git a/cpp/open3d/geometry/TriangleMesh.h b/cpp/open3d/geometry/TriangleMesh.h index ba3105f0d60..8c5b59de952 100644 --- a/cpp/open3d/geometry/TriangleMesh.h +++ b/cpp/open3d/geometry/TriangleMesh.h @@ -149,6 +149,13 @@ class TriangleMesh : public MeshBase { /// This function might help to close triangle soups. TriangleMesh &MergeCloseVertices(double eps); + /// \brief Function to interpolate UVs from input mesh to this mesh. + /// UVs are interpolated based on the UVs of the closest vertices + /// in the input mesh. + /// + /// \param input_mesh The input mesh from which UVs are interpolated. + TriangleMesh InterpolateTextureCoordinatesFrom(const TriangleMesh &input_mesh); + /// \brief Function to sharpen triangle mesh. /// /// The output value (\f$v_o\f$) is the input value (\f$v_i\f$) plus From 4fad7535a5dacacb55c47c763fa098aba03128aa Mon Sep 17 00:00:00 2001 From: Bharath Kumar Date: Thu, 4 Apr 2024 16:52:32 -0700 Subject: [PATCH 2/5] update code style --- cpp/open3d/geometry/TriangleMesh.cpp | 71 ++++++++++++++++------------ cpp/open3d/geometry/TriangleMesh.h | 7 +-- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/cpp/open3d/geometry/TriangleMesh.cpp b/cpp/open3d/geometry/TriangleMesh.cpp index 8d7d52d8a77..f2e786822f2 100644 --- a/cpp/open3d/geometry/TriangleMesh.cpp +++ b/cpp/open3d/geometry/TriangleMesh.cpp @@ -153,47 +153,59 @@ TriangleMesh &TriangleMesh::ComputeAdjacencyList() { return *this; } -TriangleMesh TriangleMesh::InterpolateTextureCoordinatesFrom(const TriangleMesh &input_mesh){ +TriangleMesh TriangleMesh::InterpolateTextureCoordinatesFrom( + const TriangleMesh &input_mesh) { KDTreeFlann kdtree(input_mesh); - - // Custom equality function for Eigen::Vector2d + + // Custom equality function for Eigen::Vector2d struct Vector2dEqual { - bool operator()(const Eigen::Vector2d& v1, const Eigen::Vector2d& v2) const { + bool operator()(const Eigen::Vector2d &v1, + const Eigen::Vector2d &v2) const { return v1.isApprox(v2); } }; - using vector2d_set = std::unordered_set, Vector2dEqual>; - - // Maps vertex index to set of uvs in input mesh + using vector2d_set = + std::unordered_set, + Vector2dEqual>; + + // Maps vertex index to set of uvs in input mesh std::unordered_map vertex_to_uvs; for (size_t i = 0; i < input_mesh.triangles_.size(); i++) { const Eigen::Vector3i &triangle = input_mesh.triangles_[i]; for (int j = 0; j < 3; j++) { int vertex_idx = triangle[j]; auto uv = input_mesh.triangle_uvs_[i * 3 + j]; - if(vertex_to_uvs[vertex_idx].find(uv) == vertex_to_uvs[vertex_idx].end()){ + if (vertex_to_uvs[vertex_idx].find(uv) == + vertex_to_uvs[vertex_idx].end()) { vertex_to_uvs[vertex_idx].insert(uv); } } } - - + auto distance = [](const Eigen::Vector2d &v1, const Eigen::Vector2d &v2) { return (v1 - v2).norm(); }; - - // Gets the uvs coordinates that are closest to each other, given 3 sets of uvs corresponding to each vertex - // of a triangle - auto get_best_uvs = [&distance](const vector2d_set &uvs1, const vector2d_set &uvs2, const vector2d_set &uvs3){ - std::vector best_uvs{Eigen::Vector2d(0, 0), Eigen::Vector2d(0, 0), Eigen::Vector2d(0, 0)}; - if (uvs1.size() == 0 || uvs2.size() == 0 || uvs3.size() == 0) return best_uvs; - + + // Gets the uvs coordinates that are closest to each other, given 3 sets of + // uvs corresponding to each vertex of a triangle + auto get_best_uvs = [&distance](const vector2d_set &uvs1, + const vector2d_set &uvs2, + const vector2d_set &uvs3) { + std::vector best_uvs{Eigen::Vector2d(0, 0), + Eigen::Vector2d(0, 0), + Eigen::Vector2d(0, 0)}; + if (uvs1.size() == 0 || uvs2.size() == 0 || uvs3.size() == 0) + return best_uvs; + double minimum_distance = std::numeric_limits::max(); - for(auto &uv1 : uvs1){ - for(auto &uv2 : uvs2){ - for(auto &uv3 : uvs3){ - auto aggregate_distance = distance(uv1, uv2) + distance(uv2, uv3) + distance(uv3, uv1); - if (aggregate_distance < minimum_distance){ + for (auto &uv1 : uvs1) { + for (auto &uv2 : uvs2) { + for (auto &uv3 : uvs3) { + auto aggregate_distance = distance(uv1, uv2) + + distance(uv2, uv3) + + distance(uv3, uv1); + if (aggregate_distance < minimum_distance) { minimum_distance = aggregate_distance; best_uvs = {uv1, uv2, uv3}; } @@ -202,18 +214,19 @@ TriangleMesh TriangleMesh::InterpolateTextureCoordinatesFrom(const TriangleMesh } return best_uvs; }; - + // Writes the uvs to the triangle mesh - for(const auto &triangle: triangles_){ - auto best_uvs = get_best_uvs(vertex_to_uvs[triangle(0)], vertex_to_uvs[triangle(1)], vertex_to_uvs[triangle(2)]); - for(auto &uv : best_uvs){ + for (const auto &triangle : triangles_) { + auto best_uvs = get_best_uvs(vertex_to_uvs[triangle(0)], + vertex_to_uvs[triangle(1)], + vertex_to_uvs[triangle(2)]); + for (auto &uv : best_uvs) { triangle_uvs_.push_back(uv); } } - - return *this; -} + return *this; +} std::shared_ptr TriangleMesh::FilterSharpen( int number_of_iterations, double strength, FilterScope scope) const { diff --git a/cpp/open3d/geometry/TriangleMesh.h b/cpp/open3d/geometry/TriangleMesh.h index 8c5b59de952..6761b8c7346 100644 --- a/cpp/open3d/geometry/TriangleMesh.h +++ b/cpp/open3d/geometry/TriangleMesh.h @@ -150,11 +150,12 @@ class TriangleMesh : public MeshBase { TriangleMesh &MergeCloseVertices(double eps); /// \brief Function to interpolate UVs from input mesh to this mesh. - /// UVs are interpolated based on the UVs of the closest vertices + /// UVs are interpolated based on the UVs of the closest vertices /// in the input mesh. - /// + /// /// \param input_mesh The input mesh from which UVs are interpolated. - TriangleMesh InterpolateTextureCoordinatesFrom(const TriangleMesh &input_mesh); + TriangleMesh InterpolateTextureCoordinatesFrom( + const TriangleMesh &input_mesh); /// \brief Function to sharpen triangle mesh. /// From 5b87e6ac6c53cb3d2db41de54bc599b36caf0237 Mon Sep 17 00:00:00 2001 From: Bharath Kumar Date: Thu, 4 Apr 2024 16:54:35 -0700 Subject: [PATCH 3/5] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3509dda95e6..e332578a7e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - Fix regression in printing cuda tensor from PR #6444 🐛 - Add Python pathlib support for file IO (PR #6619) - Fix log error message for `probability` argument validation in `PointCloud::SegmentPlane` (PR #6622) +- Copy UV coordinates from a reference mesh #6740 ## 0.13 From 8e3ba6086c982c0e689aa048bbb757a81760c792 Mon Sep 17 00:00:00 2001 From: Bharath Kumar Date: Thu, 4 Apr 2024 22:55:49 -0700 Subject: [PATCH 4/5] Added pybind changes --- cpp/open3d/geometry/TriangleMesh.h | 2 +- cpp/pybind/geometry/trianglemesh.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cpp/open3d/geometry/TriangleMesh.h b/cpp/open3d/geometry/TriangleMesh.h index 6761b8c7346..5a802c4611e 100644 --- a/cpp/open3d/geometry/TriangleMesh.h +++ b/cpp/open3d/geometry/TriangleMesh.h @@ -150,7 +150,7 @@ class TriangleMesh : public MeshBase { TriangleMesh &MergeCloseVertices(double eps); /// \brief Function to interpolate UVs from input mesh to this mesh. - /// UVs are interpolated based on the UVs of the closest vertices + /// UVs are interpolated from the UVs of the closest vertices /// in the input mesh. /// /// \param input_mesh The input mesh from which UVs are interpolated. diff --git a/cpp/pybind/geometry/trianglemesh.cpp b/cpp/pybind/geometry/trianglemesh.cpp index 311aa311b86..b8ac62b4ac1 100644 --- a/cpp/pybind/geometry/trianglemesh.cpp +++ b/cpp/pybind/geometry/trianglemesh.cpp @@ -97,6 +97,12 @@ void pybind_trianglemesh(py::module &m) { "function might help to " "close triangle soups.", "eps"_a) + .def("interpolate_texture_coordinates_from", + &TriangleMesh::InterpolateTextureCoordinatesFrom, + "Function to interpolate texture coordinates from another " + "triangle mesh. Texture is interpolated from the UVs of the " + "closest vertices in the input mesh", + "input_mesh"_a) .def("filter_sharpen", &TriangleMesh::FilterSharpen, "Function to sharpen triangle mesh. The output value " "(:math:`v_o`) is the input value (:math:`v_i`) plus strength " From 32c396c7c60ec340e20e95a0392deffa1748032e Mon Sep 17 00:00:00 2001 From: Bharath Kumar Date: Thu, 4 Apr 2024 23:07:31 -0700 Subject: [PATCH 5/5] changed comment --- cpp/open3d/geometry/TriangleMesh.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/open3d/geometry/TriangleMesh.cpp b/cpp/open3d/geometry/TriangleMesh.cpp index f2e786822f2..191cb8432f3 100644 --- a/cpp/open3d/geometry/TriangleMesh.cpp +++ b/cpp/open3d/geometry/TriangleMesh.cpp @@ -187,8 +187,9 @@ TriangleMesh TriangleMesh::InterpolateTextureCoordinatesFrom( return (v1 - v2).norm(); }; - // Gets the uvs coordinates that are closest to each other, given 3 sets of - // uvs corresponding to each vertex of a triangle + // Gets the uv coordinates combination that are closest to each other (one + // uv coordinate from each set), given 3 uv sets corresponding to each + // vertex of a triangle auto get_best_uvs = [&distance](const vector2d_set &uvs1, const vector2d_set &uvs2, const vector2d_set &uvs3) {