Updated FLANN to version 1.5
This commit is contained in:
76
modules/flann/include/opencv2/flann/all_indices.h
Normal file
76
modules/flann/include/opencv2/flann/all_indices.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
#ifndef ALL_INDICES_H_
|
||||
#define ALL_INDICES_H_
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
|
||||
#include "opencv2/flann/nn_index.h"
|
||||
#include "opencv2/flann/kdtree_index.h"
|
||||
#include "opencv2/flann/kmeans_index.h"
|
||||
#include "opencv2/flann/composite_index.h"
|
||||
#include "opencv2/flann/linear_index.h"
|
||||
#include "opencv2/flann/autotuned_index.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
NNIndex<T>* create_index_by_type(const Matrix<T>& dataset, const IndexParams& params)
|
||||
{
|
||||
flann_algorithm_t index_type = params.getIndexType();
|
||||
|
||||
NNIndex<T>* nnIndex;
|
||||
switch (index_type) {
|
||||
case LINEAR:
|
||||
nnIndex = new LinearIndex<T>(dataset, (const LinearIndexParams&)params);
|
||||
break;
|
||||
case KDTREE:
|
||||
nnIndex = new KDTreeIndex<T>(dataset, (const KDTreeIndexParams&)params);
|
||||
break;
|
||||
case KMEANS:
|
||||
nnIndex = new KMeansIndex<T>(dataset, (const KMeansIndexParams&)params);
|
||||
break;
|
||||
case COMPOSITE:
|
||||
nnIndex = new CompositeIndex<T>(dataset, (const CompositeIndexParams&) params);
|
||||
break;
|
||||
case AUTOTUNED:
|
||||
nnIndex = new AutotunedIndex<T>(dataset, (const AutotunedIndexParams&) params);
|
||||
break;
|
||||
default:
|
||||
throw FLANNException("Unknown index type");
|
||||
}
|
||||
|
||||
return nnIndex;
|
||||
}
|
||||
|
||||
} //namespace cvflann
|
||||
|
||||
#endif /* ALL_INDICES_H_ */
|
187
modules/flann/include/opencv2/flann/allocator.h
Normal file
187
modules/flann/include/opencv2/flann/allocator.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef ALLOCATOR_H
|
||||
#define ALLOCATOR_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/**
|
||||
* Allocates (using C's malloc) a generic type T.
|
||||
*
|
||||
* Params:
|
||||
* count = number of instances to allocate.
|
||||
* Returns: pointer (of type T*) to memory buffer
|
||||
*/
|
||||
template <typename T>
|
||||
T* allocate(size_t count = 1)
|
||||
{
|
||||
T* mem = (T*) ::malloc(sizeof(T)*count);
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pooled storage allocator
|
||||
*
|
||||
* The following routines allow for the efficient allocation of storage in
|
||||
* small chunks from a specified pool. Rather than allowing each structure
|
||||
* to be freed individually, an entire pool of storage is freed at once.
|
||||
* This method has two advantages over just using malloc() and free(). First,
|
||||
* it is far more efficient for allocating small objects, as there is
|
||||
* no overhead for remembering all the information needed to free each
|
||||
* object or consolidating fragmented memory. Second, the decision about
|
||||
* how long to keep an object is made at the time of allocation, and there
|
||||
* is no need to track down all the objects to free them.
|
||||
*
|
||||
*/
|
||||
|
||||
const size_t WORDSIZE=16;
|
||||
const size_t BLOCKSIZE=8192;
|
||||
|
||||
class PooledAllocator
|
||||
{
|
||||
/* We maintain memory alignment to word boundaries by requiring that all
|
||||
allocations be in multiples of the machine wordsize. */
|
||||
/* Size of machine word in bytes. Must be power of 2. */
|
||||
/* Minimum number of bytes requested at a time from the system. Must be multiple of WORDSIZE. */
|
||||
|
||||
|
||||
int remaining; /* Number of bytes left in current block of storage. */
|
||||
void* base; /* Pointer to base of current block of storage. */
|
||||
void* loc; /* Current location in block to next allocate memory. */
|
||||
int blocksize;
|
||||
|
||||
|
||||
public:
|
||||
int usedMemory;
|
||||
int wastedMemory;
|
||||
|
||||
/**
|
||||
Default constructor. Initializes a new pool.
|
||||
*/
|
||||
PooledAllocator(int blocksize = BLOCKSIZE)
|
||||
{
|
||||
this->blocksize = blocksize;
|
||||
remaining = 0;
|
||||
base = NULL;
|
||||
|
||||
usedMemory = 0;
|
||||
wastedMemory = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor. Frees all the memory allocated in this pool.
|
||||
*/
|
||||
~PooledAllocator()
|
||||
{
|
||||
void *prev;
|
||||
|
||||
while (base != NULL) {
|
||||
prev = *((void **) base); /* Get pointer to prev block. */
|
||||
::free(base);
|
||||
base = prev;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to a piece of new memory of the given size in bytes
|
||||
* allocated from the pool.
|
||||
*/
|
||||
void* malloc(int size)
|
||||
{
|
||||
int blocksize;
|
||||
|
||||
/* Round size up to a multiple of wordsize. The following expression
|
||||
only works for WORDSIZE that is a power of 2, by masking last bits of
|
||||
incremented size to zero.
|
||||
*/
|
||||
size = (size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
|
||||
|
||||
/* Check whether a new block must be allocated. Note that the first word
|
||||
of a block is reserved for a pointer to the previous block.
|
||||
*/
|
||||
if (size > remaining) {
|
||||
|
||||
wastedMemory += remaining;
|
||||
|
||||
/* Allocate new storage. */
|
||||
blocksize = (size + sizeof(void*) + (WORDSIZE-1) > BLOCKSIZE) ?
|
||||
size + sizeof(void*) + (WORDSIZE-1) : BLOCKSIZE;
|
||||
|
||||
// use the standard C malloc to allocate memory
|
||||
void* m = ::malloc(blocksize);
|
||||
if (!m) {
|
||||
fprintf(stderr,"Failed to allocate memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Fill first word of new block with pointer to previous block. */
|
||||
((void **) m)[0] = base;
|
||||
base = m;
|
||||
|
||||
int shift = 0;
|
||||
//int shift = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1);
|
||||
|
||||
remaining = blocksize - sizeof(void*) - shift;
|
||||
loc = ((char*)m + sizeof(void*) + shift);
|
||||
}
|
||||
void* rloc = loc;
|
||||
loc = (char*)loc + size;
|
||||
remaining -= size;
|
||||
|
||||
usedMemory += size;
|
||||
|
||||
return rloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates (using this pool) a generic type T.
|
||||
*
|
||||
* Params:
|
||||
* count = number of instances to allocate.
|
||||
* Returns: pointer (of type T*) to memory buffer
|
||||
*/
|
||||
template <typename T>
|
||||
T* allocate(size_t count = 1)
|
||||
{
|
||||
T* mem = (T*) this->malloc(sizeof(T)*count);
|
||||
return mem;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //ALLOCATOR_H
|
614
modules/flann/include/opencv2/flann/autotuned_index.h
Normal file
614
modules/flann/include/opencv2/flann/autotuned_index.h
Normal file
@@ -0,0 +1,614 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef AUTOTUNEDINDEX_H_
|
||||
#define AUTOTUNEDINDEX_H_
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
#include "opencv2/flann/nn_index.h"
|
||||
#include "opencv2/flann/ground_truth.h"
|
||||
#include "opencv2/flann/index_testing.h"
|
||||
#include "opencv2/flann/sampling.h"
|
||||
#include "opencv2/flann/all_indices.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
struct AutotunedIndexParams : public IndexParams {
|
||||
AutotunedIndexParams( float target_precision_ = 0.8, float build_weight_ = 0.01,
|
||||
float memory_weight_ = 0, float sample_fraction_ = 0.1) :
|
||||
IndexParams(AUTOTUNED),
|
||||
target_precision(target_precision_),
|
||||
build_weight(build_weight_),
|
||||
memory_weight(memory_weight_),
|
||||
sample_fraction(sample_fraction_) {};
|
||||
|
||||
float target_precision; // precision desired (used for autotuning, -1 otherwise)
|
||||
float build_weight; // build tree time weighting factor
|
||||
float memory_weight; // index memory weighting factor
|
||||
float sample_fraction; // what fraction of the dataset to use for autotuning
|
||||
|
||||
flann_algorithm_t getIndexType() const { return algorithm; }
|
||||
|
||||
void print() const
|
||||
{
|
||||
logger.info("Index type: %d\n",(int)algorithm);
|
||||
logger.info("Target precision: %g\n", target_precision);
|
||||
logger.info("Build weight: %g\n", build_weight);
|
||||
logger.info("Memory weight: %g\n", memory_weight);
|
||||
logger.info("Sample fraction: %g\n", sample_fraction);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
|
||||
class AutotunedIndex : public NNIndex<ELEM_TYPE>
|
||||
{
|
||||
NNIndex<ELEM_TYPE>* bestIndex;
|
||||
|
||||
IndexParams* bestParams;
|
||||
SearchParams bestSearchParams;
|
||||
|
||||
Matrix<ELEM_TYPE> sampledDataset;
|
||||
Matrix<ELEM_TYPE> testDataset;
|
||||
Matrix<int> gt_matches;
|
||||
|
||||
float speedup;
|
||||
|
||||
/**
|
||||
* The dataset used by this index
|
||||
*/
|
||||
const Matrix<ELEM_TYPE> dataset;
|
||||
|
||||
/**
|
||||
* Index parameters
|
||||
*/
|
||||
const AutotunedIndexParams& index_params;
|
||||
|
||||
public:
|
||||
|
||||
AutotunedIndex(const Matrix<ELEM_TYPE>& inputData, const AutotunedIndexParams& params = AutotunedIndexParams() ) :
|
||||
dataset(inputData), index_params(params)
|
||||
{
|
||||
bestIndex = NULL;
|
||||
bestParams = NULL;
|
||||
}
|
||||
|
||||
virtual ~AutotunedIndex()
|
||||
{
|
||||
if (bestIndex!=NULL) {
|
||||
delete bestIndex;
|
||||
}
|
||||
if (bestParams!=NULL) {
|
||||
delete bestParams;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Method responsible with building the index.
|
||||
*/
|
||||
virtual void buildIndex()
|
||||
{
|
||||
bestParams = estimateBuildParams();
|
||||
logger.info("----------------------------------------------------\n");
|
||||
logger.info("Autotuned parameters:\n");
|
||||
bestParams->print();
|
||||
logger.info("----------------------------------------------------\n");
|
||||
flann_algorithm_t index_type = bestParams->getIndexType();
|
||||
switch (index_type) {
|
||||
case LINEAR:
|
||||
bestIndex = new LinearIndex<ELEM_TYPE>(dataset, (const LinearIndexParams&)*bestParams);
|
||||
break;
|
||||
case KDTREE:
|
||||
bestIndex = new KDTreeIndex<ELEM_TYPE>(dataset, (const KDTreeIndexParams&)*bestParams);
|
||||
break;
|
||||
case KMEANS:
|
||||
bestIndex = new KMeansIndex<ELEM_TYPE>(dataset, (const KMeansIndexParams&)*bestParams);
|
||||
break;
|
||||
default:
|
||||
throw FLANNException("Unknown algorithm choosen by the autotuning, most likely a bug.");
|
||||
}
|
||||
bestIndex->buildIndex();
|
||||
speedup = estimateSearchParams(bestSearchParams);
|
||||
}
|
||||
|
||||
/**
|
||||
Saves the index to a stream
|
||||
*/
|
||||
virtual void saveIndex(FILE* stream)
|
||||
{
|
||||
save_value(stream, (int)bestIndex->getType());
|
||||
bestIndex->saveIndex(stream);
|
||||
save_value(stream, bestSearchParams);
|
||||
}
|
||||
|
||||
/**
|
||||
Loads the index from a stream
|
||||
*/
|
||||
virtual void loadIndex(FILE* stream)
|
||||
{
|
||||
int index_type;
|
||||
load_value(stream,index_type);
|
||||
IndexParams* params = ParamsFactory::instance().create((flann_algorithm_t)index_type);
|
||||
bestIndex = create_index_by_type(dataset, *params);
|
||||
bestIndex->loadIndex(stream);
|
||||
load_value(stream, bestSearchParams);
|
||||
}
|
||||
|
||||
/**
|
||||
Method that searches for nearest-neighbors
|
||||
*/
|
||||
virtual void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams)
|
||||
{
|
||||
if (searchParams.checks==-2) {
|
||||
bestIndex->findNeighbors(result, vec, bestSearchParams);
|
||||
}
|
||||
else {
|
||||
bestIndex->findNeighbors(result, vec, searchParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const IndexParams* getParameters() const
|
||||
{
|
||||
return bestIndex->getParameters();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Number of features in this index.
|
||||
*/
|
||||
virtual size_t size() const
|
||||
{
|
||||
return bestIndex->size();
|
||||
}
|
||||
|
||||
/**
|
||||
The length of each vector in this index.
|
||||
*/
|
||||
virtual size_t veclen() const
|
||||
{
|
||||
return bestIndex->veclen();
|
||||
}
|
||||
|
||||
/**
|
||||
The amount of memory (in bytes) this index uses.
|
||||
*/
|
||||
virtual int usedMemory() const
|
||||
{
|
||||
return bestIndex->usedMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Algorithm name
|
||||
*/
|
||||
virtual flann_algorithm_t getType() const
|
||||
{
|
||||
return AUTOTUNED;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct CostData {
|
||||
float searchTimeCost;
|
||||
float buildTimeCost;
|
||||
float timeCost;
|
||||
float memoryCost;
|
||||
float totalCost;
|
||||
};
|
||||
|
||||
typedef pair<CostData, KDTreeIndexParams> KDTreeCostData;
|
||||
typedef pair<CostData, KMeansIndexParams> KMeansCostData;
|
||||
|
||||
|
||||
void evaluate_kmeans(CostData& cost, const KMeansIndexParams& kmeans_params)
|
||||
{
|
||||
StartStopTimer t;
|
||||
int checks;
|
||||
const int nn = 1;
|
||||
|
||||
logger.info("KMeansTree using params: max_iterations=%d, branching=%d\n", kmeans_params.iterations, kmeans_params.branching);
|
||||
KMeansIndex<ELEM_TYPE> kmeans(sampledDataset, kmeans_params);
|
||||
// measure index build time
|
||||
t.start();
|
||||
kmeans.buildIndex();
|
||||
t.stop();
|
||||
float buildTime = t.value;
|
||||
|
||||
// measure search time
|
||||
float searchTime = test_index_precision(kmeans, sampledDataset, testDataset, gt_matches, index_params.target_precision, checks, nn);;
|
||||
|
||||
float datasetMemory = sampledDataset.rows*sampledDataset.cols*sizeof(float);
|
||||
cost.memoryCost = (kmeans.usedMemory()+datasetMemory)/datasetMemory;
|
||||
cost.searchTimeCost = searchTime;
|
||||
cost.buildTimeCost = buildTime;
|
||||
cost.timeCost = (buildTime*index_params.build_weight+searchTime);
|
||||
logger.info("KMeansTree buildTime=%g, searchTime=%g, timeCost=%g, buildTimeFactor=%g\n",buildTime, searchTime, cost.timeCost, index_params.build_weight);
|
||||
}
|
||||
|
||||
|
||||
void evaluate_kdtree(CostData& cost, const KDTreeIndexParams& kdtree_params)
|
||||
{
|
||||
StartStopTimer t;
|
||||
int checks;
|
||||
const int nn = 1;
|
||||
|
||||
logger.info("KDTree using params: trees=%d\n",kdtree_params.trees);
|
||||
KDTreeIndex<ELEM_TYPE> kdtree(sampledDataset, kdtree_params);
|
||||
|
||||
t.start();
|
||||
kdtree.buildIndex();
|
||||
t.stop();
|
||||
float buildTime = t.value;
|
||||
|
||||
//measure search time
|
||||
float searchTime = test_index_precision(kdtree, sampledDataset, testDataset, gt_matches, index_params.target_precision, checks, nn);
|
||||
|
||||
float datasetMemory = sampledDataset.rows*sampledDataset.cols*sizeof(float);
|
||||
cost.memoryCost = (kdtree.usedMemory()+datasetMemory)/datasetMemory;
|
||||
cost.searchTimeCost = searchTime;
|
||||
cost.buildTimeCost = buildTime;
|
||||
cost.timeCost = (buildTime*index_params.build_weight+searchTime);
|
||||
logger.info("KDTree buildTime=%g, searchTime=%g, timeCost=%g\n",buildTime, searchTime, cost.timeCost);
|
||||
}
|
||||
|
||||
|
||||
// struct KMeansSimpleDownhillFunctor {
|
||||
//
|
||||
// Autotune& autotuner;
|
||||
// KMeansSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {};
|
||||
//
|
||||
// float operator()(int* params) {
|
||||
//
|
||||
// float maxFloat = numeric_limits<float>::max();
|
||||
//
|
||||
// if (params[0]<2) return maxFloat;
|
||||
// if (params[1]<0) return maxFloat;
|
||||
//
|
||||
// CostData c;
|
||||
// c.params["algorithm"] = KMEANS;
|
||||
// c.params["centers-init"] = CENTERS_RANDOM;
|
||||
// c.params["branching"] = params[0];
|
||||
// c.params["max-iterations"] = params[1];
|
||||
//
|
||||
// autotuner.evaluate_kmeans(c);
|
||||
//
|
||||
// return c.timeCost;
|
||||
//
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// struct KDTreeSimpleDownhillFunctor {
|
||||
//
|
||||
// Autotune& autotuner;
|
||||
// KDTreeSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {};
|
||||
//
|
||||
// float operator()(int* params) {
|
||||
// float maxFloat = numeric_limits<float>::max();
|
||||
//
|
||||
// if (params[0]<1) return maxFloat;
|
||||
//
|
||||
// CostData c;
|
||||
// c.params["algorithm"] = KDTREE;
|
||||
// c.params["trees"] = params[0];
|
||||
//
|
||||
// autotuner.evaluate_kdtree(c);
|
||||
//
|
||||
// return c.timeCost;
|
||||
//
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
|
||||
KMeansCostData optimizeKMeans()
|
||||
{
|
||||
logger.info("KMEANS, Step 1: Exploring parameter space\n");
|
||||
|
||||
// explore kmeans parameters space using combinations of the parameters below
|
||||
int maxIterations[] = { 1, 5, 10, 15 };
|
||||
int branchingFactors[] = { 16, 32, 64, 128, 256 };
|
||||
|
||||
int kmeansParamSpaceSize = ARRAY_LEN(maxIterations)*ARRAY_LEN(branchingFactors);
|
||||
|
||||
vector<KMeansCostData> kmeansCosts(kmeansParamSpaceSize);
|
||||
|
||||
// CostData* kmeansCosts = new CostData[kmeansParamSpaceSize];
|
||||
|
||||
// evaluate kmeans for all parameter combinations
|
||||
int cnt = 0;
|
||||
for (size_t i=0; i<ARRAY_LEN(maxIterations); ++i) {
|
||||
for (size_t j=0; j<ARRAY_LEN(branchingFactors); ++j) {
|
||||
|
||||
kmeansCosts[cnt].second.centers_init = CENTERS_RANDOM;
|
||||
kmeansCosts[cnt].second.iterations = maxIterations[i];
|
||||
kmeansCosts[cnt].second.branching = branchingFactors[j];
|
||||
|
||||
evaluate_kmeans(kmeansCosts[cnt].first, kmeansCosts[cnt].second);
|
||||
|
||||
int k = cnt;
|
||||
// order by time cost
|
||||
while (k>0 && kmeansCosts[k].first.timeCost < kmeansCosts[k-1].first.timeCost) {
|
||||
swap(kmeansCosts[k],kmeansCosts[k-1]);
|
||||
--k;
|
||||
}
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
// logger.info("KMEANS, Step 2: simplex-downhill optimization\n");
|
||||
//
|
||||
// const int n = 2;
|
||||
// // choose initial simplex points as the best parameters so far
|
||||
// int kmeansNMPoints[n*(n+1)];
|
||||
// float kmeansVals[n+1];
|
||||
// for (int i=0;i<n+1;++i) {
|
||||
// kmeansNMPoints[i*n] = (int)kmeansCosts[i].params["branching"];
|
||||
// kmeansNMPoints[i*n+1] = (int)kmeansCosts[i].params["max-iterations"];
|
||||
// kmeansVals[i] = kmeansCosts[i].timeCost;
|
||||
// }
|
||||
// KMeansSimpleDownhillFunctor kmeans_cost_func(*this);
|
||||
// // run optimization
|
||||
// optimizeSimplexDownhill(kmeansNMPoints,n,kmeans_cost_func,kmeansVals);
|
||||
// // store results
|
||||
// for (int i=0;i<n+1;++i) {
|
||||
// kmeansCosts[i].params["branching"] = kmeansNMPoints[i*2];
|
||||
// kmeansCosts[i].params["max-iterations"] = kmeansNMPoints[i*2+1];
|
||||
// kmeansCosts[i].timeCost = kmeansVals[i];
|
||||
// }
|
||||
|
||||
float optTimeCost = kmeansCosts[0].first.timeCost;
|
||||
// recompute total costs factoring in the memory costs
|
||||
for (int i=0;i<kmeansParamSpaceSize;++i) {
|
||||
kmeansCosts[i].first.totalCost = (kmeansCosts[i].first.timeCost/optTimeCost + index_params.memory_weight * kmeansCosts[i].first.memoryCost);
|
||||
|
||||
int k = i;
|
||||
while (k>0 && kmeansCosts[k].first.totalCost < kmeansCosts[k-1].first.totalCost) {
|
||||
swap(kmeansCosts[k],kmeansCosts[k-1]);
|
||||
k--;
|
||||
}
|
||||
}
|
||||
// display the costs obtained
|
||||
for (int i=0;i<kmeansParamSpaceSize;++i) {
|
||||
logger.info("KMeans, branching=%d, iterations=%d, time_cost=%g[%g] (build=%g, search=%g), memory_cost=%g, cost=%g\n",
|
||||
kmeansCosts[i].second.branching, kmeansCosts[i].second.iterations,
|
||||
kmeansCosts[i].first.timeCost,kmeansCosts[i].first.timeCost/optTimeCost,
|
||||
kmeansCosts[i].first.buildTimeCost, kmeansCosts[i].first.searchTimeCost,
|
||||
kmeansCosts[i].first.memoryCost,kmeansCosts[i].first.totalCost);
|
||||
}
|
||||
|
||||
return kmeansCosts[0];
|
||||
}
|
||||
|
||||
|
||||
KDTreeCostData optimizeKDTree()
|
||||
{
|
||||
|
||||
logger.info("KD-TREE, Step 1: Exploring parameter space\n");
|
||||
|
||||
// explore kd-tree parameters space using the parameters below
|
||||
int testTrees[] = { 1, 4, 8, 16, 32 };
|
||||
|
||||
size_t kdtreeParamSpaceSize = ARRAY_LEN(testTrees);
|
||||
vector<KDTreeCostData> kdtreeCosts(kdtreeParamSpaceSize);
|
||||
|
||||
// evaluate kdtree for all parameter combinations
|
||||
int cnt = 0;
|
||||
for (size_t i=0; i<ARRAY_LEN(testTrees); ++i) {
|
||||
kdtreeCosts[cnt].second.trees = testTrees[i];
|
||||
|
||||
evaluate_kdtree(kdtreeCosts[cnt].first, kdtreeCosts[cnt].second);
|
||||
|
||||
int k = cnt;
|
||||
// order by time cost
|
||||
while (k>0 && kdtreeCosts[k].first.timeCost < kdtreeCosts[k-1].first.timeCost) {
|
||||
swap(kdtreeCosts[k],kdtreeCosts[k-1]);
|
||||
--k;
|
||||
}
|
||||
++cnt;
|
||||
}
|
||||
|
||||
// logger.info("KD-TREE, Step 2: simplex-downhill optimization\n");
|
||||
//
|
||||
// const int n = 1;
|
||||
// // choose initial simplex points as the best parameters so far
|
||||
// int kdtreeNMPoints[n*(n+1)];
|
||||
// float kdtreeVals[n+1];
|
||||
// for (int i=0;i<n+1;++i) {
|
||||
// kdtreeNMPoints[i] = (int)kdtreeCosts[i].params["trees"];
|
||||
// kdtreeVals[i] = kdtreeCosts[i].timeCost;
|
||||
// }
|
||||
// KDTreeSimpleDownhillFunctor kdtree_cost_func(*this);
|
||||
// // run optimization
|
||||
// optimizeSimplexDownhill(kdtreeNMPoints,n,kdtree_cost_func,kdtreeVals);
|
||||
// // store results
|
||||
// for (int i=0;i<n+1;++i) {
|
||||
// kdtreeCosts[i].params["trees"] = kdtreeNMPoints[i];
|
||||
// kdtreeCosts[i].timeCost = kdtreeVals[i];
|
||||
// }
|
||||
|
||||
float optTimeCost = kdtreeCosts[0].first.timeCost;
|
||||
// recompute costs for kd-tree factoring in memory cost
|
||||
for (size_t i=0;i<kdtreeParamSpaceSize;++i) {
|
||||
kdtreeCosts[i].first.totalCost = (kdtreeCosts[i].first.timeCost/optTimeCost + index_params.memory_weight * kdtreeCosts[i].first.memoryCost);
|
||||
|
||||
int k = i;
|
||||
while (k>0 && kdtreeCosts[k].first.totalCost < kdtreeCosts[k-1].first.totalCost) {
|
||||
swap(kdtreeCosts[k],kdtreeCosts[k-1]);
|
||||
k--;
|
||||
}
|
||||
}
|
||||
// display costs obtained
|
||||
for (size_t i=0;i<kdtreeParamSpaceSize;++i) {
|
||||
logger.info("kd-tree, trees=%d, time_cost=%g[%g] (build=%g, search=%g), memory_cost=%g, cost=%g\n",
|
||||
kdtreeCosts[i].second.trees,kdtreeCosts[i].first.timeCost,kdtreeCosts[i].first.timeCost/optTimeCost,
|
||||
kdtreeCosts[i].first.buildTimeCost, kdtreeCosts[i].first.searchTimeCost,
|
||||
kdtreeCosts[i].first.memoryCost,kdtreeCosts[i].first.totalCost);
|
||||
}
|
||||
|
||||
return kdtreeCosts[0];
|
||||
}
|
||||
|
||||
/**
|
||||
Chooses the best nearest-neighbor algorithm and estimates the optimal
|
||||
parameters to use when building the index (for a given precision).
|
||||
Returns a dictionary with the optimal parameters.
|
||||
*/
|
||||
IndexParams* estimateBuildParams()
|
||||
{
|
||||
int sampleSize = int(index_params.sample_fraction*dataset.rows);
|
||||
int testSampleSize = min(sampleSize/10, 1000);
|
||||
|
||||
logger.info("Entering autotuning, dataset size: %d, sampleSize: %d, testSampleSize: %d\n",dataset.rows, sampleSize, testSampleSize);
|
||||
|
||||
// For a very small dataset, it makes no sense to build any fancy index, just
|
||||
// use linear search
|
||||
if (testSampleSize<10) {
|
||||
logger.info("Choosing linear, dataset too small\n");
|
||||
return new LinearIndexParams();
|
||||
}
|
||||
|
||||
// We use a fraction of the original dataset to speedup the autotune algorithm
|
||||
sampledDataset = random_sample(dataset,sampleSize);
|
||||
// We use a cross-validation approach, first we sample a testset from the dataset
|
||||
testDataset = random_sample(sampledDataset,testSampleSize,true);
|
||||
|
||||
// We compute the ground truth using linear search
|
||||
logger.info("Computing ground truth... \n");
|
||||
gt_matches = Matrix<int>(new int[testDataset.rows],testDataset.rows, 1);
|
||||
StartStopTimer t;
|
||||
t.start();
|
||||
compute_ground_truth(sampledDataset, testDataset, gt_matches, 0);
|
||||
t.stop();
|
||||
float bestCost = t.value;
|
||||
IndexParams* bestParams = new LinearIndexParams();
|
||||
|
||||
// Start parameter autotune process
|
||||
logger.info("Autotuning parameters...\n");
|
||||
|
||||
|
||||
KMeansCostData kmeansCost = optimizeKMeans();
|
||||
if (kmeansCost.first.totalCost<bestCost) {
|
||||
bestParams = new KMeansIndexParams(kmeansCost.second);
|
||||
bestCost = kmeansCost.first.totalCost;
|
||||
}
|
||||
|
||||
KDTreeCostData kdtreeCost = optimizeKDTree();
|
||||
|
||||
if (kdtreeCost.first.totalCost<bestCost) {
|
||||
bestParams = new KDTreeIndexParams(kdtreeCost.second);
|
||||
bestCost = kdtreeCost.first.totalCost;
|
||||
}
|
||||
|
||||
gt_matches.free();
|
||||
sampledDataset.free();
|
||||
testDataset.free();
|
||||
|
||||
return bestParams;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Estimates the search time parameters needed to get the desired precision.
|
||||
Precondition: the index is built
|
||||
Postcondition: the searchParams will have the optimum params set, also the speedup obtained over linear search.
|
||||
*/
|
||||
float estimateSearchParams(SearchParams& searchParams)
|
||||
{
|
||||
const int nn = 1;
|
||||
const size_t SAMPLE_COUNT = 1000;
|
||||
|
||||
assert(bestIndex!=NULL); // must have a valid index
|
||||
|
||||
float speedup = 0;
|
||||
|
||||
int samples = min(dataset.rows/10, SAMPLE_COUNT);
|
||||
if (samples>0) {
|
||||
Matrix<ELEM_TYPE> testDataset = random_sample(dataset,samples);
|
||||
|
||||
logger.info("Computing ground truth\n");
|
||||
|
||||
// we need to compute the ground truth first
|
||||
Matrix<int> gt_matches(new int[testDataset.rows],testDataset.rows,1);
|
||||
StartStopTimer t;
|
||||
t.start();
|
||||
compute_ground_truth(dataset, testDataset, gt_matches,1);
|
||||
t.stop();
|
||||
float linear = t.value;
|
||||
|
||||
int checks;
|
||||
logger.info("Estimating number of checks\n");
|
||||
|
||||
float searchTime;
|
||||
float cb_index;
|
||||
if (bestIndex->getType() == KMEANS) {
|
||||
logger.info("KMeans algorithm, estimating cluster border factor\n");
|
||||
KMeansIndex<ELEM_TYPE>* kmeans = (KMeansIndex<ELEM_TYPE>*)bestIndex;
|
||||
float bestSearchTime = -1;
|
||||
float best_cb_index = -1;
|
||||
int best_checks = -1;
|
||||
for (cb_index = 0;cb_index<1.1; cb_index+=0.2) {
|
||||
kmeans->set_cb_index(cb_index);
|
||||
searchTime = test_index_precision(*kmeans, dataset, testDataset, gt_matches, index_params.target_precision, checks, nn, 1);
|
||||
if (searchTime<bestSearchTime || bestSearchTime == -1) {
|
||||
bestSearchTime = searchTime;
|
||||
best_cb_index = cb_index;
|
||||
best_checks = checks;
|
||||
}
|
||||
}
|
||||
searchTime = bestSearchTime;
|
||||
cb_index = best_cb_index;
|
||||
checks = best_checks;
|
||||
|
||||
kmeans->set_cb_index(best_cb_index);
|
||||
logger.info("Optimum cb_index: %g\n",cb_index);
|
||||
((KMeansIndexParams*)bestParams)->cb_index = cb_index;
|
||||
}
|
||||
else {
|
||||
searchTime = test_index_precision(*bestIndex, dataset, testDataset, gt_matches, index_params.target_precision, checks, nn, 1);
|
||||
}
|
||||
|
||||
logger.info("Required number of checks: %d \n",checks);;
|
||||
searchParams.checks = checks;
|
||||
|
||||
speedup = linear/searchTime;
|
||||
|
||||
gt_matches.free();
|
||||
}
|
||||
|
||||
return speedup;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif /* AUTOTUNEDINDEX_H_ */
|
163
modules/flann/include/opencv2/flann/composite_index.h
Normal file
163
modules/flann/include/opencv2/flann/composite_index.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef COMPOSITETREE_H
|
||||
#define COMPOSITETREE_H
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
#include "opencv2/flann/nn_index.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
|
||||
struct CompositeIndexParams : public IndexParams {
|
||||
CompositeIndexParams(int trees_ = 4, int branching_ = 32, int iterations_ = 11,
|
||||
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
|
||||
IndexParams(COMPOSITE),
|
||||
trees(trees_),
|
||||
branching(branching_),
|
||||
iterations(iterations_),
|
||||
centers_init(centers_init_),
|
||||
cb_index(cb_index_) {};
|
||||
|
||||
int trees; // number of randomized trees to use (for kdtree)
|
||||
int branching; // branching factor (for kmeans tree)
|
||||
int iterations; // max iterations to perform in one kmeans clustering (kmeans tree)
|
||||
flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree
|
||||
float cb_index; // cluster boundary index. Used when searching the kmeans tree
|
||||
|
||||
flann_algorithm_t getIndexType() const { return algorithm; }
|
||||
|
||||
void print() const
|
||||
{
|
||||
logger.info("Index type: %d\n",(int)algorithm);
|
||||
logger.info("Trees: %d\n", trees);
|
||||
logger.info("Branching: %d\n", branching);
|
||||
logger.info("Iterations: %d\n", iterations);
|
||||
logger.info("Centres initialisation: %d\n", centers_init);
|
||||
logger.info("Cluster boundary weight: %g\n", cb_index);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
|
||||
class CompositeIndex : public NNIndex<ELEM_TYPE>
|
||||
{
|
||||
KMeansIndex<ELEM_TYPE, DIST_TYPE>* kmeans;
|
||||
KDTreeIndex<ELEM_TYPE, DIST_TYPE>* kdtree;
|
||||
|
||||
const Matrix<ELEM_TYPE> dataset;
|
||||
|
||||
const IndexParams& index_params;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CompositeIndex(const Matrix<ELEM_TYPE>& inputData, const CompositeIndexParams& params = CompositeIndexParams() ) :
|
||||
dataset(inputData), index_params(params)
|
||||
{
|
||||
KDTreeIndexParams kdtree_params(params.trees);
|
||||
KMeansIndexParams kmeans_params(params.branching, params.iterations, params.centers_init, params.cb_index);
|
||||
|
||||
kdtree = new KDTreeIndex<ELEM_TYPE, DIST_TYPE>(inputData,kdtree_params);
|
||||
kmeans = new KMeansIndex<ELEM_TYPE, DIST_TYPE>(inputData,kmeans_params);
|
||||
|
||||
}
|
||||
|
||||
virtual ~CompositeIndex()
|
||||
{
|
||||
delete kdtree;
|
||||
delete kmeans;
|
||||
}
|
||||
|
||||
|
||||
flann_algorithm_t getType() const
|
||||
{
|
||||
return COMPOSITE;
|
||||
}
|
||||
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return dataset.rows;
|
||||
}
|
||||
|
||||
size_t veclen() const
|
||||
{
|
||||
return dataset.cols;
|
||||
}
|
||||
|
||||
|
||||
int usedMemory() const
|
||||
{
|
||||
return kmeans->usedMemory()+kdtree->usedMemory();
|
||||
}
|
||||
|
||||
void buildIndex()
|
||||
{
|
||||
logger.info("Building kmeans tree...\n");
|
||||
kmeans->buildIndex();
|
||||
logger.info("Building kdtree tree...\n");
|
||||
kdtree->buildIndex();
|
||||
}
|
||||
|
||||
|
||||
void saveIndex(FILE* stream)
|
||||
{
|
||||
kmeans->saveIndex(stream);
|
||||
kdtree->saveIndex(stream);
|
||||
}
|
||||
|
||||
|
||||
void loadIndex(FILE* stream)
|
||||
{
|
||||
kmeans->loadIndex(stream);
|
||||
kdtree->loadIndex(stream);
|
||||
}
|
||||
|
||||
void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams)
|
||||
{
|
||||
kmeans->findNeighbors(result,vec,searchParams);
|
||||
kdtree->findNeighbors(result,vec,searchParams);
|
||||
}
|
||||
|
||||
const IndexParams* getParameters() const
|
||||
{
|
||||
return &index_params;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //COMPOSITETREE_H
|
360
modules/flann/include/opencv2/flann/dist.h
Normal file
360
modules/flann/include/opencv2/flann/dist.h
Normal file
@@ -0,0 +1,360 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef DIST_H
|
||||
#define DIST_H
|
||||
|
||||
#include <cmath>
|
||||
using namespace std;
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/**
|
||||
* Distance function by default set to the custom distance
|
||||
* function. This can be set to a specific distance function
|
||||
* for further efficiency.
|
||||
*/
|
||||
#define flann_dist custom_dist
|
||||
//#define flann_dist euclidean_dist
|
||||
|
||||
|
||||
/**
|
||||
* Compute the squared Euclidean distance between two vectors.
|
||||
*
|
||||
* This is highly optimised, with loop unrolling, as it is one
|
||||
* of the most expensive inner loops.
|
||||
*
|
||||
* The computation of squared root at the end is omitted for
|
||||
* efficiency.
|
||||
*/
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double euclidean_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double distsq = acc;
|
||||
double diff0, diff1, diff2, diff3;
|
||||
Iterator1 lastgroup = last1 - 3;
|
||||
|
||||
/* Process 4 items with each loop for efficiency. */
|
||||
while (first1 < lastgroup) {
|
||||
diff0 = first1[0] - first2[0];
|
||||
diff1 = first1[1] - first2[1];
|
||||
diff2 = first1[2] - first2[2];
|
||||
diff3 = first1[3] - first2[3];
|
||||
distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
|
||||
first1 += 4;
|
||||
first2 += 4;
|
||||
}
|
||||
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
|
||||
while (first1 < last1) {
|
||||
diff0 = *first1++ - *first2++;
|
||||
distsq += diff0 * diff0;
|
||||
}
|
||||
return distsq;
|
||||
}
|
||||
|
||||
double euclidean_dist(const unsigned char* first1, const unsigned char* last1, unsigned char* first2, double acc);
|
||||
|
||||
|
||||
/**
|
||||
* Compute the Manhattan (L_1) distance between two vectors.
|
||||
*
|
||||
* This is highly optimised, with loop unrolling, as it is one
|
||||
* of the most expensive inner loops.
|
||||
*/
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double manhattan_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double distsq = acc;
|
||||
double diff0, diff1, diff2, diff3;
|
||||
Iterator1 lastgroup = last1 - 3;
|
||||
|
||||
/* Process 4 items with each loop for efficiency. */
|
||||
while (first1 < lastgroup) {
|
||||
diff0 = fabs(first1[0] - first2[0]);
|
||||
diff1 = fabs(first1[1] - first2[1]);
|
||||
diff2 = fabs(first1[2] - first2[2]);
|
||||
diff3 = fabs(first1[3] - first2[3]);
|
||||
distsq += diff0 + diff1 + diff2 + diff3;
|
||||
first1 += 4;
|
||||
first2 += 4;
|
||||
}
|
||||
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
|
||||
while (first1 < last1) {
|
||||
diff0 = fabs(*first1++ - *first2++);
|
||||
distsq += diff0;
|
||||
}
|
||||
return distsq;
|
||||
}
|
||||
|
||||
|
||||
extern int flann_minkowski_order;
|
||||
/**
|
||||
* Compute the Minkowski (L_p) distance between two vectors.
|
||||
*
|
||||
* This is highly optimised, with loop unrolling, as it is one
|
||||
* of the most expensive inner loops.
|
||||
*
|
||||
* The computation of squared root at the end is omitted for
|
||||
* efficiency.
|
||||
*/
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double minkowski_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double distsq = acc;
|
||||
double diff0, diff1, diff2, diff3;
|
||||
Iterator1 lastgroup = last1 - 3;
|
||||
|
||||
int p = flann_minkowski_order;
|
||||
|
||||
/* Process 4 items with each loop for efficiency. */
|
||||
while (first1 < lastgroup) {
|
||||
diff0 = fabs(first1[0] - first2[0]);
|
||||
diff1 = fabs(first1[1] - first2[1]);
|
||||
diff2 = fabs(first1[2] - first2[2]);
|
||||
diff3 = fabs(first1[3] - first2[3]);
|
||||
distsq += pow(diff0,p) + pow(diff1,p) + pow(diff2,p) + pow(diff3,p);
|
||||
first1 += 4;
|
||||
first2 += 4;
|
||||
}
|
||||
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
|
||||
while (first1 < last1) {
|
||||
diff0 = fabs(*first1++ - *first2++);
|
||||
distsq += pow(diff0,p);
|
||||
}
|
||||
return distsq;
|
||||
}
|
||||
|
||||
|
||||
// L_infinity distance (NOT A VALID KD-TREE DISTANCE - NOT DIMENSIONWISE ADDITIVE)
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double max_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double dist = acc;
|
||||
Iterator1 lastgroup = last1 - 3;
|
||||
double diff0, diff1, diff2, diff3;
|
||||
|
||||
/* Process 4 items with each loop for efficiency. */
|
||||
while (first1 < lastgroup) {
|
||||
diff0 = fabs(first1[0] - first2[0]);
|
||||
diff1 = fabs(first1[1] - first2[1]);
|
||||
diff2 = fabs(first1[2] - first2[2]);
|
||||
diff3 = fabs(first1[3] - first2[3]);
|
||||
if (diff0 > dist) dist = diff0;
|
||||
if (diff1 > dist) dist = diff1;
|
||||
if (diff2 > dist) dist = diff2;
|
||||
if (diff3 > dist) dist = diff3;
|
||||
first1 += 4;
|
||||
first2 += 4;
|
||||
}
|
||||
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
|
||||
while (first1 < last1) {
|
||||
diff0 = fabs(*first1++ - *first2++);
|
||||
dist = (diff0 > dist) ? diff0 : dist;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double hist_intersection_kernel(Iterator1 first1, Iterator1 last1, Iterator2 first2)
|
||||
{
|
||||
double kernel = 0;
|
||||
Iterator1 lastgroup = last1 - 3;
|
||||
double min0, min1, min2, min3;
|
||||
|
||||
/* Process 4 items with each loop for efficiency. */
|
||||
while (first1 < lastgroup) {
|
||||
min0 = first1[0] < first2[0] ? first1[0] : first2[0];
|
||||
min1 = first1[1] < first2[1] ? first1[1] : first2[1];
|
||||
min2 = first1[2] < first2[2] ? first1[2] : first2[2];
|
||||
min3 = first1[3] < first2[3] ? first1[3] : first2[3];
|
||||
kernel += min0 + min1 + min2 + min3;
|
||||
first1 += 4;
|
||||
first2 += 4;
|
||||
}
|
||||
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
|
||||
while (first1 < last1) {
|
||||
min0 = first1[0] < first2[0] ? first1[0] : first2[0];
|
||||
kernel += min0;
|
||||
first1++;
|
||||
first2++;
|
||||
}
|
||||
return kernel;
|
||||
}
|
||||
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double hist_intersection_dist_sq(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double dist_sq = acc - 2 * hist_intersection_kernel(first1, last1, first2);
|
||||
while (first1 < last1) {
|
||||
dist_sq += *first1 + *first2;
|
||||
first1++;
|
||||
first2++;
|
||||
}
|
||||
return dist_sq;
|
||||
}
|
||||
|
||||
|
||||
// Hellinger distance
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double hellinger_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double distsq = acc;
|
||||
double diff0, diff1, diff2, diff3;
|
||||
Iterator1 lastgroup = last1 - 3;
|
||||
|
||||
/* Process 4 items with each loop for efficiency. */
|
||||
while (first1 < lastgroup) {
|
||||
diff0 = sqrt(first1[0]) - sqrt(first2[0]);
|
||||
diff1 = sqrt(first1[1]) - sqrt(first2[1]);
|
||||
diff2 = sqrt(first1[2]) - sqrt(first2[2]);
|
||||
diff3 = sqrt(first1[3]) - sqrt(first2[3]);
|
||||
distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
|
||||
first1 += 4;
|
||||
first2 += 4;
|
||||
}
|
||||
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
|
||||
while (first1 < last1) {
|
||||
diff0 = sqrt(*first1++) - sqrt(*first2++);
|
||||
distsq += diff0 * diff0;
|
||||
}
|
||||
return distsq;
|
||||
}
|
||||
|
||||
|
||||
// chi-dsquare distance
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double chi_square_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double dist = acc;
|
||||
|
||||
while (first1 < last1) {
|
||||
double sum = *first1 + *first2;
|
||||
if (sum > 0) {
|
||||
double diff = *first1 - *first2;
|
||||
dist += diff * diff / sum;
|
||||
}
|
||||
first1++;
|
||||
first2++;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
// Kullback–Leibler divergence (NOT SYMMETRIC)
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double kl_divergence(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
double div = acc;
|
||||
|
||||
while (first1 < last1) {
|
||||
if (*first2 != 0) {
|
||||
double ratio = *first1 / *first2;
|
||||
if (ratio > 0) {
|
||||
div += *first1 * log(ratio);
|
||||
}
|
||||
}
|
||||
first1++;
|
||||
first2++;
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern flann_distance_t flann_distance_type;
|
||||
/**
|
||||
* Custom distance function. The distance computed is dependent on the value
|
||||
* of the 'flann_distance_type' global variable.
|
||||
*
|
||||
* If the last argument 'acc' is passed, the result is accumulated to the value
|
||||
* of this argument.
|
||||
*/
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
double custom_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
|
||||
{
|
||||
switch (flann_distance_type) {
|
||||
case EUCLIDEAN:
|
||||
return euclidean_dist(first1, last1, first2, acc);
|
||||
case MANHATTAN:
|
||||
return manhattan_dist(first1, last1, first2, acc);
|
||||
case MINKOWSKI:
|
||||
return minkowski_dist(first1, last1, first2, acc);
|
||||
case MAX_DIST:
|
||||
return max_dist(first1, last1, first2, acc);
|
||||
case HIK:
|
||||
return hist_intersection_dist_sq(first1, last1, first2, acc);
|
||||
case HELLINGER:
|
||||
return hellinger_dist(first1, last1, first2, acc);
|
||||
case CS:
|
||||
return chi_square_dist(first1, last1, first2, acc);
|
||||
case KL:
|
||||
return kl_divergence(first1, last1, first2, acc);
|
||||
default:
|
||||
return euclidean_dist(first1, last1, first2, acc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a "zero iterator". It basically behaves like a zero filled
|
||||
* array to all algorithms that use arrays as iterators (STL style).
|
||||
* It's useful when there's a need to compute the distance between feature
|
||||
* and origin it and allows for better compiler optimisation than using a
|
||||
* zero-filled array.
|
||||
*/
|
||||
template <typename T>
|
||||
struct ZeroIterator {
|
||||
|
||||
T operator*() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
T operator[](int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZeroIterator<T>& operator ++(int) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ZeroIterator<T>& operator+=(int) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
extern ZeroIterator<float> zero;
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //DIST_H
|
196
modules/flann/include/opencv2/flann/flann.hpp
Normal file
196
modules/flann/include/opencv2/flann/flann.hpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __OPENCV_FLANN_HPP__
|
||||
#define __OPENCV_FLANN_HPP__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "opencv2/flann/flann_base.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace flann
|
||||
{
|
||||
|
||||
template <typename T> struct CvType {};
|
||||
template <> struct CvType<unsigned char> { static int type() { return CV_8U; } };
|
||||
template <> struct CvType<char> { static int type() { return CV_8S; } };
|
||||
template <> struct CvType<unsigned short> { static int type() { return CV_16U; } };
|
||||
template <> struct CvType<short> { static int type() { return CV_16S; } };
|
||||
template <> struct CvType<int> { static int type() { return CV_32S; } };
|
||||
template <> struct CvType<float> { static int type() { return CV_32F; } };
|
||||
template <> struct CvType<double> { static int type() { return CV_64F; } };
|
||||
|
||||
|
||||
using ::cvflann::IndexParams;
|
||||
using ::cvflann::LinearIndexParams;
|
||||
using ::cvflann::KDTreeIndexParams;
|
||||
using ::cvflann::KMeansIndexParams;
|
||||
using ::cvflann::CompositeIndexParams;
|
||||
using ::cvflann::AutotunedIndexParams;
|
||||
using ::cvflann::SavedIndexParams;
|
||||
|
||||
using ::cvflann::SearchParams;
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Index_ {
|
||||
::cvflann::Index<T>* nnIndex;
|
||||
|
||||
public:
|
||||
Index_(const Mat& features, const IndexParams& params);
|
||||
|
||||
~Index_();
|
||||
|
||||
void knnSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& params);
|
||||
void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params);
|
||||
|
||||
int radiusSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, float radius, const SearchParams& params);
|
||||
int radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& params);
|
||||
|
||||
void save(std::string filename) { nnIndex->save(filename); }
|
||||
|
||||
int veclen() const { return nnIndex->veclen(); }
|
||||
|
||||
int size() const { return nnIndex->size(); }
|
||||
|
||||
const IndexParams* getIndexParameters() { return nnIndex->getParameters(); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
Index_<T>::Index_(const Mat& dataset, const IndexParams& params)
|
||||
{
|
||||
CV_Assert(dataset.type() == CvType<T>::type());
|
||||
CV_Assert(dataset.isContinuous());
|
||||
::cvflann::Matrix<float> m_dataset((T*)dataset.ptr<T>(0), dataset.rows, dataset.cols);
|
||||
|
||||
nnIndex = new ::cvflann::Index<T>(m_dataset, params);
|
||||
nnIndex->buildIndex();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Index_<T>::~Index_()
|
||||
{
|
||||
delete nnIndex;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Index_<T>::knnSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& searchParams)
|
||||
{
|
||||
::cvflann::Matrix<T> m_query((T*)&query[0], 1, (int)query.size());
|
||||
::cvflann::Matrix<int> m_indices(&indices[0], 1, (int)indices.size());
|
||||
::cvflann::Matrix<float> m_dists(&dists[0], 1, (int)dists.size());
|
||||
|
||||
nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void Index_<T>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& searchParams)
|
||||
{
|
||||
CV_Assert(queries.type() == CvType<T>::type());
|
||||
CV_Assert(queries.isContinuous());
|
||||
::cvflann::Matrix<T> m_queries((T*)queries.ptr<T>(0), queries.rows, queries.cols);
|
||||
|
||||
CV_Assert(indices.type() == CV_32S);
|
||||
CV_Assert(indices.isContinuous());
|
||||
::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
|
||||
|
||||
CV_Assert(dists.type() == CV_32F);
|
||||
CV_Assert(dists.isContinuous());
|
||||
::cvflann::Matrix<float> m_dists((float*)dists.ptr<float>(0), dists.rows, dists.cols);
|
||||
|
||||
nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int Index_<T>::radiusSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, float radius, const SearchParams& searchParams)
|
||||
{
|
||||
::cvflann::Matrix<T> m_query((T*)&query[0], 1, (int)query.size());
|
||||
::cvflann::Matrix<int> m_indices(&indices[0], 1, (int)indices.size());
|
||||
::cvflann::Matrix<float> m_dists(&dists[0], 1, (int)dists.size());
|
||||
|
||||
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int Index_<T>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& searchParams)
|
||||
{
|
||||
CV_Assert(query.type() == CvType<T>::type());
|
||||
CV_Assert(query.isContinuous());
|
||||
::cvflann::Matrix<T> m_query((T*)query.ptr<T>(0), query.rows, query.cols);
|
||||
|
||||
CV_Assert(indices.type() == CV_32S);
|
||||
CV_Assert(indices.isContinuous());
|
||||
::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
|
||||
|
||||
CV_Assert(dists.type() == CV_32F);
|
||||
CV_Assert(dists.isContinuous());
|
||||
::cvflann::Matrix<float> m_dists((float*)dists.ptr<float>(0), dists.rows, dists.cols);
|
||||
|
||||
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
|
||||
}
|
||||
|
||||
typedef Index_<float> Index;
|
||||
|
||||
template <typename ELEM_TYPE, typename DIST_TYPE>
|
||||
int hierarchicalClustering(const Mat& features, Mat& centers, const KMeansIndexParams& params)
|
||||
{
|
||||
CV_Assert(features.type() == CvType<ELEM_TYPE>::type());
|
||||
CV_Assert(features.isContinuous());
|
||||
::cvflann::Matrix<ELEM_TYPE> m_features((ELEM_TYPE*)features.ptr<ELEM_TYPE>(0), features.rows, features.cols);
|
||||
|
||||
CV_Assert(centers.type() == CvType<DIST_TYPE>::type());
|
||||
CV_Assert(centers.isContinuous());
|
||||
::cvflann::Matrix<DIST_TYPE> m_centers((DIST_TYPE*)centers.ptr<DIST_TYPE>(0), centers.rows, centers.cols);
|
||||
|
||||
return ::cvflann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE>(m_features, m_centers, params);
|
||||
}
|
||||
|
||||
} } // namespace cv::flann
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif
|
261
modules/flann/include/opencv2/flann/flann_base.hpp
Normal file
261
modules/flann/include/opencv2/flann/flann_base.hpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef FLANN_HPP_
|
||||
#define FLANN_HPP_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
#include "opencv2/flann/matrix.h"
|
||||
#include "opencv2/flann/result_set.h"
|
||||
#include "opencv2/flann/index_testing.h"
|
||||
#include "opencv2/flann/object_factory.h"
|
||||
#include "opencv2/flann/saving.h"
|
||||
|
||||
#include "opencv2/flann/all_indices.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
Sets the log level used for all flann functions
|
||||
|
||||
Params:
|
||||
level = verbosity level
|
||||
*/
|
||||
void log_verbosity(int level);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the distance type to use throughout FLANN.
|
||||
* If distance type specified is MINKOWSKI, the second argument
|
||||
* specifies which order the minkowski distance should have.
|
||||
*/
|
||||
void set_distance_type(flann_distance_t distance_type, int order);
|
||||
|
||||
|
||||
struct SavedIndexParams : public IndexParams {
|
||||
SavedIndexParams(std::string filename_) : IndexParams(SAVED), filename(filename_) {}
|
||||
|
||||
std::string filename; // filename of the stored index
|
||||
|
||||
flann_algorithm_t getIndexType() const { return algorithm; }
|
||||
|
||||
void print() const
|
||||
{
|
||||
logger.info("Index type: %d\n",(int)algorithm);
|
||||
logger.info("Filename: %s\n", filename.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Index {
|
||||
NNIndex<T>* nnIndex;
|
||||
bool built;
|
||||
|
||||
public:
|
||||
Index(const Matrix<T>& features, const IndexParams& params);
|
||||
|
||||
~Index();
|
||||
|
||||
void buildIndex();
|
||||
|
||||
void knnSearch(const Matrix<T>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& params);
|
||||
|
||||
int radiusSearch(const Matrix<T>& query, Matrix<int>& indices, Matrix<float>& dists, float radius, const SearchParams& params);
|
||||
|
||||
void save(std::string filename);
|
||||
|
||||
int veclen() const;
|
||||
|
||||
int size() const;
|
||||
|
||||
NNIndex<T>* getIndex() { return nnIndex; }
|
||||
|
||||
const IndexParams* getIndexParameters() { return nnIndex->getParameters(); }
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
NNIndex<T>* load_saved_index(const Matrix<T>& dataset, const string& filename)
|
||||
{
|
||||
FILE* fin = fopen(filename.c_str(), "rb");
|
||||
if (fin==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
IndexHeader header = load_header(fin);
|
||||
if (header.data_type!=Datatype<T>::type()) {
|
||||
throw FLANNException("Datatype of saved index is different than of the one to be created.");
|
||||
}
|
||||
if (size_t(header.rows)!=dataset.rows || size_t(header.cols)!=dataset.cols) {
|
||||
throw FLANNException("The index saved belongs to a different dataset");
|
||||
}
|
||||
|
||||
IndexParams* params = ParamsFactory::instance().create(header.index_type);
|
||||
NNIndex<T>* nnIndex = create_index_by_type(dataset, *params);
|
||||
nnIndex->loadIndex(fin);
|
||||
fclose(fin);
|
||||
|
||||
return nnIndex;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
Index<T>::Index(const Matrix<T>& dataset, const IndexParams& params)
|
||||
{
|
||||
flann_algorithm_t index_type = params.getIndexType();
|
||||
built = false;
|
||||
|
||||
if (index_type==SAVED) {
|
||||
nnIndex = load_saved_index(dataset, ((const SavedIndexParams&)params).filename);
|
||||
built = true;
|
||||
}
|
||||
else {
|
||||
nnIndex = create_index_by_type(dataset, params);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Index<T>::~Index()
|
||||
{
|
||||
delete nnIndex;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Index<T>::buildIndex()
|
||||
{
|
||||
if (!built) {
|
||||
nnIndex->buildIndex();
|
||||
built = true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Index<T>::knnSearch(const Matrix<T>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& searchParams)
|
||||
{
|
||||
if (!built) {
|
||||
throw FLANNException("You must build the index before searching.");
|
||||
}
|
||||
assert(queries.cols==nnIndex->veclen());
|
||||
assert(indices.rows>=queries.rows);
|
||||
assert(dists.rows>=queries.rows);
|
||||
assert(int(indices.cols)>=knn);
|
||||
assert(int(dists.cols)>=knn);
|
||||
|
||||
KNNResultSet<T> resultSet(knn);
|
||||
|
||||
for (size_t i = 0; i < queries.rows; i++) {
|
||||
T* target = queries[i];
|
||||
resultSet.init(target, queries.cols);
|
||||
|
||||
nnIndex->findNeighbors(resultSet, target, searchParams);
|
||||
|
||||
int* neighbors = resultSet.getNeighbors();
|
||||
float* distances = resultSet.getDistances();
|
||||
memcpy(indices[i], neighbors, knn*sizeof(int));
|
||||
memcpy(dists[i], distances, knn*sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int Index<T>::radiusSearch(const Matrix<T>& query, Matrix<int>& indices, Matrix<float>& dists, float radius, const SearchParams& searchParams)
|
||||
{
|
||||
if (!built) {
|
||||
throw FLANNException("You must build the index before searching.");
|
||||
}
|
||||
if (query.rows!=1) {
|
||||
fprintf(stderr, "I can only search one feature at a time for range search\n");
|
||||
return -1;
|
||||
}
|
||||
assert(query.cols==nnIndex->veclen());
|
||||
|
||||
RadiusResultSet<T> resultSet(radius);
|
||||
resultSet.init(query.data, query.cols);
|
||||
nnIndex->findNeighbors(resultSet,query.data,searchParams);
|
||||
|
||||
// TODO: optimise here
|
||||
int* neighbors = resultSet.getNeighbors();
|
||||
float* distances = resultSet.getDistances();
|
||||
size_t count_nn = min(resultSet.size(), indices.cols);
|
||||
|
||||
assert (dists.cols>=count_nn);
|
||||
|
||||
for (size_t i=0;i<count_nn;++i) {
|
||||
indices[0][i] = neighbors[i];
|
||||
dists[0][i] = distances[i];
|
||||
}
|
||||
|
||||
return count_nn;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void Index<T>::save(string filename)
|
||||
{
|
||||
FILE* fout = fopen(filename.c_str(), "wb");
|
||||
if (fout==NULL) {
|
||||
throw FLANNException("Cannot open file");
|
||||
}
|
||||
save_header(fout, *nnIndex);
|
||||
nnIndex->saveIndex(fout);
|
||||
fclose(fout);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Index<T>::size() const
|
||||
{
|
||||
return nnIndex->size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int Index<T>::veclen() const
|
||||
{
|
||||
return nnIndex->veclen();
|
||||
}
|
||||
|
||||
|
||||
template <typename ELEM_TYPE, typename DIST_TYPE>
|
||||
int hierarchicalClustering(const Matrix<ELEM_TYPE>& features, Matrix<DIST_TYPE>& centers, const KMeansIndexParams& params)
|
||||
{
|
||||
KMeansIndex<ELEM_TYPE, DIST_TYPE> kmeans(features, params);
|
||||
kmeans.buildIndex();
|
||||
|
||||
int clusterNum = kmeans.getClusterCenters(centers);
|
||||
return clusterNum;
|
||||
}
|
||||
|
||||
} // namespace cvflann
|
||||
#endif /* FLANN_HPP_ */
|
153
modules/flann/include/opencv2/flann/general.h
Normal file
153
modules/flann/include/opencv2/flann/general.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef CONSTANTS_H
|
||||
#define CONSTANTS_H
|
||||
|
||||
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
|
||||
|
||||
/* Nearest neighbour index algorithms */
|
||||
enum flann_algorithm_t {
|
||||
LINEAR = 0,
|
||||
KDTREE = 1,
|
||||
KMEANS = 2,
|
||||
COMPOSITE = 3,
|
||||
SAVED = 254,
|
||||
AUTOTUNED = 255
|
||||
};
|
||||
|
||||
enum flann_centers_init_t {
|
||||
CENTERS_RANDOM = 0,
|
||||
CENTERS_GONZALES = 1,
|
||||
CENTERS_KMEANSPP = 2
|
||||
};
|
||||
|
||||
enum flann_log_level_t {
|
||||
LOG_NONE = 0,
|
||||
LOG_FATAL = 1,
|
||||
LOG_ERROR = 2,
|
||||
LOG_WARN = 3,
|
||||
LOG_INFO = 4
|
||||
};
|
||||
|
||||
enum flann_distance_t {
|
||||
EUCLIDEAN = 1,
|
||||
MANHATTAN = 2,
|
||||
MINKOWSKI = 3,
|
||||
MAX_DIST = 4,
|
||||
HIK = 5,
|
||||
HELLINGER = 6,
|
||||
CS = 7,
|
||||
CHI_SQUARE = 7,
|
||||
KL = 8,
|
||||
KULLBACK_LEIBLER = 8
|
||||
};
|
||||
|
||||
enum flann_datatype_t {
|
||||
INT8 = 0,
|
||||
INT16 = 1,
|
||||
INT32 = 2,
|
||||
INT64 = 3,
|
||||
UINT8 = 4,
|
||||
UINT16 = 5,
|
||||
UINT32 = 6,
|
||||
UINT64 = 7,
|
||||
FLOAT32 = 8,
|
||||
FLOAT64 = 9
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include "opencv2/flann/object_factory.h"
|
||||
|
||||
namespace cvflann {
|
||||
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
struct DistType
|
||||
{
|
||||
typedef ELEM_TYPE type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DistType<unsigned char>
|
||||
{
|
||||
typedef float type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DistType<int>
|
||||
{
|
||||
typedef float type;
|
||||
};
|
||||
|
||||
|
||||
class FLANNException : public std::runtime_error {
|
||||
public:
|
||||
FLANNException(const char* message) : std::runtime_error(message) { }
|
||||
|
||||
FLANNException(const std::string& message) : std::runtime_error(message) { }
|
||||
};
|
||||
|
||||
|
||||
struct IndexParams {
|
||||
protected:
|
||||
IndexParams(flann_algorithm_t algorithm_) : algorithm(algorithm_) {};
|
||||
|
||||
public:
|
||||
virtual flann_algorithm_t getIndexType() const = 0;
|
||||
|
||||
virtual void print() const = 0;
|
||||
|
||||
flann_algorithm_t algorithm;
|
||||
};
|
||||
|
||||
|
||||
typedef ObjectFactory<IndexParams, flann_algorithm_t> ParamsFactory;
|
||||
|
||||
|
||||
struct SearchParams {
|
||||
SearchParams(int checks_ = 32) :
|
||||
checks(checks_) {};
|
||||
|
||||
int checks;
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CONSTANTS_H */
|
95
modules/flann/include/opencv2/flann/ground_truth.h
Normal file
95
modules/flann/include/opencv2/flann/ground_truth.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef GROUND_TRUTH_H
|
||||
#define GROUND_TRUTH_H
|
||||
|
||||
#include "opencv2/flann/dist.h"
|
||||
#include "opencv2/flann/matrix.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int skip = 0)
|
||||
{
|
||||
int n = nn + skip;
|
||||
|
||||
T* query_end = query + dataset.cols;
|
||||
|
||||
long* match = new long[n];
|
||||
T* dists = new T[n];
|
||||
|
||||
dists[0] = flann_dist(query, query_end, dataset[0]);
|
||||
match[0] = 0;
|
||||
int dcnt = 1;
|
||||
|
||||
for (size_t i=1;i<dataset.rows;++i) {
|
||||
T tmp = flann_dist(query, query_end, dataset[i]);
|
||||
|
||||
if (dcnt<n) {
|
||||
match[dcnt] = i;
|
||||
dists[dcnt++] = tmp;
|
||||
}
|
||||
else if (tmp < dists[dcnt-1]) {
|
||||
dists[dcnt-1] = tmp;
|
||||
match[dcnt-1] = i;
|
||||
}
|
||||
|
||||
int j = dcnt-1;
|
||||
// bubble up
|
||||
while (j>=1 && dists[j]<dists[j-1]) {
|
||||
swap(dists[j],dists[j-1]);
|
||||
swap(match[j],match[j-1]);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0;i<nn;++i) {
|
||||
matches[i] = match[i+skip];
|
||||
}
|
||||
|
||||
delete[] match;
|
||||
delete[] dists;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void compute_ground_truth(const Matrix<T>& dataset, const Matrix<T>& testset, Matrix<int>& matches, int skip=0)
|
||||
{
|
||||
for (size_t i=0;i<testset.rows;++i) {
|
||||
find_nearest(dataset, testset[i], matches[i], matches.cols, skip);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //GROUND_TRUTH_H
|
163
modules/flann/include/opencv2/flann/hdf5.h
Normal file
163
modules/flann/include/opencv2/flann/hdf5.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
#ifndef IO_H_
|
||||
#define IO_H_
|
||||
|
||||
#include <H5Cpp.h>
|
||||
|
||||
#include "opencv2/flann/matrix.h"
|
||||
|
||||
|
||||
|
||||
#ifndef H5_NO_NAMESPACE
|
||||
using namespace H5;
|
||||
#endif
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
PredType get_hdf5_type()
|
||||
{
|
||||
throw FLANNException("Unsupported type for IO operations");
|
||||
}
|
||||
|
||||
template<> PredType get_hdf5_type<char>() { return PredType::NATIVE_CHAR; }
|
||||
template<> PredType get_hdf5_type<unsigned char>() { return PredType::NATIVE_UCHAR; }
|
||||
template<> PredType get_hdf5_type<short int>() { return PredType::NATIVE_SHORT; }
|
||||
template<> PredType get_hdf5_type<unsigned short int>() { return PredType::NATIVE_USHORT; }
|
||||
template<> PredType get_hdf5_type<int>() { return PredType::NATIVE_INT; }
|
||||
template<> PredType get_hdf5_type<unsigned int>() { return PredType::NATIVE_UINT; }
|
||||
template<> PredType get_hdf5_type<long>() { return PredType::NATIVE_LONG; }
|
||||
template<> PredType get_hdf5_type<unsigned long>() { return PredType::NATIVE_ULONG; }
|
||||
template<> PredType get_hdf5_type<float>() { return PredType::NATIVE_FLOAT; }
|
||||
template<> PredType get_hdf5_type<double>() { return PredType::NATIVE_DOUBLE; }
|
||||
template<> PredType get_hdf5_type<long double>() { return PredType::NATIVE_LDOUBLE; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void save_to_file(const cvflann::Matrix<T>& flann_dataset, const std::string& filename, const std::string& name)
|
||||
{
|
||||
// Try block to detect exceptions raised by any of the calls inside it
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Turn off the auto-printing when failure occurs so that we can
|
||||
* handle the errors appropriately
|
||||
*/
|
||||
Exception::dontPrint();
|
||||
|
||||
/*
|
||||
* Create a new file using H5F_ACC_TRUNC access,
|
||||
* default file creation properties, and default file
|
||||
* access properties.
|
||||
*/
|
||||
H5File file( filename, H5F_ACC_TRUNC );
|
||||
|
||||
/*
|
||||
* Define the size of the array and create the data space for fixed
|
||||
* size dataset.
|
||||
*/
|
||||
hsize_t dimsf[2]; // dataset dimensions
|
||||
dimsf[0] = flann_dataset.rows;
|
||||
dimsf[1] = flann_dataset.cols;
|
||||
DataSpace dataspace( 2, dimsf );
|
||||
|
||||
/*
|
||||
* Create a new dataset within the file using defined dataspace and
|
||||
* datatype and default dataset creation properties.
|
||||
*/
|
||||
DataSet dataset = file.createDataSet( name, get_hdf5_type<T>(), dataspace );
|
||||
|
||||
/*
|
||||
* Write the data to the dataset using default memory space, file
|
||||
* space, and transfer properties.
|
||||
*/
|
||||
dataset.write( flann_dataset.data, get_hdf5_type<T>() );
|
||||
} // end of try block
|
||||
catch( H5::Exception& error )
|
||||
{
|
||||
error.printError();
|
||||
throw FLANNException(error.getDetailMsg());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void load_from_file(cvflann::Matrix<T>& flann_dataset, const std::string& filename, const std::string& name)
|
||||
{
|
||||
try
|
||||
{
|
||||
Exception::dontPrint();
|
||||
|
||||
H5File file( filename, H5F_ACC_RDONLY );
|
||||
DataSet dataset = file.openDataSet( name );
|
||||
|
||||
/*
|
||||
* Check the type used by the dataset matches
|
||||
*/
|
||||
if ( !(dataset.getDataType()==get_hdf5_type<T>())) {
|
||||
throw FLANNException("Dataset matrix type does not match the type to be read.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get dataspace of the dataset.
|
||||
*/
|
||||
DataSpace dataspace = dataset.getSpace();
|
||||
|
||||
/*
|
||||
* Get the dimension size of each dimension in the dataspace and
|
||||
* display them.
|
||||
*/
|
||||
hsize_t dims_out[2];
|
||||
dataspace.getSimpleExtentDims( dims_out, NULL);
|
||||
|
||||
flann_dataset.rows = dims_out[0];
|
||||
flann_dataset.cols = dims_out[1];
|
||||
flann_dataset.data = new T[flann_dataset.rows*flann_dataset.cols];
|
||||
|
||||
dataset.read( flann_dataset.data, get_hdf5_type<T>() );
|
||||
} // end of try block
|
||||
catch( H5::Exception &error )
|
||||
{
|
||||
error.printError();
|
||||
throw FLANNException(error.getDetailMsg());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif /* IO_H_ */
|
209
modules/flann/include/opencv2/flann/heap.h
Normal file
209
modules/flann/include/opencv2/flann/heap.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef HEAP_H
|
||||
#define HEAP_H
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/**
|
||||
* Priority Queue Implementation
|
||||
*
|
||||
* The priority queue is implemented with a heap. A heap is a complete
|
||||
* (full) binary tree in which each parent is less than both of its
|
||||
* children, but the order of the children is unspecified.
|
||||
* Note that a heap uses 1-based indexing to allow for power-of-2
|
||||
* location of parents and children. We ignore element 0 of Heap array.
|
||||
*/
|
||||
template <typename T>
|
||||
class Heap {
|
||||
|
||||
/**
|
||||
* Storage array for the heap.
|
||||
* Type T must be comparable.
|
||||
*/
|
||||
T* heap;
|
||||
int length;
|
||||
|
||||
/**
|
||||
* Number of element in the heap
|
||||
*/
|
||||
int count;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Params:
|
||||
* size = heap size
|
||||
*/
|
||||
|
||||
Heap(int size)
|
||||
{
|
||||
length = size+1;
|
||||
heap = new T[length]; // heap uses 1-based indexing
|
||||
count = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
*/
|
||||
~Heap()
|
||||
{
|
||||
delete[] heap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns: heap size
|
||||
*/
|
||||
int size()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the heap is empty
|
||||
*
|
||||
* Returns: true is heap empty, false otherwise
|
||||
*/
|
||||
bool empty()
|
||||
{
|
||||
return size()==0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the heap.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert a new element in the heap.
|
||||
*
|
||||
* We select the next empty leaf node, and then keep moving any larger
|
||||
* parents down until the right location is found to store this element.
|
||||
*
|
||||
* Params:
|
||||
* value = the new element to be inserted in the heap
|
||||
*/
|
||||
void insert(T value)
|
||||
{
|
||||
/* If heap is full, then return without adding this element. */
|
||||
if (count == length-1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int loc = ++(count); /* Remember 1-based indexing. */
|
||||
|
||||
/* Keep moving parents down until a place is found for this node. */
|
||||
int par = loc / 2; /* Location of parent. */
|
||||
while (par > 0 && value < heap[par]) {
|
||||
heap[loc] = heap[par]; /* Move parent down to loc. */
|
||||
loc = par;
|
||||
par = loc / 2;
|
||||
}
|
||||
/* Insert the element at the determined location. */
|
||||
heap[loc] = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node of minimum value from the heap (top of the heap).
|
||||
*
|
||||
* Params:
|
||||
* value = out parameter used to return the min element
|
||||
* Returns: false if heap empty
|
||||
*/
|
||||
bool popMin(T& value)
|
||||
{
|
||||
if (count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Switch first node with last. */
|
||||
swap(heap[1],heap[count]);
|
||||
|
||||
count -= 1;
|
||||
heapify(1); /* Move new node 1 to right position. */
|
||||
|
||||
value = heap[count + 1];
|
||||
return true; /* Return old last node. */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reorganizes the heap (a parent is smaller than its children)
|
||||
* starting with a node.
|
||||
*
|
||||
* Params:
|
||||
* parent = node form which to start heap reorganization.
|
||||
*/
|
||||
void heapify(int parent)
|
||||
{
|
||||
int minloc = parent;
|
||||
|
||||
/* Check the left child */
|
||||
int left = 2 * parent;
|
||||
if (left <= count && heap[left] < heap[parent]) {
|
||||
minloc = left;
|
||||
}
|
||||
|
||||
/* Check the right child */
|
||||
int right = left + 1;
|
||||
if (right <= count && heap[right] < heap[minloc]) {
|
||||
minloc = right;
|
||||
}
|
||||
|
||||
/* If a child was smaller, than swap parent with it and Heapify. */
|
||||
if (minloc != parent) {
|
||||
swap(heap[parent],heap[minloc]);
|
||||
heapify(minloc);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //HEAP_H
|
292
modules/flann/include/opencv2/flann/index_testing.h
Normal file
292
modules/flann/include/opencv2/flann/index_testing.h
Normal file
@@ -0,0 +1,292 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef TESTING_H
|
||||
#define TESTING_H
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include "opencv2/flann/matrix.h"
|
||||
#include "opencv2/flann/nn_index.h"
|
||||
#include "opencv2/flann/result_set.h"
|
||||
#include "opencv2/flann/logger.h"
|
||||
#include "opencv2/flann/timer.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
int countCorrectMatches(int* neighbors, int* groundTruth, int n);
|
||||
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
float computeDistanceRaport(const Matrix<ELEM_TYPE>& inputData, ELEM_TYPE* target, int* neighbors, int* groundTruth, int veclen, int n)
|
||||
{
|
||||
ELEM_TYPE* target_end = target + veclen;
|
||||
float ret = 0;
|
||||
for (int i=0;i<n;++i) {
|
||||
float den = flann_dist(target,target_end, inputData[groundTruth[i]]);
|
||||
float num = flann_dist(target,target_end, inputData[neighbors[i]]);
|
||||
|
||||
if (den==0 && num==0) {
|
||||
ret += 1;
|
||||
}
|
||||
else {
|
||||
ret += num/den;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
float search_with_ground_truth(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches, int nn, int checks, float& time, float& dist, int skipMatches)
|
||||
{
|
||||
if (matches.cols<size_t(nn)) {
|
||||
logger.info("matches.cols=%d, nn=%d\n",matches.cols,nn);
|
||||
|
||||
throw FLANNException("Ground truth is not computed for as many neighbors as requested");
|
||||
}
|
||||
|
||||
KNNResultSet<ELEM_TYPE> resultSet(nn+skipMatches);
|
||||
SearchParams searchParams(checks);
|
||||
|
||||
int correct;
|
||||
float distR;
|
||||
StartStopTimer t;
|
||||
int repeats = 0;
|
||||
while (t.value<0.2) {
|
||||
repeats++;
|
||||
t.start();
|
||||
correct = 0;
|
||||
distR = 0;
|
||||
for (size_t i = 0; i < testData.rows; i++) {
|
||||
ELEM_TYPE* target = testData[i];
|
||||
resultSet.init(target, testData.cols);
|
||||
index.findNeighbors(resultSet,target, searchParams);
|
||||
int* neighbors = resultSet.getNeighbors();
|
||||
neighbors = neighbors+skipMatches;
|
||||
|
||||
correct += countCorrectMatches(neighbors,matches[i], nn);
|
||||
distR += computeDistanceRaport(inputData, target,neighbors,matches[i], testData.cols, nn);
|
||||
}
|
||||
t.stop();
|
||||
}
|
||||
time = t.value/repeats;
|
||||
|
||||
|
||||
float precicion = (float)correct/(nn*testData.rows);
|
||||
|
||||
dist = distR/(testData.rows*nn);
|
||||
|
||||
logger.info("%8d %10.4g %10.5g %10.5g %10.5g\n",
|
||||
checks, precicion, time, 1000.0 * time / testData.rows, dist);
|
||||
|
||||
return precicion;
|
||||
}
|
||||
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
float test_index_checks(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches,
|
||||
int checks, float& precision, int nn = 1, int skipMatches = 0)
|
||||
{
|
||||
logger.info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n");
|
||||
logger.info("---------------------------------------------------------\n");
|
||||
|
||||
float time = 0;
|
||||
float dist = 0;
|
||||
precision = search_with_ground_truth(index, inputData, testData, matches, nn, checks, time, dist, skipMatches);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
float test_index_precision(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches,
|
||||
float precision, int& checks, int nn = 1, int skipMatches = 0)
|
||||
{
|
||||
const float SEARCH_EPS = 0.001;
|
||||
|
||||
logger.info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n");
|
||||
logger.info("---------------------------------------------------------\n");
|
||||
|
||||
int c2 = 1;
|
||||
float p2;
|
||||
int c1 = 1;
|
||||
float p1;
|
||||
float time;
|
||||
float dist;
|
||||
|
||||
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
|
||||
|
||||
if (p2>precision) {
|
||||
logger.info("Got as close as I can\n");
|
||||
checks = c2;
|
||||
return time;
|
||||
}
|
||||
|
||||
while (p2<precision) {
|
||||
c1 = c2;
|
||||
p1 = p2;
|
||||
c2 *=2;
|
||||
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
|
||||
}
|
||||
|
||||
int cx;
|
||||
float realPrecision;
|
||||
if (fabs(p2-precision)>SEARCH_EPS) {
|
||||
logger.info("Start linear estimation\n");
|
||||
// after we got to values in the vecinity of the desired precision
|
||||
// use linear approximation get a better estimation
|
||||
|
||||
cx = (c1+c2)/2;
|
||||
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
|
||||
while (fabs(realPrecision-precision)>SEARCH_EPS) {
|
||||
|
||||
if (realPrecision<precision) {
|
||||
c1 = cx;
|
||||
}
|
||||
else {
|
||||
c2 = cx;
|
||||
}
|
||||
cx = (c1+c2)/2;
|
||||
if (cx==c1) {
|
||||
logger.info("Got as close as I can\n");
|
||||
break;
|
||||
}
|
||||
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
|
||||
}
|
||||
|
||||
c2 = cx;
|
||||
p2 = realPrecision;
|
||||
|
||||
} else {
|
||||
logger.info("No need for linear estimation\n");
|
||||
cx = c2;
|
||||
realPrecision = p2;
|
||||
}
|
||||
|
||||
checks = cx;
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
float test_index_precisions(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches,
|
||||
float* precisions, int precisions_length, int nn = 1, int skipMatches = 0, float maxTime = 0)
|
||||
{
|
||||
const float SEARCH_EPS = 0.001;
|
||||
|
||||
// make sure precisions array is sorted
|
||||
sort(precisions, precisions+precisions_length);
|
||||
|
||||
int pindex = 0;
|
||||
float precision = precisions[pindex];
|
||||
|
||||
logger.info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist");
|
||||
logger.info("---------------------------------------------------------");
|
||||
|
||||
int c2 = 1;
|
||||
float p2;
|
||||
|
||||
int c1 = 1;
|
||||
float p1;
|
||||
|
||||
float time;
|
||||
float dist;
|
||||
|
||||
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
|
||||
|
||||
// if precision for 1 run down the tree is already
|
||||
// better then some of the requested precisions, then
|
||||
// skip those
|
||||
while (precisions[pindex]<p2 && pindex<precisions_length) {
|
||||
pindex++;
|
||||
}
|
||||
|
||||
if (pindex==precisions_length) {
|
||||
logger.info("Got as close as I can\n");
|
||||
return time;
|
||||
}
|
||||
|
||||
for (int i=pindex;i<precisions_length;++i) {
|
||||
|
||||
precision = precisions[i];
|
||||
while (p2<precision) {
|
||||
c1 = c2;
|
||||
p1 = p2;
|
||||
c2 *=2;
|
||||
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
|
||||
if (maxTime> 0 && time > maxTime && p2<precision) return time;
|
||||
}
|
||||
|
||||
int cx;
|
||||
float realPrecision;
|
||||
if (fabs(p2-precision)>SEARCH_EPS) {
|
||||
logger.info("Start linear estimation\n");
|
||||
// after we got to values in the vecinity of the desired precision
|
||||
// use linear approximation get a better estimation
|
||||
|
||||
cx = (c1+c2)/2;
|
||||
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
|
||||
while (fabs(realPrecision-precision)>SEARCH_EPS) {
|
||||
|
||||
if (realPrecision<precision) {
|
||||
c1 = cx;
|
||||
}
|
||||
else {
|
||||
c2 = cx;
|
||||
}
|
||||
cx = (c1+c2)/2;
|
||||
if (cx==c1) {
|
||||
logger.info("Got as close as I can\n");
|
||||
break;
|
||||
}
|
||||
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
|
||||
}
|
||||
|
||||
c2 = cx;
|
||||
p2 = realPrecision;
|
||||
|
||||
} else {
|
||||
logger.info("No need for linear estimation\n");
|
||||
cx = c2;
|
||||
realPrecision = p2;
|
||||
}
|
||||
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //TESTING_H
|
622
modules/flann/include/opencv2/flann/kdtree_index.h
Normal file
622
modules/flann/include/opencv2/flann/kdtree_index.h
Normal file
@@ -0,0 +1,622 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef KDTREE_H
|
||||
#define KDTREE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
#include "opencv2/flann/nn_index.h"
|
||||
#include "opencv2/flann/matrix.h"
|
||||
#include "opencv2/flann/result_set.h"
|
||||
#include "opencv2/flann/heap.h"
|
||||
#include "opencv2/flann/allocator.h"
|
||||
#include "opencv2/flann/random.h"
|
||||
#include "opencv2/flann/saving.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
struct KDTreeIndexParams : public IndexParams {
|
||||
KDTreeIndexParams(int trees_ = 4) : IndexParams(KDTREE), trees(trees_) {};
|
||||
|
||||
int trees; // number of randomized trees to use (for kdtree)
|
||||
|
||||
flann_algorithm_t getIndexType() const { return algorithm; }
|
||||
|
||||
void print() const
|
||||
{
|
||||
logger.info("Index type: %d\n",(int)algorithm);
|
||||
logger.info("Trees: %d\n", trees);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Randomized kd-tree index
|
||||
*
|
||||
* Contains the k-d trees and other information for indexing a set of points
|
||||
* for nearest-neighbor matching.
|
||||
*/
|
||||
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
|
||||
class KDTreeIndex : public NNIndex<ELEM_TYPE>
|
||||
{
|
||||
|
||||
enum {
|
||||
/**
|
||||
* To improve efficiency, only SAMPLE_MEAN random values are used to
|
||||
* compute the mean and variance at each level when building a tree.
|
||||
* A value of 100 seems to perform as well as using all values.
|
||||
*/
|
||||
SAMPLE_MEAN = 100,
|
||||
/**
|
||||
* Top random dimensions to consider
|
||||
*
|
||||
* When creating random trees, the dimension on which to subdivide is
|
||||
* selected at random from among the top RAND_DIM dimensions with the
|
||||
* highest variance. A value of 5 works well.
|
||||
*/
|
||||
RAND_DIM=5
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Number of randomized trees that are used
|
||||
*/
|
||||
int numTrees;
|
||||
|
||||
/**
|
||||
* Array of indices to vectors in the dataset.
|
||||
*/
|
||||
int* vind;
|
||||
|
||||
|
||||
/**
|
||||
* The dataset used by this index
|
||||
*/
|
||||
const Matrix<ELEM_TYPE> dataset;
|
||||
|
||||
const IndexParams& index_params;
|
||||
|
||||
size_t size_;
|
||||
size_t veclen_;
|
||||
|
||||
|
||||
DIST_TYPE* mean;
|
||||
DIST_TYPE* var;
|
||||
|
||||
|
||||
/*--------------------- Internal Data Structures --------------------------*/
|
||||
|
||||
/**
|
||||
* A node of the binary k-d tree.
|
||||
*
|
||||
* This is All nodes that have vec[divfeat] < divval are placed in the
|
||||
* child1 subtree, else child2., A leaf node is indicated if both children are NULL.
|
||||
*/
|
||||
struct TreeSt {
|
||||
/**
|
||||
* Index of the vector feature used for subdivision.
|
||||
* If this is a leaf node (both children are NULL) then
|
||||
* this holds vector index for this leaf.
|
||||
*/
|
||||
int divfeat;
|
||||
/**
|
||||
* The value used for subdivision.
|
||||
*/
|
||||
DIST_TYPE divval;
|
||||
/**
|
||||
* The child nodes.
|
||||
*/
|
||||
TreeSt *child1, *child2;
|
||||
};
|
||||
typedef TreeSt* Tree;
|
||||
|
||||
/**
|
||||
* Array of k-d trees used to find neighbours.
|
||||
*/
|
||||
Tree* trees;
|
||||
typedef BranchStruct<Tree> BranchSt;
|
||||
typedef BranchSt* Branch;
|
||||
|
||||
/**
|
||||
* Pooled memory allocator.
|
||||
*
|
||||
* Using a pooled memory allocator is more efficient
|
||||
* than allocating memory directly when there is a large
|
||||
* number small of memory allocations.
|
||||
*/
|
||||
PooledAllocator pool;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
flann_algorithm_t getType() const
|
||||
{
|
||||
return KDTREE;
|
||||
}
|
||||
|
||||
/**
|
||||
* KDTree constructor
|
||||
*
|
||||
* Params:
|
||||
* inputData = dataset with the input features
|
||||
* params = parameters passed to the kdtree algorithm
|
||||
*/
|
||||
KDTreeIndex(const Matrix<ELEM_TYPE>& inputData, const KDTreeIndexParams& params = KDTreeIndexParams() ) :
|
||||
dataset(inputData), index_params(params)
|
||||
{
|
||||
size_ = dataset.rows;
|
||||
veclen_ = dataset.cols;
|
||||
|
||||
numTrees = params.trees;
|
||||
trees = new Tree[numTrees];
|
||||
|
||||
// get the parameters
|
||||
// if (params.find("trees") != params.end()) {
|
||||
// numTrees = (int)params["trees"];
|
||||
// trees = new Tree[numTrees];
|
||||
// }
|
||||
// else {
|
||||
// numTrees = -1;
|
||||
// trees = NULL;
|
||||
// }
|
||||
|
||||
// Create a permutable array of indices to the input vectors.
|
||||
vind = new int[size_];
|
||||
for (size_t i = 0; i < size_; i++) {
|
||||
vind[i] = i;
|
||||
}
|
||||
|
||||
mean = new DIST_TYPE[veclen_];
|
||||
var = new DIST_TYPE[veclen_];
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard destructor
|
||||
*/
|
||||
~KDTreeIndex()
|
||||
{
|
||||
delete[] vind;
|
||||
if (trees!=NULL) {
|
||||
delete[] trees;
|
||||
}
|
||||
delete[] mean;
|
||||
delete[] var;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the index
|
||||
*/
|
||||
void buildIndex()
|
||||
{
|
||||
/* Construct the randomized trees. */
|
||||
for (int i = 0; i < numTrees; i++) {
|
||||
/* Randomize the order of vectors to allow for unbiased sampling. */
|
||||
for (int j = size_; j > 0; --j) {
|
||||
int rnd = rand_int(j);
|
||||
swap(vind[j-1], vind[rnd]);
|
||||
}
|
||||
trees[i] = divideTree(0, size_ - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void saveIndex(FILE* stream)
|
||||
{
|
||||
save_value(stream, numTrees);
|
||||
for (int i=0;i<numTrees;++i) {
|
||||
save_tree(stream, trees[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loadIndex(FILE* stream)
|
||||
{
|
||||
load_value(stream, numTrees);
|
||||
|
||||
if (trees!=NULL) {
|
||||
delete[] trees;
|
||||
}
|
||||
trees = new Tree[numTrees];
|
||||
for (int i=0;i<numTrees;++i) {
|
||||
load_tree(stream,trees[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns size of index.
|
||||
*/
|
||||
size_t size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of an index feature.
|
||||
*/
|
||||
size_t veclen() const
|
||||
{
|
||||
return veclen_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Computes the inde memory usage
|
||||
* Returns: memory used by the index
|
||||
*/
|
||||
int usedMemory() const
|
||||
{
|
||||
return pool.usedMemory+pool.wastedMemory+dataset.rows*sizeof(int); // pool memory and vind array memory
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find set of nearest neighbors to vec. Their indices are stored inside
|
||||
* the result object.
|
||||
*
|
||||
* Params:
|
||||
* result = the result object in which the indices of the nearest-neighbors are stored
|
||||
* vec = the vector for which to search the nearest neighbors
|
||||
* maxCheck = the maximum number of restarts (in a best-bin-first manner)
|
||||
*/
|
||||
void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams)
|
||||
{
|
||||
int maxChecks = searchParams.checks;
|
||||
|
||||
if (maxChecks<0) {
|
||||
getExactNeighbors(result, vec);
|
||||
} else {
|
||||
getNeighbors(result, vec, maxChecks);
|
||||
}
|
||||
}
|
||||
|
||||
const IndexParams* getParameters() const
|
||||
{
|
||||
return &index_params;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void save_tree(FILE* stream, Tree tree)
|
||||
{
|
||||
save_value(stream, *tree);
|
||||
if (tree->child1!=NULL) {
|
||||
save_tree(stream, tree->child1);
|
||||
}
|
||||
if (tree->child2!=NULL) {
|
||||
save_tree(stream, tree->child2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void load_tree(FILE* stream, Tree& tree)
|
||||
{
|
||||
tree = pool.allocate<TreeSt>();
|
||||
load_value(stream, *tree);
|
||||
if (tree->child1!=NULL) {
|
||||
load_tree(stream, tree->child1);
|
||||
}
|
||||
if (tree->child2!=NULL) {
|
||||
load_tree(stream, tree->child2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a tree node that subdivides the list of vecs from vind[first]
|
||||
* to vind[last]. The routine is called recursively on each sublist.
|
||||
* Place a pointer to this new tree node in the location pTree.
|
||||
*
|
||||
* Params: pTree = the new node to create
|
||||
* first = index of the first vector
|
||||
* last = index of the last vector
|
||||
*/
|
||||
Tree divideTree(int first, int last)
|
||||
{
|
||||
Tree node = pool.allocate<TreeSt>(); // allocate memory
|
||||
|
||||
/* If only one exemplar remains, then make this a leaf node. */
|
||||
if (first == last) {
|
||||
node->child1 = node->child2 = NULL; /* Mark as leaf node. */
|
||||
node->divfeat = vind[first]; /* Store index of this vec. */
|
||||
}
|
||||
else {
|
||||
chooseDivision(node, first, last);
|
||||
subdivide(node, first, last);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Choose which feature to use in order to subdivide this set of vectors.
|
||||
* Make a random choice among those with the highest variance, and use
|
||||
* its variance as the threshold value.
|
||||
*/
|
||||
void chooseDivision(Tree node, int first, int last)
|
||||
{
|
||||
memset(mean,0,veclen_*sizeof(DIST_TYPE));
|
||||
memset(var,0,veclen_*sizeof(DIST_TYPE));
|
||||
|
||||
/* Compute mean values. Only the first SAMPLE_MEAN values need to be
|
||||
sampled to get a good estimate.
|
||||
*/
|
||||
int end = min(first + SAMPLE_MEAN, last);
|
||||
for (int j = first; j <= end; ++j) {
|
||||
ELEM_TYPE* v = dataset[vind[j]];
|
||||
for (size_t k=0; k<veclen_; ++k) {
|
||||
mean[k] += v[k];
|
||||
}
|
||||
}
|
||||
for (size_t k=0; k<veclen_; ++k) {
|
||||
mean[k] /= (end - first + 1);
|
||||
}
|
||||
|
||||
/* Compute variances (no need to divide by count). */
|
||||
for (int j = first; j <= end; ++j) {
|
||||
ELEM_TYPE* v = dataset[vind[j]];
|
||||
for (size_t k=0; k<veclen_; ++k) {
|
||||
DIST_TYPE dist = v[k] - mean[k];
|
||||
var[k] += dist * dist;
|
||||
}
|
||||
}
|
||||
/* Select one of the highest variance indices at random. */
|
||||
node->divfeat = selectDivision(var);
|
||||
node->divval = mean[node->divfeat];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Select the top RAND_DIM largest values from v and return the index of
|
||||
* one of these selected at random.
|
||||
*/
|
||||
int selectDivision(DIST_TYPE* v)
|
||||
{
|
||||
int num = 0;
|
||||
int topind[RAND_DIM];
|
||||
|
||||
/* Create a list of the indices of the top RAND_DIM values. */
|
||||
for (size_t i = 0; i < veclen_; ++i) {
|
||||
if (num < RAND_DIM || v[i] > v[topind[num-1]]) {
|
||||
/* Put this element at end of topind. */
|
||||
if (num < RAND_DIM) {
|
||||
topind[num++] = i; /* Add to list. */
|
||||
}
|
||||
else {
|
||||
topind[num-1] = i; /* Replace last element. */
|
||||
}
|
||||
/* Bubble end value down to right location by repeated swapping. */
|
||||
int j = num - 1;
|
||||
while (j > 0 && v[topind[j]] > v[topind[j-1]]) {
|
||||
swap(topind[j], topind[j-1]);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Select a random integer in range [0,num-1], and return that index. */
|
||||
int rnd = rand_int(num);
|
||||
return topind[rnd];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subdivide the list of exemplars using the feature and division
|
||||
* value given in this node. Call divideTree recursively on each list.
|
||||
*/
|
||||
void subdivide(Tree node, int first, int last)
|
||||
{
|
||||
/* Move vector indices for left subtree to front of list. */
|
||||
int i = first;
|
||||
int j = last;
|
||||
while (i <= j) {
|
||||
int ind = vind[i];
|
||||
ELEM_TYPE val = dataset[ind][node->divfeat];
|
||||
if (val < node->divval) {
|
||||
++i;
|
||||
} else {
|
||||
/* Move to end of list by swapping vind i and j. */
|
||||
swap(vind[i], vind[j]);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
/* If either list is empty, it means we have hit the unlikely case
|
||||
in which all remaining features are identical. Split in the middle
|
||||
to maintain a balanced tree.
|
||||
*/
|
||||
if ( (i == first) || (i == last+1)) {
|
||||
i = (first+last+1)/2;
|
||||
}
|
||||
|
||||
node->child1 = divideTree(first, i - 1);
|
||||
node->child2 = divideTree(i, last);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs an exact nearest neighbor search. The exact search performs a full
|
||||
* traversal of the tree.
|
||||
*/
|
||||
void getExactNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec)
|
||||
{
|
||||
// checkID -= 1; /* Set a different unique ID for each search. */
|
||||
|
||||
if (numTrees > 1) {
|
||||
fprintf(stderr,"It doesn't make any sense to use more than one tree for exact search");
|
||||
}
|
||||
if (numTrees>0) {
|
||||
searchLevelExact(result, vec, trees[0], 0.0);
|
||||
}
|
||||
assert(result.full());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the approximate nearest-neighbor search. The search is approximate
|
||||
* because the tree traversal is abandoned after a given number of descends in
|
||||
* the tree.
|
||||
*/
|
||||
void getNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, int maxCheck)
|
||||
{
|
||||
int i;
|
||||
BranchSt branch;
|
||||
|
||||
int checkCount = 0;
|
||||
Heap<BranchSt>* heap = new Heap<BranchSt>(size_);
|
||||
vector<bool> checked(size_,false);
|
||||
|
||||
/* Search once through each tree down to root. */
|
||||
for (i = 0; i < numTrees; ++i) {
|
||||
searchLevel(result, vec, trees[i], 0.0, checkCount, maxCheck, heap, checked);
|
||||
}
|
||||
|
||||
/* Keep searching other branches from heap until finished. */
|
||||
while ( heap->popMin(branch) && (checkCount < maxCheck || !result.full() )) {
|
||||
searchLevel(result, vec, branch.node, branch.mindistsq, checkCount, maxCheck, heap, checked);
|
||||
}
|
||||
|
||||
delete heap;
|
||||
|
||||
assert(result.full());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search starting from a given node of the tree. Based on any mismatches at
|
||||
* higher levels, all exemplars below this level must have a distance of
|
||||
* at least "mindistsq".
|
||||
*/
|
||||
void searchLevel(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, Tree node, float mindistsq, int& checkCount, int maxCheck,
|
||||
Heap<BranchSt>* heap, vector<bool>& checked)
|
||||
{
|
||||
if (result.worstDist()<mindistsq) {
|
||||
// printf("Ignoring branch, too far\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this is a leaf node, then do check and return. */
|
||||
if (node->child1 == NULL && node->child2 == NULL) {
|
||||
|
||||
/* Do not check same node more than once when searching multiple trees.
|
||||
Once a vector is checked, we set its location in vind to the
|
||||
current checkID.
|
||||
*/
|
||||
if (checked[node->divfeat] == true || checkCount>=maxCheck) {
|
||||
if (result.full()) return;
|
||||
}
|
||||
checkCount++;
|
||||
checked[node->divfeat] = true;
|
||||
|
||||
result.addPoint(dataset[node->divfeat],node->divfeat);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Which child branch should be taken first? */
|
||||
ELEM_TYPE val = vec[node->divfeat];
|
||||
DIST_TYPE diff = val - node->divval;
|
||||
Tree bestChild = (diff < 0) ? node->child1 : node->child2;
|
||||
Tree otherChild = (diff < 0) ? node->child2 : node->child1;
|
||||
|
||||
/* Create a branch record for the branch not taken. Add distance
|
||||
of this feature boundary (we don't attempt to correct for any
|
||||
use of this feature in a parent node, which is unlikely to
|
||||
happen and would have only a small effect). Don't bother
|
||||
adding more branches to heap after halfway point, as cost of
|
||||
adding exceeds their value.
|
||||
*/
|
||||
|
||||
DIST_TYPE new_distsq = flann_dist(&val, &val+1, &node->divval, mindistsq);
|
||||
// if (2 * checkCount < maxCheck || !result.full()) {
|
||||
if (new_distsq < result.worstDist() || !result.full()) {
|
||||
heap->insert( BranchSt::make_branch(otherChild, new_distsq) );
|
||||
}
|
||||
|
||||
/* Call recursively to search next level down. */
|
||||
searchLevel(result, vec, bestChild, mindistsq, checkCount, maxCheck, heap, checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an exact search in the tree starting from a node.
|
||||
*/
|
||||
void searchLevelExact(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, Tree node, float mindistsq)
|
||||
{
|
||||
if (mindistsq>result.worstDist()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this is a leaf node, then do check and return. */
|
||||
if (node->child1 == NULL && node->child2 == NULL) {
|
||||
|
||||
/* Do not check same node more than once when searching multiple trees.
|
||||
Once a vector is checked, we set its location in vind to the
|
||||
current checkID.
|
||||
*/
|
||||
// if (vind[node->divfeat] == checkID)
|
||||
// return;
|
||||
// vind[node->divfeat] = checkID;
|
||||
|
||||
result.addPoint(dataset[node->divfeat],node->divfeat);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Which child branch should be taken first? */
|
||||
ELEM_TYPE val = vec[node->divfeat];
|
||||
DIST_TYPE diff = val - node->divval;
|
||||
Tree bestChild = (diff < 0) ? node->child1 : node->child2;
|
||||
Tree otherChild = (diff < 0) ? node->child2 : node->child1;
|
||||
|
||||
|
||||
/* Call recursively to search next level down. */
|
||||
searchLevelExact(result, vec, bestChild, mindistsq);
|
||||
DIST_TYPE new_distsq = flann_dist(&val, &val+1, &node->divval, mindistsq);
|
||||
searchLevelExact(result, vec, otherChild, new_distsq);
|
||||
}
|
||||
|
||||
}; // class KDTree
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //KDTREE_H
|
1117
modules/flann/include/opencv2/flann/kmeans_index.h
Normal file
1117
modules/flann/include/opencv2/flann/kmeans_index.h
Normal file
File diff suppressed because it is too large
Load Diff
120
modules/flann/include/opencv2/flann/linear_index.h
Normal file
120
modules/flann/include/opencv2/flann/linear_index.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef LINEARSEARCH_H
|
||||
#define LINEARSEARCH_H
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
#include "opencv2/flann/nn_index.h"
|
||||
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
struct LinearIndexParams : public IndexParams {
|
||||
LinearIndexParams() : IndexParams(LINEAR) {};
|
||||
|
||||
flann_algorithm_t getIndexType() const { return algorithm; }
|
||||
|
||||
void print() const
|
||||
{
|
||||
logger.info("Index type: %d\n",(int)algorithm);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
|
||||
class LinearIndex : public NNIndex<ELEM_TYPE>
|
||||
{
|
||||
const Matrix<ELEM_TYPE> dataset;
|
||||
const LinearIndexParams& index_params;
|
||||
|
||||
public:
|
||||
|
||||
LinearIndex(const Matrix<ELEM_TYPE>& inputData, const LinearIndexParams& params = LinearIndexParams() ) :
|
||||
dataset(inputData), index_params(params)
|
||||
{
|
||||
}
|
||||
|
||||
flann_algorithm_t getType() const
|
||||
{
|
||||
return LINEAR;
|
||||
}
|
||||
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return dataset.rows;
|
||||
}
|
||||
|
||||
size_t veclen() const
|
||||
{
|
||||
return dataset.cols;
|
||||
}
|
||||
|
||||
|
||||
int usedMemory() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void buildIndex()
|
||||
{
|
||||
/* nothing to do here for linear search */
|
||||
}
|
||||
|
||||
void saveIndex(FILE* stream)
|
||||
{
|
||||
/* nothing to do here for linear search */
|
||||
}
|
||||
|
||||
|
||||
void loadIndex(FILE* stream)
|
||||
{
|
||||
/* nothing to do here for linear search */
|
||||
}
|
||||
|
||||
void findNeighbors(ResultSet<ELEM_TYPE>& resultSet, const ELEM_TYPE* vec, const SearchParams& searchParams)
|
||||
{
|
||||
for (size_t i=0;i<dataset.rows;++i) {
|
||||
resultSet.addPoint(dataset[i],i);
|
||||
}
|
||||
}
|
||||
|
||||
const IndexParams* getParameters() const
|
||||
{
|
||||
return &index_params;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif // LINEARSEARCH_H
|
91
modules/flann/include/opencv2/flann/logger.h
Normal file
91
modules/flann/include/opencv2/flann/logger.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include "opencv2/flann/general.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
class Logger
|
||||
{
|
||||
FILE* stream;
|
||||
int logLevel;
|
||||
|
||||
public:
|
||||
|
||||
Logger() : stream(stdout), logLevel(LOG_WARN) {};
|
||||
|
||||
~Logger()
|
||||
{
|
||||
if (stream!=NULL && stream!=stdout) {
|
||||
fclose(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void setDestination(const char* name)
|
||||
{
|
||||
if (name==NULL) {
|
||||
stream = stdout;
|
||||
}
|
||||
else {
|
||||
stream = fopen(name,"w");
|
||||
if (stream == NULL) {
|
||||
stream = stdout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setLevel(int level) { logLevel = level; }
|
||||
|
||||
int log(int level, const char* fmt, ...);
|
||||
|
||||
int log(int level, const char* fmt, va_list arglist);
|
||||
|
||||
int fatal(const char* fmt, ...);
|
||||
|
||||
int error(const char* fmt, ...);
|
||||
|
||||
int warn(const char* fmt, ...);
|
||||
|
||||
int info(const char* fmt, ...);
|
||||
};
|
||||
|
||||
extern Logger logger;
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //LOGGER_H
|
118
modules/flann/include/opencv2/flann/matrix.h
Normal file
118
modules/flann/include/opencv2/flann/matrix.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef DATASET_H
|
||||
#define DATASET_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/**
|
||||
* Class that implements a simple rectangular matrix stored in a memory buffer and
|
||||
* provides convenient matrix-like access using the [] operators.
|
||||
*/
|
||||
template <typename T>
|
||||
class Matrix {
|
||||
public:
|
||||
size_t rows;
|
||||
size_t cols;
|
||||
T* data;
|
||||
|
||||
Matrix() : rows(0), cols(0), data(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Matrix(T* data_, long rows_, long cols_) :
|
||||
rows(rows_), cols(cols_), data(data_)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for deallocating the storage data.
|
||||
*/
|
||||
void free()
|
||||
{
|
||||
if (data!=NULL) delete[] data;
|
||||
}
|
||||
|
||||
~Matrix()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator that return a (pointer to a) row of the data.
|
||||
*/
|
||||
T* operator[](size_t index)
|
||||
{
|
||||
return data+index*cols;
|
||||
}
|
||||
|
||||
T* operator[](size_t index) const
|
||||
{
|
||||
return data+index*cols;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class UntypedMatrix
|
||||
{
|
||||
public:
|
||||
size_t rows;
|
||||
size_t cols;
|
||||
void* data;
|
||||
flann_datatype_t type;
|
||||
|
||||
UntypedMatrix(void* data_, long rows_, long cols_) :
|
||||
rows(rows_), cols(cols_), data(data_)
|
||||
{
|
||||
}
|
||||
|
||||
~UntypedMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
Matrix<T> as()
|
||||
{
|
||||
return Matrix<T>((T*)data, rows, cols);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //DATASET_H
|
108
modules/flann/include/opencv2/flann/nn_index.h
Normal file
108
modules/flann/include/opencv2/flann/nn_index.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef NNINDEX_H
|
||||
#define NNINDEX_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
#include "opencv2/flann/matrix.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
class ResultSet;
|
||||
|
||||
/**
|
||||
* Nearest-neighbour index base class
|
||||
*/
|
||||
template <typename ELEM_TYPE>
|
||||
class NNIndex
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~NNIndex() {};
|
||||
|
||||
/**
|
||||
Method responsible with building the index.
|
||||
*/
|
||||
virtual void buildIndex() = 0;
|
||||
|
||||
/**
|
||||
Saves the index to a stream
|
||||
*/
|
||||
virtual void saveIndex(FILE* stream) = 0;
|
||||
|
||||
/**
|
||||
Loads the index from a stream
|
||||
*/
|
||||
virtual void loadIndex(FILE* stream) = 0;
|
||||
|
||||
/**
|
||||
Method that searches for nearest-neighbors
|
||||
*/
|
||||
virtual void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams) = 0;
|
||||
|
||||
/**
|
||||
Number of features in this index.
|
||||
*/
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
/**
|
||||
The length of each vector in this index.
|
||||
*/
|
||||
virtual size_t veclen() const = 0;
|
||||
|
||||
/**
|
||||
The amount of memory (in bytes) this index uses.
|
||||
*/
|
||||
virtual int usedMemory() const = 0;
|
||||
|
||||
/**
|
||||
* Algorithm name
|
||||
*/
|
||||
virtual flann_algorithm_t getType() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the parameters used for the index
|
||||
*/
|
||||
virtual const IndexParams* getParameters() const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //NNINDEX_H
|
93
modules/flann/include/opencv2/flann/object_factory.h
Normal file
93
modules/flann/include/opencv2/flann/object_factory.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef OBJECT_FACTORY_H_
|
||||
#define OBJECT_FACTORY_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
template<typename BaseClass, typename DerivedClass>
|
||||
BaseClass* createObject()
|
||||
{
|
||||
return new DerivedClass();
|
||||
}
|
||||
|
||||
template<typename BaseClass, typename UniqueIdType>
|
||||
class ObjectFactory
|
||||
{
|
||||
typedef BaseClass* (*CreateObjectFunc)();
|
||||
std::map<UniqueIdType, CreateObjectFunc> object_registry;
|
||||
|
||||
// singleton class, private constructor
|
||||
ObjectFactory() {};
|
||||
|
||||
public:
|
||||
typedef typename std::map<UniqueIdType, CreateObjectFunc>::iterator Iterator;
|
||||
|
||||
|
||||
template<typename DerivedClass>
|
||||
bool register_(UniqueIdType id)
|
||||
{
|
||||
if (object_registry.find(id) != object_registry.end())
|
||||
return false;
|
||||
|
||||
object_registry[id] = &createObject<BaseClass, DerivedClass>;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unregister(UniqueIdType id)
|
||||
{
|
||||
return (object_registry.erase(id) == 1);
|
||||
}
|
||||
|
||||
BaseClass* create(UniqueIdType id)
|
||||
{
|
||||
Iterator iter = object_registry.find(id);
|
||||
|
||||
if (iter == object_registry.end())
|
||||
return NULL;
|
||||
|
||||
return ((*iter).second)();
|
||||
}
|
||||
|
||||
static ObjectFactory<BaseClass,UniqueIdType>& instance()
|
||||
{
|
||||
static ObjectFactory<BaseClass,UniqueIdType> the_factory;
|
||||
return the_factory;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif /* OBJECT_FACTORY_H_ */
|
134
modules/flann/include/opencv2/flann/random.h
Normal file
134
modules/flann/include/opencv2/flann/random.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef RANDOM_H
|
||||
#define RANDOM_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/**
|
||||
* Seeds the random number generator
|
||||
*/
|
||||
void seed_random(unsigned int seed);
|
||||
|
||||
/*
|
||||
* Generates a random double value.
|
||||
*/
|
||||
double rand_double(double high = 1.0, double low=0);
|
||||
|
||||
/*
|
||||
* Generates a random integer value.
|
||||
*/
|
||||
int rand_int(int high = RAND_MAX, int low = 0);
|
||||
|
||||
|
||||
/**
|
||||
* Random number generator that returns a distinct number from
|
||||
* the [0,n) interval each time.
|
||||
*
|
||||
* TODO: improve on this to use a generator function instead of an
|
||||
* array of randomly permuted numbers
|
||||
*/
|
||||
class UniqueRandom
|
||||
{
|
||||
int* vals;
|
||||
int size;
|
||||
int counter;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* Params:
|
||||
* n = the size of the interval from which to generate
|
||||
* random numbers.
|
||||
*/
|
||||
UniqueRandom(int n) : vals(NULL) {
|
||||
init(n);
|
||||
}
|
||||
|
||||
~UniqueRandom()
|
||||
{
|
||||
delete[] vals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the number generator.
|
||||
* Params:
|
||||
* n = the size of the interval from which to generate
|
||||
* random numbers.
|
||||
*/
|
||||
void init(int n)
|
||||
{
|
||||
// create and initialize an array of size n
|
||||
if (vals == NULL || n!=size) {
|
||||
delete[] vals;
|
||||
size = n;
|
||||
vals = new int[size];
|
||||
}
|
||||
for(int i=0;i<size;++i) {
|
||||
vals[i] = i;
|
||||
}
|
||||
|
||||
// shuffle the elements in the array
|
||||
// Fisher-Yates shuffle
|
||||
for (int i=size;i>0;--i) {
|
||||
// int rand = cast(int) (drand48() * n);
|
||||
int rnd = rand_int(i);
|
||||
assert(rnd >=0 && rnd < i);
|
||||
swap(vals[i-1], vals[rnd]);
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a distinct random integer in greater or equal to 0 and less
|
||||
* than 'n' on each call. It should be called maximum 'n' times.
|
||||
* Returns: a random integer
|
||||
*/
|
||||
int next() {
|
||||
if (counter==size) {
|
||||
return -1;
|
||||
} else {
|
||||
return vals[counter++];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //RANDOM_H
|
320
modules/flann/include/opencv2/flann/result_set.h
Normal file
320
modules/flann/include/opencv2/flann/result_set.h
Normal file
@@ -0,0 +1,320 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef RESULTSET_H
|
||||
#define RESULTSET_H
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include "opencv2/flann/dist.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/* This record represents a branch point when finding neighbors in
|
||||
the tree. It contains a record of the minimum distance to the query
|
||||
point, as well as the node at which the search resumes.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct BranchStruct {
|
||||
T node; /* Tree node at which search resumes */
|
||||
float mindistsq; /* Minimum distance to query for all nodes below. */
|
||||
|
||||
bool operator<(const BranchStruct<T>& rhs)
|
||||
{
|
||||
return mindistsq<rhs.mindistsq;
|
||||
}
|
||||
|
||||
static BranchStruct<T> make_branch(const T& aNode, float dist)
|
||||
{
|
||||
BranchStruct<T> branch;
|
||||
branch.node = aNode;
|
||||
branch.mindistsq = dist;
|
||||
return branch;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
class ResultSet
|
||||
{
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
virtual ~ResultSet() {};
|
||||
|
||||
virtual void init(const ELEM_TYPE* target_, int veclen_) = 0;
|
||||
|
||||
virtual int* getNeighbors() = 0;
|
||||
|
||||
virtual float* getDistances() = 0;
|
||||
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
virtual bool full() const = 0;
|
||||
|
||||
virtual bool addPoint(const ELEM_TYPE* point, int index) = 0;
|
||||
|
||||
virtual float worstDist() const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename ELEM_TYPE>
|
||||
class KNNResultSet : public ResultSet<ELEM_TYPE>
|
||||
{
|
||||
const ELEM_TYPE* target;
|
||||
const ELEM_TYPE* target_end;
|
||||
int veclen;
|
||||
|
||||
int* indices;
|
||||
float* dists;
|
||||
int capacity;
|
||||
|
||||
int count;
|
||||
|
||||
public:
|
||||
KNNResultSet(int capacity_, ELEM_TYPE* target_ = NULL, int veclen_ = 0 ) :
|
||||
target(target_), veclen(veclen_), capacity(capacity_), count(0)
|
||||
{
|
||||
target_end = target + veclen;
|
||||
|
||||
indices = new int[capacity_];
|
||||
dists = new float[capacity_];
|
||||
}
|
||||
|
||||
~KNNResultSet()
|
||||
{
|
||||
delete[] indices;
|
||||
delete[] dists;
|
||||
}
|
||||
|
||||
void init(const ELEM_TYPE* target_, int veclen_)
|
||||
{
|
||||
target = target_;
|
||||
veclen = veclen_;
|
||||
target_end = target + veclen;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
|
||||
int* getNeighbors()
|
||||
{
|
||||
return indices;
|
||||
}
|
||||
|
||||
float* getDistances()
|
||||
{
|
||||
return dists;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
bool full() const
|
||||
{
|
||||
return count == capacity;
|
||||
}
|
||||
|
||||
|
||||
bool addPoint(const ELEM_TYPE* point, int index)
|
||||
{
|
||||
for (int i=0;i<count;++i) {
|
||||
if (indices[i]==index) return false;
|
||||
}
|
||||
float dist = flann_dist(target, target_end, point);
|
||||
|
||||
if (count<capacity) {
|
||||
indices[count] = index;
|
||||
dists[count] = dist;
|
||||
++count;
|
||||
}
|
||||
else if (dist < dists[count-1] || (dist == dists[count-1] && index < indices[count-1])) {
|
||||
// else if (dist < dists[count-1]) {
|
||||
indices[count-1] = index;
|
||||
dists[count-1] = dist;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = count-1;
|
||||
// bubble up
|
||||
while (i>=1 && (dists[i]<dists[i-1] || (dists[i]==dists[i-1] && indices[i]<indices[i-1]) ) ) {
|
||||
// while (i>=1 && (dists[i]<dists[i-1]) ) {
|
||||
swap(indices[i],indices[i-1]);
|
||||
swap(dists[i],dists[i-1]);
|
||||
i--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float worstDist() const
|
||||
{
|
||||
return (count<capacity) ? numeric_limits<float>::max() : dists[count-1];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A result-set class used when performing a radius based search.
|
||||
*/
|
||||
template <typename ELEM_TYPE>
|
||||
class RadiusResultSet : public ResultSet<ELEM_TYPE>
|
||||
{
|
||||
const ELEM_TYPE* target;
|
||||
const ELEM_TYPE* target_end;
|
||||
int veclen;
|
||||
|
||||
struct Item {
|
||||
int index;
|
||||
float dist;
|
||||
|
||||
bool operator<(Item rhs) {
|
||||
return dist<rhs.dist;
|
||||
}
|
||||
};
|
||||
|
||||
vector<Item> items;
|
||||
float radius;
|
||||
|
||||
bool sorted;
|
||||
int* indices;
|
||||
float* dists;
|
||||
size_t count;
|
||||
|
||||
private:
|
||||
void resize_vecs()
|
||||
{
|
||||
if (items.size()>count) {
|
||||
if (indices!=NULL) delete[] indices;
|
||||
if (dists!=NULL) delete[] dists;
|
||||
count = items.size();
|
||||
indices = new int[count];
|
||||
dists = new float[count];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
RadiusResultSet(float radius_) :
|
||||
radius(radius_), indices(NULL), dists(NULL)
|
||||
{
|
||||
sorted = false;
|
||||
items.reserve(16);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
~RadiusResultSet()
|
||||
{
|
||||
if (indices!=NULL) delete[] indices;
|
||||
if (dists!=NULL) delete[] dists;
|
||||
}
|
||||
|
||||
void init(const ELEM_TYPE* target_, int veclen_)
|
||||
{
|
||||
target = target_;
|
||||
veclen = veclen_;
|
||||
target_end = target + veclen;
|
||||
items.clear();
|
||||
sorted = false;
|
||||
}
|
||||
|
||||
int* getNeighbors()
|
||||
{
|
||||
if (!sorted) {
|
||||
sorted = true;
|
||||
sort_heap(items.begin(), items.end());
|
||||
}
|
||||
resize_vecs();
|
||||
for (size_t i=0;i<items.size();++i) {
|
||||
indices[i] = items[i].index;
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
float* getDistances()
|
||||
{
|
||||
if (!sorted) {
|
||||
sorted = true;
|
||||
sort_heap(items.begin(), items.end());
|
||||
}
|
||||
resize_vecs();
|
||||
for (size_t i=0;i<items.size();++i) {
|
||||
dists[i] = items[i].dist;
|
||||
}
|
||||
return dists;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
|
||||
bool full() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addPoint(const ELEM_TYPE* point, int index)
|
||||
{
|
||||
Item it;
|
||||
it.index = index;
|
||||
it.dist = flann_dist(target, target_end, point);
|
||||
if (it.dist<=radius) {
|
||||
items.push_back(it);
|
||||
push_heap(items.begin(), items.end());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float worstDist() const
|
||||
{
|
||||
return radius;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //RESULTSET_H
|
94
modules/flann/include/opencv2/flann/sampling.h
Normal file
94
modules/flann/include/opencv2/flann/sampling.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
#ifndef SAMPLING_H_
|
||||
#define SAMPLING_H_
|
||||
|
||||
|
||||
#include "opencv2/flann/matrix.h"
|
||||
#include "opencv2/flann/random.h"
|
||||
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
Matrix<T> random_sample(Matrix<T>& srcMatrix, long size, bool remove = false)
|
||||
{
|
||||
UniqueRandom rand(srcMatrix.rows);
|
||||
Matrix<T> newSet(new T[size * srcMatrix.cols], size,srcMatrix.cols);
|
||||
|
||||
T *src,*dest;
|
||||
for (long i=0;i<size;++i) {
|
||||
long r = rand.next();
|
||||
dest = newSet[i];
|
||||
src = srcMatrix[r];
|
||||
for (size_t j=0;j<srcMatrix.cols;++j) {
|
||||
dest[j] = src[j];
|
||||
}
|
||||
if (remove) {
|
||||
dest = srcMatrix[srcMatrix.rows-i-1];
|
||||
src = srcMatrix[r];
|
||||
for (size_t j=0;j<srcMatrix.cols;++j) {
|
||||
swap(*src,*dest);
|
||||
src++;
|
||||
dest++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
srcMatrix.rows -= size;
|
||||
}
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Matrix<T> random_sample(const Matrix<T>& srcMatrix, size_t size)
|
||||
{
|
||||
UniqueRandom rand(srcMatrix.rows);
|
||||
Matrix<T> newSet(new T[size * srcMatrix.cols], size,srcMatrix.cols);
|
||||
|
||||
T *src,*dest;
|
||||
for (size_t i=0;i<size;++i) {
|
||||
long r = rand.next();
|
||||
dest = newSet[i];
|
||||
src = srcMatrix[r];
|
||||
for (size_t j=0;j<srcMatrix.cols;++j) {
|
||||
dest[j] = src[j];
|
||||
}
|
||||
}
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif /* SAMPLING_H_ */
|
115
modules/flann/include/opencv2/flann/saving.h
Normal file
115
modules/flann/include/opencv2/flann/saving.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE NNIndexGOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef SAVING_H_
|
||||
#define SAVING_H_
|
||||
|
||||
#include "opencv2/flann/general.h"
|
||||
#include "opencv2/flann/nn_index.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
template <typename T> struct Datatype {};
|
||||
template<> struct Datatype<char> { static flann_datatype_t type() { return INT8; } };
|
||||
template<> struct Datatype<short> { static flann_datatype_t type() { return INT16; } };
|
||||
template<> struct Datatype<int> { static flann_datatype_t type() { return INT32; } };
|
||||
template<> struct Datatype<unsigned char> { static flann_datatype_t type() { return UINT8; } };
|
||||
template<> struct Datatype<unsigned short> { static flann_datatype_t type() { return UINT16; } };
|
||||
template<> struct Datatype<unsigned int> { static flann_datatype_t type() { return UINT32; } };
|
||||
template<> struct Datatype<float> { static flann_datatype_t type() { return FLOAT32; } };
|
||||
template<> struct Datatype<double> { static flann_datatype_t type() { return FLOAT64; } };
|
||||
|
||||
|
||||
extern const char FLANN_SIGNATURE[];
|
||||
extern const char FLANN_VERSION[];
|
||||
|
||||
/**
|
||||
* Structure representing the index header.
|
||||
*/
|
||||
struct IndexHeader
|
||||
{
|
||||
char signature[16];
|
||||
char version[16];
|
||||
flann_datatype_t data_type;
|
||||
flann_algorithm_t index_type;
|
||||
int rows;
|
||||
int cols;
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves index header to stream
|
||||
*
|
||||
* @param stream - Stream to save to
|
||||
* @param index - The index to save
|
||||
*/
|
||||
template<typename ELEM_TYPE>
|
||||
void save_header(FILE* stream, const NNIndex<ELEM_TYPE>& index)
|
||||
{
|
||||
IndexHeader header;
|
||||
memset(header.signature, 0 , sizeof(header.signature));
|
||||
strcpy(header.signature, FLANN_SIGNATURE);
|
||||
memset(header.version, 0 , sizeof(header.version));
|
||||
strcpy(header.version, FLANN_VERSION);
|
||||
header.data_type = Datatype<ELEM_TYPE>::type();
|
||||
header.index_type = index.getType();
|
||||
header.rows = index.size();
|
||||
header.cols = index.veclen();
|
||||
|
||||
std::fwrite(&header, sizeof(header),1,stream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param stream - Stream to load from
|
||||
* @return Index header
|
||||
*/
|
||||
IndexHeader load_header(FILE* stream);
|
||||
|
||||
|
||||
template<typename T>
|
||||
void save_value(FILE* stream, const T& value, int count = 1)
|
||||
{
|
||||
fwrite(&value, sizeof(value),count, stream);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void load_value(FILE* stream, T& value, int count = 1)
|
||||
{
|
||||
int read_cnt = fread(&value, sizeof(value),count, stream);
|
||||
if (read_cnt!=count) {
|
||||
throw FLANNException("Cannot read from file");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif /* SAVING_H_ */
|
186
modules/flann/include/opencv2/flann/simplex_downhill.h
Normal file
186
modules/flann/include/opencv2/flann/simplex_downhill.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef SIMPLEX_DOWNHILL_H
|
||||
#define SIMPLEX_DOWNHILL_H
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/**
|
||||
Adds val to array vals (and point to array points) and keeping the arrays sorted by vals.
|
||||
*/
|
||||
template <typename T>
|
||||
void addValue(int pos, float val, float* vals, T* point, T* points, int n)
|
||||
{
|
||||
vals[pos] = val;
|
||||
for (int i=0;i<n;++i) {
|
||||
points[pos*n+i] = point[i];
|
||||
}
|
||||
|
||||
// bubble down
|
||||
int j=pos;
|
||||
while (j>0 && vals[j]<vals[j-1]) {
|
||||
swap(vals[j],vals[j-1]);
|
||||
for (int i=0;i<n;++i) {
|
||||
swap(points[j*n+i],points[(j-1)*n+i]);
|
||||
}
|
||||
--j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Simplex downhill optimization function.
|
||||
Preconditions: points is a 2D mattrix of size (n+1) x n
|
||||
func is the cost function taking n an array of n params and returning float
|
||||
vals is the cost function in the n+1 simplex points, if NULL it will be computed
|
||||
|
||||
Postcondition: returns optimum value and points[0..n] are the optimum parameters
|
||||
*/
|
||||
template <typename T, typename F>
|
||||
float optimizeSimplexDownhill(T* points, int n, F func, float* vals = NULL )
|
||||
{
|
||||
const int MAX_ITERATIONS = 10;
|
||||
|
||||
assert(n>0);
|
||||
|
||||
T* p_o = new T[n];
|
||||
T* p_r = new T[n];
|
||||
T* p_e = new T[n];
|
||||
|
||||
int alpha = 1;
|
||||
|
||||
int iterations = 0;
|
||||
|
||||
bool ownVals = false;
|
||||
if (vals == NULL) {
|
||||
ownVals = true;
|
||||
vals = new float[n+1];
|
||||
for (int i=0;i<n+1;++i) {
|
||||
float val = func(points+i*n);
|
||||
addValue(i, val, vals, points+i*n, points, n);
|
||||
}
|
||||
}
|
||||
int nn = n*n;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (iterations++ > MAX_ITERATIONS) break;
|
||||
|
||||
// compute average of simplex points (except the highest point)
|
||||
for (int j=0;j<n;++j) {
|
||||
p_o[j] = 0;
|
||||
for (int i=0;i<n;++i) {
|
||||
p_o[i] += points[j*n+i];
|
||||
}
|
||||
}
|
||||
for (int i=0;i<n;++i) {
|
||||
p_o[i] /= n;
|
||||
}
|
||||
|
||||
bool converged = true;
|
||||
for (int i=0;i<n;++i) {
|
||||
if (p_o[i] != points[nn+i]) {
|
||||
converged = false;
|
||||
}
|
||||
}
|
||||
if (converged) break;
|
||||
|
||||
// trying a reflection
|
||||
for (int i=0;i<n;++i) {
|
||||
p_r[i] = p_o[i] + alpha*(p_o[i]-points[nn+i]);
|
||||
}
|
||||
float val_r = func(p_r);
|
||||
|
||||
if (val_r>=vals[0] && val_r<vals[n]) {
|
||||
// reflection between second highest and lowest
|
||||
// add it to the simplex
|
||||
logger.info("Choosing reflection\n");
|
||||
addValue(n, val_r,vals, p_r, points, n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val_r<vals[0]) {
|
||||
// value is smaller than smalest in simplex
|
||||
|
||||
// expand some more to see if it drops further
|
||||
for (int i=0;i<n;++i) {
|
||||
p_e[i] = 2*p_r[i]-p_o[i];
|
||||
}
|
||||
float val_e = func(p_e);
|
||||
|
||||
if (val_e<val_r) {
|
||||
logger.info("Choosing reflection and expansion\n");
|
||||
addValue(n, val_e,vals,p_e,points,n);
|
||||
}
|
||||
else {
|
||||
logger.info("Choosing reflection\n");
|
||||
addValue(n, val_r,vals,p_r,points,n);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (val_r>=vals[n]) {
|
||||
for (int i=0;i<n;++i) {
|
||||
p_e[i] = (p_o[i]+points[nn+i])/2;
|
||||
}
|
||||
float val_e = func(p_e);
|
||||
|
||||
if (val_e<vals[n]) {
|
||||
logger.info("Choosing contraction\n");
|
||||
addValue(n,val_e,vals,p_e,points,n);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
logger.info("Full contraction\n");
|
||||
for (int j=1;j<=n;++j) {
|
||||
for (int i=0;i<n;++i) {
|
||||
points[j*n+i] = (points[j*n+i]+points[i])/2;
|
||||
}
|
||||
float val = func(points+j*n);
|
||||
addValue(j,val,vals,points+j*n,points,n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float bestVal = vals[0];
|
||||
|
||||
delete[] p_r;
|
||||
delete[] p_o;
|
||||
delete[] p_e;
|
||||
if (ownVals) delete[] vals;
|
||||
|
||||
return bestVal;
|
||||
}
|
||||
|
||||
} // namespace cvflann
|
||||
|
||||
#endif //SIMPLEX_DOWNHILL_H
|
90
modules/flann/include/opencv2/flann/timer.h
Normal file
90
modules/flann/include/opencv2/flann/timer.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/***********************************************************************
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
|
||||
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
|
||||
*
|
||||
* THE BSD LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
/**
|
||||
* A start-stop timer class.
|
||||
*
|
||||
* Can be used to time portions of code.
|
||||
*/
|
||||
class StartStopTimer
|
||||
{
|
||||
clock_t startTime;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Value of the timer.
|
||||
*/
|
||||
double value;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
StartStopTimer()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timer.
|
||||
*/
|
||||
void start() {
|
||||
startTime = clock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the timer and updates timer value.
|
||||
*/
|
||||
void stop() {
|
||||
clock_t stopTime = clock();
|
||||
value += ( (double)stopTime - startTime) / CLOCKS_PER_SEC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the timer value to 0.
|
||||
*/
|
||||
void reset() {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}// namespace cvflann
|
||||
|
||||
#endif // TIMER_H
|
Reference in New Issue
Block a user