File: Feature.cpp

package info (click to toggle)
open3d 0.19.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 83,496 kB
  • sloc: cpp: 206,543; python: 27,254; ansic: 8,356; javascript: 1,883; sh: 1,527; makefile: 259; xml: 69
file content (142 lines) | stat: -rw-r--r-- 5,849 bytes parent folder | download | duplicates (2)
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