Updated FLANN to version 1.5

This commit is contained in:
Marius Muja
2010-10-12 19:47:50 +00:00
parent 3230073b9b
commit 16b1f61c83
60 changed files with 2134 additions and 3685 deletions

View File

@@ -2,7 +2,6 @@ if(ANDROID)
configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk")
endif()
add_subdirectory(flann)
add_subdirectory(lapack)
add_subdirectory(zlib)
if(WITH_JASPER AND NOT JASPER_FOUND)

View File

@@ -1,107 +0,0 @@
if(ANDROID)
file(GLOB_RECURSE flann_sources_cpp *.cpp)
define_android_manual(flann "${flann_sources_cpp}" "$(LOCAL_PATH)/../include $(LOCAL_PATH)/../include/flann")
else(ANDROID)
if (DEFINED OPENCV_VERSION)
# ----------------------------------------------------------------------------
# CMake file for libflann. See root CMakeLists.txt
#
# ----------------------------------------------------------------------------
project(flann)
# List of C++ files:
#set(CMAKE_BUILD_TYPE Debug)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/../include/flann"
)
# The .cpp files:
file(GLOB flann_sources *.cpp *.h *.hpp)
file(GLOB flann_h "${CMAKE_CURRENT_SOURCE_DIR}/../include/flann/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/../include/flann/*.hpp")
source_group("Src" FILES ${flann_sources})
source_group("Include" FILES ${flann_h})
set(flann_sources ${flann_sources} ${flann_h})
# ----------------------------------------------------------------------------------
# Define the library target:
# ----------------------------------------------------------------------------------
set(the_target "flann")
add_library(${the_target} STATIC ${flann_sources})
add_definitions(-Dflann_EXPORTS)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3")
add_definitions(-DJAS_WIN_MSVC_BUILD)
endif()
if(UNIX)
if(CMAKE_COMPILER_IS_GNUCXX OR CV_ICC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif()
endif()
set_target_properties(${the_target}
PROPERTIES
OUTPUT_NAME "${the_target}"
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib"
)
ELSE()
INCLUDE_DIRECTORIES(algorithms util nn .)
ADD_SUBDIRECTORY( tests )
file(GLOB_RECURSE SOURCES *.cpp)
#SET(SOURCES flann.cpp util/Random.cpp nn/Testing.cpp algorithms/NNIndex.cpp algorithms/dist.cpp util/Logger.cpp util/Saving.cpp)
ADD_LIBRARY(flann ${SOURCES})
#ADD_LIBRARY(flann SHARED ${SOURCES}) #JL: Why the two versions??
#ADD_LIBRARY(flann_s STATIC ${SOURCES})
IF(WIN32)
INSTALL (
TARGETS flann
RUNTIME DESTINATION matlab
)
INSTALL (
TARGETS flann
RUNTIME DESTINATION python/pyflann/bindings
)
ELSE(WIN32)
INSTALL (
TARGETS flann
LIBRARY DESTINATION python/pyflann/bindings
)
ENDIF(WIN32)
INSTALL (
TARGETS flann # flann_s
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
# INSTALL (
# TARGETS flann flann_s
# ARCHIVE DESTINATION ${PROJECT_SOURCE_DIR}/python
# LIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/python
# )
INSTALL (
FILES flann.h constants.h
DESTINATION include
)
ENDIF()
endif(ANDROID)#android

View File

@@ -1,188 +0,0 @@
/***********************************************************************
* 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.");
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((int)(sizeof(T)*count));
return mem;
}
};
}
#endif //ALLOCATOR_H

View File

@@ -1,571 +0,0 @@
/***********************************************************************
* 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 "constants.h"
#include "nn_index.h"
#include "ground_truth.h"
#include "index_testing.h"
namespace cvflann
{
class AutotunedIndex : public NNIndex
{
NNIndex* bestIndex;
IndexParams* bestParams;
SearchParams bestSearchParams;
Matrix<float>* sampledDataset;
Matrix<float>* testDataset;
Matrix<int>* gt_matches;
float speedup;
/**
* The dataset used by this index
*/
const Matrix<float> dataset;
/**
* Index parameters
*/
const AutotunedIndexParams& params;
/**
* Number of features in the dataset.
*/
int size_;
/**
* Length of each feature.
*/
int veclen_;
public:
AutotunedIndex(const Matrix<float>& inputData, const AutotunedIndexParams& params_ = AutotunedIndexParams() ) :
dataset(inputData), params(params_)
{
size_ = dataset.rows;
veclen_ = dataset.cols;
bestIndex = NULL;
}
virtual ~AutotunedIndex()
{
delete bestIndex;
delete bestParams;
};
/**
Method responsible with building the index.
*/
virtual void buildIndex()
{
bestParams = estimateBuildParams();
bestIndex = bestParams->createIndex(dataset);
bestIndex->buildIndex();
speedup = estimateSearchParams(bestSearchParams);
}
/**
Saves the index to a stream
*/
virtual void saveIndex(FILE* stream)
{
bestIndex->saveIndex(stream);
}
/**
Loads the index from a stream
*/
virtual void loadIndex(FILE* stream)
{
bestIndex->loadIndex(stream);
}
/**
Method that searches for nearest-neighbors
*/
virtual void findNeighbors(ResultSet& result, const float* vec, const SearchParams& /*searchParams*/)
{
bestIndex->findNeighbors(result, vec, bestSearchParams);
}
/**
Number of features in this index.
*/
virtual int size() const
{
return bestIndex->size();
}
/**
The length of each vector in this index.
*/
virtual int 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 bestIndex->getType();
}
/**
Estimates the search parameters required in order to get a certain precision.
If testset is not given it uses cross-validation.
*/
// virtual Params estimateSearchParams(float precision, Dataset<float>* testset = NULL)
// {
// Params params;
//
// return params;
// }
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 kmeans(*sampledDataset, kmeans_params);
// measure index build time
t.start();
kmeans.buildIndex();
t.stop();
float buildTime = (float)t.value;
// measure search time
float searchTime = test_index_precision(kmeans, *sampledDataset, *testDataset, *gt_matches, params.target_precision, checks, nn);;
float datasetMemory = (float)(sampledDataset->rows*sampledDataset->cols*sizeof(float));
cost.memoryCost = (kmeans.usedMemory()+datasetMemory)/datasetMemory;
cost.searchTimeCost = searchTime;
cost.buildTimeCost = buildTime;
cost.timeCost = (buildTime*params.build_weight+searchTime);
logger.info("KMeansTree buildTime=%g, searchTime=%g, timeCost=%g, buildTimeFactor=%g\n",buildTime, searchTime, cost.timeCost, 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 kdtree(*sampledDataset, kdtree_params);
t.start();
kdtree.buildIndex();
t.stop();
float buildTime = (float)t.value;
//measure search time
float searchTime = test_index_precision(kdtree, *sampledDataset, *testDataset, *gt_matches, params.target_precision, checks, nn);
float datasetMemory = (float)(sampledDataset->rows*sampledDataset->cols*sizeof(float));
cost.memoryCost = (kdtree.usedMemory()+datasetMemory)/datasetMemory;
cost.searchTimeCost = searchTime;
cost.buildTimeCost = buildTime;
cost.timeCost = (buildTime*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.branching = branchingFactors[j];
kmeansCosts[cnt].second.iterations = maxIterations[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 + 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 + 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(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 = dataset.sample(sampleSize);
// We use a cross-validation approach, first we sample a testset from the dataset
testDataset = sampledDataset->sample(testSampleSize,true);
// We compute the ground truth using linear search
logger.info("Computing ground truth... \n");
gt_matches = new Matrix<int>(testDataset->rows, 1);
StartStopTimer t;
t.start();
compute_ground_truth(*sampledDataset, *testDataset, *gt_matches, 0);
t.stop();
float bestCost = (float)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;
}
// free the memory used by the datasets we sampled
delete sampledDataset;
delete testDataset;
delete gt_matches;
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 long 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<float>* testDataset = dataset.sample(samples);
logger.info("Computing ground truth\n");
// we need to compute the ground truth first
Matrix<int> gt_matches(testDataset->rows,1);
StartStopTimer t;
t.start();
compute_ground_truth(dataset, *testDataset, gt_matches,1);
t.stop();
float linear = (float)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* kmeans = (KMeansIndex*)bestIndex;
float bestSearchTime = -1;
float best_cb_index = -1;
int best_checks = -1;
for (cb_index = 0;cb_index<1.1f; cb_index+=0.2f) {
kmeans->set_cb_index(cb_index);
searchTime = test_index_precision(*kmeans, dataset, *testDataset, gt_matches, 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, params.target_precision, checks, nn, 1);
}
logger.info("Required number of checks: %d \n",checks);;
searchParams.checks = checks;
delete testDataset;
speedup = linear/searchTime;
}
return speedup;
}
};
}
#endif /* AUTOTUNEDINDEX_H_ */

