Skip to content

Commit c8856fc

Browse files
Add select_by_index method to Feature class (#7039)
* Add select_by_index method to Feature class * better comments --------- Co-authored-by: Benjamin Ummenhofer <[email protected]>
1 parent 4c3fc34 commit c8856fc

File tree

5 files changed

+75
-0
lines changed

5 files changed

+75
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
- Fix alpha shape reconstruction if alpha too small for point scale (PR #6998)
5353
- Fix render to depth image on Apple Retina displays (PR #7001)
5454
- Fix infinite loop in segment_plane if num_points < ransac_n (PR #7032)
55+
- Add select_by_index method to Feature class (PR #7039)
5556

5657
## 0.13
5758

cpp/open3d/pipelines/registration/Feature.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,31 @@ namespace open3d {
1818
namespace pipelines {
1919
namespace registration {
2020

21+
std::shared_ptr<Feature> Feature::SelectByIndex(
22+
const std::vector<size_t> &indices, bool invert /* = false */) const {
23+
auto output = std::make_shared<Feature>();
24+
output->Resize(data_.rows(), indices.size());
25+
26+
std::vector<bool> mask = std::vector<bool>(data_.cols(), invert);
27+
for (size_t i : indices) {
28+
mask[i] = !invert;
29+
}
30+
31+
size_t current_col_feature = 0;
32+
for (size_t i = 0; i < static_cast<size_t>(data_.cols()); i++) {
33+
if (mask[i]) {
34+
output->data_.col(current_col_feature) = data_.col(i);
35+
current_col_feature++;
36+
}
37+
}
38+
39+
utility::LogDebug(
40+
"Feature group down sampled from {:d} features to {:d} features.",
41+
(int)data_.cols(), (int)output->data_.cols());
42+
43+
return output;
44+
}
45+
2146
static Eigen::Vector4d ComputePairFeatures(const Eigen::Vector3d &p1,
2247
const Eigen::Vector3d &n1,
2348
const Eigen::Vector3d &p2,

cpp/open3d/pipelines/registration/Feature.h

+8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ class Feature {
4242
/// Returns number of points.
4343
size_t Num() const { return data_.cols(); }
4444

45+
/// \brief Selects features from \p input Feature group, with indices in \p
46+
/// indices, and returns a new Feature group with selected features.
47+
///
48+
/// \param indices Indices of features to be selected.
49+
/// \param invert Set to `True` to invert the selection of indices.
50+
std::shared_ptr<Feature> SelectByIndex(const std::vector<size_t> &indices,
51+
bool invert = false) const;
52+
4553
public:
4654
/// Data buffer storing features.
4755
Eigen::MatrixXd data_;

cpp/pybind/pipelines/registration/feature.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ void pybind_feature_definitions(py::module &m_registration) {
3131
.def("dimension", &Feature::Dimension,
3232
"Returns feature dimensions per point.")
3333
.def("num", &Feature::Num, "Returns number of points.")
34+
.def("select_by_index", &Feature::SelectByIndex,
35+
"Function to select features from input Feature group into "
36+
"output Feature group.",
37+
"indices"_a, "invert"_a = false)
3438
.def_readwrite("data", &Feature::data_,
3539
"``dim x n`` float64 numpy array: Data buffer "
3640
"storing features.")
@@ -48,6 +52,11 @@ void pybind_feature_definitions(py::module &m_registration) {
4852
docstring::ClassMethodDocInject(m_registration, "Feature", "resize",
4953
{{"dim", "Feature dimension per point."},
5054
{"n", "Number of points."}});
55+
docstring::ClassMethodDocInject(
56+
m_registration, "Feature", "select_by_index",
57+
{{"indices", "Indices of features to be selected."},
58+
{"invert",
59+
"Set to ``True`` to invert the selection of indices."}});
5160
m_registration.def("compute_fpfh_feature", &ComputeFPFHFeature,
5261
"Function to compute FPFH feature for a point cloud",
5362
"input"_a, "search_param"_a);

cpp/tests/t/pipelines/registration/Feature.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,38 @@ INSTANTIATE_TEST_SUITE_P(Feature,
2525
FeaturePermuteDevices,
2626
testing::ValuesIn(PermuteDevices::TestCases()));
2727

28+
TEST_P(FeaturePermuteDevices, SelectByIndex) {
29+
core::Device device = GetParam();
30+
31+
open3d::geometry::PointCloud pcd_legacy;
32+
data::BunnyMesh bunny;
33+
open3d::io::ReadPointCloud(bunny.GetPath(), pcd_legacy);
34+
35+
pcd_legacy.EstimateNormals();
36+
// Convert to float64 to avoid precision loss.
37+
const auto pcd = t::geometry::PointCloud::FromLegacy(pcd_legacy,
38+
core::Float64, device);
39+
40+
const auto fpfh = pipelines::registration::ComputeFPFHFeature(
41+
pcd_legacy, geometry::KDTreeSearchParamHybrid(0.01, 100));
42+
const auto fpfh_t =
43+
t::pipelines::registration::ComputeFPFHFeature(pcd, 100, 0.01);
44+
45+
const auto selected_fpfh =
46+
fpfh->SelectByIndex({53, 194, 839, 2543, 6391, 29483}, false);
47+
const auto selected_indeces_t =
48+
core::TensorKey::IndexTensor(core::Tensor::Init<int64_t>(
49+
{53, 194, 839, 2543, 6391, 29483}, device));
50+
const auto selected_fpfh_t = fpfh_t.GetItem(selected_indeces_t);
51+
52+
EXPECT_TRUE(selected_fpfh_t.AllClose(
53+
core::eigen_converter::EigenMatrixToTensor(selected_fpfh->data_)
54+
.T()
55+
.To(selected_fpfh_t.GetDevice(),
56+
selected_fpfh_t.GetDtype()),
57+
1e-4, 1e-4));
58+
}
59+
2860
TEST_P(FeaturePermuteDevices, ComputeFPFHFeature) {
2961
core::Device device = GetParam();
3062

0 commit comments

Comments
 (0)