-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Optimize geometric filtering performance from O(n^2) to O(n) #2435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
| my_progress_bar->Restart( putative_matches.size(), "- Geometric filtering -" ); | ||
|
|
||
| // Cache iterators to avoid O(n^2) std::map traversal with advance(). | ||
| std::vector<PairWiseMatches::const_iterator> match_iters; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it can be done in a oneliner
std::vector<PairWiseMatches::const_iterator> match_iters(putative_matches.cbegin(), putative_matches.cend());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does look simpler, and I tried, but it doesn't work.
422.1 [ 81%] Building CXX object _deps/rerun_sdk-build/CMakeFiles/rerun_sdk.dir/src/rerun/datatypes/entity_path.cpp.o 423.2 In file included from /usr/include/c++/11/vector:66, 423.2 from /opt/openMVG/src/openMVG/features/akaze/AKAZE.hpp:37, 423.2 from /opt/openMVG/src/openMVG/features/akaze/image_describer_akaze.hpp:11, 423.2 from /opt/openMVG/src/software/SfM/main_GeometricFilter.cpp:9: 423.2 /usr/include/c++/11/bits/stl_uninitialized.h: In instantiation of '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >; _ForwardIterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >*]': 423.2 /usr/include/c++/11/bits/stl_uninitialized.h:333:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >; _ForwardIterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >*; _Tp = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >]' 423.2 /usr/include/c++/11/bits/stl_vector.h:1585:33: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >; _Tp = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >; _Alloc = std::allocator<std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > > >]' 423.2 /usr/include/c++/11/bits/stl_vector.h:657:23: required from 'std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&) [with _InputIterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >; <template-parameter-2-2> = void; _Tp = std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > >; _Alloc = std::allocator<std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > > >; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<std::_Rb_tree_const_iterator<std::pair<const std::pair<unsigned int, unsigned int>, std::vector<openMVG::matching::IndMatch> > > >]' 423.2 /opt/openMVG/src/openMVG/matching_image_collection/GeometricFilter.hpp:80:48: required from 'void openMVG::matching_image_collection::ImageCollectionGeometricFilter::Robust_model_estimation(const GeometryFunctor&, const openMVG::matching::PairWiseMatches&, bool, double, openMVG::system::ProgressInterface*) [with GeometryFunctor = openMVG::matching_image_collection::GeometricFilter_HMatrix_AC]' 423.2 /opt/openMVG/src/software/SfM/main_GeometricFilter.cpp:292:44: required from here 423.2 /usr/include/c++/11/bits/stl_uninitialized.h:138:72: error: static assertion failed: result type must be constructible from value type of input range 423.2 138 | static_assert(is_constructible<_ValueType2, decltype(*__first)>::value, 423.2 | ^~~~~ 423.2 /usr/include/c++/11/bits/stl_uninitialized.h:138:72: note: 'std::integral_constant<bool, false>::value' evaluates to false 423.9 [ 81%] Building CXX object _deps/rerun_sdk-build/CMakeFiles/rerun_sdk.dir/src/rerun/datatypes/float32.cpp.o
I'm not a C++ expert but it seems something to do with the range constructor copying the map entries instead of the iterators, and thus fails.
Improve the efficiency of geometric filtering by caching iterators, reducing the traversal complexity from O(n^2) to O(n) for each pair of matches.
I've been running into a wall where as I increase the number of pictures, the processing time increased exponentially and it just didn't make any sense.
As the number of pictures and features increased, most of the time was spent on geometric filtering, which should have been a simple and fast process. Eventually traced it down to this bug and and the fix completely eliminated the bottleneck and made the processing tractable.
Hope this helps everyone else who couldn't process a large number of photos.
@pmoulon please take a look at this. It's pretty significant.