From 3d0cf908737ef0dd678b6d0a937b1a32050ebd88 Mon Sep 17 00:00:00 2001 From: Sameer Sheorey Date: Mon, 18 Nov 2024 23:54:22 -0800 Subject: [PATCH] Enable auto conversion from Python list / tuple by using deque. Add __repr__ --- cpp/open3d/t/geometry/Geometry.h | 7 +++++ cpp/pybind/t/geometry/geometry.cpp | 34 ++++++++++++++++----- cpp/pybind/utility/eigen.cpp | 1 - python/test/t/geometry/test_pointcloud.py | 4 +-- python/test/t/geometry/test_trianglemesh.py | 5 +-- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/cpp/open3d/t/geometry/Geometry.h b/cpp/open3d/t/geometry/Geometry.h index 823f670ffcb..83e566ea2fb 100644 --- a/cpp/open3d/t/geometry/Geometry.h +++ b/cpp/open3d/t/geometry/Geometry.h @@ -7,6 +7,8 @@ #pragma once +#include + #include #include "open3d/core/Device.h" @@ -106,6 +108,11 @@ struct MetricParameters { /// distance computation. This specifies the number of points sampled. No /// sampling is done for point clouds. size_t n_sampled_points = 1000; + std::string ToString() const { + return fmt::format( + "MetricParameters: fscore_radius={}, n_sampled_points={}", + fscore_radius, n_sampled_points); + } }; } // namespace geometry diff --git a/cpp/pybind/t/geometry/geometry.cpp b/cpp/pybind/t/geometry/geometry.cpp index 19140568401..f6c57124c84 100644 --- a/cpp/pybind/t/geometry/geometry.cpp +++ b/cpp/pybind/t/geometry/geometry.cpp @@ -7,8 +7,10 @@ #include "open3d/t/geometry/Geometry.h" +#include #include +#include #include #include "pybind/docstring.h" @@ -56,7 +58,6 @@ void pybind_geometry_declarations(py::module& m) { "Hausdorff Distance") .value("FScore", Metric::FScore, "F-Score") .export_values(); - py::bind_vector>(m_geometry, "VectorMetric"); py::class_ metric_parameters( m_geometry, "MetricParameters", "Holder for various parameters required by metrics."); @@ -75,23 +76,40 @@ void pybind_geometry_declarations(py::module& m) { void pybind_geometry_definitions(py::module& m) { auto m_geometry = static_cast(m.attr("geometry")); + py::bind_vector>(m_geometry, "VectorMetric"); auto metric_parameters = static_cast>( m_geometry.attr("MetricParameters")); + // Use std::deque instead of std::vector to enable automatic Python list / + // tuple conversion. FIXME: Ideally this should work for std::vector. metric_parameters - .def(py::init&, size_t>(), - "fscore_radius"_a = std::vector{0.01}, + .def(py::init([](const std::deque& fsr, size_t nsp) { + std::vector fsrvec{fsr.begin(), fsr.end()}; + return MetricParameters{fsrvec, nsp}; + }), + "fscore_radius"_a = std::deque{0.01f}, "n_sampled_points"_a = 1000) - .def_readwrite("fscore_radius", &MetricParameters::fscore_radius, - "Radius for computing the F-Score. A match between " - "a point and its nearest neighbor is sucessful if " - "it is within this radius.") + .def_property( + "fscore_radius", + [](const MetricParameters& self) { // getter + return std::deque(self.fscore_radius.begin(), + self.fscore_radius.end()); + }, + [](MetricParameters& self, + const std::deque& fsr) { // setter + self.fscore_radius = + std::vector(fsr.begin(), fsr.end()); + }, + "Radius for computing the F-Score. A match between " + "a point and its nearest neighbor is sucessful if " + "it is within this radius.") .def_readwrite("n_sampled_points", &MetricParameters::n_sampled_points, "Points are sampled uniformly from the surface of " "triangle meshes before distance computation. This " "specifies the number of points sampled. No " - "sampling is done for point clouds."); + "sampling is done for point clouds.") + .def("__repr__", &MetricParameters::ToString); pybind_geometry_class_definitions(m_geometry); pybind_drawable_geometry_class_definitions(m_geometry); diff --git a/cpp/pybind/utility/eigen.cpp b/cpp/pybind/utility/eigen.cpp index 232433642a6..1eb621772eb 100644 --- a/cpp/pybind/utility/eigen.cpp +++ b/cpp/pybind/utility/eigen.cpp @@ -308,7 +308,6 @@ namespace utility { void pybind_eigen_declarations(py::module &m) { auto intvector = pybind_eigen_vector_of_scalar(m, "IntVector"); - auto floatvector = pybind_eigen_vector_of_scalar(m, "FloatVector"); auto doublevector = pybind_eigen_vector_of_scalar(m, "DoubleVector"); auto vector3dvector = pybind_eigen_vector_of_vector( diff --git a/python/test/t/geometry/test_pointcloud.py b/python/test/t/geometry/test_pointcloud.py index ac02aa860da..dc98b1db951 100644 --- a/python/test/t/geometry/test_pointcloud.py +++ b/python/test/t/geometry/test_pointcloud.py @@ -205,13 +205,11 @@ def test_metrics(): # (1, 3, 3, 1) vertices are shifted by (0, 0.1, 0.1*sqrt(2), 0.1*sqrt(3)) # respectively - metric_params = MetricParameters( - fscore_radius=o3d.utility.FloatVector((0.01, 0.11, 0.15, 0.18))) + metric_params = MetricParameters(fscore_radius=(0.01, 0.11, 0.15, 0.18)) metrics = pcd1.compute_metrics( pcd2, (Metric.ChamferDistance, Metric.HausdorffDistance, Metric.FScore), metric_params) - print(metrics) np.testing.assert_allclose( metrics.cpu().numpy(), (0.22436734, np.sqrt(3) / 10, 100. / 8, 400. / 8, 700. / 8, 100.), diff --git a/python/test/t/geometry/test_trianglemesh.py b/python/test/t/geometry/test_trianglemesh.py index 91b130dfeae..88678e3f877 100644 --- a/python/test/t/geometry/test_trianglemesh.py +++ b/python/test/t/geometry/test_trianglemesh.py @@ -1404,14 +1404,11 @@ def test_metrics(): # 3 faces of the cube are the same, and 3 are shifted up by 0.1 - raycast # distances should follow this. - metric_params = MetricParameters(fscore_radius=o3d.utility.FloatVector( - (0.05, 0.15)), + metric_params = MetricParameters(fscore_radius=(0.05, 0.15), n_sampled_points=100000) - # n_sampled_points=100000) metrics = box1.compute_metrics( box2, (Metric.ChamferDistance, Metric.HausdorffDistance, Metric.FScore), metric_params) - print(metrics) np.testing.assert_allclose(metrics.cpu().numpy(), (0.1, 0.17, 50, 100), rtol=0.05)