Skip to content

Commit

Permalink
Bug fix, add docs example
Browse files Browse the repository at this point in the history
gcc compiler warning as error (doxygen math) fix
  • Loading branch information
ssheorey committed Nov 18, 2024
1 parent a4f379d commit 9f60d3d
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 38 deletions.
13 changes: 9 additions & 4 deletions cpp/open3d/t/geometry/PointCloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1335,14 +1335,18 @@ int PointCloud::PCAPartition(int max_points) {
core::Tensor PointCloud::ComputeMetrics(const PointCloud &pcd2,
std::vector<Metric> metrics,
MetricParameters params) const {
if (IsEmpty() || pcd2.IsEmpty()) {
utility::LogError("One or both input point clouds are empty!");
}
if (!IsCPU() || !pcd2.IsCPU()) {
utility::LogWarning(
"ComputeDistance is implemented only on CPU. Computing on "
"CPU.");
}
core::Tensor points1 = GetPointPositions().To(core::Device("CPU:0")),
points2 = pcd2.GetPointPositions().To(core::Device("CPU:0"));
core::Tensor indices12, distance12, indices21, distance21;
[[maybe_unused]] core::Tensor indices12, indices21;
core::Tensor sqr_distance12, sqr_distance21;

core::nns::NearestNeighborSearch tree1(points1);
core::nns::NearestNeighborSearch tree2(points2);
Expand All @@ -1354,10 +1358,11 @@ core::Tensor PointCloud::ComputeMetrics(const PointCloud &pcd2,
utility::LogError("[ComputeDistance] Building KNN-Index failed!");
}

std::tie(indices12, distance12) = tree2.KnnSearch(points1, 1);
std::tie(indices21, distance21) = tree2.KnnSearch(points2, 1);
std::tie(indices12, sqr_distance12) = tree2.KnnSearch(points1, 1);
std::tie(indices21, sqr_distance21) = tree1.KnnSearch(points2, 1);

return ComputeMetricsCommon(distance12, distance21, metrics, params);
return ComputeMetricsCommon(sqr_distance12.Sqrt_(), sqr_distance21.Sqrt_(),
metrics, params);
}

} // namespace geometry
Expand Down
12 changes: 6 additions & 6 deletions cpp/open3d/t/geometry/PointCloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -712,17 +712,17 @@ class PointCloud : public Geometry, public DrawableGeometry {

/// \f{eqnarray*}{
/// \text{Chamfer Distance: } d_{CD}(X,Y) &=& \frac{1}{|X|}\sum_{i \in X}
/// || x_i - n(x_i, Y) || +
/// \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X) || \\
/// || x_i - n(x_i, Y) || + \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X)
/// || \\{}
/// \text{Hausdorff distance: } d_H(X,Y) &=& \max \left\{ \max_{i \in X}
/// || x_i - n(x_i, Y) ||, \max_{i \in Y} || y_i - n(y_i, X) || \right\}
/// \\
/// \\{}
/// \text{Precision: } P(X,Y|d) &=& \frac{100}{|X|} \sum_{i \in X} || x_i
/// - n(x_i, Y) || < d \\
/// - n(x_i, Y) || < d \\{}
/// \text{Recall: } R(X,Y|d) &=& \frac{100}{|Y|} \sum_{i \in Y} || y_i -
/// n(y_i, X) || < d \\
/// n(y_i, X) || < d \\{}
/// \text{F-Score: } F(X,Y|d) &=& \frac{2 P(X,Y|d) R(X,Y|d)}{P(X,Y|d) +
/// R(X,Y|d)} \\
/// R(X,Y|d)}
/// \f}

/// \param pcd2 Other point cloud to compare with.
Expand Down
3 changes: 3 additions & 0 deletions cpp/open3d/t/geometry/TriangleMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,9 @@ PointCloud TriangleMesh::SamplePointsUniformly(
core::Tensor TriangleMesh::ComputeMetrics(const TriangleMesh &mesh2,
std::vector<Metric> metrics,
MetricParameters params) const {
if (IsEmpty() || mesh2.IsEmpty()) {
utility::LogError("One or both input triangle meshes are empty!");
}
if (!IsCPU() || !mesh2.IsCPU()) {
utility::LogWarning(
"ComputeDistance is implemented only on CPU. Computing on "
Expand Down
12 changes: 6 additions & 6 deletions cpp/open3d/t/geometry/TriangleMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -1036,17 +1036,17 @@ class TriangleMesh : public Geometry, public DrawableGeometry {

/// \f{eqnarray*}{
/// \text{Chamfer Distance: } d_{CD}(X,Y) &=& \frac{1}{|X|}\sum_{i \in X}
/// || x_i - n(x_i, Y) || +
/// \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X) || \\
/// || x_i - n(x_i, Y) || + \frac{1}{|Y|}\sum_{i \in Y} || y_i - n(y_i, X)
/// || \\{}
/// \text{Hausdorff distance: } d_H(X,Y) &=& \max \left\{ \max_{i \in X}
/// || x_i - n(x_i, Y) ||, \max_{i \in Y} || y_i - n(y_i, X) || \right\}
/// \\
/// \\{}
/// \text{Precision: } P(X,Y|d) &=& \frac{100}{|X|} \sum_{i \in X} || x_i
/// - n(x_i, Y) || < d \\
/// - n(x_i, Y) || < d \\{}
/// \text{Recall: } R(X,Y|d) &=& \frac{100}{|Y|} \sum_{i \in Y} || y_i -
/// n(y_i, X) || < d \\
/// n(y_i, X) || < d \\{}
/// \text{F-Score: } F(X,Y|d) &=& \frac{2 P(X,Y|d) R(X,Y|d)}{P(X,Y|d) +
/// R(X,Y|d)} \\
/// R(X,Y|d)}
/// \f}

/// As a side effect, the triangle areas are saved in the "areas" attribute.
Expand Down
8 changes: 4 additions & 4 deletions cpp/open3d/t/geometry/kernel/Metrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ core::Tensor ComputeMetricsCommon(core::Tensor distance12,
for (Metric metric : metrics) {
switch (metric) {
case Metric::ChamferDistance:
metric_val = (distance21.Reshape({-1}).Mean({0}).Item<float>() +
distance12.Reshape({-1}).Mean({0}).Item<float>());
metric_val = distance21.Reshape({-1}).Mean({-1}).Item<float>() +
distance12.Reshape({-1}).Mean({-1}).Item<float>();
metric_values[idx++] = metric_val;
break;
case Metric::HausdorffDistance:
metric_val = std::max(
distance12.Reshape({-1}).Max({0}).Item<float>(),
distance21.Reshape({-1}).Max({0}).Item<float>());
distance12.Reshape({-1}).Max({-1}).Item<float>(),
distance21.Reshape({-1}).Max({-1}).Item<float>());
metric_values[idx++] = metric_val;
break;
case Metric::FScore:
Expand Down
5 changes: 4 additions & 1 deletion cpp/open3d/t/geometry/kernel/Metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ namespace open3d {
namespace t {
namespace geometry {

/// Common code for computing geometry metrics from pairwise point distances.
/// This function expects Euclidean distances as input and returns the requested
/// metrics between point clouds / meshes.
core::Tensor ComputeMetricsCommon(core::Tensor distance12,
core::Tensor distance21,
std::vector<Metric> metrics,
MetricParameters params);
}
} // namespace geometry
} // namespace t
} // namespace open3d
25 changes: 24 additions & 1 deletion cpp/pybind/t/geometry/pointcloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,30 @@ the partition id for each point.
params (t.geometry.MetricParameters): This holds parameters required by different metrics.
Returns:
Tensor containing the requested metrics.)");
Tensor containing the requested metrics.
Example::
from open3d.t.geometry import TriangleMesh, PointCloud, Metric, MetricParameters
# box is a cube with one vertex at the origin and a side length 1
pos = TriangleMesh.create_box().vertex.positions
pcd1 = PointCloud(pos.clone())
pcd2 = PointCloud(pos * 1.1)
# (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)))
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.),
rtol=1e-6)
)");
}

} // namespace geometry
Expand Down
22 changes: 21 additions & 1 deletion cpp/pybind/t/geometry/trianglemesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,27 @@ As a side effect, the triangle areas are saved in the "areas" attribute.
params (t.geometry.MetricParameters): This holds parameters required by different metrics.
Returns:
Tensor containing the requested metrics.)");
Tensor containing the requested metrics.
Example::
from open3d.t.geometry import TriangleMesh, Metric, MetricParameters
# box is a cube with one vertex at the origin and a side length 1
box1 = TriangleMesh.create_box()
box2 = TriangleMesh.create_box()
box2.vertex.positions *= 1.1
# 3 faces of the cube are the same, and 3 are shifted up by 0.1
metric_params = MetricParameters(fscore_radius=o3d.utility.FloatVector(
(0.05, 0.15)), 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)
)");
}

} // namespace geometry
Expand Down
22 changes: 13 additions & 9 deletions python/test/t/geometry/test_pointcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,18 +197,22 @@ def test_pickle(device):

