Path: blob/master/modules/features2d/test/test_nearestneighbors.cpp
16339 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Copyright (C) 2014, Itseez Inc, all rights reserved.15// Third party copyrights are property of their respective owners.16//17// Redistribution and use in source and binary forms, with or without modification,18// are permitted provided that the following conditions are met:19//20// * Redistribution's of source code must retain the above copyright notice,21// this list of conditions and the following disclaimer.22//23// * Redistribution's in binary form must reproduce the above copyright notice,24// this list of conditions and the following disclaimer in the documentation25// and/or other materials provided with the distribution.26//27// * The name of the copyright holders may not be used to endorse or promote products28// derived from this software without specific prior written permission.29//30// This software is provided by the copyright holders and contributors "as is" and31// any express or implied warranties, including, but not limited to, the implied32// warranties of merchantability and fitness for a particular purpose are disclaimed.33// In no event shall the Intel Corporation or contributors be liable for any direct,34// indirect, incidental, special, exemplary, or consequential damages35// (including, but not limited to, procurement of substitute goods or services;36// loss of use, data, or profits; or business interruption) however caused37// and on any theory of liability, whether in contract, strict liability,38// or tort (including negligence or otherwise) arising in any way out of39// the use of this software, even if advised of the possibility of such damage.40//41//M*/4243#include "test_precomp.hpp"4445namespace opencv_test { namespace {4647#ifdef HAVE_OPENCV_FLANN48using namespace cv::flann;49#endif5051//--------------------------------------------------------------------------------52class NearestNeighborTest : public cvtest::BaseTest53{54public:55NearestNeighborTest() {}56protected:57static const int minValue = 0;58static const int maxValue = 1;59static const int dims = 30;60static const int featuresCount = 2000;61static const int K = 1; // * should also test 2nd nn etc.?626364virtual void run( int start_from );65virtual void createModel( const Mat& data ) = 0;66virtual int findNeighbors( Mat& points, Mat& neighbors ) = 0;67virtual int checkGetPoints( const Mat& data );68virtual int checkFindBoxed();69virtual int checkFind( const Mat& data );70virtual void releaseModel() = 0;71};7273int NearestNeighborTest::checkGetPoints( const Mat& )74{75return cvtest::TS::OK;76}7778int NearestNeighborTest::checkFindBoxed()79{80return cvtest::TS::OK;81}8283int NearestNeighborTest::checkFind( const Mat& data )84{85int code = cvtest::TS::OK;86int pointsCount = 1000;87float noise = 0.2f;8889RNG rng;90Mat points( pointsCount, dims, CV_32FC1 );91Mat results( pointsCount, K, CV_32SC1 );9293std::vector<int> fmap( pointsCount );94for( int pi = 0; pi < pointsCount; pi++ )95{96int fi = rng.next() % featuresCount;97fmap[pi] = fi;98for( int d = 0; d < dims; d++ )99points.at<float>(pi, d) = data.at<float>(fi, d) + rng.uniform(0.0f, 1.0f) * noise;100}101102code = findNeighbors( points, results );103104if( code == cvtest::TS::OK )105{106int correctMatches = 0;107for( int pi = 0; pi < pointsCount; pi++ )108{109if( fmap[pi] == results.at<int>(pi, 0) )110correctMatches++;111}112113double correctPerc = correctMatches / (double)pointsCount;114EXPECT_GE(correctPerc, .75) << "correctMatches=" << correctMatches << " pointsCount=" << pointsCount;115}116117return code;118}119120void NearestNeighborTest::run( int /*start_from*/ ) {121int code = cvtest::TS::OK, tempCode;122Mat desc( featuresCount, dims, CV_32FC1 );123ts->get_rng().fill( desc, RNG::UNIFORM, minValue, maxValue );124125createModel( desc );126127tempCode = checkGetPoints( desc );128if( tempCode != cvtest::TS::OK )129{130ts->printf( cvtest::TS::LOG, "bad accuracy of GetPoints \n" );131code = tempCode;132}133134tempCode = checkFindBoxed();135if( tempCode != cvtest::TS::OK )136{137ts->printf( cvtest::TS::LOG, "bad accuracy of FindBoxed \n" );138code = tempCode;139}140141tempCode = checkFind( desc );142if( tempCode != cvtest::TS::OK )143{144ts->printf( cvtest::TS::LOG, "bad accuracy of Find \n" );145code = tempCode;146}147148releaseModel();149150if (::testing::Test::HasFailure()) code = cvtest::TS::FAIL_BAD_ACCURACY;151ts->set_failed_test_info( code );152}153154//--------------------------------------------------------------------------------155#ifdef HAVE_OPENCV_FLANN156157class CV_FlannTest : public NearestNeighborTest158{159public:160CV_FlannTest() : NearestNeighborTest(), index(NULL) { }161protected:162void createIndex( const Mat& data, const IndexParams& params );163int knnSearch( Mat& points, Mat& neighbors );164int radiusSearch( Mat& points, Mat& neighbors );165virtual void releaseModel();166Index* index;167};168169void CV_FlannTest::createIndex( const Mat& data, const IndexParams& params )170{171// release previously allocated index172releaseModel();173174index = new Index( data, params );175}176177int CV_FlannTest::knnSearch( Mat& points, Mat& neighbors )178{179Mat dist( points.rows, neighbors.cols, CV_32FC1);180int knn = 1, j;181182// 1st way183index->knnSearch( points, neighbors, dist, knn, SearchParams() );184185// 2nd way186Mat neighbors1( neighbors.size(), CV_32SC1 );187for( int i = 0; i < points.rows; i++ )188{189float* fltPtr = points.ptr<float>(i);190vector<float> query( fltPtr, fltPtr + points.cols );191vector<int> indices( neighbors1.cols, 0 );192vector<float> dists( dist.cols, 0 );193index->knnSearch( query, indices, dists, knn, SearchParams() );194vector<int>::const_iterator it = indices.begin();195for( j = 0; it != indices.end(); ++it, j++ )196neighbors1.at<int>(i,j) = *it;197}198199// compare results200EXPECT_LE(cvtest::norm(neighbors, neighbors1, NORM_L1), 0);201202return ::testing::Test::HasFailure() ? cvtest::TS::FAIL_BAD_ACCURACY : cvtest::TS::OK;203}204205int CV_FlannTest::radiusSearch( Mat& points, Mat& neighbors )206{207Mat dist( 1, neighbors.cols, CV_32FC1);208Mat neighbors1( neighbors.size(), CV_32SC1 );209float radius = 10.0f;210int j;211212// radiusSearch can only search one feature at a time for range search213for( int i = 0; i < points.rows; i++ )214{215// 1st way216Mat p( 1, points.cols, CV_32FC1, points.ptr<float>(i) ),217n( 1, neighbors.cols, CV_32SC1, neighbors.ptr<int>(i) );218index->radiusSearch( p, n, dist, radius, neighbors.cols, SearchParams() );219220// 2nd way221float* fltPtr = points.ptr<float>(i);222vector<float> query( fltPtr, fltPtr + points.cols );223vector<int> indices( neighbors1.cols, 0 );224vector<float> dists( dist.cols, 0 );225index->radiusSearch( query, indices, dists, radius, neighbors.cols, SearchParams() );226vector<int>::const_iterator it = indices.begin();227for( j = 0; it != indices.end(); ++it, j++ )228neighbors1.at<int>(i,j) = *it;229}230231// compare results232EXPECT_LE(cvtest::norm(neighbors, neighbors1, NORM_L1), 0);233234return ::testing::Test::HasFailure() ? cvtest::TS::FAIL_BAD_ACCURACY : cvtest::TS::OK;235}236237void CV_FlannTest::releaseModel()238{239if (index)240{241delete index;242index = NULL;243}244}245246//---------------------------------------247class CV_FlannLinearIndexTest : public CV_FlannTest248{249public:250CV_FlannLinearIndexTest() {}251protected:252virtual void createModel( const Mat& data ) { createIndex( data, LinearIndexParams() ); }253virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }254};255256//---------------------------------------257class CV_FlannKMeansIndexTest : public CV_FlannTest258{259public:260CV_FlannKMeansIndexTest() {}261protected:262virtual void createModel( const Mat& data ) { createIndex( data, KMeansIndexParams() ); }263virtual int findNeighbors( Mat& points, Mat& neighbors ) { return radiusSearch( points, neighbors ); }264};265266//---------------------------------------267class CV_FlannKDTreeIndexTest : public CV_FlannTest268{269public:270CV_FlannKDTreeIndexTest() {}271protected:272virtual void createModel( const Mat& data ) { createIndex( data, KDTreeIndexParams() ); }273virtual int findNeighbors( Mat& points, Mat& neighbors ) { return radiusSearch( points, neighbors ); }274};275276//----------------------------------------277class CV_FlannCompositeIndexTest : public CV_FlannTest278{279public:280CV_FlannCompositeIndexTest() {}281protected:282virtual void createModel( const Mat& data ) { createIndex( data, CompositeIndexParams() ); }283virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }284};285286//----------------------------------------287class CV_FlannAutotunedIndexTest : public CV_FlannTest288{289public:290CV_FlannAutotunedIndexTest() {}291protected:292virtual void createModel( const Mat& data ) { createIndex( data, AutotunedIndexParams() ); }293virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }294};295//----------------------------------------296class CV_FlannSavedIndexTest : public CV_FlannTest297{298public:299CV_FlannSavedIndexTest() {}300protected:301virtual void createModel( const Mat& data );302virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }303};304305void CV_FlannSavedIndexTest::createModel(const cv::Mat &data)306{307switch ( cvtest::randInt(ts->get_rng()) % 2 )308{309//case 0: createIndex( data, LinearIndexParams() ); break; // nothing to save for linear search310case 0: createIndex( data, KMeansIndexParams() ); break;311case 1: createIndex( data, KDTreeIndexParams() ); break;312//case 2: createIndex( data, CompositeIndexParams() ); break; // nothing to save for linear search313//case 2: createIndex( data, AutotunedIndexParams() ); break; // possible linear index !314default: assert(0);315}316string filename = tempfile();317index->save( filename );318319createIndex( data, SavedIndexParams(filename.c_str()));320remove( filename.c_str() );321}322323TEST(Features2d_FLANN_Linear, regression) { CV_FlannLinearIndexTest test; test.safe_run(); }324TEST(Features2d_FLANN_KMeans, regression) { CV_FlannKMeansIndexTest test; test.safe_run(); }325TEST(Features2d_FLANN_KDTree, regression) { CV_FlannKDTreeIndexTest test; test.safe_run(); }326TEST(Features2d_FLANN_Composite, regression) { CV_FlannCompositeIndexTest test; test.safe_run(); }327TEST(Features2d_FLANN_Auto, regression) { CV_FlannAutotunedIndexTest test; test.safe_run(); }328TEST(Features2d_FLANN_Saved, regression) { CV_FlannSavedIndexTest test; test.safe_run(); }329330#endif331332}} // namespace333334335