35
#ifndef OPENCV_FLANN_LSH_TABLE_H_
36
#define OPENCV_FLANN_LSH_TABLE_H_
45
#ifdef __GXX_EXPERIMENTAL_CXX0X__
46
# define USE_UNORDERED_MAP 1
48
# define USE_UNORDERED_MAP 0
51
#include <unordered_map>
58
#include "dynamic_bitset.h"
63
#pragma warning(disable: 4702)
77
typedef
uint32_t FeatureIndex;
80
typedef
unsigned
int
BucketKey;
84
typedef
std::vector<FeatureIndex> Bucket;
92
std::vector<unsigned int> bucket_sizes_;
94
size_t
bucket_size_mean_;
95
size_t
bucket_size_median_;
96
size_t
bucket_size_min_;
97
size_t
bucket_size_max_;
98
size_t
bucket_size_std_dev;
101
std::vector<std::vector<unsigned int> > size_histogram_;
109
inline
std::ostream& operator <<(std::ostream& out,
const
LshStats& stats)
112
out <<
"Lsh Table Stats:\n"
<< std::setw(w) << std::setiosflags(std::ios::right) <<
"N buckets : "
113
<< stats.n_buckets_ <<
"\n"
<< std::setw(w) << std::setiosflags(std::ios::right) <<
"mean size : "
114
<< std::setiosflags(std::ios::left) << stats.bucket_size_mean_ <<
"\n"
<< std::setw(w)
115
<< std::setiosflags(std::ios::right) <<
"median size : "
<< stats.bucket_size_median_ <<
"\n"
<< std::setw(w)
116
<< std::setiosflags(std::ios::right) <<
"min size : "
<< std::setiosflags(std::ios::left)
117
<< stats.bucket_size_min_ <<
"\n"
<< std::setw(w) << std::setiosflags(std::ios::right) <<
"max size : "
118
<< std::setiosflags(std::ios::left) << stats.bucket_size_max_;
121
out << std::endl << std::setw(w) << std::setiosflags(std::ios::right) <<
"histogram : "
122
<< std::setiosflags(std::ios::left);
123
for
(std::vector<std::vector<unsigned int> >::const_iterator iterator = stats.size_histogram_.begin(), end =
124
stats.size_histogram_.end(); iterator != end; ++iterator) out << (*iterator)[0] <<
"-"
<< (*iterator)[1] <<
": "
<< (*iterator)[2] <<
", ";
137
template<
typename
ElementType>
143
#if USE_UNORDERED_MAP
144
typedef
std::unordered_map<BucketKey, Bucket> BucketsSpace;
146
typedef
std::map<BucketKey, Bucket> BucketsSpace;
151
typedef
std::vector<Bucket> BucketsSpeed;
159
speed_level_ = kArray;
167
LshTable(
unsigned
int
feature_size,
unsigned
int
key_size)
169
feature_size_ = feature_size;
171
CV_Error(cv::Error::StsUnsupportedFormat,
"LSH is not implemented for that type"
);
178
void
add(
unsigned
int
value,
const
ElementType* feature)
181
BucketKey key = (lsh::BucketKey)getKey(feature);
183
switch
(speed_level_) {
186
buckets_speed_[key].push_back(value);
190
key_bitset_.set(key);
191
buckets_space_[key].push_back(value);
196
buckets_space_[key].push_back(value);
205
void
add(Matrix<ElementType> dataset)
207
#if USE_UNORDERED_MAP
208
buckets_space_.rehash((buckets_space_.size() + dataset.rows) * 1.2);
211
for
(
unsigned
int
i = 0; i < dataset.rows; ++i)
add(i, dataset[i]);
220
inline
const
Bucket* getBucketFromKey(BucketKey key)
const
223
switch
(speed_level_) {
226
return
&buckets_speed_[key];
230
if
(key_bitset_.test(key))
return
&buckets_space_.find(key)->second;
236
BucketsSpace::const_iterator bucket_it, bucket_end = buckets_space_.end();
237
bucket_it = buckets_space_.find(key);
239
if
(bucket_it == bucket_end)
return
0;
240
else
return
&bucket_it->second;
249
size_t
getKey(
const
ElementType*
)
const
251
CV_Error(cv::Error::StsUnsupportedFormat,
"LSH is not implemented for that type"
);
258
LshStats getStats()
const;
268
kArray, kBitsetHash, kHash
273
void
initialize(
size_t
key_size)
275
const
size_t
key_size_lower_bound = 1;
277
const
size_t
key_size_upper_bound = (
std::min)(
sizeof(BucketKey) * CHAR_BIT + 1,
sizeof(size_t) * CHAR_BIT);
278
if
(key_size < key_size_lower_bound || key_size >= key_size_upper_bound)
280
CV_Error(cv::Error::StsBadArg, cv::format(
"Invalid key_size (=%d). Valid values for your system are %d <= key_size < %d.", (
int)key_size, (
int)key_size_lower_bound, (
int)key_size_upper_bound));
283
speed_level_ = kHash;
284
key_size_ = (unsigned)key_size;
292
if
(speed_level_ == kArray)
return;
295
if
(buckets_space_.size() > ((
size_t(1) << key_size_) / 2)) {
296
speed_level_ = kArray;
298
buckets_speed_.resize(
size_t(1) << key_size_);
299
for
(BucketsSpace::const_iterator key_bucket = buckets_space_.begin(); key_bucket != buckets_space_.end(); ++key_bucket) buckets_speed_[key_bucket->first] = key_bucket->second;
302
buckets_space_.clear();
308
if
(((
std::max(buckets_space_.size(), buckets_speed_.size()) * CHAR_BIT * 3 *
sizeof(BucketKey)) / 10
309
>= (
size_t(1) << key_size_)) || (key_size_ <= 32)) {
310
speed_level_ = kBitsetHash;
311
key_bitset_.resize(
size_t(1) << key_size_);
314
for
(BucketsSpace::const_iterator key_bucket = buckets_space_.begin(); key_bucket != buckets_space_.end(); ++key_bucket) key_bitset_.set(key_bucket->first);
317
speed_level_ = kHash;
324
BucketsSpeed buckets_speed_;
328
BucketsSpace buckets_space_;
331
SpeedLevel speed_level_;
336
DynamicBitset key_bitset_;
340
unsigned
int
key_size_;
342
unsigned
int
feature_size_;
348
std::vector<size_t> mask_;
355
inline
LshTable<unsigned char>::LshTable(
unsigned
int
feature_size,
unsigned
int
subsignature_size)
357
feature_size_ = feature_size;
358
initialize(subsignature_size);
360
mask_ = std::vector<size_t>((feature_size *
sizeof(
char) +
sizeof(
size_t) - 1) /
sizeof(
size_t), 0);
363
std::vector<int> indices(feature_size * CHAR_BIT);
364
for
(
size_t
i = 0; i < feature_size * CHAR_BIT; ++i) indices[i] = (
int)i;
365
#ifndef OPENCV_FLANN_USE_STD_RAND
368
std::random_shuffle(indices.begin(), indices.end());
372
for
(
unsigned
int
i = 0; i < key_size_; ++i) {
373
size_t
index = indices[i];
376
size_t
divisor = CHAR_BIT *
sizeof(size_t);
377
size_t
idx = index / divisor;
378
mask_[idx] |= size_t(1) << (index % divisor);
385
BOOST_FOREACH(
size_t
mask_block, mask_){
386
out << std::setw(
sizeof(
size_t) * CHAR_BIT / 4) << std::setfill(
'0') << std::hex << mask_block
388
bcount += __builtin_popcountll(mask_block);
390
out <<
"bit count : "
<< std::dec << bcount << std::endl;
391
out <<
"mask size : "
<< mask_.size() << std::endl;
401
inline
size_t
LshTable<unsigned char>::getKey(
const
unsigned
char* feature)
const
406
const
size_t* feature_block_ptr =
reinterpret_cast<
const
size_t*
>
((
const
void*)feature);
411
size_t
subsignature = 0;
412
size_t
bit_index = 1;
414
for
(
unsigned
i = 0; i < feature_size_; i +=
sizeof(size_t)) {
416
size_t
feature_block;
417
if
(i <= feature_size_ -
sizeof(
size_t))
419
feature_block = *feature_block_ptr;
424
memcpy(&tmp, feature_block_ptr, feature_size_ - i);
427
size_t
mask_block = mask_[i /
sizeof(size_t)];
430
size_t
lowest_bit = mask_block & (-(ptrdiff_t)mask_block);
432
subsignature += (feature_block & lowest_bit) ? bit_index : 0;
434
mask_block ^= lowest_bit;
445
inline
LshStats LshTable<unsigned char>::getStats()
const
448
stats.bucket_size_mean_ = 0;
449
if
((buckets_speed_.empty()) && (buckets_space_.empty())) {
450
stats.n_buckets_ = 0;
451
stats.bucket_size_median_ = 0;
452
stats.bucket_size_min_ = 0;
453
stats.bucket_size_max_ = 0;
457
if
(!buckets_speed_.empty()) {
458
for
(BucketsSpeed::const_iterator pbucket = buckets_speed_.begin(); pbucket != buckets_speed_.end(); ++pbucket) {
459
stats.bucket_sizes_.push_back((lsh::FeatureIndex)pbucket->size());
460
stats.bucket_size_mean_ += pbucket->size();
462
stats.bucket_size_mean_ /= buckets_speed_.size();
463
stats.n_buckets_ = buckets_speed_.size();
466
for
(BucketsSpace::const_iterator x = buckets_space_.begin(); x != buckets_space_.end(); ++x) {
467
stats.bucket_sizes_.push_back((lsh::FeatureIndex)x->second.size());
468
stats.bucket_size_mean_ += x->second.size();
470
stats.bucket_size_mean_ /= buckets_space_.size();
471
stats.n_buckets_ = buckets_space_.size();
474
std::sort(stats.bucket_sizes_.begin(), stats.bucket_sizes_.end());
479
stats.bucket_size_median_ = stats.bucket_sizes_[stats.bucket_sizes_.size() / 2];
480
stats.bucket_size_min_ = stats.bucket_sizes_.front();
481
stats.bucket_size_max_ = stats.bucket_sizes_.back();
489
unsigned
int
bin_start = 0;
490
unsigned
int
bin_end = 20;
491
bool
is_new_bin =
true;
492
for
(std::vector<unsigned int>::iterator iterator = stats.bucket_sizes_.begin(), end = stats.bucket_sizes_.end(); iterator
494
if
(*iterator < bin_end) {
496
stats.size_histogram_.push_back(std::vector<unsigned int>(3, 0));
497
stats.size_histogram_.back()[0] = bin_start;
498
stats.size_histogram_.back()[1] = bin_end - 1;
501
++stats.size_histogram_.back()[2];
CV_EXPORTS_W void max(InputArray src1, InputArray src2, OutputArray dst)
Calculates per-element maximum of two arrays or an array and a scalar.
CV_EXPORTS_W void sort(InputArray src, OutputArray dst, int flags)
Sorts each row or each column of a matrix.
CV_EXPORTS_W void min(InputArray src1, InputArray src2, OutputArray dst)
Calculates per-element minimum of two arrays or an array and a scalar.
CV_EXPORTS_W void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1)
Calculates the per-element sum of two arrays or an array and a scalar.
CV_EXPORTS_W void randShuffle(InputOutputArray dst, double iterFactor=1., RNG *rng=0)
Shuffles the array elements randomly.
#define CV_Error(code, msg)
Call the error handler.
Definition:
base.hpp:320