def test_metrics():

from open3d.t.geometry import Metric, MetricParameters
pos = o3d.t.geometry.TriangleMesh.create_box().vertex.positions
pcd1 = o3d.t.geometry.PointCloud(pos.clone())
pcd2 = o3d.t.geometry.PointCloud(pos * 1.2)

from open3d.t.geometry import TriangleMesh, PointCloud, Metric, MetricParameters
# box is a cube with one vertex at the origin and a side length 1
pos = TriangleMesh.create_box().vertex.positions
pcd1 = PointCloud(pos.clone())
pcd2 = PointCloud(pos * 1.1)

# (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.05, 0.15)))
fscore_radius=o3d.utility.FloatVector((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.06, 0.12, 200. / 3, 100),
rtol=1e-6)
np.testing.assert_allclose(
metrics.cpu().numpy(),
(0.22436734, np.sqrt(3) / 10, 100. / 8, 400. / 8, 700. / 8, 100.),
rtol=1e-6)
16 changes: 10 additions & 6 deletions python/test/t/geometry/test_trianglemesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -1396,18 +1396,22 @@ def test_remove_non_manifold_edges(device, int_t, float_t):

def test_metrics():

from open3d.t.geometry import Metric, MetricParameters
box1 = o3d.t.geometry.TriangleMesh.create_box()
box2 = o3d.t.geometry.TriangleMesh.create_box()
box2.vertex.positions *= 1.2

from open3d.t.geometry import TriangleMesh, Metric, MetricParameters
# box is a cube with one vertex at the origin and a side length 1
box1 = TriangleMesh.create_box()
box2 = TriangleMesh.create_box()
box2.vertex.positions *= 1.1

# 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)),
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.2, 0.34, 45, 53.2),
np.testing.assert_allclose(metrics.cpu().numpy(), (0.1, 0.17, 50, 100),
rtol=0.05)

0 comments on commit 9f60d3d

Please sign in to comment.