Skip to content

Commit 86afa0d

Browse files
committed
Improved OpenCV FLANN benchmark.
1 parent 73037e1 commit 86afa0d

File tree

1 file changed

+75
-26
lines changed

1 file changed

+75
-26
lines changed

examples/benchmark/bm_opencv_flann.cpp

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,81 @@
66
// simply include the original FLANN <flann/flann.hpp> and replace the cvflann
77
// namespace by the flann namespace and the benchmark will still work.
88
// NOTE: The OpenCV version of FLANN performs quite a bit faster for queries
9-
// than https://github.com/mariusmuja/flann. About 30% for a single NN. Tree
10-
// build times are the same. Simply used Release for building like with all
11-
// other libs.
9+
// than https://github.com/mariusmuja/flann. About an order of magnitude for a
10+
// single NN. Tree build times are the same.
1211
class BmOpenCvFlann : public pico_tree::Benchmark {
1312
public:
1413
};
1514

15+
// Change the namespace below to switch between FLANN versions.
16+
namespace fl = cvflann;
17+
// namespace fl = flann;
18+
19+
// The OpenCV version of FLANN has improved query performance over the original
20+
// but does not include the flann::L2_3D<Scalar> distance class:
21+
// https://github.com/mariusmuja/flann/blob/master/src/cpp/flann/algorithms/dist.h
22+
// This distance class gives a reasonable performance boost over
23+
// (cv)flann::L2_Simple because it uses a compile time constant dimension count.
24+
// NOTE: Strictly speaking it shouldn't be part of the performance test.
25+
namespace cvflann {
26+
27+
template <class T>
28+
struct L2_3D {
29+
typedef bool is_kdtree_distance;
30+
31+
typedef T ElementType;
32+
typedef typename Accumulator<T>::Type ResultType;
33+
34+
template <typename Iterator1, typename Iterator2>
35+
ResultType operator()(
36+
Iterator1 a,
37+
Iterator2 b,
38+
size_t size,
39+
ResultType /*worst_dist*/ = -1) const {
40+
ResultType result = ResultType();
41+
ResultType diff;
42+
diff = *a++ - *b++;
43+
result += diff * diff;
44+
diff = *a++ - *b++;
45+
result += diff * diff;
46+
diff = *a++ - *b++;
47+
result += diff * diff;
48+
return result;
49+
}
50+
51+
template <typename U, typename V>
52+
inline ResultType accum_dist(const U& a, const V& b, int) const {
53+
return (a - b) * (a - b);
54+
}
55+
};
56+
57+
} // namespace cvflann
58+
59+
template <typename Scalar, int Dim>
60+
Scalar* RawCopy(std::vector<Point<Scalar, Dim>> const& points) {
61+
Scalar* copy = new Scalar[points.size() * Dim];
62+
std::copy(
63+
points.begin()->data, points.begin()->data + points.size() * Dim, copy);
64+
return copy;
65+
}
66+
1667
// ****************************************************************************
1768
// Building the tree
1869
// ****************************************************************************
1970

2071
BENCHMARK_DEFINE_F(BmOpenCvFlann, BuildRt)(benchmark::State& state) {
2172
int max_leaf_size = state.range(0);
22-
cvflann::Matrix<Scalar> matrix(
23-
points_tree_.data()->data, points_tree_.size(), 3);
73+
2474
// Reorder will change the order of the input to fit the generated indices,
25-
// but it will replace (delete) the original input.
26-
cvflann::KDTreeSingleIndexParams pindex(max_leaf_size, false);
75+
// but it will replace (delete) the original input. It is set to true because
76+
// we use it to improve query times during the Knn test.
77+
// The tree takes ownership of the copied data.
78+
// NOTE: One could argue the copy is part of the benchmark, but didn't add it.
79+
fl::Matrix<Scalar> matrix(RawCopy(points_tree_), points_tree_.size(), 3);
80+
fl::KDTreeSingleIndexParams pindex(max_leaf_size, true);
2781

2882
for (auto _ : state) {
29-
cvflann::KDTreeSingleIndex<cvflann::L2_Simple<Scalar>> tree(matrix, pindex);
83+
fl::KDTreeSingleIndex<fl::L2_3D<Scalar>> tree(matrix, pindex);
3084
tree.buildIndex();
3185
}
3286
}
@@ -40,46 +94,41 @@ BENCHMARK_REGISTER_F(BmOpenCvFlann, BuildRt)
4094
// Knn
4195
// ****************************************************************************
4296

