Functor4pcs.h
Go to the documentation of this file.
1 //
2 // Created by Sandra Alfaro on 24/04/18.
3 //
4 
5 #ifndef OPENGR_FUNCTOR4PCS_H
6 #define OPENGR_FUNCTOR4PCS_H
7 
8 #include <vector>
9 #include "gr/utils/shared.h"
10 
11 
12 namespace gr {
13  /// Processing functor for the computation of the 4PCS algorithm
14  /// \see Match4pcsBase
15  /// \tparam PairFilterFunctor filters pairs of points during the exploration.
16  /// Must implement PairFilterConcept
17  template <typename PointType, typename PairFilterFunctor, typename Options>
18  struct Functor4PCS {
19  public :
21  using Scalar = typename PointType::Scalar;
22  using PairsVector = std::vector< std::pair<int, int> >;
23  using VectorType = typename PointType::VectorType;
24  using OptionType = Options;
25 
26 
27  private :
28  OptionType myOptions_;
29  std::vector<PointType>& mySampled_Q_3D_;
30  BaseCoordinates &myBase_3D_;
31 
32 
33  public :
34  inline Functor4PCS(std::vector<PointType> &sampled_Q_3D_,
35  BaseCoordinates& base_3D_,
36  const OptionType &options)
39  ,myOptions_ (options) {}
40 
41  /// Initializes the data structures and needed values before the match
42  /// computation.
43  inline void Initialize() {}
44 
45  /// Finds congruent candidates in the set Q, given the invariants and threshold distances.
46  /// Returns true if a non empty set can be found, false otherwise.
47  /// @param invariant1 [in] The first invariant corresponding to the set P_pairs
48  /// of pairs, previously extracted from Q.
49  /// @param invariant2 [in] The second invariant corresponding to the set
50  /// Q_pairs of pairs, previously extracted from Q.
51  /// @param [in] distance_threshold1 The distance for verification.
52  /// @param [in] distance_threshold2 The distance for matching middle points due
53  /// to the invariants (See the paper for e1, e2).
54  /// @param [in] First_pairs The first set of pairs found in Q.
55  /// @param [in] Second_pairs The second set of pairs found in Q.
56  /// @param [out] quadrilaterals The set of congruent quadrilateral. In fact,
57  /// it's a super set from which we extract the real congruent set.
59  Scalar invariant1,
60  Scalar invariant2,
61  Scalar /*distance_threshold1*/,
62  Scalar distance_threshold2,
63  const std::vector <std::pair<int, int>> &First_pairs,
64  const std::vector <std::pair<int, int>> &Second_pairs,
65  typename Traits4pcs<PointType>::Set* quadrilaterals) const {
66  using RangeQuery = typename gr::KdTree<Scalar>::template RangeQuery<>;
67 
68  if (quadrilaterals == nullptr) return false;
69 
70  size_t number_of_points = 2 * First_pairs.size();
71 
72  // We need a temporary kdtree to store the new points corresponding to
73  // invariants in the First_pairs and then query them (for range search) for all
74  // the new points corresponding to the invariants in Second_pairs.
75  quadrilaterals->clear();
76 
77  gr::KdTree<Scalar> kdtree(number_of_points);
78 
79  // Build the kdtree tree using the invariants on First_pairs.
80  for (size_t i = 0; i < First_pairs.size(); ++i) {
81  const VectorType &p1 = mySampled_Q_3D_[First_pairs[i].first].pos();
82  const VectorType &p2 = mySampled_Q_3D_[First_pairs[i].second].pos();
83  kdtree.add(p1 + invariant1 * (p2 - p1));
84  }
85  kdtree.finalize();
86 
87  //Point3D invRes;
88  // Query the Kdtree for all the points corresponding to the invariants in Second_pairs.
89  for (size_t i = 0; i < Second_pairs.size(); ++i) {
90  const VectorType &p1 = mySampled_Q_3D_[Second_pairs[i].first].pos();
91  const VectorType &p2 = mySampled_Q_3D_[Second_pairs[i].second].pos();
92 
93  RangeQuery query;
94  query.queryPoint = p1 + invariant2 * (p2 - p1);
95  query.sqdist = distance_threshold2;
96 
97  kdtree.doQueryDistProcessIndices(query,
98  [quadrilaterals, i, &First_pairs, &Second_pairs](int id) {
99  quadrilaterals->push_back(
100  { First_pairs[id].first,
101  First_pairs[id].second,
102  Second_pairs[i].first,
103  Second_pairs[i].second });
104  });
105  }
106 
107  return quadrilaterals->size() != 0;
108  }
109 
110  /// Constructs pairs of points in Q, corresponding to a single pair in the
111  /// in basein P.
112  /// @param [in] pair_distance The distance between the pairs in P that we have
113  /// to match in the pairs we select from Q.
114  /// @param [in] pair_normal_distance The angle between the normals of the pair
115  /// in P.
116  /// @param [in] pair_distance_epsilon Tolerance on the pair distance. We allow
117  /// candidate pair in Q to have distance of
118  /// pair_distance+-pair_distance_epsilon.
119  /// @param [in] base_point1 The index of the first point in P.
120  /// @param [in] base_point2 The index of the second point in P.
121  /// @param [out] pairs A set of pairs in Q that match the pair in P with
122  /// respect to distance and normals, up to the given tolerance.
123  inline void ExtractPairs(Scalar pair_distance,
124  Scalar pair_normals_angle,
125  Scalar pair_distance_epsilon,
126  int base_point1,
127  int base_point2,
128  PairsVector* pairs) const {
129  if (pairs == nullptr) return;
130 
131  pairs->clear();
132  pairs->reserve(2 * mySampled_Q_3D_.size());
133 
134  PairFilterFunctor fun;
135 
136  // Go over all ordered pairs in Q.
137  for (size_t j = 0; j < mySampled_Q_3D_.size(); ++j) {
138  const PointType& p = mySampled_Q_3D_[j];
139  for (size_t i = j + 1; i < mySampled_Q_3D_.size(); ++i) {
140  const PointType& q = mySampled_Q_3D_[i];
141 #ifndef MULTISCALE
142  // Compute the distance and two normal angles to ensure working with
143  // wrong orientation. We want to verify that the angle between the
144  // normals is close to the angle between normals in the base. This can be
145  // checked independent of the full rotation angles which are not yet
146  // defined by segment matching alone..
147  const Scalar distance = (q.pos() - p.pos()).norm();
148  if (std::abs(distance - pair_distance) > pair_distance_epsilon) continue;
149 #endif
150 
151  std::pair<bool,bool> res = fun(p,q, pair_normals_angle, *myBase_3D_[base_point1],*myBase_3D_[base_point2], myOptions_);
152  if (res.first)
153  pairs->emplace_back(i, j);
154  if (res.second)
155  pairs->emplace_back(j, i);
156  }
157  }
158  }
159 
160  };
161 }
162 
163 
164 #endif //OPENGR_FUNCTOR4PCS_H
Functor4PCS(std::vector< PointType > &sampled_Q_3D_, BaseCoordinates &base_3D_, const OptionType &options)
Definition: Functor4pcs.h:34
Processing functor for the computation of the 4PCS algorithm.
Definition: Functor4pcs.h:18
bool FindCongruentQuadrilaterals(Scalar invariant1, Scalar invariant2, Scalar, Scalar distance_threshold2, const std::vector< std::pair< int, int >> &First_pairs, const std::vector< std::pair< int, int >> &Second_pairs, typename Traits4pcs< PointType >::Set *quadrilaterals) const
Finds congruent candidates in the set Q, given the invariants and threshold distances. Returns true if a non empty set can be found, false otherwise.
Definition: Functor4pcs.h:58
CongruentSetExplorationBase< Traits, PointType, TransformVisitor, PairFilteringFunctor, OptExts... >::Scalar ComputeTransformation(const InputRange1 &P, const InputRange2 &Q, Eigen::Ref< typename CongruentSetExplorationBase< Traits, PointType, TransformVisitor, PairFilteringFunctor, OptExts... >::MatrixType > transformation, const Sampler< PointType > &sampler, TransformVisitor &v)
Definition: congruentSetExplorationBase.hpp:61
void Initialize()
Initializes the data structures and needed values before the match computation.
Definition: Functor4pcs.h:43
void ExtractPairs(Scalar pair_distance, Scalar pair_normals_angle, Scalar pair_distance_epsilon, int base_point1, int base_point2, PairsVector *pairs) const
Constructs pairs of points in Q, corresponding to a single pair in the in basein P.
Definition: Functor4pcs.h:123