View File

@@ -1,48 +0,0 @@
/***********************************************************************
* 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 COMMOM_H
#define COMMOM_H
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
#include <stdexcept>
namespace cvflann
{
class FLANNException : public std::runtime_error {
public:
FLANNException(const char* message) : std::runtime_error(message) { }
};
}
#endif //COMMOM_H

View File

@@ -1,128 +0,0 @@
/***********************************************************************
* 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 "constants.h"
#include "nn_index.h"
namespace cvflann
{
class CompositeIndex : public NNIndex
{
KMeansIndex* kmeans;
KDTreeIndex* kdtree;
const Matrix<float> dataset;
public:
CompositeIndex(const Matrix<float>& inputData, const CompositeIndexParams& params = CompositeIndexParams() ) : dataset(inputData)
{
KDTreeIndexParams kdtree_params(params.trees);
KMeansIndexParams kmeans_params(params.branching, params.iterations, params.centers_init, params.cb_index);
kdtree = new KDTreeIndex(inputData,kdtree_params);
kmeans = new KMeansIndex(inputData,kmeans_params);
}
virtual ~CompositeIndex()
{
delete kdtree;
delete kmeans;
}
flann_algorithm_t getType() const
{
return COMPOSITE;
}
int size() const
{
return dataset.rows;
}
int 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*/)
{
}
void loadIndex(FILE* /*stream*/)
{
}
void findNeighbors(ResultSet& result, const float* vec, const SearchParams& searchParams)
{
kmeans->findNeighbors(result,vec,searchParams);
kdtree->findNeighbors(result,vec,searchParams);
}
// Params estimateSearchParams(float precision, Dataset<float>* testset = NULL)
// {
// Params params;
//
// return params;
// }
};
}
#endif //COMPOSITETREE_H

View File

@@ -1,68 +0,0 @@
/***********************************************************************
* 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
const double FLANN_VERSION = 1.20;
/* Nearest neighbor 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
};
#endif // CONSTANTS_H

View File

@@ -1,51 +0,0 @@
/***********************************************************************
* 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.
*************************************************************************/
#include "dist.h"
namespace cvflann
{
/** Global variable indicating the distance metric
* to be used.
*/
flann_distance_t flann_distance_type = EUCLIDEAN;
/**
* Zero iterator that emulates a zero feature.
*/
ZeroIterator<float> zero;
/**
* Order of Minkowski distance to use.
*/
int flann_minkowski_order;
}

211
3rdparty/flann/dist.h vendored
View File

