Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/features2d/test/test_nearestneighbors.cpp
16339 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15
// Copyright (C) 2014, Itseez Inc, all rights reserved.
16
// Third party copyrights are property of their respective owners.
17
//
18
// Redistribution and use in source and binary forms, with or without modification,
19
// are permitted provided that the following conditions are met:
20
//
21
// * Redistribution's of source code must retain the above copyright notice,
22
// this list of conditions and the following disclaimer.
23
//
24
// * Redistribution's in binary form must reproduce the above copyright notice,
25
// this list of conditions and the following disclaimer in the documentation
26
// and/or other materials provided with the distribution.
27
//
28
// * The name of the copyright holders may not be used to endorse or promote products
29
// derived from this software without specific prior written permission.
30
//
31
// This software is provided by the copyright holders and contributors "as is" and
32
// any express or implied warranties, including, but not limited to, the implied
33
// warranties of merchantability and fitness for a particular purpose are disclaimed.
34
// In no event shall the Intel Corporation or contributors be liable for any direct,
35
// indirect, incidental, special, exemplary, or consequential damages
36
// (including, but not limited to, procurement of substitute goods or services;
37
// loss of use, data, or profits; or business interruption) however caused
38
// and on any theory of liability, whether in contract, strict liability,
39
// or tort (including negligence or otherwise) arising in any way out of
40
// the use of this software, even if advised of the possibility of such damage.
41
//
42
//M*/
43
44
#include "test_precomp.hpp"
45
46
namespace opencv_test { namespace {
47
48
#ifdef HAVE_OPENCV_FLANN
49
using namespace cv::flann;
50
#endif
51
52
//--------------------------------------------------------------------------------
53
class NearestNeighborTest : public cvtest::BaseTest
54
{
55
public:
56
NearestNeighborTest() {}
57
protected:
58
static const int minValue = 0;
59
static const int maxValue = 1;
60
static const int dims = 30;
61
static const int featuresCount = 2000;
62
static const int K = 1; // * should also test 2nd nn etc.?
63
64
65
virtual void run( int start_from );
66
virtual void createModel( const Mat& data ) = 0;
67
virtual int findNeighbors( Mat& points, Mat& neighbors ) = 0;
68
virtual int checkGetPoints( const Mat& data );
69
virtual int checkFindBoxed();
70
virtual int checkFind( const Mat& data );
71
virtual void releaseModel() = 0;
72
};
73
74
int NearestNeighborTest::checkGetPoints( const Mat& )
75
{
76
return cvtest::TS::OK;
77
}
78
79
int NearestNeighborTest::checkFindBoxed()
80
{
81
return cvtest::TS::OK;
82
}
83
84
int NearestNeighborTest::checkFind( const Mat& data )
85
{
86
int code = cvtest::TS::OK;
87
int pointsCount = 1000;
88
float noise = 0.2f;
89
90
RNG rng;
91
Mat points( pointsCount, dims, CV_32FC1 );
92
Mat results( pointsCount, K, CV_32SC1 );
93
94
std::vector<int> fmap( pointsCount );
95
for( int pi = 0; pi < pointsCount; pi++ )
96
{
97
int fi = rng.next() % featuresCount;
98
fmap[pi] = fi;
99
for( int d = 0; d < dims; d++ )
100
points.at<float>(pi, d) = data.at<float>(fi, d) + rng.uniform(0.0f, 1.0f) * noise;
101
}
102
103
code = findNeighbors( points, results );
104
105
if( code == cvtest::TS::OK )
106
{
107
int correctMatches = 0;
108
for( int pi = 0; pi < pointsCount; pi++ )
109
{
110
if( fmap[pi] == results.at<int>(pi, 0) )
111
correctMatches++;
112
}
113
114
double correctPerc = correctMatches / (double)pointsCount;
115
EXPECT_GE(correctPerc, .75) << "correctMatches=" << correctMatches << " pointsCount=" << pointsCount;
116
}
117
118
return code;
119
}
120
121
void NearestNeighborTest::run( int /*start_from*/ ) {
122
int code = cvtest::TS::OK, tempCode;
123
Mat desc( featuresCount, dims, CV_32FC1 );
124
ts->get_rng().fill( desc, RNG::UNIFORM, minValue, maxValue );
125
126
createModel( desc );
127
128
tempCode = checkGetPoints( desc );
129
if( tempCode != cvtest::TS::OK )
130
{
131
ts->printf( cvtest::TS::LOG, "bad accuracy of GetPoints \n" );
132
code = tempCode;
133
}
134
135
tempCode = checkFindBoxed();
136
if( tempCode != cvtest::TS::OK )
137
{
138
ts->printf( cvtest::TS::LOG, "bad accuracy of FindBoxed \n" );
139
code = tempCode;
140
}
141
142
tempCode = checkFind( desc );
143
if( tempCode != cvtest::TS::OK )
144
{
145
ts->printf( cvtest::TS::LOG, "bad accuracy of Find \n" );
146
code = tempCode;
147
}
148
149
releaseModel();
150
151
if (::testing::Test::HasFailure()) code = cvtest::TS::FAIL_BAD_ACCURACY;
152
ts->set_failed_test_info( code );
153
}
154
155
//--------------------------------------------------------------------------------
156
#ifdef HAVE_OPENCV_FLANN
157
158
class CV_FlannTest : public NearestNeighborTest
159
{
160
public:
161
CV_FlannTest() : NearestNeighborTest(), index(NULL) { }
162
protected:
163
void createIndex( const Mat& data, const IndexParams& params );
164
int knnSearch( Mat& points, Mat& neighbors );
165
int radiusSearch( Mat& points, Mat& neighbors );
166
virtual void releaseModel();
167
Index* index;
168
};
169
170
void CV_FlannTest::createIndex( const Mat& data, const IndexParams& params )
171
{
172
// release previously allocated index
173
releaseModel();
174
175
index = new Index( data, params );
176
}
177
178
int CV_FlannTest::knnSearch( Mat& points, Mat& neighbors )
179
{
180
Mat dist( points.rows, neighbors.cols, CV_32FC1);
181
int knn = 1, j;
182
183
// 1st way
184
index->knnSearch( points, neighbors, dist, knn, SearchParams() );
185
186
// 2nd way
187
Mat neighbors1( neighbors.size(), CV_32SC1 );
188
for( int i = 0; i < points.rows; i++ )
189
{
190
float* fltPtr = points.ptr<float>(i);
191
vector<float> query( fltPtr, fltPtr + points.cols );
192
vector<int> indices( neighbors1.cols, 0 );
193
vector<float> dists( dist.cols, 0 );
194
index->knnSearch( query, indices, dists, knn, SearchParams() );
195
vector<int>::const_iterator it = indices.begin();
196
for( j = 0; it != indices.end(); ++it, j++ )
197
neighbors1.at<int>(i,j) = *it;
198
}
199
200
// compare results
201
EXPECT_LE(cvtest::norm(neighbors, neighbors1, NORM_L1), 0);
202
203
return ::testing::Test::HasFailure() ? cvtest::TS::FAIL_BAD_ACCURACY : cvtest::TS::OK;
204
}
205
206
int CV_FlannTest::radiusSearch( Mat& points, Mat& neighbors )
207
{
208
Mat dist( 1, neighbors.cols, CV_32FC1);
209
Mat neighbors1( neighbors.size(), CV_32SC1 );
210
float radius = 10.0f;
211
int j;
212
213
// radiusSearch can only search one feature at a time for range search
214
for( int i = 0; i < points.rows; i++ )
215
{
216
// 1st way
217
Mat p( 1, points.cols, CV_32FC1, points.ptr<float>(i) ),
218
n( 1, neighbors.cols, CV_32SC1, neighbors.ptr<int>(i) );
219
index->radiusSearch( p, n, dist, radius, neighbors.cols, SearchParams() );
220
221
// 2nd way
222
float* fltPtr = points.ptr<float>(i);
223
vector<float> query( fltPtr, fltPtr + points.cols );
224
vector<int> indices( neighbors1.cols, 0 );
225
vector<float> dists( dist.cols, 0 );
226
index->radiusSearch( query, indices, dists, radius, neighbors.cols, SearchParams() );
227
vector<int>::const_iterator it = indices.begin();
228
for( j = 0; it != indices.end(); ++it, j++ )
229
neighbors1.at<int>(i,j) = *it;
230
}
231
232
// compare results
233
EXPECT_LE(cvtest::norm(neighbors, neighbors1, NORM_L1), 0);
234
235
return ::testing::Test::HasFailure() ? cvtest::TS::FAIL_BAD_ACCURACY : cvtest::TS::OK;
236
}
237
238
void CV_FlannTest::releaseModel()
239
{
240
if (index)
241
{
242
delete index;
243
index = NULL;
244
}
245
}
246
247
//---------------------------------------
248
class CV_FlannLinearIndexTest : public CV_FlannTest
249
{
250
public:
251
CV_FlannLinearIndexTest() {}
252
protected:
253
virtual void createModel( const Mat& data ) { createIndex( data, LinearIndexParams() ); }
254
virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
255
};
256
257
//---------------------------------------
258
class CV_FlannKMeansIndexTest : public CV_FlannTest
259
{
260
public:
261
CV_FlannKMeansIndexTest() {}
262
protected:
263
virtual void createModel( const Mat& data ) { createIndex( data, KMeansIndexParams() ); }
264
virtual int findNeighbors( Mat& points, Mat& neighbors ) { return radiusSearch( points, neighbors ); }
265
};
266
267
//---------------------------------------
268
class CV_FlannKDTreeIndexTest : public CV_FlannTest
269
{
270
public:
271
CV_FlannKDTreeIndexTest() {}
272
protected:
273
virtual void createModel( const Mat& data ) { createIndex( data, KDTreeIndexParams() ); }
274
virtual int findNeighbors( Mat& points, Mat& neighbors ) { return radiusSearch( points, neighbors ); }
275
};
276
277
//----------------------------------------
278
class CV_FlannCompositeIndexTest : public CV_FlannTest
279
{
280
public:
281
CV_FlannCompositeIndexTest() {}
282
protected:
283
virtual void createModel( const Mat& data ) { createIndex( data, CompositeIndexParams() ); }
284
virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
285
};
286
287
//----------------------------------------
288
class CV_FlannAutotunedIndexTest : public CV_FlannTest
289
{
290
public:
291
CV_FlannAutotunedIndexTest() {}
292
protected:
293
virtual void createModel( const Mat& data ) { createIndex( data, AutotunedIndexParams() ); }
294
virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
295
};
296
//----------------------------------------
297
class CV_FlannSavedIndexTest : public CV_FlannTest
298
{
299
public:
300
CV_FlannSavedIndexTest() {}
301
protected:
302
virtual void createModel( const Mat& data );
303
virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
304
};
305
306
void CV_FlannSavedIndexTest::createModel(const cv::Mat &data)
307
{
308
switch ( cvtest::randInt(ts->get_rng()) % 2 )
309
{
310
//case 0: createIndex( data, LinearIndexParams() ); break; // nothing to save for linear search
311
case 0: createIndex( data, KMeansIndexParams() ); break;
312
case 1: createIndex( data, KDTreeIndexParams() ); break;
313
//case 2: createIndex( data, CompositeIndexParams() ); break; // nothing to save for linear search
314
//case 2: createIndex( data, AutotunedIndexParams() ); break; // possible linear index !
315
default: assert(0);
316
}
317
string filename = tempfile();
318
index->save( filename );
319
320
createIndex( data, SavedIndexParams(filename.c_str()));
321
remove( filename.c_str() );
322
}
323
324
TEST(Features2d_FLANN_Linear, regression) { CV_FlannLinearIndexTest test; test.safe_run(); }
325
TEST(Features2d_FLANN_KMeans, regression) { CV_FlannKMeansIndexTest test; test.safe_run(); }
326
TEST(Features2d_FLANN_KDTree, regression) { CV_FlannKDTreeIndexTest test; test.safe_run(); }
327
TEST(Features2d_FLANN_Composite, regression) { CV_FlannCompositeIndexTest test; test.safe_run(); }
328
TEST(Features2d_FLANN_Auto, regression) { CV_FlannAutotunedIndexTest test; test.safe_run(); }
329
TEST(Features2d_FLANN_Saved, regression) { CV_FlannSavedIndexTest test; test.safe_run(); }
330
331
#endif
332
333
}} // namespace
334
335