test_matchers_algorithmic.cpp 23 KB

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