EstervQrCode 2.0.0
Library for qr code manipulation
Loading...
Searching...
No Matches
lsh_index.h
1/***********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
5 * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
6 *
7 * THE BSD LICENSE
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *************************************************************************/
30
31/***********************************************************************
32 * Author: Vincent Rabaud
33 *************************************************************************/
34
35#ifndef OPENCV_FLANN_LSH_INDEX_H_
36#define OPENCV_FLANN_LSH_INDEX_H_
37
39
40#include <algorithm>
41#include <cstring>
42#include <map>
43#include <vector>
44
45#include "nn_index.h"
46#include "matrix.h"
47#include "result_set.h"
48#include "heap.h"
49#include "lsh_table.h"
50#include "allocator.h"
51#include "random.h"
52#include "saving.h"
53
54#ifdef _MSC_VER
55#pragma warning(push)
56#pragma warning(disable: 4702) //disable unreachable code
57#endif
58
59namespace cvflann
60{
61
62struct LshIndexParams : public IndexParams
63{
64 LshIndexParams(int table_number = 12, int key_size = 20, int multi_probe_level = 2)
65 {
66 (*this)["algorithm"] = FLANN_INDEX_LSH;
67 // The number of hash tables to use
68 (*this)["table_number"] = table_number;
69 // The length of the key in the hash tables
70 (*this)["key_size"] = key_size;
71 // Number of levels to use in multi-probe (0 for standard LSH)
72 (*this)["multi_probe_level"] = multi_probe_level;
73 }
74};
75
82template<typename Distance>
83class LshIndex : public NNIndex<Distance>
84{
85public:
86 typedef typename Distance::ElementType ElementType;
87 typedef typename Distance::ResultType DistanceType;
88
94 LshIndex(const Matrix<ElementType>& input_data, const IndexParams& params = LshIndexParams(),
95 Distance d = Distance()) :
96 dataset_(input_data), index_params_(params), distance_(d)
97 {
98 // cv::flann::IndexParams sets integer params as 'int', so it is used with get_param
99 // in place of 'unsigned int'
100 table_number_ = get_param(index_params_,"table_number",12);
101 key_size_ = get_param(index_params_,"key_size",20);
102 multi_probe_level_ = get_param(index_params_,"multi_probe_level",2);
103
104 feature_size_ = (unsigned)dataset_.cols;
105 fill_xor_mask(0, key_size_, multi_probe_level_, xor_masks_);
106 }
107
108
109 LshIndex(const LshIndex&);
110 LshIndex& operator=(const LshIndex&);
111
115 void buildIndex() CV_OVERRIDE
116 {
117 tables_.resize(table_number_);
118 for (int i = 0; i < table_number_; ++i) {
119 lsh::LshTable<ElementType>& table = tables_[i];
120 table = lsh::LshTable<ElementType>(feature_size_, key_size_);
121
122 // Add the features to the table
123 table.add(dataset_);
124 }
125 }
126
127 flann_algorithm_t getType() const CV_OVERRIDE
128 {
129 return FLANN_INDEX_LSH;
130 }
131
132
133 void saveIndex(FILE* stream) CV_OVERRIDE
134 {
135 save_value(stream,table_number_);
136 save_value(stream,key_size_);
137 save_value(stream,multi_probe_level_);
138 save_value(stream, dataset_);
139 }
140
141 void loadIndex(FILE* stream) CV_OVERRIDE
142 {
143 load_value(stream, table_number_);
144 load_value(stream, key_size_);
145 load_value(stream, multi_probe_level_);
146 load_value(stream, dataset_);
147 // Building the index is so fast we can afford not storing it
148 buildIndex();
149
150 index_params_["algorithm"] = getType();
151 index_params_["table_number"] = table_number_;
152 index_params_["key_size"] = key_size_;
153 index_params_["multi_probe_level"] = multi_probe_level_;
154 }
155
159 size_t size() const CV_OVERRIDE
160 {
161 return dataset_.rows;
162 }
163
167 size_t veclen() const CV_OVERRIDE
168 {
169 return feature_size_;
170 }
171
176 int usedMemory() const CV_OVERRIDE
177 {
178 return (int)(dataset_.rows * sizeof(int));
179 }
180
181
182 IndexParams getParameters() const CV_OVERRIDE
183 {
184 return index_params_;
185 }
186
195 virtual void knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& params) CV_OVERRIDE
196 {
197 CV_Assert(queries.cols == veclen());
198 CV_Assert(indices.rows >= queries.rows);
199 CV_Assert(dists.rows >= queries.rows);
200 CV_Assert(int(indices.cols) >= knn);
201 CV_Assert(int(dists.cols) >= knn);
202
203
204 KNNUniqueResultSet<DistanceType> resultSet(knn);
205 for (size_t i = 0; i < queries.rows; i++) {
206 resultSet.clear();
207 std::fill_n(indices[i], knn, -1);
209 findNeighbors(resultSet, queries[i], params);
210 if (get_param(params,"sorted",true)) resultSet.sortAndCopy(indices[i], dists[i], knn);
211 else resultSet.copy(indices[i], dists[i], knn);
212 }
213 }
214
215
225 void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& /*searchParams*/) CV_OVERRIDE
226 {
227 getNeighbors(vec, result);
228 }
229
230private:
233 typedef std::pair<float, unsigned int> ScoreIndexPair;
234 struct SortScoreIndexPairOnSecond
235 {
236 bool operator()(const ScoreIndexPair& left, const ScoreIndexPair& right) const
237 {
238 return left.second < right.second;
239 }
240 };
241
248 void fill_xor_mask(lsh::BucketKey key, int lowest_index, unsigned int level,
250 {
251 xor_masks.push_back(key);
252 if (level == 0) return;
253 for (int index = lowest_index - 1; index >= 0; --index) {
254 // Create a new key
255 lsh::BucketKey new_key = key | (1 << index);
256 fill_xor_mask(new_key, index, level - 1, xor_masks);
257 }
258 }
259
268 void getNeighbors(const ElementType* vec, bool /*do_radius*/, float radius, bool do_k, unsigned int k_nn,
269 float& /*checked_average*/)
270 {
271 static std::vector<ScoreIndexPair> score_index_heap;
272
273 if (do_k) {
274 unsigned int worst_score = std::numeric_limits<unsigned int>::max();
275 typename std::vector<lsh::LshTable<ElementType> >::const_iterator table = tables_.begin();
276 typename std::vector<lsh::LshTable<ElementType> >::const_iterator table_end = tables_.end();
277 for (; table != table_end; ++table) {
278 size_t key = table->getKey(vec);
280 std::vector<lsh::BucketKey>::const_iterator xor_mask_end = xor_masks_.end();
281 for (; xor_mask != xor_mask_end; ++xor_mask) {
282 size_t sub_key = key ^ (*xor_mask);
283 const lsh::Bucket* bucket = table->getBucketFromKey(sub_key);
284 if (bucket == 0) continue;
285
286 // Go over each descriptor index
287 std::vector<lsh::FeatureIndex>::const_iterator training_index = bucket->begin();
288 std::vector<lsh::FeatureIndex>::const_iterator last_training_index = bucket->end();
289 DistanceType hamming_distance;
290
291 // Process the rest of the candidates
292 for (; training_index < last_training_index; ++training_index) {
293 hamming_distance = distance_(vec, dataset_[*training_index], dataset_.cols);
294
295 if (hamming_distance < worst_score) {
296 // Insert the new element
297 score_index_heap.push_back(ScoreIndexPair(hamming_distance, training_index));
298 std::push_heap(score_index_heap.begin(), score_index_heap.end());
299
300 if (score_index_heap.size() > (unsigned int)k_nn) {
301 // Remove the highest distance value as we have too many elements
302 std::pop_heap(score_index_heap.begin(), score_index_heap.end());
303 score_index_heap.pop_back();
304 // Keep track of the worst score
305 worst_score = score_index_heap.front().first;
306 }
307 }
308 }
309 }
310 }
311 }
312 else {
313 typename std::vector<lsh::LshTable<ElementType> >::const_iterator table = tables_.begin();
314 typename std::vector<lsh::LshTable<ElementType> >::const_iterator table_end = tables_.end();
315 for (; table != table_end; ++table) {
316 size_t key = table->getKey(vec);
318 std::vector<lsh::BucketKey>::const_iterator xor_mask_end = xor_masks_.end();
319 for (; xor_mask != xor_mask_end; ++xor_mask) {
320 size_t sub_key = key ^ (*xor_mask);
321 const lsh::Bucket* bucket = table->getBucketFromKey(sub_key);
322 if (bucket == 0) continue;
323
324 // Go over each descriptor index
325 std::vector<lsh::FeatureIndex>::const_iterator training_index = bucket->begin();
326 std::vector<lsh::FeatureIndex>::const_iterator last_training_index = bucket->end();
327 DistanceType hamming_distance;
328
329 // Process the rest of the candidates
330 for (; training_index < last_training_index; ++training_index) {
331 // Compute the Hamming distance
332 hamming_distance = distance_(vec, dataset_[*training_index], dataset_.cols);
333 if (hamming_distance < radius) score_index_heap.push_back(ScoreIndexPair(hamming_distance, training_index));
334 }
335 }
336 }
337 }
338 }
339
344 void getNeighbors(const ElementType* vec, ResultSet<DistanceType>& result)
345 {
346 typename std::vector<lsh::LshTable<ElementType> >::const_iterator table = tables_.begin();
347 typename std::vector<lsh::LshTable<ElementType> >::const_iterator table_end = tables_.end();
348 for (; table != table_end; ++table) {
349 size_t key = table->getKey(vec);
351 std::vector<lsh::BucketKey>::const_iterator xor_mask_end = xor_masks_.end();
352 for (; xor_mask != xor_mask_end; ++xor_mask) {
353 size_t sub_key = key ^ (*xor_mask);
354 const lsh::Bucket* bucket = table->getBucketFromKey((lsh::BucketKey)sub_key);
355 if (bucket == 0) continue;
356
357 // Go over each descriptor index
358 std::vector<lsh::FeatureIndex>::const_iterator training_index = bucket->begin();
359 std::vector<lsh::FeatureIndex>::const_iterator last_training_index = bucket->end();
360 DistanceType hamming_distance;
361
362 // Process the rest of the candidates
363 for (; training_index < last_training_index; ++training_index) {
364 // Compute the Hamming distance
365 hamming_distance = distance_(vec, dataset_[*training_index], (int)dataset_.cols);
366 result.addPoint(hamming_distance, *training_index);
367 }
368 }
369 }
370 }
371
374
376 Matrix<ElementType> dataset_;
377
379 unsigned int feature_size_;
380
381 IndexParams index_params_;
382
384 int table_number_;
386 int key_size_;
388 int multi_probe_level_;
389
392
393 Distance distance_;
394};
395}
396
397#ifdef _MSC_VER
398#pragma warning(pop)
399#endif
400
402
403#endif //OPENCV_FLANN_LSH_INDEX_H_
T begin(T... args)
T end(T... args)
T fill_n(T... args)
T front(T... args)
int index
Definition core_c.h:634
CvSize size
Definition core_c.h:112
const CvArr const CvArr CvArr * result
Definition core_c.h:1423
#define CV_OVERRIDE
Definition cvdef.h:792
#define CV_Assert(expr)
Checks a condition at runtime and throws exception if it fails.
Definition base.hpp:342
CvPoint2D32f float * radius
Definition imgproc_c.h:534
T max(T... args)
Definition flann.hpp:60
T pop_back(T... args)
T pop_heap(T... args)
T push_back(T... args)
T push_heap(T... args)
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
T size(T... args)