@@ -1,211 +0,0 @@
/***********************************************************************
* 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 "constants.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;
}
/**
* 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;
}
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>
float custom_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
switch (flann_distance_type) {
case EUCLIDEAN:
return (float)euclidean_dist(first1, last1, first2, acc);
case MANHATTAN:
return (float)manhattan_dist(first1, last1, first2, acc);
case MINKOWSKI:
return (float)minkowski_dist(first1, last1, first2, acc);
default:
return (float)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;
}
#endif //DIST_H

View File

@@ -1,476 +0,0 @@
/***********************************************************************
* 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.
*************************************************************************/
#include <stdexcept>
#include <vector>
#include "flann.h"
#include "timer.h"
#include "common.h"
#include "logger.h"
#include "index_testing.h"
#include "saving.h"
#include "object_factory.h"
// index types
#include "kdtree_index.h"
#include "kmeans_index.h"
#include "composite_index.h"
#include "linear_index.h"
#include "autotuned_index.h"
#include <typeinfo>
using namespace std;
#include "flann.h"
#ifdef WIN32
#define EXPORTED extern "C" __declspec(dllexport)
#else
#define EXPORTED extern "C"
#endif
namespace cvflann
{
typedef ObjectFactory<IndexParams, flann_algorithm_t> ParamsFactory;
IndexParams* IndexParams::createFromParameters(const FLANNParameters& p)
{
IndexParams* params = ParamsFactory::instance().create(p.algorithm);
params->fromParameters(p);
return params;
}
NNIndex* LinearIndexParams::createIndex(const Matrix<float>& dataset) const
{
return new LinearIndex(dataset, *this);
}
NNIndex* KDTreeIndexParams::createIndex(const Matrix<float>& dataset) const
{
return new KDTreeIndex(dataset, *this);
}
NNIndex* KMeansIndexParams::createIndex(const Matrix<float>& dataset) const
{
return new KMeansIndex(dataset, *this);
}
NNIndex* CompositeIndexParams::createIndex(const Matrix<float>& dataset) const
{
return new CompositeIndex(dataset, *this);
}
NNIndex* AutotunedIndexParams::createIndex(const Matrix<float>& dataset) const
{
return new AutotunedIndex(dataset, *this);
}
NNIndex* SavedIndexParams::createIndex(const Matrix<float>& dataset) const
{
FILE* fin = fopen(filename.c_str(), "rb");
if (fin==NULL) {
return NULL;
}
IndexHeader header = load_header(fin);
rewind(fin);
IndexParams* params = ParamsFactory::instance().create(header.index_type);
NNIndex* nnIndex = params->createIndex(dataset);
nnIndex->loadIndex(fin);
fclose(fin);
delete params; //?
return nnIndex;
}
class StaticInit
{
public:
StaticInit()
{
ParamsFactory::instance().register_<LinearIndexParams>(LINEAR);
ParamsFactory::instance().register_<KDTreeIndexParams>(KDTREE);
ParamsFactory::instance().register_<KMeansIndexParams>(KMEANS);
ParamsFactory::instance().register_<CompositeIndexParams>(COMPOSITE);
ParamsFactory::instance().register_<AutotunedIndexParams>(AUTOTUNED);
ParamsFactory::instance().register_<SavedIndexParams>(SAVED);
}
};
StaticInit __init;
Index::Index(const Matrix<float>& dataset, const IndexParams& params)
{
nnIndex = params.createIndex(dataset);
nnIndex->buildIndex();
}
Index::~Index()
{
delete nnIndex;
}
void Index::knnSearch(const Matrix<float>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& searchParams)
{
assert(queries.cols==nnIndex->veclen());
assert(indices.rows>=queries.rows);
assert(dists.rows>=queries.rows);
assert(indices.cols>=knn);
assert(dists.cols>=knn);
search_for_neighbors(*nnIndex, queries, indices, dists, searchParams);
}
int Index::radiusSearch(const Matrix<float>& query, Matrix<int> indices, Matrix<float> dists, float radius, const SearchParams& searchParams)
{
if (query.rows!=1) {
printf("I can only search one feature at a time for range search\n");
return -1;
}
assert(query.cols==nnIndex->veclen());
RadiusResultSet resultSet(radius);
resultSet.init(query.data, query.cols);
nnIndex->findNeighbors(resultSet,query.data,searchParams);
// TODO: optimize here
int* neighbors = resultSet.getNeighbors();
float* distances = resultSet.getDistances();
int count_nn = min((long)resultSet.size(), indices.cols);
assert (dists.cols>=count_nn);
for (int i=0;i<count_nn;++i) {
indices[0][i] = neighbors[i];
dists[0][i] = distances[i];
}
return count_nn;
}
void Index::save(string filename)
{
FILE* fout = fopen(filename.c_str(), "wb");
if (fout==NULL) {
logger.error("Cannot open file: %s", filename.c_str());
throw FLANNException("Cannot open file");
}
nnIndex->saveIndex(fout);
fclose(fout);
}
int Index::size() const
{
return nnIndex->size();
}
int Index::veclen() const
{
return nnIndex->veclen();
}
int hierarchicalClustering(const Matrix<float>& features, Matrix<float>& centers, const KMeansIndexParams& params)
{
KMeansIndex kmeans(features, params);
kmeans.buildIndex();
int clusterNum = kmeans.getClusterCenters(centers);
return clusterNum;
}
} // namespace FLANN
using namespace cvflann;
typedef NNIndex* NNIndexPtr;
typedef Matrix<float>* MatrixPtr;
void init_flann_parameters(FLANNParameters* p)
{
if (p != NULL) {
flann_log_verbosity(p->log_level);
if (p->random_seed>0) {
seed_random(p->random_seed);
}
}
}
EXPORTED void flann_log_verbosity(int level)
{
if (level>=0) {
logger.setLevel(level);
}
}
EXPORTED void flann_set_distance_type(flann_distance_t distance_type, int order)
{
flann_distance_type = distance_type;
flann_minkowski_order = order;
}
EXPORTED flann_index_t flann_build_index(float* dataset, int rows, int cols, float* /*speedup*/, FLANNParameters* flann_params)
{
try {
init_flann_parameters(flann_params);
if (flann_params == NULL) {
throw FLANNException("The flann_params argument must be non-null");
}
IndexParams* params = IndexParams::createFromParameters(*flann_params);
Index* index = new Index(Matrix<float>(rows,cols,dataset), *params);
return index;
}
catch (runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return NULL;
}
}
EXPORTED int flann_save_index(flann_index_t index_ptr, char* filename)
{
try {
if (index_ptr==NULL) {
throw FLANNException("Invalid index");
}
Index* index = (Index*)index_ptr;
index->save(filename);
return 0;
}
catch(runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return -1;
}
}
EXPORTED FLANN_INDEX flann_load_index(char* filename, float* dataset, int rows, int cols)
{
try {
Index* index = new Index(Matrix<float>(rows,cols,dataset), SavedIndexParams(filename));
return index;
}
catch(runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return NULL;
}
}
EXPORTED int flann_find_nearest_neighbors(float* dataset, int rows, int cols, float* testset, int tcount, int* result, float* dists, int nn, FLANNParameters* flann_params)
{
int _result = 0;
try {
init_flann_parameters(flann_params);
IndexParams* params = IndexParams::createFromParameters(*flann_params);
Index* index = new Index(Matrix<float>(rows,cols,dataset), *params);
Matrix<int> m_indices(tcount, nn, result);
Matrix<float> m_dists(tcount, nn, dists);
index->knnSearch(Matrix<float>(tcount, index->veclen(), testset),
m_indices,
m_dists, nn, SearchParams(flann_params->checks) );
}
catch(runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
_result = -1;
}
return _result;
}
EXPORTED int flann_find_nearest_neighbors_index(flann_index_t index_ptr, float* testset, int tcount, int* result, float* dists, int nn, int checks, FLANNParameters* flann_params)
{
try {
init_flann_parameters(flann_params);
if (index_ptr==NULL) {
throw FLANNException("Invalid index");
}
Index* index = (Index*) index_ptr;
Matrix<int> m_indices(tcount, nn, result);
Matrix<float> m_dists(tcount, nn, dists);
index->knnSearch(Matrix<float>(tcount, index->veclen(), testset),
m_indices,
m_dists, nn, SearchParams(checks) );
}
catch(runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return -1;
}
return -1;
}
EXPORTED int flann_radius_search(FLANN_INDEX index_ptr,
float* query,
int* indices,
float* dists,
int max_nn,
float radius,
int checks,
FLANNParameters* flann_params)
{
try {
init_flann_parameters(flann_params);
if (index_ptr==NULL) {
throw FLANNException("Invalid index");
}
Index* index = (Index*) index_ptr;
Matrix<int> m_indices(1, max_nn, indices);
Matrix<float> m_dists(1, max_nn, dists);
int count = index->radiusSearch(Matrix<float>(1, index->veclen(), query),
m_indices,
m_dists, radius, SearchParams(checks) );
return count;
}
catch(runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return -1;
}
}
EXPORTED int flann_free_index(FLANN_INDEX index_ptr, FLANNParameters* flann_params)
{
try {
init_flann_parameters(flann_params);
if (index_ptr==NULL) {
throw FLANNException("Invalid index");
}
Index* index = (Index*) index_ptr;
delete index;
return 0;
}
catch(runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return -1;
}
}
EXPORTED int flann_compute_cluster_centers(float* dataset, int rows, int cols, int clusters, float* result, FLANNParameters* flann_params)
{
try {
init_flann_parameters(flann_params);
MatrixPtr inputData = new Matrix<float>(rows,cols,dataset);
KMeansIndexParams params(flann_params->branching, flann_params->iterations, flann_params->centers_init, flann_params->cb_index);
Matrix<float> centers(clusters, cols, result);
int clusterNum = hierarchicalClustering(*inputData,centers, params);
return clusterNum;
} catch (runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return -1;
}
}
EXPORTED void compute_ground_truth_float(float* dataset, int dshape[], float* testset, int tshape[], int* match, int mshape[], int skip)
{
assert(dshape[1]==tshape[1]);
assert(tshape[0]==mshape[0]);
Matrix<int> _match(mshape[0], mshape[1], match);
compute_ground_truth(Matrix<float>(dshape[0], dshape[1], dataset), Matrix<float>(tshape[0], tshape[1], testset), _match, skip);
}
EXPORTED float test_with_precision(FLANN_INDEX index_ptr, float* dataset, int dshape[], float* testset, int tshape[], int* matches, int mshape[],
int nn, float precision, int* checks, int skip = 0)
{
assert(dshape[1]==tshape[1]);
assert(tshape[0]==mshape[0]);
try {
if (index_ptr==NULL) {
throw FLANNException("Invalid index");
}
NNIndexPtr index = (NNIndexPtr)index_ptr;
return test_index_precision(*index, Matrix<float>(dshape[0], dshape[1],dataset), Matrix<float>(tshape[0], tshape[1], testset),
Matrix<int>(mshape[0],mshape[1],matches), precision, *checks, nn, skip);
} catch (runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return -1;
}
}
EXPORTED float test_with_checks(FLANN_INDEX index_ptr, float* dataset, int dshape[], float* testset, int tshape[], int* matches, int mshape[],
int nn, int checks, float* precision, int skip = 0)
{
assert(dshape[1]==tshape[1]);
assert(tshape[0]==mshape[0]);
try {
if (index_ptr==NULL) {
throw FLANNException("Invalid index");
}
NNIndexPtr index = (NNIndexPtr)index_ptr;
return test_index_checks(*index, Matrix<float>(dshape[0], dshape[1],dataset), Matrix<float>(tshape[0], tshape[1], testset),
Matrix<int>(mshape[0],mshape[1],matches), checks, *precision, nn, skip);
} catch (runtime_error& e) {
logger.error("Caught exception: %s\n",e.what());
return -1;
}
}

278
3rdparty/flann/flann.h vendored
View File

