Repository: opencv
Issue: Flann LshIndexParams save and load does not work - SEGFAULT
Labels: bug,auto-transferred,priority: normal,affected: 3.4,category: flann

Transferred from http://code.opencv.org/issues/3720

```
|| Puneet Jain on 2014-05-28 02:07
|| Priority: Normal
|| Affected: branch 'master' (3.0-dev)
|| Category: flann
|| Tracker: Bug
|| Difficulty: Easy
|| PR: 
|| Platform: x64 / Linux
```
## Flann LshIndexParams save and load does not work - SEGFAULT

```
Test case: pass any binary descriptors (use AKAZE, ORB, or KAZE). This will through an error. I think /modules/flann/include/opencv2/flann/lsh_index.h 
needs some fixes in loadIndex (load_value and save_value)


<pre>
void flannSaveAndLoadTest(Mat descriptor) {
    // construct an index
   flann::LshIndexParams lshIndexParams(20,10,2);
   flann::Index kdtree(descriptor, lshIndexParams, cvflann::FLANN_DIST_HAMMING);

   // save descriptors to file
   writeMatToFile(descriptor, "before_index_save.dat");

   // save index to file
   kdtree.save("index.dat");

   // load index from file
   Mat mat = Mat(descriptor.rows, descriptor.cols, CV_8UC1);
   flann::Index kdtree1(mat, flann::SavedIndexParams("index.dat"), cvflann::FLANN_DIST_HAMMING);

   // save loaded mat
   writeMatToFile(mat, "after_index_save.dat");

   // search in this tree
   Mat dists = Mat(descriptor.rows, 2, CV_32S);
   Mat indices = Mat(descriptor.rows, 3, CV_32S);
   kdtree1.knnSearch(descriptor, indices, dists, 2);

}

</pre>
```
## History
##### Dmitry Retinskiy on 2014-05-28 04:25

```
Hi Puneet Jain,

it would be appreciated if you could suggest a fix for the reported issue.
(see here for instructions on how to do it: http://www.code.opencv.org/projects/opencv/wiki/How_to_contribute)
-   Assignee set to Puneet Jain
-   Status changed from New to Open
-   Category set to flann
```
##### Puneet Jain on 2014-05-28 23:54

```
Hi  Dmitry Retinskiy,

After spending several hours, I was able to triage the issue. The issue is not in save/load of indices in LSH but in modules/flann/include/opencv2/flann/lsh_tables.h. The problem is as follows:

lsh_index.h when loads saved indices data, it uses add() method defined in lsh_tables.

<pre>
  /** Add a feature to the table
     * @param value the value to store for that feature
     * @param feature the feature itself
     */
    void add(unsigned int value, const ElementType* feature)
    {
        // Add the value to the corresponding bucket
        BucketKey key = (lsh::BucketKey)getKey(feature);

        switch (speed_level_) {
        case kArray:
            // That means we get the buckets from an array
            buckets_speed_[key].push_back(value);
            break;
        case kBitsetHash:
            // That means we can check the bitset for the presence of a key
            key_bitset_.set(key);
            buckets_space_[key].push_back(value);
            break;
        case kHash:
        {
            // That means we have to check for the hash table for the presence of a key
            buckets_space_[key].push_back(value);
            break;
        }
        }
    }

</pre>

There is something called speed_level which is decided based on the your amount of data/ or some other parameter. The problem occurs when addition is done at one speed and retrieval (getBucketFromKey) at a different speed. In my case, the addition was happening at kHash speed, but retrieval at kBitHash speed.

The quick fix for this is to make kHash as default speed for everthing:

<pre>
 inline const Bucket* getBucketFromKey(BucketKey key) const
    {
        // Generate other buckets
        switch (speed_level_) {
        case kArray:
       /*   // That means we get the buckets from an array
            return &buckets_speed_[key];
       */    

  {
            // That means we have to check for the hash table for the presence of a key
            BucketsSpace::const_iterator bucket_it, bucket_end = buckets_space_.end();
            bucket_it = buckets_space_.find(key);
            // Stop here if that bucket does not exist
            if (bucket_it == bucket_end) return 0;
            else return &bucket_it->second;
            }

        break;
        case kBitsetHash:
/*          // That means we can check the bitset for the presence of a key
            if (key_bitset_.test(key)) return &buckets_space_.find(key)->second;
            else return 0;
*/
            {
            // That means we have to check for the hash table for the presence of a key
            BucketsSpace::const_iterator bucket_it, bucket_end = buckets_space_.end();
            bucket_it = buckets_space_.find(key);
            // Stop here if that bucket does not exist
            if (bucket_it == bucket_end) return 0;
            else return &bucket_it->second;
            }
            break;
        case kHash:
        {
            // That means we have to check for the hash table for the presence of a key
            BucketsSpace::const_iterator bucket_it, bucket_end = buckets_space_.end();
            bucket_it = buckets_space_.find(key);
            // Stop here if that bucket does not exist
            if (bucket_it == bucket_end) return 0;
            else return &bucket_it->second;
            break;
        }
        }
        return 0;
    }

</pre>

The commented part of code is the current code in OpenCV. I have pasted kHash in all three cases. It seem to work fine now. (I am not certain about correctness though). Hope someone can pick it from here and fix this issue.


Thanks
Puneet
```