1 #include "precomp.hpp" 2 3 #define MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 0 4 5 static cvflann::IndexParams& get_params(const cv::flann::IndexParams& p) 6 { 7 return *(cvflann::IndexParams*)(p.params); 8 } 9 10 cv::flann::IndexParams::~IndexParams() 11 { 12 delete &get_params(*this); 13 } 14 15 namespace cv 16 { 17 18 namespace flann 19 { 20 21 using namespace cvflann; 22 23 IndexParams::IndexParams() 24 { 25 params = new ::cvflann::IndexParams(); 26 } 27 28 template<typename T> 29 T getParam(const IndexParams& _p, const String& key, const T& defaultVal=T()) 30 { 31 ::cvflann::IndexParams& p = get_params(_p); 32 ::cvflann::IndexParams::const_iterator it = p.find(key); 33 if( it == p.end() ) 34 return defaultVal; 35 return it->second.cast<T>(); 36 } 37 38 template<typename T> 39 void setParam(IndexParams& _p, const String& key, const T& value) 40 { 41 ::cvflann::IndexParams& p = get_params(_p); 42 p[key] = value; 43 } 44 45 String IndexParams::getString(const String& key, const String& defaultVal) const 46 { 47 return getParam(*this, key, defaultVal); 48 } 49 50 int IndexParams::getInt(const String& key, int defaultVal) const 51 { 52 return getParam(*this, key, defaultVal); 53 } 54 55 double IndexParams::getDouble(const String& key, double defaultVal) const 56 { 57 return getParam(*this, key, defaultVal); 58 } 59 60 61 void IndexParams::setString(const String& key, const String& value) 62 { 63 setParam(*this, key, value); 64 } 65 66 void IndexParams::setInt(const String& key, int value) 67 { 68 setParam(*this, key, value); 69 } 70 71 void IndexParams::setDouble(const String& key, double value) 72 { 73 setParam(*this, key, value); 74 } 75 76 void IndexParams::setFloat(const String& key, float value) 77 { 78 setParam(*this, key, value); 79 } 80 81 void IndexParams::setBool(const String& key, bool value) 82 { 83 setParam(*this, key, value); 84 } 85 86 void IndexParams::setAlgorithm(int value) 87 { 88 setParam(*this, "algorithm", (cvflann::flann_algorithm_t)value); 89 } 90 91 void IndexParams::getAll(std::vector<String>& names, 92 std::vector<int>& types, 93 std::vector<String>& strValues, 94 std::vector<double>& numValues) const 95 { 96 names.clear(); 97 types.clear(); 98 strValues.clear(); 99 numValues.clear(); 100 101 ::cvflann::IndexParams& p = get_params(*this); 102 ::cvflann::IndexParams::const_iterator it = p.begin(), it_end = p.end(); 103 104 for( ; it != it_end; ++it ) 105 { 106 names.push_back(it->first); 107 try 108 { 109 String val = it->second.cast<String>(); 110 types.push_back(CV_USRTYPE1); 111 strValues.push_back(val); 112 numValues.push_back(-1); 113 continue; 114 } 115 catch (...) {} 116 117 strValues.push_back(it->second.type().name()); 118 119 try 120 { 121 double val = it->second.cast<double>(); 122 types.push_back( CV_64F ); 123 numValues.push_back(val); 124 continue; 125 } 126 catch (...) {} 127 try 128 { 129 float val = it->second.cast<float>(); 130 types.push_back( CV_32F ); 131 numValues.push_back(val); 132 continue; 133 } 134 catch (...) {} 135 try 136 { 137 int val = it->second.cast<int>(); 138 types.push_back( CV_32S ); 139 numValues.push_back(val); 140 continue; 141 } 142 catch (...) {} 143 try 144 { 145 short val = it->second.cast<short>(); 146 types.push_back( CV_16S ); 147 numValues.push_back(val); 148 continue; 149 } 150 catch (...) {} 151 try 152 { 153 ushort val = it->second.cast<ushort>(); 154 types.push_back( CV_16U ); 155 numValues.push_back(val); 156 continue; 157 } 158 catch (...) {} 159 try 160 { 161 char val = it->second.cast<char>(); 162 types.push_back( CV_8S ); 163 numValues.push_back(val); 164 continue; 165 } 166 catch (...) {} 167 try 168 { 169 uchar val = it->second.cast<uchar>(); 170 types.push_back( CV_8U ); 171 numValues.push_back(val); 172 continue; 173 } 174 catch (...) {} 175 try 176 { 177 bool val = it->second.cast<bool>(); 178 types.push_back( CV_MAKETYPE(CV_USRTYPE1,2) ); 179 numValues.push_back(val); 180 continue; 181 } 182 catch (...) {} 183 try 184 { 185 cvflann::flann_algorithm_t val = it->second.cast<cvflann::flann_algorithm_t>(); 186 types.push_back( CV_MAKETYPE(CV_USRTYPE1,3) ); 187 numValues.push_back(val); 188 continue; 189 } 190 catch (...) {} 191 192 193 types.push_back(-1); // unknown type 194 numValues.push_back(-1); 195 } 196 } 197 198 199 KDTreeIndexParams::KDTreeIndexParams(int trees) 200 { 201 ::cvflann::IndexParams& p = get_params(*this); 202 p["algorithm"] = FLANN_INDEX_KDTREE; 203 p["trees"] = trees; 204 } 205 206 LinearIndexParams::LinearIndexParams() 207 { 208 ::cvflann::IndexParams& p = get_params(*this); 209 p["algorithm"] = FLANN_INDEX_LINEAR; 210 } 211 212 CompositeIndexParams::CompositeIndexParams(int trees, int branching, int iterations, 213 flann_centers_init_t centers_init, float cb_index ) 214 { 215 ::cvflann::IndexParams& p = get_params(*this); 216 p["algorithm"] = FLANN_INDEX_KMEANS; 217 // number of randomized trees to use (for kdtree) 218 p["trees"] = trees; 219 // branching factor 220 p["branching"] = branching; 221 // max iterations to perform in one kmeans clustering (kmeans tree) 222 p["iterations"] = iterations; 223 // algorithm used for picking the initial cluster centers for kmeans tree 224 p["centers_init"] = centers_init; 225 // cluster boundary index. Used when searching the kmeans tree 226 p["cb_index"] = cb_index; 227 } 228 229 AutotunedIndexParams::AutotunedIndexParams(float target_precision, float build_weight, 230 float memory_weight, float sample_fraction) 231 { 232 ::cvflann::IndexParams& p = get_params(*this); 233 p["algorithm"] = FLANN_INDEX_AUTOTUNED; 234 // precision desired (used for autotuning, -1 otherwise) 235 p["target_precision"] = target_precision; 236 // build tree time weighting factor 237 p["build_weight"] = build_weight; 238 // index memory weighting factor 239 p["memory_weight"] = memory_weight; 240 // what fraction of the dataset to use for autotuning 241 p["sample_fraction"] = sample_fraction; 242 } 243 244 245 KMeansIndexParams::KMeansIndexParams(int branching, int iterations, 246 flann_centers_init_t centers_init, float cb_index ) 247 { 248 ::cvflann::IndexParams& p = get_params(*this); 249 p["algorithm"] = FLANN_INDEX_KMEANS; 250 // branching factor 251 p["branching"] = branching; 252 // max iterations to perform in one kmeans clustering (kmeans tree) 253 p["iterations"] = iterations; 254 // algorithm used for picking the initial cluster centers for kmeans tree 255 p["centers_init"] = centers_init; 256 // cluster boundary index. Used when searching the kmeans tree 257 p["cb_index"] = cb_index; 258 } 259 260 HierarchicalClusteringIndexParams::HierarchicalClusteringIndexParams(int branching , 261 flann_centers_init_t centers_init, 262 int trees, int leaf_size) 263 { 264 ::cvflann::IndexParams& p = get_params(*this); 265 p["algorithm"] = FLANN_INDEX_HIERARCHICAL; 266 // The branching factor used in the hierarchical clustering 267 p["branching"] = branching; 268 // Algorithm used for picking the initial cluster centers 269 p["centers_init"] = centers_init; 270 // number of parallel trees to build 271 p["trees"] = trees; 272 // maximum leaf size 273 p["leaf_size"] = leaf_size; 274 } 275 276 LshIndexParams::LshIndexParams(int table_number, int key_size, int multi_probe_level) 277 { 278 ::cvflann::IndexParams& p = get_params(*this); 279 p["algorithm"] = FLANN_INDEX_LSH; 280 // The number of hash tables to use 281 p["table_number"] = table_number; 282 // The length of the key in the hash tables 283 p["key_size"] = key_size; 284 // Number of levels to use in multi-probe (0 for standard LSH) 285 p["multi_probe_level"] = multi_probe_level; 286 } 287 288 SavedIndexParams::SavedIndexParams(const String& _filename) 289 { 290 String filename = _filename; 291 ::cvflann::IndexParams& p = get_params(*this); 292 293 p["algorithm"] = FLANN_INDEX_SAVED; 294 p["filename"] = filename; 295 } 296 297 SearchParams::SearchParams( int checks, float eps, bool sorted ) 298 { 299 ::cvflann::IndexParams& p = get_params(*this); 300 301 // how many leafs to visit when searching for neighbours (-1 for unlimited) 302 p["checks"] = checks; 303 // search for eps-approximate neighbours (default: 0) 304 p["eps"] = eps; 305 // only for radius search, require neighbours sorted by distance (default: true) 306 p["sorted"] = sorted; 307 } 308 309 310 template<typename Distance, typename IndexType> void 311 buildIndex_(void*& index, const Mat& data, const IndexParams& params, const Distance& dist = Distance()) 312 { 313 typedef typename Distance::ElementType ElementType; 314 if(DataType<ElementType>::type != data.type()) 315 CV_Error_(Error::StsUnsupportedFormat, ("type=%d\n", data.type())); 316 if(!data.isContinuous()) 317 CV_Error(Error::StsBadArg, "Only continuous arrays are supported"); 318 319 ::cvflann::Matrix<ElementType> dataset((ElementType*)data.data, data.rows, data.cols); 320 IndexType* _index = new IndexType(dataset, get_params(params), dist); 321 _index->buildIndex(); 322 index = _index; 323 } 324 325 template<typename Distance> void 326 buildIndex(void*& index, const Mat& data, const IndexParams& params, const Distance& dist = Distance()) 327 { 328 buildIndex_<Distance, ::cvflann::Index<Distance> >(index, data, params, dist); 329 } 330 331 #if CV_NEON 332 typedef ::cvflann::Hamming<uchar> HammingDistance; 333 #else 334 typedef ::cvflann::HammingLUT HammingDistance; 335 #endif 336 337 Index::Index() 338 { 339 index = 0; 340 featureType = CV_32F; 341 algo = FLANN_INDEX_LINEAR; 342 distType = FLANN_DIST_L2; 343 } 344 345 Index::Index(InputArray _data, const IndexParams& params, flann_distance_t _distType) 346 { 347 index = 0; 348 featureType = CV_32F; 349 algo = FLANN_INDEX_LINEAR; 350 distType = FLANN_DIST_L2; 351 build(_data, params, _distType); 352 } 353 354 void Index::build(InputArray _data, const IndexParams& params, flann_distance_t _distType) 355 { 356 release(); 357 algo = getParam<flann_algorithm_t>(params, "algorithm", FLANN_INDEX_LINEAR); 358 if( algo == FLANN_INDEX_SAVED ) 359 { 360 load(_data, getParam<String>(params, "filename", String())); 361 return; 362 } 363 364 Mat data = _data.getMat(); 365 index = 0; 366 featureType = data.type(); 367 distType = _distType; 368 369 if ( algo == FLANN_INDEX_LSH) 370 { 371 distType = FLANN_DIST_HAMMING; 372 } 373 374 switch( distType ) 375 { 376 case FLANN_DIST_HAMMING: 377 buildIndex< HammingDistance >(index, data, params); 378 break; 379 case FLANN_DIST_L2: 380 buildIndex< ::cvflann::L2<float> >(index, data, params); 381 break; 382 case FLANN_DIST_L1: 383 buildIndex< ::cvflann::L1<float> >(index, data, params); 384 break; 385 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 386 case FLANN_DIST_MAX: 387 buildIndex< ::cvflann::MaxDistance<float> >(index, data, params); 388 break; 389 case FLANN_DIST_HIST_INTERSECT: 390 buildIndex< ::cvflann::HistIntersectionDistance<float> >(index, data, params); 391 break; 392 case FLANN_DIST_HELLINGER: 393 buildIndex< ::cvflann::HellingerDistance<float> >(index, data, params); 394 break; 395 case FLANN_DIST_CHI_SQUARE: 396 buildIndex< ::cvflann::ChiSquareDistance<float> >(index, data, params); 397 break; 398 case FLANN_DIST_KL: 399 buildIndex< ::cvflann::KL_Divergence<float> >(index, data, params); 400 break; 401 #endif 402 default: 403 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type"); 404 } 405 } 406 407 template<typename IndexType> void deleteIndex_(void* index) 408 { 409 delete (IndexType*)index; 410 } 411 412 template<typename Distance> void deleteIndex(void* index) 413 { 414 deleteIndex_< ::cvflann::Index<Distance> >(index); 415 } 416 417 Index::~Index() 418 { 419 release(); 420 } 421 422 void Index::release() 423 { 424 if( !index ) 425 return; 426 427 switch( distType ) 428 { 429 case FLANN_DIST_HAMMING: 430 deleteIndex< HammingDistance >(index); 431 break; 432 case FLANN_DIST_L2: 433 deleteIndex< ::cvflann::L2<float> >(index); 434 break; 435 case FLANN_DIST_L1: 436 deleteIndex< ::cvflann::L1<float> >(index); 437 break; 438 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 439 case FLANN_DIST_MAX: 440 deleteIndex< ::cvflann::MaxDistance<float> >(index); 441 break; 442 case FLANN_DIST_HIST_INTERSECT: 443 deleteIndex< ::cvflann::HistIntersectionDistance<float> >(index); 444 break; 445 case FLANN_DIST_HELLINGER: 446 deleteIndex< ::cvflann::HellingerDistance<float> >(index); 447 break; 448 case FLANN_DIST_CHI_SQUARE: 449 deleteIndex< ::cvflann::ChiSquareDistance<float> >(index); 450 break; 451 case FLANN_DIST_KL: 452 deleteIndex< ::cvflann::KL_Divergence<float> >(index); 453 break; 454 #endif 455 default: 456 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type"); 457 } 458 index = 0; 459 } 460 461 template<typename Distance, typename IndexType> 462 void runKnnSearch_(void* index, const Mat& query, Mat& indices, Mat& dists, 463 int knn, const SearchParams& params) 464 { 465 typedef typename Distance::ElementType ElementType; 466 typedef typename Distance::ResultType DistanceType; 467 int type = DataType<ElementType>::type; 468 int dtype = DataType<DistanceType>::type; 469 CV_Assert(query.type() == type && indices.type() == CV_32S && dists.type() == dtype); 470 CV_Assert(query.isContinuous() && indices.isContinuous() && dists.isContinuous()); 471 472 ::cvflann::Matrix<ElementType> _query((ElementType*)query.data, query.rows, query.cols); 473 ::cvflann::Matrix<int> _indices(indices.ptr<int>(), indices.rows, indices.cols); 474 ::cvflann::Matrix<DistanceType> _dists(dists.ptr<DistanceType>(), dists.rows, dists.cols); 475 476 ((IndexType*)index)->knnSearch(_query, _indices, _dists, knn, 477 (const ::cvflann::SearchParams&)get_params(params)); 478 } 479 480 template<typename Distance> 481 void runKnnSearch(void* index, const Mat& query, Mat& indices, Mat& dists, 482 int knn, const SearchParams& params) 483 { 484 runKnnSearch_<Distance, ::cvflann::Index<Distance> >(index, query, indices, dists, knn, params); 485 } 486 487 template<typename Distance, typename IndexType> 488 int runRadiusSearch_(void* index, const Mat& query, Mat& indices, Mat& dists, 489 double radius, const SearchParams& params) 490 { 491 typedef typename Distance::ElementType ElementType; 492 typedef typename Distance::ResultType DistanceType; 493 int type = DataType<ElementType>::type; 494 int dtype = DataType<DistanceType>::type; 495 CV_Assert(query.type() == type && indices.type() == CV_32S && dists.type() == dtype); 496 CV_Assert(query.isContinuous() && indices.isContinuous() && dists.isContinuous()); 497 498 ::cvflann::Matrix<ElementType> _query((ElementType*)query.data, query.rows, query.cols); 499 ::cvflann::Matrix<int> _indices(indices.ptr<int>(), indices.rows, indices.cols); 500 ::cvflann::Matrix<DistanceType> _dists(dists.ptr<DistanceType>(), dists.rows, dists.cols); 501 502 return ((IndexType*)index)->radiusSearch(_query, _indices, _dists, 503 saturate_cast<float>(radius), 504 (const ::cvflann::SearchParams&)get_params(params)); 505 } 506 507 template<typename Distance> 508 int runRadiusSearch(void* index, const Mat& query, Mat& indices, Mat& dists, 509 double radius, const SearchParams& params) 510 { 511 return runRadiusSearch_<Distance, ::cvflann::Index<Distance> >(index, query, indices, dists, radius, params); 512 } 513 514 515 static void createIndicesDists(OutputArray _indices, OutputArray _dists, 516 Mat& indices, Mat& dists, int rows, 517 int minCols, int maxCols, int dtype) 518 { 519 if( _indices.needed() ) 520 { 521 indices = _indices.getMat(); 522 if( !indices.isContinuous() || indices.type() != CV_32S || 523 indices.rows != rows || indices.cols < minCols || indices.cols > maxCols ) 524 { 525 if( !indices.isContinuous() ) 526 _indices.release(); 527 _indices.create( rows, minCols, CV_32S ); 528 indices = _indices.getMat(); 529 } 530 } 531 else 532 indices.create( rows, minCols, CV_32S ); 533 534 if( _dists.needed() ) 535 { 536 dists = _dists.getMat(); 537 if( !dists.isContinuous() || dists.type() != dtype || 538 dists.rows != rows || dists.cols < minCols || dists.cols > maxCols ) 539 { 540 if( !indices.isContinuous() ) 541 _dists.release(); 542 _dists.create( rows, minCols, dtype ); 543 dists = _dists.getMat(); 544 } 545 } 546 else 547 dists.create( rows, minCols, dtype ); 548 } 549 550 551 void Index::knnSearch(InputArray _query, OutputArray _indices, 552 OutputArray _dists, int knn, const SearchParams& params) 553 { 554 Mat query = _query.getMat(), indices, dists; 555 int dtype = distType == FLANN_DIST_HAMMING ? CV_32S : CV_32F; 556 557 createIndicesDists( _indices, _dists, indices, dists, query.rows, knn, knn, dtype ); 558 559 switch( distType ) 560 { 561 case FLANN_DIST_HAMMING: 562 runKnnSearch<HammingDistance>(index, query, indices, dists, knn, params); 563 break; 564 case FLANN_DIST_L2: 565 runKnnSearch< ::cvflann::L2<float> >(index, query, indices, dists, knn, params); 566 break; 567 case FLANN_DIST_L1: 568 runKnnSearch< ::cvflann::L1<float> >(index, query, indices, dists, knn, params); 569 break; 570 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 571 case FLANN_DIST_MAX: 572 runKnnSearch< ::cvflann::MaxDistance<float> >(index, query, indices, dists, knn, params); 573 break; 574 case FLANN_DIST_HIST_INTERSECT: 575 runKnnSearch< ::cvflann::HistIntersectionDistance<float> >(index, query, indices, dists, knn, params); 576 break; 577 case FLANN_DIST_HELLINGER: 578 runKnnSearch< ::cvflann::HellingerDistance<float> >(index, query, indices, dists, knn, params); 579 break; 580 case FLANN_DIST_CHI_SQUARE: 581 runKnnSearch< ::cvflann::ChiSquareDistance<float> >(index, query, indices, dists, knn, params); 582 break; 583 case FLANN_DIST_KL: 584 runKnnSearch< ::cvflann::KL_Divergence<float> >(index, query, indices, dists, knn, params); 585 break; 586 #endif 587 default: 588 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type"); 589 } 590 } 591 592 int Index::radiusSearch(InputArray _query, OutputArray _indices, 593 OutputArray _dists, double radius, int maxResults, 594 const SearchParams& params) 595 { 596 Mat query = _query.getMat(), indices, dists; 597 int dtype = distType == FLANN_DIST_HAMMING ? CV_32S : CV_32F; 598 CV_Assert( maxResults > 0 ); 599 createIndicesDists( _indices, _dists, indices, dists, query.rows, maxResults, INT_MAX, dtype ); 600 601 if( algo == FLANN_INDEX_LSH ) 602 CV_Error( Error::StsNotImplemented, "LSH index does not support radiusSearch operation" ); 603 604 switch( distType ) 605 { 606 case FLANN_DIST_HAMMING: 607 return runRadiusSearch< HammingDistance >(index, query, indices, dists, radius, params); 608 609 case FLANN_DIST_L2: 610 return runRadiusSearch< ::cvflann::L2<float> >(index, query, indices, dists, radius, params); 611 case FLANN_DIST_L1: 612 return runRadiusSearch< ::cvflann::L1<float> >(index, query, indices, dists, radius, params); 613 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 614 case FLANN_DIST_MAX: 615 return runRadiusSearch< ::cvflann::MaxDistance<float> >(index, query, indices, dists, radius, params); 616 case FLANN_DIST_HIST_INTERSECT: 617 return runRadiusSearch< ::cvflann::HistIntersectionDistance<float> >(index, query, indices, dists, radius, params); 618 case FLANN_DIST_HELLINGER: 619 return runRadiusSearch< ::cvflann::HellingerDistance<float> >(index, query, indices, dists, radius, params); 620 case FLANN_DIST_CHI_SQUARE: 621 return runRadiusSearch< ::cvflann::ChiSquareDistance<float> >(index, query, indices, dists, radius, params); 622 case FLANN_DIST_KL: 623 return runRadiusSearch< ::cvflann::KL_Divergence<float> >(index, query, indices, dists, radius, params); 624 #endif 625 default: 626 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type"); 627 } 628 return -1; 629 } 630 631 flann_distance_t Index::getDistance() const 632 { 633 return distType; 634 } 635 636 flann_algorithm_t Index::getAlgorithm() const 637 { 638 return algo; 639 } 640 641 template<typename IndexType> void saveIndex_(const Index* index0, const void* index, FILE* fout) 642 { 643 IndexType* _index = (IndexType*)index; 644 ::cvflann::save_header(fout, *_index); 645 // some compilers may store short enumerations as bytes, 646 // so make sure we always write integers (which are 4-byte values in any modern C compiler) 647 int idistType = (int)index0->getDistance(); 648 ::cvflann::save_value<int>(fout, idistType); 649 _index->saveIndex(fout); 650 } 651 652 template<typename Distance> void saveIndex(const Index* index0, const void* index, FILE* fout) 653 { 654 saveIndex_< ::cvflann::Index<Distance> >(index0, index, fout); 655 } 656 657 void Index::save(const String& filename) const 658 { 659 FILE* fout = fopen(filename.c_str(), "wb"); 660 if (fout == NULL) 661 CV_Error_( Error::StsError, ("Can not open file %s for writing FLANN index\n", filename.c_str()) ); 662 663 switch( distType ) 664 { 665 case FLANN_DIST_HAMMING: 666 saveIndex< HammingDistance >(this, index, fout); 667 break; 668 case FLANN_DIST_L2: 669 saveIndex< ::cvflann::L2<float> >(this, index, fout); 670 break; 671 case FLANN_DIST_L1: 672 saveIndex< ::cvflann::L1<float> >(this, index, fout); 673 break; 674 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 675 case FLANN_DIST_MAX: 676 saveIndex< ::cvflann::MaxDistance<float> >(this, index, fout); 677 break; 678 case FLANN_DIST_HIST_INTERSECT: 679 saveIndex< ::cvflann::HistIntersectionDistance<float> >(this, index, fout); 680 break; 681 case FLANN_DIST_HELLINGER: 682 saveIndex< ::cvflann::HellingerDistance<float> >(this, index, fout); 683 break; 684 case FLANN_DIST_CHI_SQUARE: 685 saveIndex< ::cvflann::ChiSquareDistance<float> >(this, index, fout); 686 break; 687 case FLANN_DIST_KL: 688 saveIndex< ::cvflann::KL_Divergence<float> >(this, index, fout); 689 break; 690 #endif 691 default: 692 fclose(fout); 693 fout = 0; 694 CV_Error(Error::StsBadArg, "Unknown/unsupported distance type"); 695 } 696 if( fout ) 697 fclose(fout); 698 } 699 700 701 template<typename Distance, typename IndexType> 702 bool loadIndex_(Index* index0, void*& index, const Mat& data, FILE* fin, const Distance& dist=Distance()) 703 { 704 typedef typename Distance::ElementType ElementType; 705 CV_Assert(DataType<ElementType>::type == data.type() && data.isContinuous()); 706 707 ::cvflann::Matrix<ElementType> dataset((ElementType*)data.data, data.rows, data.cols); 708 709 ::cvflann::IndexParams params; 710 params["algorithm"] = index0->getAlgorithm(); 711 IndexType* _index = new IndexType(dataset, params, dist); 712 _index->loadIndex(fin); 713 index = _index; 714 return true; 715 } 716 717 template<typename Distance> 718 bool loadIndex(Index* index0, void*& index, const Mat& data, FILE* fin, const Distance& dist=Distance()) 719 { 720 return loadIndex_<Distance, ::cvflann::Index<Distance> >(index0, index, data, fin, dist); 721 } 722 723 bool Index::load(InputArray _data, const String& filename) 724 { 725 Mat data = _data.getMat(); 726 bool ok = true; 727 release(); 728 FILE* fin = fopen(filename.c_str(), "rb"); 729 if (fin == NULL) 730 return false; 731 732 ::cvflann::IndexHeader header = ::cvflann::load_header(fin); 733 algo = header.index_type; 734 featureType = header.data_type == FLANN_UINT8 ? CV_8U : 735 header.data_type == FLANN_INT8 ? CV_8S : 736 header.data_type == FLANN_UINT16 ? CV_16U : 737 header.data_type == FLANN_INT16 ? CV_16S : 738 header.data_type == FLANN_INT32 ? CV_32S : 739 header.data_type == FLANN_FLOAT32 ? CV_32F : 740 header.data_type == FLANN_FLOAT64 ? CV_64F : -1; 741 742 if( (int)header.rows != data.rows || (int)header.cols != data.cols || 743 featureType != data.type() ) 744 { 745 fprintf(stderr, "Reading FLANN index error: the saved data size (%d, %d) or type (%d) is different from the passed one (%d, %d), %d\n", 746 (int)header.rows, (int)header.cols, featureType, data.rows, data.cols, data.type()); 747 fclose(fin); 748 return false; 749 } 750 751 int idistType = 0; 752 ::cvflann::load_value(fin, idistType); 753 distType = (flann_distance_t)idistType; 754 755 if( !((distType == FLANN_DIST_HAMMING && featureType == CV_8U) || 756 (distType != FLANN_DIST_HAMMING && featureType == CV_32F)) ) 757 { 758 fprintf(stderr, "Reading FLANN index error: unsupported feature type %d for the index type %d\n", featureType, algo); 759 fclose(fin); 760 return false; 761 } 762 763 switch( distType ) 764 { 765 case FLANN_DIST_HAMMING: 766 loadIndex< HammingDistance >(this, index, data, fin); 767 break; 768 case FLANN_DIST_L2: 769 loadIndex< ::cvflann::L2<float> >(this, index, data, fin); 770 break; 771 case FLANN_DIST_L1: 772 loadIndex< ::cvflann::L1<float> >(this, index, data, fin); 773 break; 774 #if MINIFLANN_SUPPORT_EXOTIC_DISTANCE_TYPES 775 case FLANN_DIST_MAX: 776 loadIndex< ::cvflann::MaxDistance<float> >(this, index, data, fin); 777 break; 778 case FLANN_DIST_HIST_INTERSECT: 779 loadIndex< ::cvflann::HistIntersectionDistance<float> >(index, data, fin); 780 break; 781 case FLANN_DIST_HELLINGER: 782 loadIndex< ::cvflann::HellingerDistance<float> >(this, index, data, fin); 783 break; 784 case FLANN_DIST_CHI_SQUARE: 785 loadIndex< ::cvflann::ChiSquareDistance<float> >(this, index, data, fin); 786 break; 787 case FLANN_DIST_KL: 788 loadIndex< ::cvflann::KL_Divergence<float> >(this, index, data, fin); 789 break; 790 #endif 791 default: 792 fprintf(stderr, "Reading FLANN index error: unsupported distance type %d\n", distType); 793 ok = false; 794 } 795 796 if( fin ) 797 fclose(fin); 798 return ok; 799 } 800 801 } 802 803 } 804