@@ -1,278 +0,0 @@
/***********************************************************************
* 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_H
#define FLANN_H
#include "constants.h"
#ifdef WIN32
/* win32 dll export/import directives */
#ifdef flann_EXPORTS
#define LIBSPEC __declspec(dllexport)
#else
#define LIBSPEC __declspec(dllimport)
#endif
#else
/* unix needs nothing */
#define LIBSPEC
#endif
struct FLANNParameters {
flann_algorithm_t algorithm; // the algorithm to use (see constants.h)
int checks; // how many leafs (features) to check in one search
float cb_index; // cluster boundary index. Used when searching the kmeans tree
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 cluetering (kmeans tree)
flann_centers_init_t centers_init; // algorithm used for picking the initial cluetr centers for kmeans tree
float target_precision; // precision desired (used for autotuning, -1 otherwise)
float build_weight; // build tree time weighting factor
float memory_weight; // index memory weigthing factor
float sample_fraction; // what fraction of the dataset to use for autotuning
flann_log_level_t log_level; // determines the verbosity of each flann function
char* log_destination; // file where the output should go, NULL for the console
long random_seed; // random seed to use
};
typedef void* FLANN_INDEX; // deprecated
typedef void* flann_index_t;
#ifdef __cplusplus
extern "C" {
#endif
/**
Sets the log level used for all flann functions (unless
specified in FLANNParameters for each call
Params:
level = verbosity level (defined in constants.h)
*/
LIBSPEC void flann_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.
*/
LIBSPEC void flann_set_distance_type(flann_distance_t distance_type, int order);
/**
Builds and returns an index. It uses autotuning if the target_precision field of index_params
is between 0 and 1, or the parameters specified if it's -1.
Params:
dataset = pointer to a data set stored in row major order
rows = number of rows (features) in the dataset
cols = number of columns in the dataset (feature dimensionality)
speedup = speedup over linear search, estimated if using autotuning, output parameter
index_params = index related parameters
flann_params = generic flann parameters
Returns: the newly created index or a number <0 for error
*/
LIBSPEC FLANN_INDEX flann_build_index(float* dataset,
int rows,
int cols,
float* speedup,
struct FLANNParameters* flann_params);
/**
* Saves the index to a file. Only the index is saved into the file, the dataset corresponding to the index is not saved.
*
* @param index_id The index that should be saved
* @param filename The filename the index should be saved to
* @return Returns 0 on success, negative value on error.
*/
LIBSPEC int flann_save_index(FLANN_INDEX index_id,
char* filename);
/**
* Loads an index from a file.
*
* @param filename File to load the index from.
* @param dataset The dataset corresponding to the index.
* @param rows Dataset tors
* @param cols Dataset columns
* @return
*/
LIBSPEC FLANN_INDEX flann_load_index(char* filename,
float* dataset,
int rows,
int cols);
/**
Builds an index and uses it to find nearest neighbors.
Params:
dataset = pointer to a data set stored in row major order
rows = number of rows (features) in the dataset
cols = number of columns in the dataset (feature dimensionality)
testset = pointer to a query set stored in row major order
trows = number of rows (features) in the query dataset (same dimensionality as features in the dataset)
indices = pointer to matrix for the indices of the nearest neighbors of the testset features in the dataset
(must have trows number of rows and nn number of columns)
nn = how many nearest neighbors to return
index_params = index related parameters
flann_params = generic flann parameters
Returns: zero or -1 for error
*/
LIBSPEC int flann_find_nearest_neighbors(float* dataset,
int rows,
int cols,
float* testset,
int trows,
int* indices,
float* dists,
int nn,
struct FLANNParameters* flann_params);
/**
Searches for nearest neighbors using the index provided
Params:
index_id = the index (constructed previously using flann_build_index).
testset = pointer to a query set stored in row major order
trows = number of rows (features) in the query dataset (same dimensionality as features in the dataset)
indices = pointer to matrix for the indices of the nearest neighbors of the testset features in the dataset
(must have trows number of rows and nn number of columns)
nn = how many nearest neighbors to return
checks = number of checks to perform before the search is stopped
flann_params = generic flann parameters
Returns: zero or a number <0 for error
*/
LIBSPEC int flann_find_nearest_neighbors_index(FLANN_INDEX index_id,
float* testset,
int trows,
int* indices,
float* dists,
int nn,
int checks,
struct FLANNParameters* flann_params);
/**
* Performs an radius search using an already constructed index.
*
* In case of radius search, instead of always returning a predetermined
* number of nearest neighbours (for example the 10 nearest neighbours), the
* search will return all the neighbours found within a search radius
* of the query point.
*
* The check parameter in the function below sets the level of approximation
* for the search by only visiting "checks" number of features in the index
* (the same way as for the KNN search). A lower value for checks will give
* a higher search speedup at the cost of potentially not returning all the
* neighbours in the specified radius.
*/
LIBSPEC int flann_radius_search(FLANN_INDEX index_ptr, /* the index */
float* query, /* query point */
int* indices, /* array for storing the indices found (will be modified) */
float* dists, /* similar, but for storing distances */
int max_nn, /* size of arrays indices and dists */
float radius, /* search radius (squared radius for euclidian metric) */
int checks, /* number of features to check, sets the level of approximation */
FLANNParameters* flann_params);
/**
Deletes an index and releases the memory used by it.
Params:
index_id = the index (constructed previously using flann_build_index).
flann_params = generic flann parameters
Returns: zero or a number <0 for error
*/
LIBSPEC int flann_free_index(FLANN_INDEX index_id,
struct FLANNParameters* flann_params);
/**
Clusters the features in the dataset using a hierarchical kmeans clustering approach.
This is significantly faster than using a flat kmeans clustering for a large number
of clusters.
Params:
dataset = pointer to a data set stored in row major order
rows = number of rows (features) in the dataset
cols = number of columns in the dataset (feature dimensionality)
clusters = number of cluster to compute
result = memory buffer where the output cluster centers are storred
index_params = used to specify the kmeans tree parameters (branching factor, max number of iterations to use)
flann_params = generic flann parameters
Returns: number of clusters computed or a number <0 for error. This number can be different than the number of clusters requested, due to the
way hierarchical clusters are computed. The number of clusters returned will be the highest number of the form
(branch_size-1)*K+1 smaller than the number of clusters requested.
*/
LIBSPEC int flann_compute_cluster_centers(float* dataset,
int rows,
int cols,
int clusters,
float* result,
struct FLANNParameters* flann_params);
#ifdef __cplusplus
};
#include "flann.hpp"
#endif
#endif /*FLANN_H*/

View File

@@ -1,247 +0,0 @@
/***********************************************************************
* 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 "constants.h"
#include "common.h"
#include "matrix.h"
#include "flann.h"
namespace cvflann
{
class NNIndex;
class IndexFactory
{
public:
virtual ~IndexFactory() {}
virtual NNIndex* createIndex(const Matrix<float>& dataset) const = 0;
};
struct IndexParams : public IndexFactory {
protected:
IndexParams() {};
public:
static IndexParams* createFromParameters(const FLANNParameters& p);
virtual void fromParameters(const FLANNParameters&) {};
virtual void toParameters(FLANNParameters&) { };
};
struct LinearIndexParams : public IndexParams {
LinearIndexParams() {};
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct KDTreeIndexParams : public IndexParams {
KDTreeIndexParams(int trees_ = 4) : trees(trees_) {};
int trees; // number of randomized trees to use (for kdtree)
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KDTREE;
p.trees = trees;
};
};
struct KMeansIndexParams : public IndexParams {
KMeansIndexParams(int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
branching(branching_),
iterations(iterations_),
centers_init(centers_init_),
cb_index(cb_index_) {};
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
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KMEANS;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
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 ) :
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
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = COMPOSITE;
p.trees = trees;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
struct AutotunedIndexParams : public IndexParams {
AutotunedIndexParams( float target_precision_ = 0.9, float build_weight_ = 0.01,
float memory_weight_ = 0, float sample_fraction_ = 0.1) :
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
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
target_precision = p.target_precision;
build_weight = p.build_weight;
memory_weight = p.memory_weight;
sample_fraction = p.sample_fraction;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = AUTOTUNED;
p.target_precision = target_precision;
p.build_weight = build_weight;
p.memory_weight = memory_weight;
p.sample_fraction = sample_fraction;
};
};
struct SavedIndexParams : public IndexParams {
SavedIndexParams() {
throw FLANNException("I don't know which index to load");
}
SavedIndexParams(std::string filename_) : filename(filename_) {}
std::string filename; // filename of the stored index
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct SearchParams {
SearchParams(int checks_ = 32) :
checks(checks_) {};
int checks;
};
class Index {
NNIndex* nnIndex;
public:
Index(const Matrix<float>& features, const IndexParams& params);
~Index();
void knnSearch(const Matrix<float>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& params);
int radiusSearch(const Matrix<float>& query, Matrix<int> indices, Matrix<float> dists, float radius, const SearchParams& params);
void save(std::string filename);
int veclen() const;
int size() const;
};
int hierarchicalClustering(const Matrix<float>& features, Matrix<float>& centers, const KMeansIndexParams& params);
}
#endif /* FLANN_HPP_ */

