@@ -45,30 +45,32 @@ namespace fs = boost::filesystem;
4545
4646static const std::size_t MAX_LEAF_ELEMENTS = 10 ;
4747
48- template <typename DATA>
49- struct PointVectorAdaptator
48+ struct LandmarksAdaptator
5049{
51- using Derived = PointVectorAdaptator ; // !< In this case the dataset class is myself.
50+ using Derived = LandmarksAdaptator ; // !< In this case the dataset class is myself.
5251 using T = double ;
5352
54- const DATA& _data;
55- PointVectorAdaptator (const DATA& data)
56- : _data(data)
57- {
58- }
59-
6053 // / CRTP helper method
6154 inline const Derived& derived () const { return *static_cast <const Derived*>(this ); }
6255 // / CRTP helper method
6356 inline Derived& derived () { return *static_cast <Derived*>(this ); }
6457
58+ const sfmData::Landmarks& _data;
59+ LandmarksAdaptator (const sfmData::Landmarks& data)
60+ : _data(data)
61+ {
62+ }
63+
6564 // Must return the number of data points
6665 inline size_t kdtree_get_point_count () const { return _data.size (); }
6766
6867 // Returns the dim'th component of the idx'th point in the class:
69- // Since this is inlined and the "dim" argument is typically an immediate value, the
70- // "if/else's" are actually solved at compile time.
71- inline T kdtree_get_pt (const size_t idx, int dim) const { return _data.at (idx).m [dim]; }
68+ inline T kdtree_get_pt (const size_t idx, int dim) const
69+ {
70+ auto it = _data.begin ();
71+ std::advance (it, idx);
72+ return it->second .X (dim);
73+ }
7274
7375 // Optional bounding-box computation: return false to default to a standard bbox computation loop.
7476 // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it
@@ -80,50 +82,52 @@ struct PointVectorAdaptator
8082 }
8183};
8284
83- template <typename DATA>
8485using KdTree = nanoflann::KDTreeSingleIndexAdaptor<
85- nanoflann::L2_Simple_Adaptor<double , PointVectorAdaptator>,
86- PointVectorAdaptator, 3 /* dim */
86+ nanoflann::L2_Simple_Adaptor<double , LandmarksAdaptator>,
87+ LandmarksAdaptator,
88+ 3 , /* dim */
89+ IndexT
8790>;
8891
89- template <typename DATA>
90- class Tree
92+ /* *
93+ * A result-set class used when performing a radius based search.
94+ */
95+ class PixSizeSearch
9196{
92- std::unique_ptr<KdTree> _tree;
93- std::unique_ptr<PointVectorAdaptator> _pointCloudRef;
94-
9597public:
96- Tree (const DATA& data) { initKdTree (data); }
97-
98- void initKdTree (const DATA& data)
98+ const double _radius_sq;
99+ const std::vector<double >& _pixSize;
100+ const double _pixSize_i;
101+ bool found = false ;
102+
103+ inline PixSizeSearch (double radius, const std::vector<double >& pixSize, int i)
104+ : _radius_sq(radius * radius)
105+ , _pixSize(pixSize)
106+ , _pixSize_i(pixSize[i])
99107 {
100- ALICEVISION_LOG_INFO (" Build nanoflann KdTree index." );
101- _pointCloudRef = std::make_unique<PointVectorAdaptator>(data);
102- _tree = std::make_unique<KdTree>(3 /* dim*/ , *_pointCloudRef.get (),
103- nanoflann::KDTreeSingleIndexAdaptorParams (MAX_LEAF_ELEMENTS));
104- _tree->buildIndex ();
105- ALICEVISION_LOG_INFO (" KdTree created for " << data.size () << " points." );
106108 }
107109
108- bool locateNearestVertex (const Point3d& p, std::size_t & index, double & sq_dist) const
110+ inline bool full () const { return found; }
111+
112+ inline bool addPoint (double dist, IndexT index)
109113 {
110- index = std::numeric_limits<std::size_t >::max ();
111- sq_dist = std::numeric_limits<double >::max ();
112- nanoflann::KNNResultSet<double , std::size_t > resultSet (1 );
113- resultSet.init (&index, &sq_dist);
114- if (!_tree->findNeighbors (resultSet, p.m , nanoflann::SearchParams ()))
114+ if (dist < _radius_sq && _pixSize[index] < _pixSize_i)
115115 {
116+ found = true ;
116117 return false ;
117118 }
118119 return true ;
119120 }
121+
122+ inline double worstDist () const { return _radius_sq; }
120123};
121124
122- bool filterLandmarks (SfMData& sfmData)
125+ bool filterLandmarks (SfMData& sfmData, double radiusScale )
123126{
124127 mvsUtils::MultiViewParams mp (sfmData, " " , " " , " " , false );
125- std::vector<std::pair< double , IndexT> > landmarksPixSize (sfmData.getLandmarks ().size ());
128+ std::vector<double > landmarksPixSize (sfmData.getLandmarks ().size ());
126129
130+ ALICEVISION_LOG_INFO (" Computing pixel size: started." );
127131 #pragma omp parallel for
128132 for (auto i = 0 ; i < sfmData.getLandmarks ().size (); i++)
129133 {
@@ -137,26 +141,56 @@ bool filterLandmarks(SfMData& sfmData)
137141 for (const auto & observationPair : landmark.observations )
138142 {
139143 const IndexT viewId = observationPair.first ;
140- auto d = mp.getCamPixelSize (Point3d (landmark.X .x (), landmark.X .y (), landmark.X .z ()),
144+ pixSize + = mp.getCamPixelSize (Point3d (landmark.X .x (), landmark.X .y (), landmark.X .z ()),
141145 mp.getIndexFromViewId (viewId), observationPair.second .scale );
142- if (d < 0 .)
143- d = 0 .;
144- pixSize += d;
145- if (pixSize < 0 .)
146- pixSize = 0 .;
147146 n++;
148147 }
149- if (pixSize < 0 .)
150- pixSize = 0 .;
151148 pixSize /= n;
152- if (pixSize < 0 .)
153- pixSize = 0 .;
154149
155- landmarksPixSize[i] = std::pair< double , IndexT>( pixSize, landmarkPair-> first ) ;
150+ landmarksPixSize[i] = pixSize;
156151 }
152+ ALICEVISION_LOG_INFO (" Computing pixel size: done." );
153+
154+ // // sort landmarks by descending pixSize order
155+ // std::stable_sort(landmarksPixSize.begin(), landmarksPixSize.end(), std::greater<>{});
157156
158- // sort landmarks by descending pixSize order
159- std::stable_sort (landmarksPixSize.begin (), landmarksPixSize.end (), std::greater<>{});
157+ ALICEVISION_LOG_INFO (" Build nanoflann KdTree index." );
158+ LandmarksAdaptator data (sfmData.getLandmarks ());
159+ KdTree tree (3 , data, nanoflann::KDTreeSingleIndexAdaptorParams (10 ));
160+ tree.buildIndex ();
161+ ALICEVISION_LOG_INFO (" KdTree created for " << sfmData.getLandmarks ().size () << " points." );
162+ std::vector<IndexT> newIdx (sfmData.getLandmarks ().size ());
163+ IndexT currentIdx = 0 ;
164+
165+ ALICEVISION_LOG_INFO (" Identifying landmarks to remove: started." );
166+ #pragma omp parallel for
167+ for (auto i = 0 ; i < sfmData.getLandmarks ().size (); i++)
168+ {
169+ PixSizeSearch search (landmarksPixSize[i] * radiusScale, landmarksPixSize, i);
170+ bool found = tree.findNeighbors (search, sfmData.getLandmarks ().at (i).X .data (), nanoflann::SearchParams ());
171+ if (!found)
172+ {
173+ newIdx[i] = -1 ;
174+ }
175+ else
176+ {
177+ newIdx[i] = currentIdx++;
178+ }
179+ }
180+ ALICEVISION_LOG_INFO (" Identifying landmarks to remove: done." );
181+
182+ ALICEVISION_LOG_INFO (" Removing landmarks: started." );
183+ Landmarks filteredLandmarks;
184+ #pragma omp parallel for
185+ for (auto i = 0 ; i < sfmData.getLandmarks ().size (); i++)
186+ {
187+ if (newIdx[i] != -1 )
188+ {
189+ filteredLandmarks[newIdx[i]] = sfmData.getLandmarks ().at (i);
190+ }
191+ }
192+ sfmData.getLandmarks () = filteredLandmarks;
193+ ALICEVISION_LOG_INFO (" Removing landmarks: done." );
160194
161195 // // take only best observations
162196 // observationScores.resize(maxNbObservationsPerLandmark);
@@ -230,6 +264,7 @@ int aliceVision_main(int argc, char *argv[])
230264 std::string inputSfmFilename;
231265 std::string outputSfmFilename;
232266 int maxNbObservationsPerLandmark = 5 ;
267+ double radiusScale = 2 ;
233268
234269 po::options_description requiredParams (" Required parameters" );
235270 requiredParams.add_options ()
@@ -241,7 +276,9 @@ int aliceVision_main(int argc, char *argv[])
241276 po::options_description optionalParams (" Optional parameters" );
242277 optionalParams.add_options ()
243278 (" maxNbObservationsPerLandmark" , po::value<int >(&maxNbObservationsPerLandmark)->default_value (maxNbObservationsPerLandmark),
244- " Maximum number of allowed observations per landmark." );
279+ " Maximum number of allowed observations per landmark." )
280+ (" radiusScale" , po::value<double >(&radiusScale)->default_value (radiusScale),
281+ " Scale factor applied to pixel size based radius filter applied to landmarks." );
245282
246283 CmdLine cmdline (" AliceVision SfM filtering." );
247284 cmdline.add (requiredParams);
@@ -267,8 +304,12 @@ int aliceVision_main(int argc, char *argv[])
267304 }
268305
269306 // filter SfM data
270- bool success2 = filterLandmarks (sfmData);
307+ ALICEVISION_LOG_INFO (" Filtering landmarks: started." );
308+ bool success2 = filterLandmarks (sfmData, radiusScale);
309+ ALICEVISION_LOG_INFO (" Filtering landmarks: done." );
310+ ALICEVISION_LOG_INFO (" Filtering observations: started." );
271311 bool success1 = filterObservations (sfmData, maxNbObservationsPerLandmark);
312+ ALICEVISION_LOG_INFO (" Filtering observations: done." );
272313
273314 if (success1)
274315 {
0 commit comments