21 namespace registration {
29 {core::Float64, core::Float32});
46 bool tree_set =
false;
48 const bool filter_fpfh = indices.
has_value();
52 const double cache_info_indices_ratio_thresh = 0.01;
53 bool cache_fpfh_info =
true;
59 core::Tensor save_p_indices, save_p_distance2, save_p_counts;
65 if (indices.
value().GetLength() == 0) {
80 std::tie(p_indices, p_distance2, p_counts) = tree.
HybridSearch(
81 query_point_positions, radius.
value(), max_nn.
value());
87 std::tie(p_indices, p_distance2) =
91 const int fill_value =
92 max_nn.
value() > num_points ? num_points : max_nn.
value();
101 query_point_positions, radius.
value());
111 map_required_point_idx_to_point_idx =
114 indices_fpfh_points =
117 const bool is_radius_search = p_indices.
GetShape().
size() == 1;
123 cache_fpfh_info = !is_radius_search &&
125 cache_info_indices_ratio_thresh * num_points);
127 if (cache_fpfh_info) {
128 map_point_idx_to_required_point_idx =
130 map_point_idx_to_required_point_idx.
IndexSet(
131 {map_required_point_idx_to_point_idx},
133 0, map_required_point_idx_to_point_idx.
GetLength(),
137 save_p_indices_shape[0] =
138 map_required_point_idx_to_point_idx.
GetLength();
144 {map_required_point_idx_to_point_idx.
GetLength() +
145 (is_radius_search ? 1 : 0)},
149 map_point_idx_to_required_point_idx
153 save_p_indices.
IndexSet({map_fpfh_point_idx_to_required_point_idx},
156 {map_fpfh_point_idx_to_required_point_idx}, p_distance2);
157 save_p_counts.
IndexSet({map_fpfh_point_idx_to_required_point_idx},
167 {map_required_point_idx_to_point_idx},
170 {indices_fpfh_points},
173 mask_spfh_points = mask_required_points;
191 std::tie(p_indices, p_distance2, p_counts) = tree.
HybridSearch(
192 query_point_positions, radius.
value(), max_nn.
value());
194 "Use HybridSearch [max_nn: {} | radius {}] for computing FPFH "
206 if (query_point_positions.
GetLength() > 0) {
207 std::tie(p_indices, p_distance2) =
210 const int fill_value =
211 max_nn.
value() > num_points ? num_points : max_nn.
value();
224 "Use KNNSearch [max_nn: {}] for computing FPFH feature.",
233 std::tie(p_indices, p_distance2, p_counts) =
236 "Use RadiusSearch [radius: {}] for computing FPFH feature.",
246 core::Tensor final_p_indices, final_p_distance2, final_p_counts;
247 if (cache_fpfh_info) {
249 map_point_idx_to_required_point_idx
252 save_p_indices.
IndexSet({map_spfh_idx_to_required_point_idx},
254 save_p_distance2.
IndexSet({map_spfh_idx_to_required_point_idx},
256 save_p_counts.
IndexSet({map_spfh_idx_to_required_point_idx},
258 final_p_indices = save_p_indices;
259 final_p_distance2 = save_p_distance2;
260 final_p_counts = save_p_counts;
262 final_p_indices = p_indices;
263 final_p_distance2 = p_distance2;
264 final_p_counts = p_counts;
268 final_p_indices, final_p_distance2, final_p_counts, fpfh,
269 mask_fpfh_points, map_required_point_idx_to_point_idx);
275 p_distance2, p_counts, fpfh);
283 float mutual_consistent_ratio) {
284 const int num_searches = mutual_filter ? 2 : 1;
286 std::array<core::Tensor, 2> features{source_features, target_features};
287 std::vector<core::Tensor> corres(num_searches);
290 const int kOuterThreads =
std::min(kMaxThreads, num_searches);
294 #pragma omp parallel for num_threads(kOuterThreads)
295 for (
int i = 0; i < num_searches; ++i) {
301 corres[i] =
result.first.View({-1});
304 auto corres_ij = corres[0];
307 corres_ij.GetDtype(), corres_ij.GetDevice());
311 arange_source.
View({-1, 1}).
Append(corres_ij.View({-1, 1}), 1);
313 if (!mutual_filter) {
317 auto corres_ji = corres[1];
323 mutual_consistent_ratio * arange_source.
GetLength()) {
326 return arange_source.
IndexGet({identical})
332 "Too few correspondences ({:d}) after mutual filter, fall back to "
333 "original correspondences.",
#define AssertTensorDtypes(tensor,...)
static TensorKey Index(int64_t index)
void IndexSet(const std::vector< Tensor > &index_tensors, const Tensor &src_tensor)
Advanced indexing getter.
Tensor Eq(const Tensor &value) const
Element-wise equals-to of tensors, returning a new boolean tensor.
static Tensor Arange(const Scalar start, const Scalar stop, const Scalar step=1, const Dtype dtype=core::Int64, const Device &device=core::Device("CPU:0"))
Create a 1D tensor with evenly spaced values in the given interval.
int64_t GetLength() const
Tensor GetItem(const TensorKey &tk) const
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter. This will always allocate a new Tensor.
static Tensor Zeros(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with zeros.
Tensor View(const SizeVector &dst_shape) const
Device GetDevice() const override
static Tensor Ones(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with ones.
SizeVector GetShape() const
Tensor To(Dtype dtype, bool copy=false) const
static Tensor Full(const SizeVector &shape, T fill_value, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with specified value.
A Class for nearest neighbor search.
std::tuple< Tensor, Tensor, Tensor > FixedRadiusSearch(const Tensor &query_points, double radius, bool sort=true)
bool HybridIndex(utility::optional< double > radius={})
bool FixedRadiusIndex(utility::optional< double > radius={})
std::tuple< Tensor, Tensor, Tensor > HybridSearch(const Tensor &query_points, const double radius, const int max_knn) const
std::pair< Tensor, Tensor > KnnSearch(const Tensor &query_points, int knn)
A point cloud contains a list of 3D points.
core::Tensor & GetPointNormals()
Get the value of the "normals" attribute. Convenience function.
core::Tensor & GetPointPositions()
Get the value of the "positions" attribute. Convenience function.
bool HasPointNormals() const
constexpr bool has_value() const noexcept
constexpr T const & value() const &
Tensor Append(const Tensor &self, const Tensor &other, const utility::optional< int64_t > &axis)
Appends the two tensors, along the given axis into a new tensor. Both the tensors must have same data...
void To(const core::Tensor &src, core::Tensor &dst, double scale, double offset)
void ComputeFPFHFeature(const core::Tensor &points, const core::Tensor &normals, const core::Tensor &indices, const core::Tensor &distance2, const core::Tensor &counts, core::Tensor &fpfhs, const utility::optional< core::Tensor > &mask, const utility::optional< core::Tensor > &map_info_idx_to_point_idx)
core::Tensor ComputeFPFHFeature(const geometry::PointCloud &input, const utility::optional< int > max_nn, const utility::optional< double > radius, const utility::optional< core::Tensor > &indices)
core::Tensor CorrespondencesFromFeatures(const core::Tensor &source_features, const core::Tensor &target_features, bool mutual_filter, float mutual_consistent_ratio)
Function to find correspondences via 1-nearest neighbor feature matching. Target is used to construct...
int EstimateMaxThreads()
Estimate the maximum number of threads to be used in a parallel region.
Generic file read and write utility for python interface.