1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
// ----------------------------------------------------------------------------
// - Open3D: www.open3d.org -
// ----------------------------------------------------------------------------
// Copyright (c) 2018-2024 www.open3d.org
// SPDX-License-Identifier: MIT
// ----------------------------------------------------------------------------
#include "open3d/t/pipelines/registration/Feature.h"
#include "core/CoreTest.h"
#include "open3d/core/EigenConverter.h"
#include "open3d/core/Tensor.h"
#include "open3d/data/Dataset.h"
#include "open3d/geometry/PointCloud.h"
#include "open3d/pipelines/registration/Feature.h"
#include "open3d/t/geometry/PointCloud.h"
#include "open3d/t/io/PointCloudIO.h"
#include "tests/Tests.h"
namespace open3d {
namespace tests {
class FeaturePermuteDevices : public PermuteDevices {};
INSTANTIATE_TEST_SUITE_P(Feature,
FeaturePermuteDevices,
testing::ValuesIn(PermuteDevices::TestCases()));
TEST_P(FeaturePermuteDevices, SelectByIndex) {
core::Device device = GetParam();
open3d::geometry::PointCloud pcd_legacy;
data::BunnyMesh bunny;
open3d::io::ReadPointCloud(bunny.GetPath(), pcd_legacy);
pcd_legacy.EstimateNormals();
// Convert to float64 to avoid precision loss.
const auto pcd = t::geometry::PointCloud::FromLegacy(pcd_legacy,
core::Float64, device);
const auto fpfh = pipelines::registration::ComputeFPFHFeature(
pcd_legacy, geometry::KDTreeSearchParamHybrid(0.01, 100));
const auto fpfh_t =
t::pipelines::registration::ComputeFPFHFeature(pcd, 100, 0.01);
const auto selected_fpfh =
fpfh->SelectByIndex({53, 194, 839, 2543, 6391, 29483}, false);
const auto selected_indeces_t =
core::TensorKey::IndexTensor(core::Tensor::Init<int64_t>(
{53, 194, 839, 2543, 6391, 29483}, device));
const auto selected_fpfh_t = fpfh_t.GetItem(selected_indeces_t);
EXPECT_TRUE(selected_fpfh_t.AllClose(
core::eigen_converter::EigenMatrixToTensor(selected_fpfh->data_)
.T()
.To(selected_fpfh_t.GetDevice(),
selected_fpfh_t.GetDtype()),
1e-4, 1e-4));
}
TEST_P(FeaturePermuteDevices, ComputeFPFHFeature) {
core::Device device = GetParam();
open3d::geometry::PointCloud pcd_legacy;
data::BunnyMesh byunny;
open3d::io::ReadPointCloud(byunny.GetPath(), pcd_legacy);
pcd_legacy.EstimateNormals();
// Convert to float64 to avoid precision loss.
const auto pcd = t::geometry::PointCloud::FromLegacy(pcd_legacy,
core::Float64, device);
const auto fpfh = pipelines::registration::ComputeFPFHFeature(
pcd_legacy, geometry::KDTreeSearchParamHybrid(0.01, 100));
const auto fpfh_t =
t::pipelines::registration::ComputeFPFHFeature(pcd, 100, 0.01);
EXPECT_TRUE(fpfh_t.AllClose(
core::eigen_converter::EigenMatrixToTensor(fpfh->data_)
.T()
.To(fpfh_t.GetDevice(), fpfh_t.GetDtype()),
1e-4, 1e-4));
}
TEST_P(FeaturePermuteDevices, CorrespondencesFromFeatures) {
core::Device device = GetParam();
const float kVoxelSize = 0.05f;
const float kFPFHRadius = kVoxelSize * 5;
t::geometry::PointCloud source_tpcd, target_tpcd;
data::DemoICPPointClouds pcd_fragments;
t::io::ReadPointCloud(pcd_fragments.GetPaths()[0], source_tpcd);
t::io::ReadPointCloud(pcd_fragments.GetPaths()[1], target_tpcd);
source_tpcd = source_tpcd.To(device).VoxelDownSample(kVoxelSize);
target_tpcd = target_tpcd.To(device).VoxelDownSample(kVoxelSize);
auto t_source_fpfh = t::pipelines::registration::ComputeFPFHFeature(
source_tpcd, 100, kFPFHRadius);
auto t_target_fpfh = t::pipelines::registration::ComputeFPFHFeature(
target_tpcd, 100, kFPFHRadius);
pipelines::registration::Feature source_fpfh, target_fpfh;
source_fpfh.data_ =
core::eigen_converter::TensorToEigenMatrixXd(t_source_fpfh.T());
target_fpfh.data_ =
core::eigen_converter::TensorToEigenMatrixXd(t_target_fpfh.T());
for (auto mutual_filter : std::vector<bool>{true, false}) {
auto t_correspondences =
t::pipelines::registration::CorrespondencesFromFeatures(
t_source_fpfh, t_target_fpfh, mutual_filter);
auto correspondences =
pipelines::registration::CorrespondencesFromFeatures(
source_fpfh, target_fpfh, mutual_filter);
auto t_correspondence_idx =
t_correspondences.T().GetItem(core::TensorKey::Index(1));
auto correspondence_idx =
core::eigen_converter::EigenVector2iVectorToTensor(
correspondences, core::Dtype::Int64, device)
.T()
.GetItem(core::TensorKey::Index(1));
// TODO(wei): mask.to(float).sum() has ISPC issues. Use advanced
// indexing instead.
if (!mutual_filter) {
auto mask = t_correspondence_idx.Eq(correspondence_idx);
auto masked_idx = t_correspondence_idx.IndexGet({mask});
float valid_ratio = float(masked_idx.GetLength()) /
float(t_correspondence_idx.GetLength());
EXPECT_NEAR(valid_ratio, 1.0, 1e-2);
} else {
auto consistent_ratio = float(t_correspondence_idx.GetLength()) /
float(correspondences.size());
EXPECT_NEAR(consistent_ratio, 1.0, 1e-2);
}
}
}
} // namespace tests
} // namespace open3d
|