View File

@@ -1,95 +0,0 @@
/***********************************************************************
* 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 "matrix.h"
#include "dist.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 (int 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 (int i=0;i<testset.rows;++i) {
find_nearest(dataset, testset[i], matches[i], matches.cols, skip);
}
}
}
#endif //GROUND_TRUTH_H

209
3rdparty/flann/heap.h vendored
View File

@@ -1,209 +0,0 @@
/***********************************************************************
* 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);
}
}
};
}
#endif //HEAP_H

View File

@@ -1,314 +0,0 @@
/***********************************************************************
* 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.
*************************************************************************/
#include "index_testing.h"
#include "result_set.h"
#include "timer.h"
#include "logger.h"
#include "dist.h"
#include "common.h"
#include <algorithm>
#include <math.h>
#include <string.h>
#include <stdlib.h>
namespace cvflann
{
const float SEARCH_EPS = 0.001f;
int countCorrectMatches(int* neighbors, int* groundTruth, int n)
{
int count = 0;
for (int i=0;i<n;++i) {
for (int k=0;k<n;++k) {
if (neighbors[i]==groundTruth[k]) {
count++;
break;
}
}
}
return count;
}
float computeDistanceRaport(const Matrix<float>& inputData, float* target, int* neighbors, int* groundTruth, int veclen, int n)
{
float* target_end = target + veclen;
float ret = 0;
for (int i=0;i<n;++i) {
float den = (float)flann_dist(target,target_end, inputData[groundTruth[i]]);
float num = (float)flann_dist(target,target_end, inputData[neighbors[i]]);
// printf("den=%g,num=%g\n",den,num);
if (den==0 && num==0) {
ret += 1;
} else {
ret += num/den;
}
}
return ret;
}
float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches, int nn, int checks, float& time, float& dist, int skipMatches)
{
if (matches.cols<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 resultSet(nn+skipMatches);
SearchParams searchParams(checks);
int correct = 0;
float distR = 0;
StartStopTimer t;
int repeats = 0;
while (t.value<0.2) {
repeats++;
t.start();
correct = 0;
distR = 0;
for (int i = 0; i < testData.rows; i++) {
float* 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 = (float)(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;
}
void search_for_neighbors(NNIndex& index, const Matrix<float>& testset, Matrix<int>& result, Matrix<float>& dists, const SearchParams& searchParams, int skip)
{
assert(testset.rows == result.rows);
int nn = result.cols;
KNNResultSet resultSet(nn+skip);
for (int i = 0; i < testset.rows; i++) {
float* target = testset[i];
resultSet.init(target, testset.cols);
index.findNeighbors(resultSet,target, searchParams);
int* neighbors = resultSet.getNeighbors();
float* distances = resultSet.getDistances();
memcpy(result[i], neighbors+skip, nn*sizeof(int));
memcpy(dists[i], distances+skip, nn*sizeof(float));
}
}
float test_index_checks(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches, int checks, float& precision, int nn, int skipMatches)
{
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;
}
float test_index_precision(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
float precision, int& checks, int nn, int skipMatches)
{
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;
}
float test_index_precisions(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
float* precisions, int precisions_length, int nn, int skipMatches, float maxTime)
{
// 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;
}
}

View File

@@ -1,57 +0,0 @@
/***********************************************************************
* 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 "nn_index.h"
#include "matrix.h"
using namespace std;
namespace cvflann
{
void search_for_neighbors(NNIndex& index, const Matrix<float>& testset, Matrix<int>& result, Matrix<float>& dists, const SearchParams &searchParams, int skip = 0);
float test_index_checks(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
int checks, float& precision, int nn = 1, int skipMatches = 0);
float test_index_precision(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
float precision, int& checks, int nn = 1, int skipMatches = 0);
float test_index_precisions(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
float* precisions, int precisions_length, int nn = 1, int skipMatches = 0, float maxTime = 0);
}
#endif //TESTING_H

View File

@@ -1,653 +0,0 @@
/***********************************************************************
* 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 "heap.h"
#include "common.h"
#include "constants.h"
#include "allocator.h"
#include "matrix.h"
#include "result_set.h"
#include "random.h"
#include "nn_index.h"
#include "saving.h"
using namespace std;
namespace cvflann
{
/**
* Randomized kd-tree index
*
* Contains the k-d trees and other information for indexing a set of points
* for nearest-neighbor matching.
*/
class KDTreeIndex : public NNIndex
{
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. When doing lookup,
* this is used instead to mark checkID.
*/
int* vind;
/**
* An unique ID for each lookup.
*/
int checkID;
/**
* The dataset used by this index
*/
const Matrix<float> dataset;
int size_;
int veclen_;
float* mean;
float* 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.
*/
float divval;
/**
* The child nodes.
*/
TreeSt *child1, *child2;
};
typedef TreeSt* Tree;
/**
* Array of k-d trees used to find neighbors.
*/
Tree* trees;
typedef BranchStruct<Tree> BranchSt;
typedef BranchSt* Branch;
/**
* Priority queue storing intermediate branches in the best-bin-first search
*/
Heap<BranchSt>* heap;
/**
* 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<float>& inputData, const KDTreeIndexParams& params = KDTreeIndexParams() ) : dataset(inputData)
{
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;
// }
heap = new Heap<BranchSt>(size_);
checkID = -1000;
// Create a permutable array of indices to the input vectors.
vind = new int[size_];
for (int i = 0; i < size_; i++) {
vind[i] = i;
}
mean = new float[veclen_];
var = new float[veclen_];
}
/**
* Standard destructor
*/
~KDTreeIndex()
{
delete[] vind;
if (trees!=NULL) {
delete[] trees;
}
delete heap;
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 rand = cast(int) (drand48() * size);
int rnd = rand_int(j);
assert(rnd >=0 && rnd < size_);
swap(vind[j-1], vind[rnd]);
}
trees[i] = NULL;
divideTree(&trees[i], 0, size_ - 1);
}
}
void saveIndex(FILE* stream)
{
save_header(stream, *this);
save_value(stream, numTrees);
for (int i=0;i<numTrees;++i) {
save_tree(stream, trees[i]);
}
}
void loadIndex(FILE* stream)
{
IndexHeader header = load_header(stream);
if (header.rows!=size() || header.cols!=veclen()) {
throw FLANNException("The index saved belongs to a different dataset");
}
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.
*/
int size() const
{
return size_;
}
/**
* Returns the length of an index feature.
*/
int 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& result, const float* vec, const SearchParams& searchParams)
{
int maxChecks = searchParams.checks;
if (maxChecks<0) {
getExactNeighbors(result, vec);
} else {
getNeighbors(result, vec, maxChecks);
}
}
void continueSearch(ResultSet& result, float* vec, int maxCheck)
{
BranchSt branch;
int checkCount = 0;
/* 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);
}
assert(result.full());
}
// Params estimateSearchParams(float precision, Dataset<float>* testset = NULL)
// {
// Params params;
//
// return 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
*/
void divideTree(Tree* pTree, int first, int last)
{
Tree node;
node = pool.allocate<TreeSt>(); // allocate memory
*pTree = node;
/* 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);
}
}
/**
* 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(float));
memset(var,0,veclen_*sizeof(float));
/* 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);
int count = end - first + 1;
for (int j = first; j <= end; ++j) {
float* v = dataset[vind[j]];
for (int k=0; k<veclen_; ++k) {
mean[k] += v[k];
}
}
for (int k=0; k<veclen_; ++k) {
mean[k] /= count;
}
/* Compute variances (no need to divide by count). */
for (int j = first; j <= end; ++j) {
float* v = dataset[vind[j]];
for (int k=0; k<veclen_; ++k) {
float 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(float* v)
{
int num = 0;
int topind[RAND_DIM];
/* Create a list of the indices of the top RAND_DIM values. */
for (int 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 rand = cast(int) (drand48() * num);
int rnd = rand_int(num);
assert(rnd >=0 && rnd < 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];
float 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;
}
divideTree(& node->child1, first, i - 1);
divideTree(& node->child2, i, last);
}
/**
* Performs an exact nearest neighbor search. The exact search performs a full
* traversal of the tree.
*/
void getExactNeighbors(ResultSet& result, const float* 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& result, const float* vec, int maxCheck)
{
int i;
BranchSt branch;
int checkCount = 0;
heap->clear();
checkID -= 1; /* Set a different unique ID for each search. */
/* Search once through each tree down to root. */
for (i = 0; i < numTrees; ++i) {
searchLevel(result, vec, trees[i], 0.0, checkCount, maxCheck);
}
/* 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);
}
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& result, const float* vec, Tree node, float mindistsq, int& checkCount, int maxCheck)
{
if (result.worstDist()<mindistsq) {
// printf("Ignoring branch, too far\n");
return;
}
float val, diff;
Tree bestChild, otherChild;
/* 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 || checkCount>=maxCheck) {
if (result.full()) return;
}
checkCount++;
vind[node->divfeat] = checkID;
result.addPoint(dataset[node->divfeat],node->divfeat);
return;
}
/* Which child branch should be taken first? */
val = vec[node->divfeat];
diff = val - node->divval;
bestChild = (diff < 0) ? node->child1 : node->child2;
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.
*/
float 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);
}
/**
* Performs an exact search in the tree starting from a node.
*/
void searchLevelExact(ResultSet& result, const float* vec, Tree node, float mindistsq)
{
if (mindistsq>result.worstDist()) {
return;
}
float val, diff;
Tree bestChild, otherChild;
/* 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? */
val = vec[node->divfeat];
diff = val - node->divval;
bestChild = (diff < 0) ? node->child1 : node->child2;
otherChild = (diff < 0) ? node->child2 : node->child1;
/* Call recursively to search next level down. */
searchLevelExact(result, vec, bestChild, mindistsq);
float new_distsq = flann_dist(&val, &val+1, &node->divval, mindistsq);
searchLevelExact(result, vec, otherChild, new_distsq);
}
}; // class KDTree
}
#endif //KDTREE_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,105 +0,0 @@
/***********************************************************************
* 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 "constants.h"
#include "nn_index.h"
namespace cvflann
{
class LinearIndex : public NNIndex {
const Matrix<float> dataset;
public:
LinearIndex(const Matrix<float>& inputData, const LinearIndexParams& params = LinearIndexParams() ) : dataset(inputData)
{
}
flann_algorithm_t getType() const
{
return LINEAR;
}
int size() const
{
return dataset.rows;
}
int 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& resultSet, const float* /*vec*/, const SearchParams& /*searchParams*/)
{
for (int i=0;i<dataset.rows;++i) {
resultSet.addPoint(dataset[i],i);
}
}
// Params estimateSearchParams(float precision, Matrix<float>* testset = NULL)
// {
// Params params;
// return params;
// }
};
}
#endif // LINEARSEARCH_H

