test_matchers_algorithmic.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  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. // Intel License Agreement
  11. // For Open Source Computer Vision Library
  12. //
  13. // Copyright (C) 2000, Intel Corporation, all rights reserved.
  14. // Third party copyrights are property of their respective owners.
  15. //
  16. // Redistribution and use in source and binary forms, with or without modification,
  17. // are permitted provided that the following conditions are met:
  18. //
  19. // * Redistribution's of source code must retain the above copyright notice,
  20. // this list of conditions and the following disclaimer.
  21. //
  22. // * Redistribution's in binary form must reproduce the above copyright notice,
  23. // this list of conditions and the following disclaimer in the documentation
  24. // and/or other materials provided with the distribution.
  25. //
  26. // * The name of Intel Corporation may not be used to endorse or promote products
  27. // derived from this software without specific prior written permission.
  28. //
  29. // This software is provided by the copyright holders and contributors "as is" and
  30. // any express or implied warranties, including, but not limited to, the implied
  31. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  32. // In no event shall the Intel Corporation or contributors be liable for any direct,
  33. // indirect, incidental, special, exemplary, or consequential damages
  34. // (including, but not limited to, procurement of substitute goods or services;
  35. // loss of use, data, or profits; or business interruption) however caused
  36. // and on any theory of liability, whether in contract, strict liability,
  37. // or tort (including negligence or otherwise) arising in any way out of
  38. // the use of this software, even if advised of the possibility of such damage.
  39. //
  40. //M*/
  41. #include "test_precomp.hpp"
  42. namespace opencv_test { namespace {
  43. const string FEATURES2D_DIR = "features2d";
  44. const string IMAGE_FILENAME = "tsukuba.png";
  45. /****************************************************************************************\
  46. * Algorithmic tests for descriptor matchers *
  47. \****************************************************************************************/
  48. class CV_DescriptorMatcherTest : public cvtest::BaseTest
  49. {
  50. public:
  51. CV_DescriptorMatcherTest( const string& _name, const Ptr<DescriptorMatcher>& _dmatcher, float _badPart ) :
  52. badPart(_badPart), name(_name), dmatcher(_dmatcher)
  53. {}
  54. protected:
  55. static const int dim = 500;
  56. static const int queryDescCount = 300; // must be even number because we split train data in some cases in two
  57. static const int countFactor = 4; // do not change it
  58. const float badPart;
  59. virtual void run( int );
  60. void generateData( Mat& query, Mat& train );
  61. #if 0
  62. void emptyDataTest(); // FIXIT not used
  63. #endif
  64. void matchTest( const Mat& query, const Mat& train );
  65. void knnMatchTest( const Mat& query, const Mat& train );
  66. void radiusMatchTest( const Mat& query, const Mat& train );
  67. string name;
  68. Ptr<DescriptorMatcher> dmatcher;
  69. private:
  70. CV_DescriptorMatcherTest& operator=(const CV_DescriptorMatcherTest&) { return *this; }
  71. };
  72. #if 0
  73. void CV_DescriptorMatcherTest::emptyDataTest()
  74. {
  75. assert( !dmatcher.empty() );
  76. Mat queryDescriptors, trainDescriptors, mask;
  77. vector<Mat> trainDescriptorCollection, masks;
  78. vector<DMatch> matches;
  79. vector<vector<DMatch> > vmatches;
  80. try
  81. {
  82. dmatcher->match( queryDescriptors, trainDescriptors, matches, mask );
  83. }
  84. catch(...)
  85. {
  86. ts->printf( cvtest::TS::LOG, "match() on empty descriptors must not generate exception (1).\n" );
  87. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  88. }
  89. try
  90. {
  91. dmatcher->knnMatch( queryDescriptors, trainDescriptors, vmatches, 2, mask );
  92. }
  93. catch(...)
  94. {
  95. ts->printf( cvtest::TS::LOG, "knnMatch() on empty descriptors must not generate exception (1).\n" );
  96. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  97. }
  98. try
  99. {
  100. dmatcher->radiusMatch( queryDescriptors, trainDescriptors, vmatches, 10.f, mask );
  101. }
  102. catch(...)
  103. {
  104. ts->printf( cvtest::TS::LOG, "radiusMatch() on empty descriptors must not generate exception (1).\n" );
  105. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  106. }
  107. try
  108. {
  109. dmatcher->add( trainDescriptorCollection );
  110. }
  111. catch(...)
  112. {
  113. ts->printf( cvtest::TS::LOG, "add() on empty descriptors must not generate exception.\n" );
  114. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  115. }
  116. try
  117. {
  118. dmatcher->match( queryDescriptors, matches, masks );
  119. }
  120. catch(...)
  121. {
  122. ts->printf( cvtest::TS::LOG, "match() on empty descriptors must not generate exception (2).\n" );
  123. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  124. }
  125. try
  126. {
  127. dmatcher->knnMatch( queryDescriptors, vmatches, 2, masks );
  128. }
  129. catch(...)
  130. {
  131. ts->printf( cvtest::TS::LOG, "knnMatch() on empty descriptors must not generate exception (2).\n" );
  132. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  133. }
  134. try
  135. {
  136. dmatcher->radiusMatch( queryDescriptors, vmatches, 10.f, masks );
  137. }
  138. catch(...)
  139. {
  140. ts->printf( cvtest::TS::LOG, "radiusMatch() on empty descriptors must not generate exception (2).\n" );
  141. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  142. }
  143. }
  144. #endif
  145. void CV_DescriptorMatcherTest::generateData( Mat& query, Mat& train )
  146. {
  147. RNG& rng = theRNG();
  148. // Generate query descriptors randomly.
  149. // Descriptor vector elements are integer values.
  150. Mat buf( queryDescCount, dim, CV_32SC1 );
  151. rng.fill( buf, RNG::UNIFORM, Scalar::all(0), Scalar(3) );
  152. buf.convertTo( query, CV_32FC1 );
  153. // Generate train descriptors as follows:
  154. // copy each query descriptor to train set countFactor times
  155. // and perturb some one element of the copied descriptors in
  156. // in ascending order. General boundaries of the perturbation
  157. // are (0.f, 1.f).
  158. train.create( query.rows*countFactor, query.cols, CV_32FC1 );
  159. float step = 1.f / countFactor;
  160. for( int qIdx = 0; qIdx < query.rows; qIdx++ )
  161. {
  162. Mat queryDescriptor = query.row(qIdx);
  163. for( int c = 0; c < countFactor; c++ )
  164. {
  165. int tIdx = qIdx * countFactor + c;
  166. Mat trainDescriptor = train.row(tIdx);
  167. queryDescriptor.copyTo( trainDescriptor );
  168. int elem = rng(dim);
  169. float diff = rng.uniform( step*c, step*(c+1) );
  170. trainDescriptor.at<float>(0, elem) += diff;
  171. }
  172. }
  173. }
  174. void CV_DescriptorMatcherTest::matchTest( const Mat& query, const Mat& train )
  175. {
  176. dmatcher->clear();
  177. // test const version of match()
  178. {
  179. vector<DMatch> matches;
  180. dmatcher->match( query, train, matches );
  181. if( (int)matches.size() != queryDescCount )
  182. {
  183. ts->printf(cvtest::TS::LOG, "Incorrect matches count while test match() function (1).\n");
  184. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  185. }
  186. else
  187. {
  188. int badCount = 0;
  189. for( size_t i = 0; i < matches.size(); i++ )
  190. {
  191. DMatch& match = matches[i];
  192. if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor) || (match.imgIdx != 0) )
  193. badCount++;
  194. }
  195. if( (float)badCount > (float)queryDescCount*badPart )
  196. {
  197. ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test match() function (1).\n",
  198. (float)badCount/(float)queryDescCount );
  199. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  200. }
  201. }
  202. }
  203. // test const version of match() for the same query and test descriptors
  204. {
  205. vector<DMatch> matches;
  206. dmatcher->match( query, query, matches );
  207. if( (int)matches.size() != query.rows )
  208. {
  209. ts->printf(cvtest::TS::LOG, "Incorrect matches count while test match() function for the same query and test descriptors (1).\n");
  210. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  211. }
  212. else
  213. {
  214. for( size_t i = 0; i < matches.size(); i++ )
  215. {
  216. DMatch& match = matches[i];
  217. //std::cout << match.distance << std::endl;
  218. if( match.queryIdx != (int)i || match.trainIdx != (int)i || std::abs(match.distance) > FLT_EPSILON )
  219. {
  220. ts->printf( cvtest::TS::LOG, "Bad match (i=%d, queryIdx=%d, trainIdx=%d, distance=%f) while test match() function for the same query and test descriptors (1).\n",
  221. i, match.queryIdx, match.trainIdx, match.distance );
  222. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  223. }
  224. }
  225. }
  226. }
  227. // test version of match() with add()
  228. {
  229. vector<DMatch> matches;
  230. // make add() twice to test such case
  231. dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
  232. dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
  233. // prepare masks (make first nearest match illegal)
  234. vector<Mat> masks(2);
  235. for(int mi = 0; mi < 2; mi++ )
  236. {
  237. masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
  238. for( int di = 0; di < queryDescCount/2; di++ )
  239. masks[mi].col(di*countFactor).setTo(Scalar::all(0));
  240. }
  241. dmatcher->match( query, matches, masks );
  242. if( (int)matches.size() != queryDescCount )
  243. {
  244. ts->printf(cvtest::TS::LOG, "Incorrect matches count while test match() function (2).\n");
  245. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  246. }
  247. else
  248. {
  249. int badCount = 0;
  250. for( size_t i = 0; i < matches.size(); i++ )
  251. {
  252. DMatch& match = matches[i];
  253. int shift = dmatcher->isMaskSupported() ? 1 : 0;
  254. {
  255. if( i < queryDescCount/2 )
  256. {
  257. if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + shift) || (match.imgIdx != 0) )
  258. badCount++;
  259. }
  260. else
  261. {
  262. if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + shift) || (match.imgIdx != 1) )
  263. badCount++;
  264. }
  265. }
  266. }
  267. if( (float)badCount > (float)queryDescCount*badPart )
  268. {
  269. ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test match() function (2).\n",
  270. (float)badCount/(float)queryDescCount );
  271. ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
  272. }
  273. }
  274. }
  275. }
  276. void CV_DescriptorMatcherTest::knnMatchTest( const Mat& query, const Mat& train )
  277. {
  278. dmatcher->clear();
  279. // test const version of knnMatch()
  280. {
  281. const int knn = 3;
  282. vector<vector<DMatch> > matches;
  283. dmatcher->knnMatch( query, train, matches, knn );
  284. if( (int)matches.size() != queryDescCount )
  285. {
  286. ts->printf(cvtest::TS::LOG, "Incorrect matches count while test knnMatch() function (1).\n");
  287. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  288. }
  289. else
  290. {
  291. int badCount = 0;
  292. for( size_t i = 0; i < matches.size(); i++ )
  293. {
  294. if( (int)matches[i].size() != knn )
  295. badCount++;
  296. else
  297. {
  298. int localBadCount = 0;
  299. for( int k = 0; k < knn; k++ )
  300. {
  301. DMatch& match = matches[i][k];
  302. if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor+k) || (match.imgIdx != 0) )
  303. localBadCount++;
  304. }
  305. badCount += localBadCount > 0 ? 1 : 0;
  306. }
  307. }
  308. if( (float)badCount > (float)queryDescCount*badPart )
  309. {
  310. ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test knnMatch() function (1).\n",
  311. (float)badCount/(float)queryDescCount );
  312. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  313. }
  314. }
  315. }
  316. // test version of knnMatch() with add()
  317. {
  318. const int knn = 2;
  319. vector<vector<DMatch> > matches;
  320. // make add() twice to test such case
  321. dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
  322. dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
  323. // prepare masks (make first nearest match illegal)
  324. vector<Mat> masks(2);
  325. for(int mi = 0; mi < 2; mi++ )
  326. {
  327. masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
  328. for( int di = 0; di < queryDescCount/2; di++ )
  329. masks[mi].col(di*countFactor).setTo(Scalar::all(0));
  330. }
  331. dmatcher->knnMatch( query, matches, knn, masks );
  332. if( (int)matches.size() != queryDescCount )
  333. {
  334. ts->printf(cvtest::TS::LOG, "Incorrect matches count while test knnMatch() function (2).\n");
  335. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  336. }
  337. else
  338. {
  339. int badCount = 0;
  340. int shift = dmatcher->isMaskSupported() ? 1 : 0;
  341. for( size_t i = 0; i < matches.size(); i++ )
  342. {
  343. if( (int)matches[i].size() != knn )
  344. badCount++;
  345. else
  346. {
  347. int localBadCount = 0;
  348. for( int k = 0; k < knn; k++ )
  349. {
  350. DMatch& match = matches[i][k];
  351. {
  352. if( i < queryDescCount/2 )
  353. {
  354. if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + k + shift) ||
  355. (match.imgIdx != 0) )
  356. localBadCount++;
  357. }
  358. else
  359. {
  360. if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + k + shift) ||
  361. (match.imgIdx != 1) )
  362. localBadCount++;
  363. }
  364. }
  365. }
  366. badCount += localBadCount > 0 ? 1 : 0;
  367. }
  368. }
  369. if( (float)badCount > (float)queryDescCount*badPart )
  370. {
  371. ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test knnMatch() function (2).\n",
  372. (float)badCount/(float)queryDescCount );
  373. ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
  374. }
  375. }
  376. }
  377. }
  378. void CV_DescriptorMatcherTest::radiusMatchTest( const Mat& query, const Mat& train )
  379. {
  380. dmatcher->clear();
  381. // test const version of match()
  382. {
  383. const float radius = 1.f/countFactor;
  384. vector<vector<DMatch> > matches;
  385. dmatcher->radiusMatch( query, train, matches, radius );
  386. if( (int)matches.size() != queryDescCount )
  387. {
  388. ts->printf(cvtest::TS::LOG, "Incorrect matches count while test radiusMatch() function (1).\n");
  389. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  390. }
  391. else
  392. {
  393. int badCount = 0;
  394. for( size_t i = 0; i < matches.size(); i++ )
  395. {
  396. if( (int)matches[i].size() != 1 )
  397. badCount++;
  398. else
  399. {
  400. DMatch& match = matches[i][0];
  401. if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor) || (match.imgIdx != 0) )
  402. badCount++;
  403. }
  404. }
  405. if( (float)badCount > (float)queryDescCount*badPart )
  406. {
  407. ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test radiusMatch() function (1).\n",
  408. (float)badCount/(float)queryDescCount );
  409. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  410. }
  411. }
  412. }
  413. // test version of match() with add()
  414. {
  415. int n = 3;
  416. const float radius = 1.f/countFactor * n;
  417. vector<vector<DMatch> > matches;
  418. // make add() twice to test such case
  419. dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
  420. dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
  421. // prepare masks (make first nearest match illegal)
  422. vector<Mat> masks(2);
  423. for(int mi = 0; mi < 2; mi++ )
  424. {
  425. masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
  426. for( int di = 0; di < queryDescCount/2; di++ )
  427. masks[mi].col(di*countFactor).setTo(Scalar::all(0));
  428. }
  429. dmatcher->radiusMatch( query, matches, radius, masks );
  430. //int curRes = cvtest::TS::OK;
  431. if( (int)matches.size() != queryDescCount )
  432. {
  433. ts->printf(cvtest::TS::LOG, "Incorrect matches count while test radiusMatch() function (1).\n");
  434. ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
  435. }
  436. int badCount = 0;
  437. int shift = dmatcher->isMaskSupported() ? 1 : 0;
  438. int needMatchCount = dmatcher->isMaskSupported() ? n-1 : n;
  439. for( size_t i = 0; i < matches.size(); i++ )
  440. {
  441. if( (int)matches[i].size() != needMatchCount )
  442. badCount++;
  443. else
  444. {
  445. int localBadCount = 0;
  446. for( int k = 0; k < needMatchCount; k++ )
  447. {
  448. DMatch& match = matches[i][k];
  449. {
  450. if( i < queryDescCount/2 )
  451. {
  452. if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + k + shift) ||
  453. (match.imgIdx != 0) )
  454. localBadCount++;
  455. }
  456. else
  457. {
  458. if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + k + shift) ||
  459. (match.imgIdx != 1) )
  460. localBadCount++;
  461. }
  462. }
  463. }
  464. badCount += localBadCount > 0 ? 1 : 0;
  465. }
  466. }
  467. if( (float)badCount > (float)queryDescCount*badPart )
  468. {
  469. //curRes = cvtest::TS::FAIL_INVALID_OUTPUT;
  470. ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test radiusMatch() function (2).\n",
  471. (float)badCount/(float)queryDescCount );
  472. ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
  473. }
  474. }
  475. }
  476. void CV_DescriptorMatcherTest::run( int )
  477. {
  478. Mat query, train;
  479. generateData( query, train );
  480. matchTest( query, train );
  481. knnMatchTest( query, train );
  482. radiusMatchTest( query, train );
  483. }
  484. /****************************************************************************************\
  485. * Tests registrations *
  486. \****************************************************************************************/
  487. TEST( Features2d_DescriptorMatcher_BruteForce, regression )
  488. {
  489. CV_DescriptorMatcherTest test( "descriptor-matcher-brute-force",
  490. DescriptorMatcher::create("BruteForce"), 0.01f );
  491. test.safe_run();
  492. }
  493. #ifdef HAVE_OPENCV_FLANN
  494. TEST( Features2d_DescriptorMatcher_FlannBased, regression )
  495. {
  496. CV_DescriptorMatcherTest test( "descriptor-matcher-flann-based",
  497. DescriptorMatcher::create("FlannBased"), 0.04f );
  498. test.safe_run();
  499. }
  500. #endif
  501. TEST( Features2d_DMatch, read_write )
  502. {
  503. FileStorage fs(".xml", FileStorage::WRITE + FileStorage::MEMORY);
  504. vector<DMatch> matches;
  505. matches.push_back(DMatch(1,2,3,4.5f));
  506. fs << "Match" << matches;
  507. String str = fs.releaseAndGetString();
  508. ASSERT_NE( strstr(str.c_str(), "4.5"), (char*)0 );
  509. }
  510. #ifdef HAVE_OPENCV_FLANN
  511. TEST( Features2d_FlannBasedMatcher, read_write )
  512. {
  513. static const char* ymlfile = "%YAML:1.0\n---\n"
  514. "format: 3\n"
  515. "indexParams:\n"
  516. " -\n"
  517. " name: algorithm\n"
  518. " type: 9\n" // FLANN_INDEX_TYPE_ALGORITHM
  519. " value: 6\n"// this line is changed!
  520. " -\n"
  521. " name: trees\n"
  522. " type: 4\n"
  523. " value: 4\n"
  524. "searchParams:\n"
  525. " -\n"
  526. " name: checks\n"
  527. " type: 4\n"
  528. " value: 32\n"
  529. " -\n"
  530. " name: eps\n"
  531. " type: 5\n"
  532. " value: 4.\n"// this line is changed!
  533. " -\n"
  534. " name: explore_all_trees\n"
  535. " type: 8\n"
  536. " value: 0\n"
  537. " -\n"
  538. " name: sorted\n"
  539. " type: 8\n" // FLANN_INDEX_TYPE_BOOL
  540. " value: 1\n";
  541. Ptr<DescriptorMatcher> matcher = FlannBasedMatcher::create();
  542. FileStorage fs_in(ymlfile, FileStorage::READ + FileStorage::MEMORY);
  543. matcher->read(fs_in.root());
  544. FileStorage fs_out(".yml", FileStorage::WRITE + FileStorage::MEMORY);
  545. matcher->write(fs_out);
  546. std::string out = fs_out.releaseAndGetString();
  547. EXPECT_EQ(ymlfile, out);
  548. }
  549. #endif
  550. TEST(Features2d_DMatch, issue_11855)
  551. {
  552. Mat sources = (Mat_<uchar>(2, 3) << 1, 1, 0,
  553. 1, 1, 1);
  554. Mat targets = (Mat_<uchar>(2, 3) << 1, 1, 1,
  555. 0, 0, 0);
  556. Ptr<BFMatcher> bf = BFMatcher::create(NORM_HAMMING, true);
  557. vector<vector<DMatch> > match;
  558. bf->knnMatch(sources, targets, match, 1, noArray(), true);
  559. ASSERT_EQ((size_t)1, match.size());
  560. ASSERT_EQ((size_t)1, match[0].size());
  561. EXPECT_EQ(1, match[0][0].queryIdx);
  562. EXPECT_EQ(0, match[0][0].trainIdx);
  563. EXPECT_EQ(0.0f, match[0][0].distance);
  564. }
  565. TEST(Features2d_DMatch, issue_17771)
  566. {
  567. Mat sources = (Mat_<uchar>(2, 3) << 1, 1, 0,
  568. 1, 1, 1);
  569. Mat targets = (Mat_<uchar>(2, 3) << 1, 1, 1,
  570. 0, 0, 0);
  571. UMat usources = sources.getUMat(ACCESS_READ);
  572. UMat utargets = targets.getUMat(ACCESS_READ);
  573. vector<vector<DMatch> > match;
  574. Ptr<BFMatcher> ubf = BFMatcher::create(NORM_HAMMING);
  575. Mat mask = (Mat_<uchar>(2, 2) << 1, 0, 0, 1);
  576. EXPECT_NO_THROW(ubf->knnMatch(usources, utargets, match, 1, mask, true));
  577. }
  578. }} // namespace