43-
BENCHMARK_DEFINE_F(BmOpenCvFlann, KnnRt)(benchmark::State& state) {
97+
BENCHMARK_DEFINE_F(BmOpenCvFlann, KnnCt)(benchmark::State& state) {
4498
int max_leaf_size = state.range(0);
4599
int knn_count = state.range(1);
46100

47-
cvflann::Matrix<Scalar> matrix(
48-
points_tree_.data()->data, points_tree_.size(), 3);
49101
// Reorder will change the order of the input to fit the generated indices,
50-
// but it will replace (and delete) the original input. Note that the reorder
51-
// option does not appear to have effect on the performance of the queries.
52-
cvflann::KDTreeSingleIndexParams pindex(max_leaf_size, false);
53-
// It seems that there are different versions of FLANN. For example, the
54-
// OpenCV version does not have the flann::L2_3D<Scalar> distance class, like
55-
// found on the following GitHub respository:
56-
// https://github.com/mariusmuja/flann/blob/master/src/cpp/flann/algorithms/dist.h
57-
// However, using the exact same one or a custom metric where the dimensions
58-
// are know at compile time does not appear to really impact the performance.
59-
cvflann::KDTreeSingleIndex<cvflann::L2_Simple<Scalar>> tree(matrix, pindex);
102+
// but it will replace (and delete) the original input. The reorder option
103+
// does has a small positive effect on the performance of the queries.
104+
// The tree takes ownership of the copied data.
105+
fl::Matrix<Scalar> matrix(RawCopy(points_tree_), points_tree_.size(), 3);
106+
fl::KDTreeSingleIndexParams pindex(max_leaf_size, true);
107+
// "Custom" L2_3D metric has a decent positive effect on query times.
108+
fl::KDTreeSingleIndex<fl::L2_3D<Scalar>> tree(matrix, pindex);
60109
tree.buildIndex();
61110

62111
// Search all nodes, no approximate search and no sorting.
63-
cvflann::SearchParams psearch(-1, 0.0f, false);
112+
fl::SearchParams psearch(-1, 0.0f, false);
64113

65114
// There is also the option to query them all at once, but this doesn't really
66115
// change performance and this version looks more like the other benchmarks.
67116
for (auto _ : state) {
68117
std::vector<Index> indices(knn_count);
69118
std::vector<Scalar> distances(knn_count);
70-
cvflann::Matrix<Index> mat_indices(indices.data(), 1, knn_count);
71-
cvflann::Matrix<Scalar> mat_distances(distances.data(), 1, knn_count);
119+
fl::Matrix<Index> mat_indices(indices.data(), 1, knn_count);
120+
fl::Matrix<Scalar> mat_distances(distances.data(), 1, knn_count);
72121

73122
for (auto& p : points_test_) {
74-
cvflann::Matrix<Scalar> query(p.data, 1, 3);
123+
fl::Matrix<Scalar> query(p.data, 1, 3);
75124
tree.knnSearch(query, mat_indices, mat_distances, knn_count, psearch);
76125
}
77126
}
78127
}
79128

80129
// Argument 1: Maximum leaf size.
81130
// Argument 2: K nearest neighbors.
82-
BENCHMARK_REGISTER_F(BmOpenCvFlann, KnnRt)
131+
BENCHMARK_REGISTER_F(BmOpenCvFlann, KnnCt)
83132
->Unit(benchmark::kMillisecond)
84133
->Args({1, 1})
85134
->Args({6, 1})

0 commit comments

Comments
 (0)