View File

@@ -1,85 +0,0 @@
/***********************************************************************
* 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.
*************************************************************************/
#include "logger.h"
#include <cstdio>
#include <cstdarg>
#include <sstream>
using namespace std;
namespace cvflann
{
Logger logger;
int Logger::log(int level, const char* fmt, ...)
{
if (level > logLevel ) return -1;
int ret;
va_list arglist;
va_start(arglist, fmt);
ret = vfprintf(stream, fmt, arglist);
va_end(arglist);
return ret;
}
int Logger::log(int level, const char* fmt, va_list arglist)
{
if (level > logLevel ) return -1;
int ret;
ret = vfprintf(stream, fmt, arglist);
return ret;
}
#define LOG_METHOD(NAME,LEVEL) \
int Logger::NAME(const char* fmt, ...) \
{ \
int ret; \
va_list ap; \
va_start(ap, fmt); \
ret = log(LEVEL, fmt, ap); \
va_end(ap); \
return ret; \
}
LOG_METHOD(fatal, LOG_FATAL)
LOG_METHOD(error, LOG_ERROR)
LOG_METHOD(warn, LOG_WARN)
LOG_METHOD(info, LOG_INFO)
}

View File

@@ -1,93 +0,0 @@
/***********************************************************************
* 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 <stdarg.h>
#include "common.h"
#include "flann.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;
}
#endif //LOGGER_H

View File

@@ -1,163 +0,0 @@
/***********************************************************************
* 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 <random.h>
namespace cvflann
{
/**
* Class implementing a generic rectangular dataset.
*/
template <typename T>
class Matrix {
/**
* Flag showing if the class owns its data storage.
*/
bool ownData;
void shallow_copy(const Matrix& rhs)
{
data = rhs.data;
rows = rhs.rows;
cols = rhs.cols;
ownData = false;
}
public:
long rows;
long cols;
T* data;
Matrix(long rows_, long cols_, T* data_ = NULL) :
ownData(false), rows(rows_), cols(cols_), data(data_)
{
if (data_==NULL) {
data = new T[rows*cols];
ownData = true;
}
}
Matrix(const Matrix& d)
{
shallow_copy(d);
}
const Matrix& operator=(const Matrix& rhs)
{
if (this!=&rhs) {
shallow_copy(rhs);
}
return *this;
}
~Matrix()
{
if (ownData) {
delete[] data;
}
}
/**
* Operator that return a (pointer to a) row of the data.
*/
T* operator[](long index)
{
return data+index*cols;
}
T* operator[](long index) const
{
return data+index*cols;
}
Matrix<T>* sample(long size, bool remove = false)
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
if (remove) {
dest = (*this)[rows-i-1];
src = (*this)[r];
for (long j=0;j<cols;++j) {
swap(*src,*dest);
src++;
dest++;
}
}
}
if (remove) {
rows -= size;
}
return newSet;
}
Matrix<T>* sample(long size) const
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
}
return newSet;
}
};
}
#endif //DATASET_H

View File

@@ -1,109 +0,0 @@
/***********************************************************************
* 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 "flann.hpp"
#include "constants.h"
#include "common.h"
#include "matrix.h"
#include <string>
#include <string.h>
using namespace std;
namespace cvflann
{
class ResultSet;
/**
* Nearest-neighbor index base class
*/
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& result, const float* vec, const SearchParams& searchParams) = 0;
/**
Number of features in this index.
*/
virtual int size() const = 0;
/**
The length of each vector in this index.
*/
virtual int 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;
/**
Estimates the search parameters required in order to get a certain precision.
If testset is not given it uses cross-validation.
*/
// virtual Params estimateSearchParams(float precision, Matrix<float>* testset = NULL) = 0;
};
}
#endif //NNINDEX_H

View File

@@ -1,93 +0,0 @@
/***********************************************************************
* 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;
}
};
}
#endif /* OBJECT_FACTORY_H_ */

View File

@@ -1,53 +0,0 @@
/***********************************************************************
* 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.
*************************************************************************/
#include "random.h"
namespace cvflann
{
void seed_random(unsigned int seed)
{
srand(seed);
}
double rand_double(double high, double low)
{
return low + ((high-low) * (std::rand() / (RAND_MAX + 1.0)));
}
int rand_int(int high, int low)
{
return low + (int) ( double(high-low) * (std::rand() / (RAND_MAX + 1.0)));
}
}

View File

@@ -1,134 +0,0 @@
/***********************************************************************
* 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++];
}
}
};
}
#endif //RANDOM_H

View File

@@ -1,314 +0,0 @@
/***********************************************************************
* 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 "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(T aNode, float dist)
{
BranchStruct<T> branch;
branch.node = aNode;
branch.mindistsq = dist;
return branch;
}
};
class ResultSet
{
protected:
const float* target;
const float* target_end;
int veclen;
public:
ResultSet(float* target_ = NULL, int veclen_ = 0) :
target(target_), veclen(veclen_) { target_end = target + veclen;}
virtual ~ResultSet() {}
virtual void init(const float* target_, int veclen_) = 0;
virtual int* getNeighbors() = 0;
virtual float* getDistances() = 0;
virtual int size() const = 0;
virtual bool full() const = 0;
virtual bool addPoint(float* point, int index) = 0;
virtual float worstDist() const = 0;
};
class KNNResultSet : public ResultSet
{
int* indices;
float* dists;
int capacity;
int count;
public:
KNNResultSet(int capacity_, float* target_ = NULL, int veclen_ = 0 ) :
ResultSet(target_, veclen_), capacity(capacity_), count(0)
{
indices = new int[capacity_];
dists = new float[capacity_];
}
~KNNResultSet()
{
delete[] indices;
delete[] dists;
}
void init(const float* target_, int veclen_)
{
target = target_;
veclen = veclen_;
target_end = target + veclen;
count = 0;
}
int* getNeighbors()
{
return indices;
}
float* getDistances()
{
return dists;
}
int size() const
{
return count;
}
bool full() const
{
return count == capacity;
}
bool addPoint(float* point, int index)
{
for (int i=0;i<count;++i) {
if (indices[i]==index) return false;
}
float dist = (float)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.
*/
class RadiusResultSet : public ResultSet
{
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 float* 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;
}
int size() const
{
return (int)items.size();
}
bool full() const
{
return true;
}
bool addPoint(float* point, int index)
{
Item it;
it.index = index;
it.dist = (float)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;
}
};
}
#endif //RESULTSET_H

View File

@@ -1,73 +0,0 @@
/***********************************************************************
* 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.
*************************************************************************/
#include "common.h"
#include "saving.h"
#include "nn_index.h"
#include <cstdio>
namespace cvflann
{
const char FLANN_SIGNATURE[] = "FLANN_INDEX";
void save_header(FILE* stream, const NNIndex& index)
{
IndexHeader header;
memset(header.signature, 0 , sizeof(header.signature));
strcpy(header.signature, FLANN_SIGNATURE);
header.flann_version = (int)FLANN_VERSION;
header.index_type = index.getType();
header.rows = index.size();
header.cols = index.veclen();
std::fwrite(&header, sizeof(header),1,stream);
}
IndexHeader load_header(FILE* stream)
{
IndexHeader header;
int read_size = (int)fread(&header,sizeof(header),1,stream);
if (read_size!=1) {
throw FLANNException("Invalid index file, cannot read");
}
if (strcmp(header.signature,FLANN_SIGNATURE)!=0) {
throw FLANNException("Invalid index file, wrong signature");
}
return header;
}
}

View File

@@ -1,87 +0,0 @@
/***********************************************************************
* 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 SAVING_H_
#define SAVING_H_
#include "constants.h"
#include "nn_index.h"
namespace cvflann
{
/**
* Structure representing the index header.
*/
struct IndexHeader
{
char signature[16];
int flann_version;
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
*/
void save_header(FILE* stream, const NNIndex& index);
/**
*
* @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 = (int)fread(&value, sizeof(value),count, stream);
if (read_cnt!=count) {
throw FLANNException("Cannot read from file");
}
}
}
#endif /* SAVING_H_ */

View File

@@ -1,186 +0,0 @@
/***********************************************************************
* 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;
}
}
#endif //SIMPLEX_DOWNHILL_H

View File

@@ -1,90 +0,0 @@
/***********************************************************************
* 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;
}
};
}
#endif // TIMER_H

View File

@@ -1,48 +0,0 @@
/***********************************************************************
* 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 COMMOM_H
#define COMMOM_H
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
#include <stdexcept>
namespace cvflann
{
class FLANNException : public std::runtime_error {
public:
FLANNException(const char* message) : std::runtime_error(message) { }
};
}
#endif //COMMOM_H

View File

@@ -1,68 +0,0 @@
/***********************************************************************
* 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
const double FLANN_VERSION = 1.20;
/* Nearest neighbor 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
};
#endif // CONSTANTS_H

View File

@@ -1,278 +0,0 @@
/***********************************************************************
* 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_H
#define FLANN_H
#include "constants.h"
#ifdef WIN32
/* win32 dll export/import directives */
#ifdef flann_EXPORTS
#define LIBSPEC __declspec(dllexport)
#else
#define LIBSPEC __declspec(dllimport)
#endif
#else
/* unix needs nothing */
#define LIBSPEC
#endif
struct FLANNParameters {
flann_algorithm_t algorithm; // the algorithm to use (see constants.h)
int checks; // how many leafs (features) to check in one search
float cb_index; // cluster boundary index. Used when searching the kmeans tree
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 cluetering (kmeans tree)
flann_centers_init_t centers_init; // algorithm used for picking the initial cluetr centers for kmeans tree
float target_precision; // precision desired (used for autotuning, -1 otherwise)
float build_weight; // build tree time weighting factor
float memory_weight; // index memory weigthing factor
float sample_fraction; // what fraction of the dataset to use for autotuning
flann_log_level_t log_level; // determines the verbosity of each flann function
char* log_destination; // file where the output should go, NULL for the console
long random_seed; // random seed to use
};
typedef void* FLANN_INDEX; // deprecated
typedef void* flann_index_t;
#ifdef __cplusplus
extern "C" {
#endif
/**
Sets the log level used for all flann functions (unless
specified in FLANNParameters for each call
Params:
level = verbosity level (defined in constants.h)
*/
LIBSPEC void flann_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.
*/
LIBSPEC void flann_set_distance_type(flann_distance_t distance_type, int order);
/**
Builds and returns an index. It uses autotuning if the target_precision field of index_params
is between 0 and 1, or the parameters specified if it's -1.
Params:
dataset = pointer to a data set stored in row major order
rows = number of rows (features) in the dataset
cols = number of columns in the dataset (feature dimensionality)
speedup = speedup over linear search, estimated if using autotuning, output parameter
index_params = index related parameters
flann_params = generic flann parameters
Returns: the newly created index or a number <0 for error
*/
LIBSPEC FLANN_INDEX flann_build_index(float* dataset,
int rows,
int cols,
float* speedup,
struct FLANNParameters* flann_params);
/**
* Saves the index to a file. Only the index is saved into the file, the dataset corresponding to the index is not saved.
*
* @param index_id The index that should be saved
* @param filename The filename the index should be saved to
* @return Returns 0 on success, negative value on error.
*/
LIBSPEC int flann_save_index(FLANN_INDEX index_id,
char* filename);
/**
* Loads an index from a file.
*
* @param filename File to load the index from.
* @param dataset The dataset corresponding to the index.
* @param rows Dataset tors
* @param cols Dataset columns
* @return
*/
LIBSPEC FLANN_INDEX flann_load_index(char* filename,
float* dataset,
int rows,
int cols);
/**
Builds an index and uses it to find nearest neighbors.
Params:
dataset = pointer to a data set stored in row major order
rows = number of rows (features) in the dataset
cols = number of columns in the dataset (feature dimensionality)
testset = pointer to a query set stored in row major order
trows = number of rows (features) in the query dataset (same dimensionality as features in the dataset)
indices = pointer to matrix for the indices of the nearest neighbors of the testset features in the dataset
(must have trows number of rows and nn number of columns)
nn = how many nearest neighbors to return
index_params = index related parameters
flann_params = generic flann parameters
Returns: zero or -1 for error
*/
LIBSPEC int flann_find_nearest_neighbors(float* dataset,
int rows,
int cols,
float* testset,
int trows,
int* indices,
float* dists,
int nn,
struct FLANNParameters* flann_params);
/**
Searches for nearest neighbors using the index provided
Params:
index_id = the index (constructed previously using flann_build_index).
testset = pointer to a query set stored in row major order
trows = number of rows (features) in the query dataset (same dimensionality as features in the dataset)
indices = pointer to matrix for the indices of the nearest neighbors of the testset features in the dataset
(must have trows number of rows and nn number of columns)
nn = how many nearest neighbors to return
checks = number of checks to perform before the search is stopped
flann_params = generic flann parameters
Returns: zero or a number <0 for error
*/
LIBSPEC int flann_find_nearest_neighbors_index(FLANN_INDEX index_id,
float* testset,
int trows,
int* indices,
float* dists,
int nn,
int checks,
struct FLANNParameters* flann_params);
/**
* Performs an radius search using an already constructed index.
*
* In case of radius search, instead of always returning a predetermined
* number of nearest neighbours (for example the 10 nearest neighbours), the
* search will return all the neighbours found within a search radius
* of the query point.
*
* The check parameter in the function below sets the level of approximation
* for the search by only visiting "checks" number of features in the index
* (the same way as for the KNN search). A lower value for checks will give
* a higher search speedup at the cost of potentially not returning all the
* neighbours in the specified radius.
*/
LIBSPEC int flann_radius_search(FLANN_INDEX index_ptr, /* the index */
float* query, /* query point */
int* indices, /* array for storing the indices found (will be modified) */
float* dists, /* similar, but for storing distances */
int max_nn, /* size of arrays indices and dists */
float radius, /* search radius (squared radius for euclidian metric) */
int checks, /* number of features to check, sets the level of approximation */
FLANNParameters* flann_params);
/**
Deletes an index and releases the memory used by it.
Params:
index_id = the index (constructed previously using flann_build_index).
flann_params = generic flann parameters
Returns: zero or a number <0 for error
*/
LIBSPEC int flann_free_index(FLANN_INDEX index_id,
struct FLANNParameters* flann_params);
/**
Clusters the features in the dataset using a hierarchical kmeans clustering approach.
This is significantly faster than using a flat kmeans clustering for a large number
of clusters.
Params:
dataset = pointer to a data set stored in row major order
rows = number of rows (features) in the dataset
cols = number of columns in the dataset (feature dimensionality)
clusters = number of cluster to compute
result = memory buffer where the output cluster centers are storred
index_params = used to specify the kmeans tree parameters (branching factor, max number of iterations to use)
flann_params = generic flann parameters
Returns: number of clusters computed or a number <0 for error. This number can be different than the number of clusters requested, due to the
way hierarchical clusters are computed. The number of clusters returned will be the highest number of the form
(branch_size-1)*K+1 smaller than the number of clusters requested.
*/
LIBSPEC int flann_compute_cluster_centers(float* dataset,
int rows,
int cols,
int clusters,
float* result,
struct FLANNParameters* flann_params);
#ifdef __cplusplus
};
#include "flann.hpp"
#endif
#endif /*FLANN_H*/

View File

@@ -1,246 +0,0 @@
/***********************************************************************
* 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 "constants.h"
#include "common.h"
#include "matrix.h"
#include "flann.h"
namespace cvflann
{
class NNIndex;
class IndexFactory
{
public:
virtual ~IndexFactory() {}
virtual NNIndex* createIndex(const Matrix<float>& dataset) const = 0;
};
struct IndexParams : public IndexFactory {
protected:
IndexParams() {};
public:
static IndexParams* createFromParameters(const FLANNParameters& p);
void fromParameters(const FLANNParameters&) {};
void toParameters(FLANNParameters&) { };
};
struct LinearIndexParams : public IndexParams {
LinearIndexParams() {};
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct KDTreeIndexParams : public IndexParams {
KDTreeIndexParams(int trees_ = 4) : trees(trees_) {};
int trees; // number of randomized trees to use (for kdtree)
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KDTREE;
p.trees = trees;
};
};
struct KMeansIndexParams : public IndexParams {
KMeansIndexParams(int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
branching(branching_),
iterations(iterations_),
centers_init(centers_init_),
cb_index(cb_index_) {};
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
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KMEANS;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
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 ) :
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
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = COMPOSITE;
p.trees = trees;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
struct AutotunedIndexParams : public IndexParams {
AutotunedIndexParams( float target_precision_ = 0.9, float build_weight_ = 0.01,
float memory_weight_ = 0, float sample_fraction_ = 0.1) :
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
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
target_precision = p.target_precision;
build_weight = p.build_weight;
memory_weight = p.memory_weight;
sample_fraction = p.sample_fraction;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = AUTOTUNED;
p.target_precision = target_precision;
p.build_weight = build_weight;
p.memory_weight = memory_weight;
p.sample_fraction = sample_fraction;
};
};
struct SavedIndexParams : public IndexParams {
SavedIndexParams() {
throw FLANNException("I don't know which index to load");
}
SavedIndexParams(std::string filename_) : filename(filename_) {}
std::string filename; // filename of the stored index
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct SearchParams {
SearchParams(int checks_ = 32) :
checks(checks_) {};
int checks;
};
class Index {
NNIndex* nnIndex;
public:
Index(const Matrix<float>& features, const IndexParams& params);
~Index();
void knnSearch(const Matrix<float>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& params);
int radiusSearch(const Matrix<float>& query, Matrix<int> indices, Matrix<float> dists, float radius, const SearchParams& params);
void save(std::string filename);
int veclen() const;
int size() const;
};
int hierarchicalClustering(const Matrix<float>& features, Matrix<float>& centers, const KMeansIndexParams& params);
}
#endif /* FLANN_HPP_ */

View File

@@ -1,163 +0,0 @@
/***********************************************************************
* 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 "random.h"
namespace cvflann
{
/**
* Class implementing a generic rectangular dataset.
*/
template <typename T>
class Matrix {
/**
* Flag showing if the class owns its data storage.
*/
bool ownData;
void shallow_copy(const Matrix& rhs)
{
data = rhs.data;
rows = rhs.rows;
cols = rhs.cols;
ownData = false;
}
public:
long rows;
long cols;
T* data;
Matrix(long rows_, long cols_, T* data_ = NULL) :
ownData(false), rows(rows_), cols(cols_), data(data_)
{
if (data_==NULL) {
data = new T[rows*cols];
ownData = true;
}
}
Matrix(const Matrix& d)
{
shallow_copy(d);
}
const Matrix& operator=(const Matrix& rhs)
{
if (this!=&rhs) {
shallow_copy(rhs);
}
return *this;
}
~Matrix()
{
if (ownData) {
delete[] data;
}
}
/**
* Operator that return a (pointer to a) row of the data.
*/
T* operator[](long index)
{
return data+index*cols;
}
T* operator[](long index) const
{
return data+index*cols;
}
Matrix<T>* sample(long size, bool remove = false)
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
if (remove) {
dest = (*this)[rows-i-1];
src = (*this)[r];
for (long j=0;j<cols;++j) {
swap(*src,*dest);
src++;
dest++;
}
}
}
if (remove) {
rows -= size;
}
return newSet;
}
Matrix<T>* sample(long size) const
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
}
return newSet;
}
};
}
#endif //DATASET_H

View File

@@ -1,134 +0,0 @@
/***********************************************************************
* 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++];
}
}
};
}
#endif //RANDOM_H