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

@@ -5,6 +5,7 @@ endif()
add_subdirectory(calib3d)
add_subdirectory(core)
add_subdirectory(features2d)
add_subdirectory(flann)
if(MSVC OR MINGW)
if(NOT CMAKE_CL_64)

View File

@@ -1 +1 @@
define_opencv_module(contrib opencv_core opencv_imgproc opencv_calib3d opencv_features2d opencv_highgui opencv_ml opencv_video opencv_objdetect)
define_opencv_module(contrib opencv_core opencv_imgproc opencv_calib3d opencv_features2d opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_flann)

View File

@@ -1,3 +1,3 @@
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/include")
set(deps opencv_lapack zlib flann)
set(deps opencv_lapack zlib)
define_opencv_module(core ${deps})

View File

@@ -3985,6 +3985,5 @@ public:
#include "opencv2/core/operations.hpp"
#include "opencv2/core/mat.hpp"
#include "opencv2/core/flann.hpp" // FLANN (Fast Library for Approximate Nearest Neighbors)
#endif /*__OPENCV_CORE_HPP__*/

View File

@@ -1,220 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_CORE_FLANN_HPP__
#define __OPENCV_CORE_FLANN_HPP__
#ifdef __cplusplus
namespace cvflann
{
class Index;
}
namespace cv {
namespace flann {
/* 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
};
class CV_EXPORTS IndexFactory
{
public:
virtual ~IndexFactory() {}
virtual ::cvflann::Index* createIndex(const Mat& dataset) const = 0;
};
struct CV_EXPORTS IndexParams : public IndexFactory {
protected:
IndexParams() {};
};
struct CV_EXPORTS LinearIndexParams : public IndexParams {
LinearIndexParams() {};
::cvflann::Index* createIndex(const Mat& dataset) const;
};
struct CV_EXPORTS KDTreeIndexParams : public IndexParams {
KDTreeIndexParams(int trees_ = 4) : trees(trees_) {};
int trees; // number of randomized trees to use (for kdtree)
::cvflann::Index* createIndex(const Mat& dataset) const;
};
struct CV_EXPORTS 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
::cvflann::Index* createIndex(const Mat& dataset) const;
};
struct CV_EXPORTS 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
::cvflann::Index* createIndex(const Mat& dataset) const;
};
struct CV_EXPORTS 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
::cvflann::Index* createIndex(const Mat& dataset) const;
};
struct CV_EXPORTS SavedIndexParams : public IndexParams {
SavedIndexParams() {}
SavedIndexParams(std::string filename_) : filename(filename_) {}
std::string filename; // filename of the stored index
::cvflann::Index* createIndex(const Mat& dataset) const;
};
struct CV_EXPORTS SearchParams {
SearchParams(int checks_ = 32) :
checks(checks_) {};
int checks;
};
class CV_EXPORTS Index {
::cvflann::Index* nnIndex;
public:
Index(const Mat& features, const IndexParams& params);
~Index();
void knnSearch(const vector<float>& queries, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& params);
void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params);
int radiusSearch(const vector<float>& query, vector<int>& indices, vector<float>& dists, float radius, const SearchParams& params);
int radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& params);
void save(std::string filename);
int veclen() const;
int size() const;
};
CV_EXPORTS int hierarchicalClustering(const Mat& features, Mat& centers,
const KMeansIndexParams& params);
}
}
#endif // __cplusplus
#endif

View File

@@ -1,211 +0,0 @@
/*********************************************************************
* Software License Agreement (BSD License)
*
* Copyright (c) 2009, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the Willow Garage nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/
#include "precomp.hpp"
#include "flann/flann.hpp"
namespace cv
{
namespace flann {
::cvflann::Index* LinearIndexParams::createIndex(const Mat& dataset) const
{
CV_Assert(dataset.type() == CV_32F);
CV_Assert(dataset.isContinuous());
// TODO: fix ::cvflann::Matrix class so it can be constructed with a const float*
::cvflann::Matrix<float> mat(dataset.rows, dataset.cols, (float*)dataset.ptr<float>(0));
return new ::cvflann::Index(mat, ::cvflann::LinearIndexParams());
}
::cvflann::Index* KDTreeIndexParams::createIndex(const Mat& dataset) const
{
CV_Assert(dataset.type() == CV_32F);
CV_Assert(dataset.isContinuous());
// TODO: fix ::cvflann::Matrix class so it can be constructed with a const float*
::cvflann::Matrix<float> mat(dataset.rows, dataset.cols, (float*)dataset.ptr<float>(0));
return new ::cvflann::Index(mat, ::cvflann::KDTreeIndexParams(trees));
}
::cvflann::Index* KMeansIndexParams::createIndex(const Mat& dataset) const
{
CV_Assert(dataset.type() == CV_32F);
CV_Assert(dataset.isContinuous());
// TODO: fix ::cvflann::Matrix class so it can be constructed with a const float*
::cvflann::Matrix<float> mat(dataset.rows, dataset.cols, (float*)dataset.ptr<float>(0));
return new ::cvflann::Index(mat, ::cvflann::KMeansIndexParams(branching,iterations, (::flann_centers_init_t)centers_init, cb_index));
}
::cvflann::Index* CompositeIndexParams::createIndex(const Mat& dataset) const
{
CV_Assert(dataset.type() == CV_32F);
CV_Assert(dataset.isContinuous());
// TODO: fix ::cvflann::Matrix class so it can be constructed with a const float*
::cvflann::Matrix<float> mat(dataset.rows, dataset.cols, (float*)dataset.ptr<float>(0));
return new ::cvflann::Index(mat, ::cvflann::CompositeIndexParams(trees, branching, iterations, (::flann_centers_init_t)centers_init, cb_index));
}
::cvflann::Index* AutotunedIndexParams::createIndex(const Mat& dataset) const
{
CV_Assert(dataset.type() == CV_32F);
CV_Assert(dataset.isContinuous());
// TODO: fix ::cvflann::Matrix class so it can be constructed with a const float*
::cvflann::Matrix<float> mat(dataset.rows, dataset.cols, (float*)dataset.ptr<float>(0));
return new ::cvflann::Index(mat, ::cvflann::AutotunedIndexParams(target_precision, build_weight, memory_weight, sample_fraction));
}
::cvflann::Index* SavedIndexParams::createIndex(const Mat& dataset) const
{
CV_Assert(dataset.type() == CV_32F);
CV_Assert(dataset.isContinuous());
// TODO: fix ::cvflann::Matrix class so it can be constructed with a const float*
::cvflann::Matrix<float> mat(dataset.rows, dataset.cols, (float*)dataset.ptr<float>(0));
return new ::cvflann::Index(mat, ::cvflann::SavedIndexParams(filename));
}
Index::Index(const Mat& dataset, const IndexParams& params)
{
nnIndex = params.createIndex(dataset);
}
Index::~Index()
{
delete nnIndex;
}
void Index::knnSearch(const vector<float>& query, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& searchParams)
{
::cvflann::Matrix<float> m_query(1, (int)query.size(), (float*)&query[0]);
::cvflann::Matrix<int> m_indices(1, (int)indices.size(), &indices[0]);
::cvflann::Matrix<float> m_dists(1, (int)dists.size(), &dists[0]);
nnIndex->knnSearch(m_query,m_indices,m_dists,knn,::cvflann::SearchParams(searchParams.checks));
}
void Index::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& searchParams)
{
CV_Assert(queries.type() == CV_32F);
CV_Assert(queries.isContinuous());
::cvflann::Matrix<float> m_queries(queries.rows, queries.cols, (float*)queries.ptr<float>(0));
CV_Assert(indices.type() == CV_32S);
CV_Assert(indices.isContinuous());
::cvflann::Matrix<int> m_indices(indices.rows, indices.cols, (int*)indices.ptr<int>(0));
CV_Assert(dists.type() == CV_32F);
CV_Assert(dists.isContinuous());
::cvflann::Matrix<float> m_dists(dists.rows, dists.cols, (float*)dists.ptr<float>(0));
nnIndex->knnSearch(m_queries,m_indices,m_dists,knn,::cvflann::SearchParams(searchParams.checks));
}
int Index::radiusSearch(const vector<float>& query, vector<int>& indices, vector<float>& dists, float radius, const SearchParams& searchParams)
{
::cvflann::Matrix<float> m_query(1, (int)query.size(), (float*)&query[0]);
::cvflann::Matrix<int> m_indices(1, (int)indices.size(), &indices[0]);
::cvflann::Matrix<float> m_dists(1, (int)dists.size(), &dists[0]);
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,::cvflann::SearchParams(searchParams.checks));
}
int Index::radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& searchParams)
{
CV_Assert(query.type() == CV_32F);
CV_Assert(query.isContinuous());
::cvflann::Matrix<float> m_query(query.rows, query.cols, (float*)query.ptr<float>(0));
CV_Assert(indices.type() == CV_32S);
CV_Assert(indices.isContinuous());
::cvflann::Matrix<int> m_indices(indices.rows, indices.cols, (int*)indices.ptr<int>(0));
CV_Assert(dists.type() == CV_32F);
CV_Assert(dists.isContinuous());
::cvflann::Matrix<float> m_dists(dists.rows, dists.cols, (float*)dists.ptr<float>(0));
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,::cvflann::SearchParams(searchParams.checks));
}
void Index::save(string filename)
{
nnIndex->save(filename);
}
int Index::size() const
{
return nnIndex->size();
}
int Index::veclen() const
{
return nnIndex->veclen();
}
int hierarchicalClustering(const Mat& features, Mat& centers, const KMeansIndexParams& params)
{
CV_Assert(features.type() == CV_32F);
CV_Assert(features.isContinuous());
::cvflann::Matrix<float> m_features(features.rows, features.cols, (float*)features.ptr<float>(0));
CV_Assert(features.type() == CV_32F);
CV_Assert(features.isContinuous());
::cvflann::Matrix<float> m_centers(centers.rows, centers.cols, (float*)centers.ptr<float>(0));
return ::cvflann::hierarchicalClustering(m_features, m_centers, ::cvflann::KMeansIndexParams(params.branching, params.iterations,
(::flann_centers_init_t)params.centers_init, params.cb_index));
}
}
}

View File

@@ -1,2 +1,2 @@
define_opencv_module(features2d opencv_core opencv_imgproc opencv_calib3d opencv_highgui)
define_opencv_module(features2d opencv_core opencv_imgproc opencv_calib3d opencv_highgui opencv_flann)

View File

@@ -44,6 +44,7 @@
#define __OPENCV_FEATURES_2D_HPP__
#include "opencv2/core/core.hpp"
#include "opencv2/flann/flann.hpp"
#ifdef __cplusplus
#include <limits>

View File

@@ -0,0 +1,2 @@
define_opencv_module(flann opencv_core)

View File

@@ -0,0 +1,76 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef ALL_INDICES_H_
#define ALL_INDICES_H_
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
#include "opencv2/flann/kdtree_index.h"
#include "opencv2/flann/kmeans_index.h"
#include "opencv2/flann/composite_index.h"
#include "opencv2/flann/linear_index.h"
#include "opencv2/flann/autotuned_index.h"
namespace cvflann
{
template<typename T>
NNIndex<T>* create_index_by_type(const Matrix<T>& dataset, const IndexParams& params)
{
flann_algorithm_t index_type = params.getIndexType();
NNIndex<T>* nnIndex;
switch (index_type) {
case LINEAR:
nnIndex = new LinearIndex<T>(dataset, (const LinearIndexParams&)params);
break;
case KDTREE:
nnIndex = new KDTreeIndex<T>(dataset, (const KDTreeIndexParams&)params);
break;
case KMEANS:
nnIndex = new KMeansIndex<T>(dataset, (const KMeansIndexParams&)params);
break;
case COMPOSITE:
nnIndex = new CompositeIndex<T>(dataset, (const CompositeIndexParams&) params);
break;
case AUTOTUNED:
nnIndex = new AutotunedIndex<T>(dataset, (const AutotunedIndexParams&) params);
break;
default:
throw FLANNException("Unknown index type");
}
return nnIndex;
}
} //namespace cvflann
#endif /* ALL_INDICES_H_ */

View File

@@ -0,0 +1,187 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
#include <stdlib.h>
#include <stdio.h>
namespace cvflann
{
/**
* Allocates (using C's malloc) a generic type T.
*
* Params:
* count = number of instances to allocate.
* Returns: pointer (of type T*) to memory buffer
*/
template <typename T>
T* allocate(size_t count = 1)
{
T* mem = (T*) ::malloc(sizeof(T)*count);
return mem;
}
/**
* Pooled storage allocator
*
* The following routines allow for the efficient allocation of storage in
* small chunks from a specified pool. Rather than allowing each structure
* to be freed individually, an entire pool of storage is freed at once.
* This method has two advantages over just using malloc() and free(). First,
* it is far more efficient for allocating small objects, as there is
* no overhead for remembering all the information needed to free each
* object or consolidating fragmented memory. Second, the decision about
* how long to keep an object is made at the time of allocation, and there
* is no need to track down all the objects to free them.
*
*/
const size_t WORDSIZE=16;
const size_t BLOCKSIZE=8192;
class PooledAllocator
{
/* We maintain memory alignment to word boundaries by requiring that all
allocations be in multiples of the machine wordsize. */
/* Size of machine word in bytes. Must be power of 2. */
/* Minimum number of bytes requested at a time from the system. Must be multiple of WORDSIZE. */
int remaining; /* Number of bytes left in current block of storage. */
void* base; /* Pointer to base of current block of storage. */
void* loc; /* Current location in block to next allocate memory. */
int blocksize;
public:
int usedMemory;
int wastedMemory;
/**
Default constructor. Initializes a new pool.
*/
PooledAllocator(int blocksize = BLOCKSIZE)
{
this->blocksize = blocksize;
remaining = 0;
base = NULL;
usedMemory = 0;
wastedMemory = 0;
}
/**
* Destructor. Frees all the memory allocated in this pool.
*/
~PooledAllocator()
{
void *prev;
while (base != NULL) {
prev = *((void **) base); /* Get pointer to prev block. */
::free(base);
base = prev;
}
}
/**
* Returns a pointer to a piece of new memory of the given size in bytes
* allocated from the pool.
*/
void* malloc(int size)
{
int blocksize;
/* Round size up to a multiple of wordsize. The following expression
only works for WORDSIZE that is a power of 2, by masking last bits of
incremented size to zero.
*/
size = (size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
/* Check whether a new block must be allocated. Note that the first word
of a block is reserved for a pointer to the previous block.
*/
if (size > remaining) {
wastedMemory += remaining;
/* Allocate new storage. */
blocksize = (size + sizeof(void*) + (WORDSIZE-1) > BLOCKSIZE) ?
size + sizeof(void*) + (WORDSIZE-1) : BLOCKSIZE;
// use the standard C malloc to allocate memory
void* m = ::malloc(blocksize);
if (!m) {
fprintf(stderr,"Failed to allocate memory.\n");
exit(1);
}
/* Fill first word of new block with pointer to previous block. */
((void **) m)[0] = base;
base = m;
int shift = 0;
//int shift = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1);
remaining = blocksize - sizeof(void*) - shift;
loc = ((char*)m + sizeof(void*) + shift);
}
void* rloc = loc;
loc = (char*)loc + size;
remaining -= size;
usedMemory += size;
return rloc;
}
/**
* Allocates (using this pool) a generic type T.
*
* Params:
* count = number of instances to allocate.
* Returns: pointer (of type T*) to memory buffer
*/
template <typename T>
T* allocate(size_t count = 1)
{
T* mem = (T*) this->malloc(sizeof(T)*count);
return mem;
}
};
} // namespace cvflann
#endif //ALLOCATOR_H

View File

@@ -0,0 +1,614 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef AUTOTUNEDINDEX_H_
#define AUTOTUNEDINDEX_H_
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
#include "opencv2/flann/ground_truth.h"
#include "opencv2/flann/index_testing.h"
#include "opencv2/flann/sampling.h"
#include "opencv2/flann/all_indices.h"
namespace cvflann
{
struct AutotunedIndexParams : public IndexParams {
AutotunedIndexParams( float target_precision_ = 0.8, float build_weight_ = 0.01,
float memory_weight_ = 0, float sample_fraction_ = 0.1) :
IndexParams(AUTOTUNED),
target_precision(target_precision_),
build_weight(build_weight_),
memory_weight(memory_weight_),
sample_fraction(sample_fraction_) {};
float target_precision; // precision desired (used for autotuning, -1 otherwise)
float build_weight; // build tree time weighting factor
float memory_weight; // index memory weighting factor
float sample_fraction; // what fraction of the dataset to use for autotuning
flann_algorithm_t getIndexType() const { return algorithm; }
void print() const
{
logger.info("Index type: %d\n",(int)algorithm);
logger.info("Target precision: %g\n", target_precision);
logger.info("Build weight: %g\n", build_weight);
logger.info("Memory weight: %g\n", memory_weight);
logger.info("Sample fraction: %g\n", sample_fraction);
}
};
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
class AutotunedIndex : public NNIndex<ELEM_TYPE>
{
NNIndex<ELEM_TYPE>* bestIndex;
IndexParams* bestParams;
SearchParams bestSearchParams;
Matrix<ELEM_TYPE> sampledDataset;
Matrix<ELEM_TYPE> testDataset;
Matrix<int> gt_matches;
float speedup;
/**
* The dataset used by this index
*/
const Matrix<ELEM_TYPE> dataset;
/**
* Index parameters
*/
const AutotunedIndexParams& index_params;
public:
AutotunedIndex(const Matrix<ELEM_TYPE>& inputData, const AutotunedIndexParams& params = AutotunedIndexParams() ) :
dataset(inputData), index_params(params)
{
bestIndex = NULL;
bestParams = NULL;
}
virtual ~AutotunedIndex()
{
if (bestIndex!=NULL) {
delete bestIndex;
}
if (bestParams!=NULL) {
delete bestParams;
}
};
/**
Method responsible with building the index.
*/
virtual void buildIndex()
{
bestParams = estimateBuildParams();
logger.info("----------------------------------------------------\n");
logger.info("Autotuned parameters:\n");
bestParams->print();
logger.info("----------------------------------------------------\n");
flann_algorithm_t index_type = bestParams->getIndexType();
switch (index_type) {
case LINEAR:
bestIndex = new LinearIndex<ELEM_TYPE>(dataset, (const LinearIndexParams&)*bestParams);
break;
case KDTREE:
bestIndex = new KDTreeIndex<ELEM_TYPE>(dataset, (const KDTreeIndexParams&)*bestParams);
break;
case KMEANS:
bestIndex = new KMeansIndex<ELEM_TYPE>(dataset, (const KMeansIndexParams&)*bestParams);
break;
default:
throw FLANNException("Unknown algorithm choosen by the autotuning, most likely a bug.");
}
bestIndex->buildIndex();
speedup = estimateSearchParams(bestSearchParams);
}
/**
Saves the index to a stream
*/
virtual void saveIndex(FILE* stream)
{
save_value(stream, (int)bestIndex->getType());
bestIndex->saveIndex(stream);
save_value(stream, bestSearchParams);
}
/**
Loads the index from a stream
*/
virtual void loadIndex(FILE* stream)
{
int index_type;
load_value(stream,index_type);
IndexParams* params = ParamsFactory::instance().create((flann_algorithm_t)index_type);
bestIndex = create_index_by_type(dataset, *params);
bestIndex->loadIndex(stream);
load_value(stream, bestSearchParams);
}
/**
Method that searches for nearest-neighbors
*/
virtual void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams)
{
if (searchParams.checks==-2) {
bestIndex->findNeighbors(result, vec, bestSearchParams);
}
else {
bestIndex->findNeighbors(result, vec, searchParams);
}
}
const IndexParams* getParameters() const
{
return bestIndex->getParameters();
}
/**
Number of features in this index.
*/
virtual size_t size() const
{
return bestIndex->size();
}
/**
The length of each vector in this index.
*/
virtual size_t veclen() const
{
return bestIndex->veclen();
}
/**
The amount of memory (in bytes) this index uses.
*/
virtual int usedMemory() const
{
return bestIndex->usedMemory();
}
/**
* Algorithm name
*/
virtual flann_algorithm_t getType() const
{
return AUTOTUNED;
}
private:
struct CostData {
float searchTimeCost;
float buildTimeCost;
float timeCost;
float memoryCost;
float totalCost;
};
typedef pair<CostData, KDTreeIndexParams> KDTreeCostData;
typedef pair<CostData, KMeansIndexParams> KMeansCostData;
void evaluate_kmeans(CostData& cost, const KMeansIndexParams& kmeans_params)
{
StartStopTimer t;
int checks;
const int nn = 1;
logger.info("KMeansTree using params: max_iterations=%d, branching=%d\n", kmeans_params.iterations, kmeans_params.branching);
KMeansIndex<ELEM_TYPE> kmeans(sampledDataset, kmeans_params);
// measure index build time
t.start();
kmeans.buildIndex();
t.stop();
float buildTime = t.value;
// measure search time
float searchTime = test_index_precision(kmeans, sampledDataset, testDataset, gt_matches, index_params.target_precision, checks, nn);;
float datasetMemory = sampledDataset.rows*sampledDataset.cols*sizeof(float);
cost.memoryCost = (kmeans.usedMemory()+datasetMemory)/datasetMemory;
cost.searchTimeCost = searchTime;
cost.buildTimeCost = buildTime;
cost.timeCost = (buildTime*index_params.build_weight+searchTime);
logger.info("KMeansTree buildTime=%g, searchTime=%g, timeCost=%g, buildTimeFactor=%g\n",buildTime, searchTime, cost.timeCost, index_params.build_weight);
}
void evaluate_kdtree(CostData& cost, const KDTreeIndexParams& kdtree_params)
{
StartStopTimer t;
int checks;
const int nn = 1;
logger.info("KDTree using params: trees=%d\n",kdtree_params.trees);
KDTreeIndex<ELEM_TYPE> kdtree(sampledDataset, kdtree_params);
t.start();
kdtree.buildIndex();
t.stop();
float buildTime = t.value;
//measure search time
float searchTime = test_index_precision(kdtree, sampledDataset, testDataset, gt_matches, index_params.target_precision, checks, nn);
float datasetMemory = sampledDataset.rows*sampledDataset.cols*sizeof(float);
cost.memoryCost = (kdtree.usedMemory()+datasetMemory)/datasetMemory;
cost.searchTimeCost = searchTime;
cost.buildTimeCost = buildTime;
cost.timeCost = (buildTime*index_params.build_weight+searchTime);
logger.info("KDTree buildTime=%g, searchTime=%g, timeCost=%g\n",buildTime, searchTime, cost.timeCost);
}
// struct KMeansSimpleDownhillFunctor {
//
// Autotune& autotuner;
// KMeansSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {};
//
// float operator()(int* params) {
//
// float maxFloat = numeric_limits<float>::max();
//
// if (params[0]<2) return maxFloat;
// if (params[1]<0) return maxFloat;
//
// CostData c;
// c.params["algorithm"] = KMEANS;
// c.params["centers-init"] = CENTERS_RANDOM;
// c.params["branching"] = params[0];
// c.params["max-iterations"] = params[1];
//
// autotuner.evaluate_kmeans(c);
//
// return c.timeCost;
//
// }
// };
//
// struct KDTreeSimpleDownhillFunctor {
//
// Autotune& autotuner;
// KDTreeSimpleDownhillFunctor(Autotune& autotuner_) : autotuner(autotuner_) {};
//
// float operator()(int* params) {
// float maxFloat = numeric_limits<float>::max();
//
// if (params[0]<1) return maxFloat;
//
// CostData c;
// c.params["algorithm"] = KDTREE;
// c.params["trees"] = params[0];
//
// autotuner.evaluate_kdtree(c);
//
// return c.timeCost;
//
// }
// };
KMeansCostData optimizeKMeans()
{
logger.info("KMEANS, Step 1: Exploring parameter space\n");
// explore kmeans parameters space using combinations of the parameters below
int maxIterations[] = { 1, 5, 10, 15 };
int branchingFactors[] = { 16, 32, 64, 128, 256 };
int kmeansParamSpaceSize = ARRAY_LEN(maxIterations)*ARRAY_LEN(branchingFactors);
vector<KMeansCostData> kmeansCosts(kmeansParamSpaceSize);
// CostData* kmeansCosts = new CostData[kmeansParamSpaceSize];
// evaluate kmeans for all parameter combinations
int cnt = 0;
for (size_t i=0; i<ARRAY_LEN(maxIterations); ++i) {
for (size_t j=0; j<ARRAY_LEN(branchingFactors); ++j) {
kmeansCosts[cnt].second.centers_init = CENTERS_RANDOM;
kmeansCosts[cnt].second.iterations = maxIterations[i];
kmeansCosts[cnt].second.branching = branchingFactors[j];
evaluate_kmeans(kmeansCosts[cnt].first, kmeansCosts[cnt].second);
int k = cnt;
// order by time cost
while (k>0 && kmeansCosts[k].first.timeCost < kmeansCosts[k-1].first.timeCost) {
swap(kmeansCosts[k],kmeansCosts[k-1]);
--k;
}
++cnt;
}
}
// logger.info("KMEANS, Step 2: simplex-downhill optimization\n");
//
// const int n = 2;
// // choose initial simplex points as the best parameters so far
// int kmeansNMPoints[n*(n+1)];
// float kmeansVals[n+1];
// for (int i=0;i<n+1;++i) {
// kmeansNMPoints[i*n] = (int)kmeansCosts[i].params["branching"];
// kmeansNMPoints[i*n+1] = (int)kmeansCosts[i].params["max-iterations"];
// kmeansVals[i] = kmeansCosts[i].timeCost;
// }
// KMeansSimpleDownhillFunctor kmeans_cost_func(*this);
// // run optimization
// optimizeSimplexDownhill(kmeansNMPoints,n,kmeans_cost_func,kmeansVals);
// // store results
// for (int i=0;i<n+1;++i) {
// kmeansCosts[i].params["branching"] = kmeansNMPoints[i*2];
// kmeansCosts[i].params["max-iterations"] = kmeansNMPoints[i*2+1];
// kmeansCosts[i].timeCost = kmeansVals[i];
// }
float optTimeCost = kmeansCosts[0].first.timeCost;
// recompute total costs factoring in the memory costs
for (int i=0;i<kmeansParamSpaceSize;++i) {
kmeansCosts[i].first.totalCost = (kmeansCosts[i].first.timeCost/optTimeCost + index_params.memory_weight * kmeansCosts[i].first.memoryCost);
int k = i;
while (k>0 && kmeansCosts[k].first.totalCost < kmeansCosts[k-1].first.totalCost) {
swap(kmeansCosts[k],kmeansCosts[k-1]);
k--;
}
}
// display the costs obtained
for (int i=0;i<kmeansParamSpaceSize;++i) {
logger.info("KMeans, branching=%d, iterations=%d, time_cost=%g[%g] (build=%g, search=%g), memory_cost=%g, cost=%g\n",
kmeansCosts[i].second.branching, kmeansCosts[i].second.iterations,
kmeansCosts[i].first.timeCost,kmeansCosts[i].first.timeCost/optTimeCost,
kmeansCosts[i].first.buildTimeCost, kmeansCosts[i].first.searchTimeCost,
kmeansCosts[i].first.memoryCost,kmeansCosts[i].first.totalCost);
}
return kmeansCosts[0];
}
KDTreeCostData optimizeKDTree()
{
logger.info("KD-TREE, Step 1: Exploring parameter space\n");
// explore kd-tree parameters space using the parameters below
int testTrees[] = { 1, 4, 8, 16, 32 };
size_t kdtreeParamSpaceSize = ARRAY_LEN(testTrees);
vector<KDTreeCostData> kdtreeCosts(kdtreeParamSpaceSize);
// evaluate kdtree for all parameter combinations
int cnt = 0;
for (size_t i=0; i<ARRAY_LEN(testTrees); ++i) {
kdtreeCosts[cnt].second.trees = testTrees[i];
evaluate_kdtree(kdtreeCosts[cnt].first, kdtreeCosts[cnt].second);
int k = cnt;
// order by time cost
while (k>0 && kdtreeCosts[k].first.timeCost < kdtreeCosts[k-1].first.timeCost) {
swap(kdtreeCosts[k],kdtreeCosts[k-1]);
--k;
}
++cnt;
}
// logger.info("KD-TREE, Step 2: simplex-downhill optimization\n");
//
// const int n = 1;
// // choose initial simplex points as the best parameters so far
// int kdtreeNMPoints[n*(n+1)];
// float kdtreeVals[n+1];
// for (int i=0;i<n+1;++i) {
// kdtreeNMPoints[i] = (int)kdtreeCosts[i].params["trees"];
// kdtreeVals[i] = kdtreeCosts[i].timeCost;
// }
// KDTreeSimpleDownhillFunctor kdtree_cost_func(*this);
// // run optimization
// optimizeSimplexDownhill(kdtreeNMPoints,n,kdtree_cost_func,kdtreeVals);
// // store results
// for (int i=0;i<n+1;++i) {
// kdtreeCosts[i].params["trees"] = kdtreeNMPoints[i];
// kdtreeCosts[i].timeCost = kdtreeVals[i];
// }
float optTimeCost = kdtreeCosts[0].first.timeCost;
// recompute costs for kd-tree factoring in memory cost
for (size_t i=0;i<kdtreeParamSpaceSize;++i) {
kdtreeCosts[i].first.totalCost = (kdtreeCosts[i].first.timeCost/optTimeCost + index_params.memory_weight * kdtreeCosts[i].first.memoryCost);
int k = i;
while (k>0 && kdtreeCosts[k].first.totalCost < kdtreeCosts[k-1].first.totalCost) {
swap(kdtreeCosts[k],kdtreeCosts[k-1]);
k--;
}
}
// display costs obtained
for (size_t i=0;i<kdtreeParamSpaceSize;++i) {
logger.info("kd-tree, trees=%d, time_cost=%g[%g] (build=%g, search=%g), memory_cost=%g, cost=%g\n",
kdtreeCosts[i].second.trees,kdtreeCosts[i].first.timeCost,kdtreeCosts[i].first.timeCost/optTimeCost,
kdtreeCosts[i].first.buildTimeCost, kdtreeCosts[i].first.searchTimeCost,
kdtreeCosts[i].first.memoryCost,kdtreeCosts[i].first.totalCost);
}
return kdtreeCosts[0];
}
/**
Chooses the best nearest-neighbor algorithm and estimates the optimal
parameters to use when building the index (for a given precision).
Returns a dictionary with the optimal parameters.
*/
IndexParams* estimateBuildParams()
{
int sampleSize = int(index_params.sample_fraction*dataset.rows);
int testSampleSize = min(sampleSize/10, 1000);
logger.info("Entering autotuning, dataset size: %d, sampleSize: %d, testSampleSize: %d\n",dataset.rows, sampleSize, testSampleSize);
// For a very small dataset, it makes no sense to build any fancy index, just
// use linear search
if (testSampleSize<10) {
logger.info("Choosing linear, dataset too small\n");
return new LinearIndexParams();
}
// We use a fraction of the original dataset to speedup the autotune algorithm
sampledDataset = random_sample(dataset,sampleSize);
// We use a cross-validation approach, first we sample a testset from the dataset
testDataset = random_sample(sampledDataset,testSampleSize,true);
// We compute the ground truth using linear search
logger.info("Computing ground truth... \n");
gt_matches = Matrix<int>(new int[testDataset.rows],testDataset.rows, 1);
StartStopTimer t;
t.start();
compute_ground_truth(sampledDataset, testDataset, gt_matches, 0);
t.stop();
float bestCost = t.value;
IndexParams* bestParams = new LinearIndexParams();
// Start parameter autotune process
logger.info("Autotuning parameters...\n");
KMeansCostData kmeansCost = optimizeKMeans();
if (kmeansCost.first.totalCost<bestCost) {
bestParams = new KMeansIndexParams(kmeansCost.second);
bestCost = kmeansCost.first.totalCost;
}
KDTreeCostData kdtreeCost = optimizeKDTree();
if (kdtreeCost.first.totalCost<bestCost) {
bestParams = new KDTreeIndexParams(kdtreeCost.second);
bestCost = kdtreeCost.first.totalCost;
}
gt_matches.free();
sampledDataset.free();
testDataset.free();
return bestParams;
}
/**
Estimates the search time parameters needed to get the desired precision.
Precondition: the index is built
Postcondition: the searchParams will have the optimum params set, also the speedup obtained over linear search.
*/
float estimateSearchParams(SearchParams& searchParams)
{
const int nn = 1;
const size_t SAMPLE_COUNT = 1000;
assert(bestIndex!=NULL); // must have a valid index
float speedup = 0;
int samples = min(dataset.rows/10, SAMPLE_COUNT);
if (samples>0) {
Matrix<ELEM_TYPE> testDataset = random_sample(dataset,samples);
logger.info("Computing ground truth\n");
// we need to compute the ground truth first
Matrix<int> gt_matches(new int[testDataset.rows],testDataset.rows,1);
StartStopTimer t;
t.start();
compute_ground_truth(dataset, testDataset, gt_matches,1);
t.stop();
float linear = t.value;
int checks;
logger.info("Estimating number of checks\n");
float searchTime;
float cb_index;
if (bestIndex->getType() == KMEANS) {
logger.info("KMeans algorithm, estimating cluster border factor\n");
KMeansIndex<ELEM_TYPE>* kmeans = (KMeansIndex<ELEM_TYPE>*)bestIndex;
float bestSearchTime = -1;
float best_cb_index = -1;
int best_checks = -1;
for (cb_index = 0;cb_index<1.1; cb_index+=0.2) {
kmeans->set_cb_index(cb_index);
searchTime = test_index_precision(*kmeans, dataset, testDataset, gt_matches, index_params.target_precision, checks, nn, 1);
if (searchTime<bestSearchTime || bestSearchTime == -1) {
bestSearchTime = searchTime;
best_cb_index = cb_index;
best_checks = checks;
}
}
searchTime = bestSearchTime;
cb_index = best_cb_index;
checks = best_checks;
kmeans->set_cb_index(best_cb_index);
logger.info("Optimum cb_index: %g\n",cb_index);
((KMeansIndexParams*)bestParams)->cb_index = cb_index;
}
else {
searchTime = test_index_precision(*bestIndex, dataset, testDataset, gt_matches, index_params.target_precision, checks, nn, 1);
}
logger.info("Required number of checks: %d \n",checks);;
searchParams.checks = checks;
speedup = linear/searchTime;
gt_matches.free();
}
return speedup;
}
};
} // namespace cvflann
#endif /* AUTOTUNEDINDEX_H_ */

View File

@@ -0,0 +1,163 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef COMPOSITETREE_H
#define COMPOSITETREE_H
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
namespace cvflann
{
struct CompositeIndexParams : public IndexParams {
CompositeIndexParams(int trees_ = 4, int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
IndexParams(COMPOSITE),
trees(trees_),
branching(branching_),
iterations(iterations_),
centers_init(centers_init_),
cb_index(cb_index_) {};
int trees; // number of randomized trees to use (for kdtree)
int branching; // branching factor (for kmeans tree)
int iterations; // max iterations to perform in one kmeans clustering (kmeans tree)
flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree
float cb_index; // cluster boundary index. Used when searching the kmeans tree
flann_algorithm_t getIndexType() const { return algorithm; }
void print() const
{
logger.info("Index type: %d\n",(int)algorithm);
logger.info("Trees: %d\n", trees);
logger.info("Branching: %d\n", branching);
logger.info("Iterations: %d\n", iterations);
logger.info("Centres initialisation: %d\n", centers_init);
logger.info("Cluster boundary weight: %g\n", cb_index);
}
};
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
class CompositeIndex : public NNIndex<ELEM_TYPE>
{
KMeansIndex<ELEM_TYPE, DIST_TYPE>* kmeans;
KDTreeIndex<ELEM_TYPE, DIST_TYPE>* kdtree;
const Matrix<ELEM_TYPE> dataset;
const IndexParams& index_params;
public:
CompositeIndex(const Matrix<ELEM_TYPE>& inputData, const CompositeIndexParams& params = CompositeIndexParams() ) :
dataset(inputData), index_params(params)
{
KDTreeIndexParams kdtree_params(params.trees);
KMeansIndexParams kmeans_params(params.branching, params.iterations, params.centers_init, params.cb_index);
kdtree = new KDTreeIndex<ELEM_TYPE, DIST_TYPE>(inputData,kdtree_params);
kmeans = new KMeansIndex<ELEM_TYPE, DIST_TYPE>(inputData,kmeans_params);
}
virtual ~CompositeIndex()
{
delete kdtree;
delete kmeans;
}
flann_algorithm_t getType() const
{
return COMPOSITE;
}
size_t size() const
{
return dataset.rows;
}
size_t veclen() const
{
return dataset.cols;
}
int usedMemory() const
{
return kmeans->usedMemory()+kdtree->usedMemory();
}
void buildIndex()
{
logger.info("Building kmeans tree...\n");
kmeans->buildIndex();
logger.info("Building kdtree tree...\n");
kdtree->buildIndex();
}
void saveIndex(FILE* stream)
{
kmeans->saveIndex(stream);
kdtree->saveIndex(stream);
}
void loadIndex(FILE* stream)
{
kmeans->loadIndex(stream);
kdtree->loadIndex(stream);
}
void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams)
{
kmeans->findNeighbors(result,vec,searchParams);
kdtree->findNeighbors(result,vec,searchParams);
}
const IndexParams* getParameters() const
{
return &index_params;
}
};
} // namespace cvflann
#endif //COMPOSITETREE_H

View File

@@ -0,0 +1,360 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef DIST_H
#define DIST_H
#include <cmath>
using namespace std;
#include "opencv2/flann/general.h"
namespace cvflann
{
/**
* Distance function by default set to the custom distance
* function. This can be set to a specific distance function
* for further efficiency.
*/
#define flann_dist custom_dist
//#define flann_dist euclidean_dist
/**
* Compute the squared Euclidean distance between two vectors.
*
* This is highly optimised, with loop unrolling, as it is one
* of the most expensive inner loops.
*
* The computation of squared root at the end is omitted for
* efficiency.
*/
template <typename Iterator1, typename Iterator2>
double euclidean_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double distsq = acc;
double diff0, diff1, diff2, diff3;
Iterator1 lastgroup = last1 - 3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
diff0 = first1[0] - first2[0];
diff1 = first1[1] - first2[1];
diff2 = first1[2] - first2[2];
diff3 = first1[3] - first2[3];
distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
diff0 = *first1++ - *first2++;
distsq += diff0 * diff0;
}
return distsq;
}
double euclidean_dist(const unsigned char* first1, const unsigned char* last1, unsigned char* first2, double acc);
/**
* Compute the Manhattan (L_1) distance between two vectors.
*
* This is highly optimised, with loop unrolling, as it is one
* of the most expensive inner loops.
*/
template <typename Iterator1, typename Iterator2>
double manhattan_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double distsq = acc;
double diff0, diff1, diff2, diff3;
Iterator1 lastgroup = last1 - 3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
diff0 = fabs(first1[0] - first2[0]);
diff1 = fabs(first1[1] - first2[1]);
diff2 = fabs(first1[2] - first2[2]);
diff3 = fabs(first1[3] - first2[3]);
distsq += diff0 + diff1 + diff2 + diff3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
diff0 = fabs(*first1++ - *first2++);
distsq += diff0;
}
return distsq;
}
extern int flann_minkowski_order;
/**
* Compute the Minkowski (L_p) distance between two vectors.
*
* This is highly optimised, with loop unrolling, as it is one
* of the most expensive inner loops.
*
* The computation of squared root at the end is omitted for
* efficiency.
*/
template <typename Iterator1, typename Iterator2>
double minkowski_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double distsq = acc;
double diff0, diff1, diff2, diff3;
Iterator1 lastgroup = last1 - 3;
int p = flann_minkowski_order;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
diff0 = fabs(first1[0] - first2[0]);
diff1 = fabs(first1[1] - first2[1]);
diff2 = fabs(first1[2] - first2[2]);
diff3 = fabs(first1[3] - first2[3]);
distsq += pow(diff0,p) + pow(diff1,p) + pow(diff2,p) + pow(diff3,p);
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
diff0 = fabs(*first1++ - *first2++);
distsq += pow(diff0,p);
}
return distsq;
}
// L_infinity distance (NOT A VALID KD-TREE DISTANCE - NOT DIMENSIONWISE ADDITIVE)
template <typename Iterator1, typename Iterator2>
double max_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double dist = acc;
Iterator1 lastgroup = last1 - 3;
double diff0, diff1, diff2, diff3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
diff0 = fabs(first1[0] - first2[0]);
diff1 = fabs(first1[1] - first2[1]);
diff2 = fabs(first1[2] - first2[2]);
diff3 = fabs(first1[3] - first2[3]);
if (diff0 > dist) dist = diff0;
if (diff1 > dist) dist = diff1;
if (diff2 > dist) dist = diff2;
if (diff3 > dist) dist = diff3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
diff0 = fabs(*first1++ - *first2++);
dist = (diff0 > dist) ? diff0 : dist;
}
return dist;
}
template <typename Iterator1, typename Iterator2>
double hist_intersection_kernel(Iterator1 first1, Iterator1 last1, Iterator2 first2)
{
double kernel = 0;
Iterator1 lastgroup = last1 - 3;
double min0, min1, min2, min3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
min0 = first1[0] < first2[0] ? first1[0] : first2[0];
min1 = first1[1] < first2[1] ? first1[1] : first2[1];
min2 = first1[2] < first2[2] ? first1[2] : first2[2];
min3 = first1[3] < first2[3] ? first1[3] : first2[3];
kernel += min0 + min1 + min2 + min3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
min0 = first1[0] < first2[0] ? first1[0] : first2[0];
kernel += min0;
first1++;
first2++;
}
return kernel;
}
template <typename Iterator1, typename Iterator2>
double hist_intersection_dist_sq(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double dist_sq = acc - 2 * hist_intersection_kernel(first1, last1, first2);
while (first1 < last1) {
dist_sq += *first1 + *first2;
first1++;
first2++;
}
return dist_sq;
}
// Hellinger distance
template <typename Iterator1, typename Iterator2>
double hellinger_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double distsq = acc;
double diff0, diff1, diff2, diff3;
Iterator1 lastgroup = last1 - 3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
diff0 = sqrt(first1[0]) - sqrt(first2[0]);
diff1 = sqrt(first1[1]) - sqrt(first2[1]);
diff2 = sqrt(first1[2]) - sqrt(first2[2]);
diff3 = sqrt(first1[3]) - sqrt(first2[3]);
distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
diff0 = sqrt(*first1++) - sqrt(*first2++);
distsq += diff0 * diff0;
}
return distsq;
}
// chi-dsquare distance
template <typename Iterator1, typename Iterator2>
double chi_square_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double dist = acc;
while (first1 < last1) {
double sum = *first1 + *first2;
if (sum > 0) {
double diff = *first1 - *first2;
dist += diff * diff / sum;
}
first1++;
first2++;
}
return dist;
}
// KullbackLeibler divergence (NOT SYMMETRIC)
template <typename Iterator1, typename Iterator2>
double kl_divergence(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double div = acc;
while (first1 < last1) {
if (*first2 != 0) {
double ratio = *first1 / *first2;
if (ratio > 0) {
div += *first1 * log(ratio);
}
}
first1++;
first2++;
}
return div;
}
extern flann_distance_t flann_distance_type;
/**
* Custom distance function. The distance computed is dependent on the value
* of the 'flann_distance_type' global variable.
*
* If the last argument 'acc' is passed, the result is accumulated to the value
* of this argument.
*/
template <typename Iterator1, typename Iterator2>
double custom_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
switch (flann_distance_type) {
case EUCLIDEAN:
return euclidean_dist(first1, last1, first2, acc);
case MANHATTAN:
return manhattan_dist(first1, last1, first2, acc);
case MINKOWSKI:
return minkowski_dist(first1, last1, first2, acc);
case MAX_DIST:
return max_dist(first1, last1, first2, acc);
case HIK:
return hist_intersection_dist_sq(first1, last1, first2, acc);
case HELLINGER:
return hellinger_dist(first1, last1, first2, acc);
case CS:
return chi_square_dist(first1, last1, first2, acc);
case KL:
return kl_divergence(first1, last1, first2, acc);
default:
return euclidean_dist(first1, last1, first2, acc);
}
}
/*
* This is a "zero iterator". It basically behaves like a zero filled
* array to all algorithms that use arrays as iterators (STL style).
* It's useful when there's a need to compute the distance between feature
* and origin it and allows for better compiler optimisation than using a
* zero-filled array.
*/
template <typename T>
struct ZeroIterator {
T operator*() {
return 0;
}
T operator[](int index) {
return 0;
}
ZeroIterator<T>& operator ++(int) {
return *this;
}
ZeroIterator<T>& operator+=(int) {
return *this;
}
};
extern ZeroIterator<float> zero;
} // namespace cvflann
#endif //DIST_H

View File

@@ -0,0 +1,196 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_FLANN_HPP__
#define __OPENCV_FLANN_HPP__
#ifdef __cplusplus
#include "opencv2/flann/flann_base.hpp"
namespace cv
{
namespace flann
{
template <typename T> struct CvType {};
template <> struct CvType<unsigned char> { static int type() { return CV_8U; } };
template <> struct CvType<char> { static int type() { return CV_8S; } };
template <> struct CvType<unsigned short> { static int type() { return CV_16U; } };
template <> struct CvType<short> { static int type() { return CV_16S; } };
template <> struct CvType<int> { static int type() { return CV_32S; } };
template <> struct CvType<float> { static int type() { return CV_32F; } };
template <> struct CvType<double> { static int type() { return CV_64F; } };
using ::cvflann::IndexParams;
using ::cvflann::LinearIndexParams;
using ::cvflann::KDTreeIndexParams;
using ::cvflann::KMeansIndexParams;
using ::cvflann::CompositeIndexParams;
using ::cvflann::AutotunedIndexParams;
using ::cvflann::SavedIndexParams;
using ::cvflann::SearchParams;
template <typename T>
class Index_ {
::cvflann::Index<T>* nnIndex;
public:
Index_(const Mat& features, const IndexParams& params);
~Index_();
void knnSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& params);
void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params);
int radiusSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, float radius, const SearchParams& params);
int radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& params);
void save(std::string filename) { nnIndex->save(filename); }
int veclen() const { return nnIndex->veclen(); }
int size() const { return nnIndex->size(); }
const IndexParams* getIndexParameters() { return nnIndex->getParameters(); }
};
template <typename T>
Index_<T>::Index_(const Mat& dataset, const IndexParams& params)
{
CV_Assert(dataset.type() == CvType<T>::type());
CV_Assert(dataset.isContinuous());
::cvflann::Matrix<float> m_dataset((T*)dataset.ptr<T>(0), dataset.rows, dataset.cols);
nnIndex = new ::cvflann::Index<T>(m_dataset, params);
nnIndex->buildIndex();
}
template <typename T>
Index_<T>::~Index_()
{
delete nnIndex;
}
template <typename T>
void Index_<T>::knnSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& searchParams)
{
::cvflann::Matrix<T> m_query((T*)&query[0], 1, (int)query.size());
::cvflann::Matrix<int> m_indices(&indices[0], 1, (int)indices.size());
::cvflann::Matrix<float> m_dists(&dists[0], 1, (int)dists.size());
nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
}
template <typename T>
void Index_<T>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& searchParams)
{
CV_Assert(queries.type() == CvType<T>::type());
CV_Assert(queries.isContinuous());
::cvflann::Matrix<T> m_queries((T*)queries.ptr<T>(0), queries.rows, queries.cols);
CV_Assert(indices.type() == CV_32S);
CV_Assert(indices.isContinuous());
::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
CV_Assert(dists.type() == CV_32F);
CV_Assert(dists.isContinuous());
::cvflann::Matrix<float> m_dists((float*)dists.ptr<float>(0), dists.rows, dists.cols);
nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
}
template <typename T>
int Index_<T>::radiusSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, float radius, const SearchParams& searchParams)
{
::cvflann::Matrix<T> m_query((T*)&query[0], 1, (int)query.size());
::cvflann::Matrix<int> m_indices(&indices[0], 1, (int)indices.size());
::cvflann::Matrix<float> m_dists(&dists[0], 1, (int)dists.size());
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
}
template <typename T>
int Index_<T>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, float radius, const SearchParams& searchParams)
{
CV_Assert(query.type() == CvType<T>::type());
CV_Assert(query.isContinuous());
::cvflann::Matrix<T> m_query((T*)query.ptr<T>(0), query.rows, query.cols);
CV_Assert(indices.type() == CV_32S);
CV_Assert(indices.isContinuous());
::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
CV_Assert(dists.type() == CV_32F);
CV_Assert(dists.isContinuous());
::cvflann::Matrix<float> m_dists((float*)dists.ptr<float>(0), dists.rows, dists.cols);
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
}
typedef Index_<float> Index;
template <typename ELEM_TYPE, typename DIST_TYPE>
int hierarchicalClustering(const Mat& features, Mat& centers, const KMeansIndexParams& params)
{
CV_Assert(features.type() == CvType<ELEM_TYPE>::type());
CV_Assert(features.isContinuous());
::cvflann::Matrix<ELEM_TYPE> m_features((ELEM_TYPE*)features.ptr<ELEM_TYPE>(0), features.rows, features.cols);
CV_Assert(centers.type() == CvType<DIST_TYPE>::type());
CV_Assert(centers.isContinuous());
::cvflann::Matrix<DIST_TYPE> m_centers((DIST_TYPE*)centers.ptr<DIST_TYPE>(0), centers.rows, centers.cols);
return ::cvflann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE>(m_features, m_centers, params);
}
} } // namespace cv::flann
#endif // __cplusplus
#endif

View File

@@ -0,0 +1,261 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef FLANN_HPP_
#define FLANN_HPP_
#include <vector>
#include <string>
#include <cassert>
#include <cstdio>
#include "opencv2/flann/general.h"
#include "opencv2/flann/matrix.h"
#include "opencv2/flann/result_set.h"
#include "opencv2/flann/index_testing.h"
#include "opencv2/flann/object_factory.h"
#include "opencv2/flann/saving.h"
#include "opencv2/flann/all_indices.h"
namespace cvflann
{
/**
Sets the log level used for all flann functions
Params:
level = verbosity level
*/
void log_verbosity(int level);
/**
* Sets the distance type to use throughout FLANN.
* If distance type specified is MINKOWSKI, the second argument
* specifies which order the minkowski distance should have.
*/
void set_distance_type(flann_distance_t distance_type, int order);
struct SavedIndexParams : public IndexParams {
SavedIndexParams(std::string filename_) : IndexParams(SAVED), filename(filename_) {}
std::string filename; // filename of the stored index
flann_algorithm_t getIndexType() const { return algorithm; }
void print() const
{
logger.info("Index type: %d\n",(int)algorithm);
logger.info("Filename: %s\n", filename.c_str());
}
};
template<typename T>
class Index {
NNIndex<T>* nnIndex;
bool built;
public:
Index(const Matrix<T>& features, const IndexParams& params);
~Index();
void buildIndex();
void knnSearch(const Matrix<T>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& params);
int radiusSearch(const Matrix<T>& query, Matrix<int>& indices, Matrix<float>& dists, float radius, const SearchParams& params);
void save(std::string filename);
int veclen() const;
int size() const;
NNIndex<T>* getIndex() { return nnIndex; }
const IndexParams* getIndexParameters() { return nnIndex->getParameters(); }
};
template<typename T>
NNIndex<T>* load_saved_index(const Matrix<T>& dataset, const string& filename)
{
FILE* fin = fopen(filename.c_str(), "rb");
if (fin==NULL) {
return NULL;
}
IndexHeader header = load_header(fin);
if (header.data_type!=Datatype<T>::type()) {
throw FLANNException("Datatype of saved index is different than of the one to be created.");
}
if (size_t(header.rows)!=dataset.rows || size_t(header.cols)!=dataset.cols) {
throw FLANNException("The index saved belongs to a different dataset");
}
IndexParams* params = ParamsFactory::instance().create(header.index_type);
NNIndex<T>* nnIndex = create_index_by_type(dataset, *params);
nnIndex->loadIndex(fin);
fclose(fin);
return nnIndex;
}
template<typename T>
Index<T>::Index(const Matrix<T>& dataset, const IndexParams& params)
{
flann_algorithm_t index_type = params.getIndexType();
built = false;
if (index_type==SAVED) {
nnIndex = load_saved_index(dataset, ((const SavedIndexParams&)params).filename);
built = true;
}
else {
nnIndex = create_index_by_type(dataset, params);
}
}
template<typename T>
Index<T>::~Index()
{
delete nnIndex;
}
template<typename T>
void Index<T>::buildIndex()
{
if (!built) {
nnIndex->buildIndex();
built = true;
}
}
template<typename T>
void Index<T>::knnSearch(const Matrix<T>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& searchParams)
{
if (!built) {
throw FLANNException("You must build the index before searching.");
}
assert(queries.cols==nnIndex->veclen());
assert(indices.rows>=queries.rows);
assert(dists.rows>=queries.rows);
assert(int(indices.cols)>=knn);
assert(int(dists.cols)>=knn);
KNNResultSet<T> resultSet(knn);
for (size_t i = 0; i < queries.rows; i++) {
T* target = queries[i];
resultSet.init(target, queries.cols);
nnIndex->findNeighbors(resultSet, target, searchParams);
int* neighbors = resultSet.getNeighbors();
float* distances = resultSet.getDistances();
memcpy(indices[i], neighbors, knn*sizeof(int));
memcpy(dists[i], distances, knn*sizeof(float));
}
}
template<typename T>
int Index<T>::radiusSearch(const Matrix<T>& query, Matrix<int>& indices, Matrix<float>& dists, float radius, const SearchParams& searchParams)
{
if (!built) {
throw FLANNException("You must build the index before searching.");
}
if (query.rows!=1) {
fprintf(stderr, "I can only search one feature at a time for range search\n");
return -1;
}
assert(query.cols==nnIndex->veclen());
RadiusResultSet<T> resultSet(radius);
resultSet.init(query.data, query.cols);
nnIndex->findNeighbors(resultSet,query.data,searchParams);
// TODO: optimise here
int* neighbors = resultSet.getNeighbors();
float* distances = resultSet.getDistances();
size_t count_nn = min(resultSet.size(), indices.cols);
assert (dists.cols>=count_nn);
for (size_t i=0;i<count_nn;++i) {
indices[0][i] = neighbors[i];
dists[0][i] = distances[i];
}
return count_nn;
}
template<typename T>
void Index<T>::save(string filename)
{
FILE* fout = fopen(filename.c_str(), "wb");
if (fout==NULL) {
throw FLANNException("Cannot open file");
}
save_header(fout, *nnIndex);
nnIndex->saveIndex(fout);
fclose(fout);
}
template<typename T>
int Index<T>::size() const
{
return nnIndex->size();
}
template<typename T>
int Index<T>::veclen() const
{
return nnIndex->veclen();
}
template <typename ELEM_TYPE, typename DIST_TYPE>
int hierarchicalClustering(const Matrix<ELEM_TYPE>& features, Matrix<DIST_TYPE>& centers, const KMeansIndexParams& params)
{
KMeansIndex<ELEM_TYPE, DIST_TYPE> kmeans(features, params);
kmeans.buildIndex();
int clusterNum = kmeans.getClusterCenters(centers);
return clusterNum;
}
} // namespace cvflann
#endif /* FLANN_HPP_ */

View File

@@ -0,0 +1,153 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
/* Nearest neighbour index algorithms */
enum flann_algorithm_t {
LINEAR = 0,
KDTREE = 1,
KMEANS = 2,
COMPOSITE = 3,
SAVED = 254,
AUTOTUNED = 255
};
enum flann_centers_init_t {
CENTERS_RANDOM = 0,
CENTERS_GONZALES = 1,
CENTERS_KMEANSPP = 2
};
enum flann_log_level_t {
LOG_NONE = 0,
LOG_FATAL = 1,
LOG_ERROR = 2,
LOG_WARN = 3,
LOG_INFO = 4
};
enum flann_distance_t {
EUCLIDEAN = 1,
MANHATTAN = 2,
MINKOWSKI = 3,
MAX_DIST = 4,
HIK = 5,
HELLINGER = 6,
CS = 7,
CHI_SQUARE = 7,
KL = 8,
KULLBACK_LEIBLER = 8
};
enum flann_datatype_t {
INT8 = 0,
INT16 = 1,
INT32 = 2,
INT64 = 3,
UINT8 = 4,
UINT16 = 5,
UINT32 = 6,
UINT64 = 7,
FLOAT32 = 8,
FLOAT64 = 9
};
#ifdef __cplusplus
#include <stdexcept>
#include <cassert>
#include "opencv2/flann/object_factory.h"
namespace cvflann {
template <typename ELEM_TYPE>
struct DistType
{
typedef ELEM_TYPE type;
};
template <>
struct DistType<unsigned char>
{
typedef float type;
};
template <>
struct DistType<int>
{
typedef float type;
};
class FLANNException : public std::runtime_error {
public:
FLANNException(const char* message) : std::runtime_error(message) { }
FLANNException(const std::string& message) : std::runtime_error(message) { }
};
struct IndexParams {
protected:
IndexParams(flann_algorithm_t algorithm_) : algorithm(algorithm_) {};
public:
virtual flann_algorithm_t getIndexType() const = 0;
virtual void print() const = 0;
flann_algorithm_t algorithm;
};
typedef ObjectFactory<IndexParams, flann_algorithm_t> ParamsFactory;
struct SearchParams {
SearchParams(int checks_ = 32) :
checks(checks_) {};
int checks;
};
} // namespace cvflann
#endif
#endif /* CONSTANTS_H */

View File

@@ -0,0 +1,95 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef GROUND_TRUTH_H
#define GROUND_TRUTH_H
#include "opencv2/flann/dist.h"
#include "opencv2/flann/matrix.h"
namespace cvflann
{
template <typename T>
void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int skip = 0)
{
int n = nn + skip;
T* query_end = query + dataset.cols;
long* match = new long[n];
T* dists = new T[n];
dists[0] = flann_dist(query, query_end, dataset[0]);
match[0] = 0;
int dcnt = 1;
for (size_t i=1;i<dataset.rows;++i) {
T tmp = flann_dist(query, query_end, dataset[i]);
if (dcnt<n) {
match[dcnt] = i;
dists[dcnt++] = tmp;
}
else if (tmp < dists[dcnt-1]) {
dists[dcnt-1] = tmp;
match[dcnt-1] = i;
}
int j = dcnt-1;
// bubble up
while (j>=1 && dists[j]<dists[j-1]) {
swap(dists[j],dists[j-1]);
swap(match[j],match[j-1]);
j--;
}
}
for (int i=0;i<nn;++i) {
matches[i] = match[i+skip];
}
delete[] match;
delete[] dists;
}
template <typename T>
void compute_ground_truth(const Matrix<T>& dataset, const Matrix<T>& testset, Matrix<int>& matches, int skip=0)
{
for (size_t i=0;i<testset.rows;++i) {
find_nearest(dataset, testset[i], matches[i], matches.cols, skip);
}
}
} // namespace cvflann
#endif //GROUND_TRUTH_H

View File

@@ -0,0 +1,163 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef IO_H_
#define IO_H_
#include <H5Cpp.h>
#include "opencv2/flann/matrix.h"
#ifndef H5_NO_NAMESPACE
using namespace H5;
#endif
namespace cvflann
{
namespace {
template<typename T>
PredType get_hdf5_type()
{
throw FLANNException("Unsupported type for IO operations");
}
template<> PredType get_hdf5_type<char>() { return PredType::NATIVE_CHAR; }
template<> PredType get_hdf5_type<unsigned char>() { return PredType::NATIVE_UCHAR; }
template<> PredType get_hdf5_type<short int>() { return PredType::NATIVE_SHORT; }
template<> PredType get_hdf5_type<unsigned short int>() { return PredType::NATIVE_USHORT; }
template<> PredType get_hdf5_type<int>() { return PredType::NATIVE_INT; }
template<> PredType get_hdf5_type<unsigned int>() { return PredType::NATIVE_UINT; }
template<> PredType get_hdf5_type<long>() { return PredType::NATIVE_LONG; }
template<> PredType get_hdf5_type<unsigned long>() { return PredType::NATIVE_ULONG; }
template<> PredType get_hdf5_type<float>() { return PredType::NATIVE_FLOAT; }
template<> PredType get_hdf5_type<double>() { return PredType::NATIVE_DOUBLE; }
template<> PredType get_hdf5_type<long double>() { return PredType::NATIVE_LDOUBLE; }
}
template<typename T>
void save_to_file(const cvflann::Matrix<T>& flann_dataset, const std::string& filename, const std::string& name)
{
// Try block to detect exceptions raised by any of the calls inside it
try
{
/*
* Turn off the auto-printing when failure occurs so that we can
* handle the errors appropriately
*/
Exception::dontPrint();
/*
* Create a new file using H5F_ACC_TRUNC access,
* default file creation properties, and default file
* access properties.
*/
H5File file( filename, H5F_ACC_TRUNC );
/*
* Define the size of the array and create the data space for fixed
* size dataset.
*/
hsize_t dimsf[2]; // dataset dimensions
dimsf[0] = flann_dataset.rows;
dimsf[1] = flann_dataset.cols;
DataSpace dataspace( 2, dimsf );
/*
* Create a new dataset within the file using defined dataspace and
* datatype and default dataset creation properties.
*/
DataSet dataset = file.createDataSet( name, get_hdf5_type<T>(), dataspace );
/*
* Write the data to the dataset using default memory space, file
* space, and transfer properties.
*/
dataset.write( flann_dataset.data, get_hdf5_type<T>() );
} // end of try block
catch( H5::Exception& error )
{
error.printError();
throw FLANNException(error.getDetailMsg());
}
}
template<typename T>
void load_from_file(cvflann::Matrix<T>& flann_dataset, const std::string& filename, const std::string& name)
{
try
{
Exception::dontPrint();
H5File file( filename, H5F_ACC_RDONLY );
DataSet dataset = file.openDataSet( name );
/*
* Check the type used by the dataset matches
*/
if ( !(dataset.getDataType()==get_hdf5_type<T>())) {
throw FLANNException("Dataset matrix type does not match the type to be read.");
}
/*
* Get dataspace of the dataset.
*/
DataSpace dataspace = dataset.getSpace();
/*
* Get the dimension size of each dimension in the dataspace and
* display them.
*/
hsize_t dims_out[2];
dataspace.getSimpleExtentDims( dims_out, NULL);
flann_dataset.rows = dims_out[0];
flann_dataset.cols = dims_out[1];
flann_dataset.data = new T[flann_dataset.rows*flann_dataset.cols];
dataset.read( flann_dataset.data, get_hdf5_type<T>() );
} // end of try block
catch( H5::Exception &error )
{
error.printError();
throw FLANNException(error.getDetailMsg());
}
}
} // namespace cvflann
#endif /* IO_H_ */

View File

@@ -0,0 +1,209 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef HEAP_H
#define HEAP_H
#include <algorithm>
using namespace std;
namespace cvflann
{
/**
* Priority Queue Implementation
*
* The priority queue is implemented with a heap. A heap is a complete
* (full) binary tree in which each parent is less than both of its
* children, but the order of the children is unspecified.
* Note that a heap uses 1-based indexing to allow for power-of-2
* location of parents and children. We ignore element 0 of Heap array.
*/
template <typename T>
class Heap {
/**
* Storage array for the heap.
* Type T must be comparable.
*/
T* heap;
int length;
/**
* Number of element in the heap
*/
int count;
public:
/**
* Constructor.
*
* Params:
* size = heap size
*/
Heap(int size)
{
length = size+1;
heap = new T[length]; // heap uses 1-based indexing
count = 0;
}
/**
* Destructor.
*
*/
~Heap()
{
delete[] heap;
}
/**
*
* Returns: heap size
*/
int size()
{
return count;
}
/**
* Tests if the heap is empty
*
* Returns: true is heap empty, false otherwise
*/
bool empty()
{
return size()==0;
}
/**
* Clears the heap.
*/
void clear()
{
count = 0;
}
/**
* Insert a new element in the heap.
*
* We select the next empty leaf node, and then keep moving any larger
* parents down until the right location is found to store this element.
*
* Params:
* value = the new element to be inserted in the heap
*/
void insert(T value)
{
/* If heap is full, then return without adding this element. */
if (count == length-1) {
return;
}
int loc = ++(count); /* Remember 1-based indexing. */
/* Keep moving parents down until a place is found for this node. */
int par = loc / 2; /* Location of parent. */
while (par > 0 && value < heap[par]) {
heap[loc] = heap[par]; /* Move parent down to loc. */
loc = par;
par = loc / 2;
}
/* Insert the element at the determined location. */
heap[loc] = value;
}
/**
* Returns the node of minimum value from the heap (top of the heap).
*
* Params:
* value = out parameter used to return the min element
* Returns: false if heap empty
*/
bool popMin(T& value)
{
if (count == 0) {
return false;
}
/* Switch first node with last. */
swap(heap[1],heap[count]);
count -= 1;
heapify(1); /* Move new node 1 to right position. */
value = heap[count + 1];
return true; /* Return old last node. */
}
/**
* Reorganizes the heap (a parent is smaller than its children)
* starting with a node.
*
* Params:
* parent = node form which to start heap reorganization.
*/
void heapify(int parent)
{
int minloc = parent;
/* Check the left child */
int left = 2 * parent;
if (left <= count && heap[left] < heap[parent]) {
minloc = left;
}
/* Check the right child */
int right = left + 1;
if (right <= count && heap[right] < heap[minloc]) {
minloc = right;
}
/* If a child was smaller, than swap parent with it and Heapify. */
if (minloc != parent) {
swap(heap[parent],heap[minloc]);
heapify(minloc);
}
}
};
} // namespace cvflann
#endif //HEAP_H

View File

@@ -0,0 +1,292 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef TESTING_H
#define TESTING_H
#include <cstring>
#include <cassert>
#include "opencv2/flann/matrix.h"
#include "opencv2/flann/nn_index.h"
#include "opencv2/flann/result_set.h"
#include "opencv2/flann/logger.h"
#include "opencv2/flann/timer.h"
using namespace std;
namespace cvflann
{
int countCorrectMatches(int* neighbors, int* groundTruth, int n);
template <typename ELEM_TYPE>
float computeDistanceRaport(const Matrix<ELEM_TYPE>& inputData, ELEM_TYPE* target, int* neighbors, int* groundTruth, int veclen, int n)
{
ELEM_TYPE* target_end = target + veclen;
float ret = 0;
for (int i=0;i<n;++i) {
float den = flann_dist(target,target_end, inputData[groundTruth[i]]);
float num = flann_dist(target,target_end, inputData[neighbors[i]]);
if (den==0 && num==0) {
ret += 1;
}
else {
ret += num/den;
}
}
return ret;
}
template <typename ELEM_TYPE>
float search_with_ground_truth(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches, int nn, int checks, float& time, float& dist, int skipMatches)
{
if (matches.cols<size_t(nn)) {
logger.info("matches.cols=%d, nn=%d\n",matches.cols,nn);
throw FLANNException("Ground truth is not computed for as many neighbors as requested");
}
KNNResultSet<ELEM_TYPE> resultSet(nn+skipMatches);
SearchParams searchParams(checks);
int correct;
float distR;
StartStopTimer t;
int repeats = 0;
while (t.value<0.2) {
repeats++;
t.start();
correct = 0;
distR = 0;
for (size_t i = 0; i < testData.rows; i++) {
ELEM_TYPE* target = testData[i];
resultSet.init(target, testData.cols);
index.findNeighbors(resultSet,target, searchParams);
int* neighbors = resultSet.getNeighbors();
neighbors = neighbors+skipMatches;
correct += countCorrectMatches(neighbors,matches[i], nn);
distR += computeDistanceRaport(inputData, target,neighbors,matches[i], testData.cols, nn);
}
t.stop();
}
time = t.value/repeats;
float precicion = (float)correct/(nn*testData.rows);
dist = distR/(testData.rows*nn);
logger.info("%8d %10.4g %10.5g %10.5g %10.5g\n",
checks, precicion, time, 1000.0 * time / testData.rows, dist);
return precicion;
}
template <typename ELEM_TYPE>
float test_index_checks(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches,
int checks, float& precision, int nn = 1, int skipMatches = 0)
{
logger.info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n");
logger.info("---------------------------------------------------------\n");
float time = 0;
float dist = 0;
precision = search_with_ground_truth(index, inputData, testData, matches, nn, checks, time, dist, skipMatches);
return time;
}
template <typename ELEM_TYPE>
float test_index_precision(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches,
float precision, int& checks, int nn = 1, int skipMatches = 0)
{
const float SEARCH_EPS = 0.001;
logger.info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n");
logger.info("---------------------------------------------------------\n");
int c2 = 1;
float p2;
int c1 = 1;
float p1;
float time;
float dist;
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
if (p2>precision) {
logger.info("Got as close as I can\n");
checks = c2;
return time;
}
while (p2<precision) {
c1 = c2;
p1 = p2;
c2 *=2;
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
}
int cx;
float realPrecision;
if (fabs(p2-precision)>SEARCH_EPS) {
logger.info("Start linear estimation\n");
// after we got to values in the vecinity of the desired precision
// use linear approximation get a better estimation
cx = (c1+c2)/2;
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
while (fabs(realPrecision-precision)>SEARCH_EPS) {
if (realPrecision<precision) {
c1 = cx;
}
else {
c2 = cx;
}
cx = (c1+c2)/2;
if (cx==c1) {
logger.info("Got as close as I can\n");
break;
}
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
}
c2 = cx;
p2 = realPrecision;
} else {
logger.info("No need for linear estimation\n");
cx = c2;
realPrecision = p2;
}
checks = cx;
return time;
}
template <typename ELEM_TYPE>
float test_index_precisions(NNIndex<ELEM_TYPE>& index, const Matrix<ELEM_TYPE>& inputData, const Matrix<ELEM_TYPE>& testData, const Matrix<int>& matches,
float* precisions, int precisions_length, int nn = 1, int skipMatches = 0, float maxTime = 0)
{
const float SEARCH_EPS = 0.001;
// make sure precisions array is sorted
sort(precisions, precisions+precisions_length);
int pindex = 0;
float precision = precisions[pindex];
logger.info(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist");
logger.info("---------------------------------------------------------");
int c2 = 1;
float p2;
int c1 = 1;
float p1;
float time;
float dist;
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
// if precision for 1 run down the tree is already
// better then some of the requested precisions, then
// skip those
while (precisions[pindex]<p2 && pindex<precisions_length) {
pindex++;
}
if (pindex==precisions_length) {
logger.info("Got as close as I can\n");
return time;
}
for (int i=pindex;i<precisions_length;++i) {
precision = precisions[i];
while (p2<precision) {
c1 = c2;
p1 = p2;
c2 *=2;
p2 = search_with_ground_truth(index, inputData, testData, matches, nn, c2, time, dist, skipMatches);
if (maxTime> 0 && time > maxTime && p2<precision) return time;
}
int cx;
float realPrecision;
if (fabs(p2-precision)>SEARCH_EPS) {
logger.info("Start linear estimation\n");
// after we got to values in the vecinity of the desired precision
// use linear approximation get a better estimation
cx = (c1+c2)/2;
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
while (fabs(realPrecision-precision)>SEARCH_EPS) {
if (realPrecision<precision) {
c1 = cx;
}
else {
c2 = cx;
}
cx = (c1+c2)/2;
if (cx==c1) {
logger.info("Got as close as I can\n");
break;
}
realPrecision = search_with_ground_truth(index, inputData, testData, matches, nn, cx, time, dist, skipMatches);
}
c2 = cx;
p2 = realPrecision;
} else {
logger.info("No need for linear estimation\n");
cx = c2;
realPrecision = p2;
}
}
return time;
}
} // namespace cvflann
#endif //TESTING_H

View File

@@ -0,0 +1,622 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef KDTREE_H
#define KDTREE_H
#include <algorithm>
#include <map>
#include <cassert>
#include <cstring>
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
#include "opencv2/flann/matrix.h"
#include "opencv2/flann/result_set.h"
#include "opencv2/flann/heap.h"
#include "opencv2/flann/allocator.h"
#include "opencv2/flann/random.h"
#include "opencv2/flann/saving.h"
using namespace std;
namespace cvflann
{
struct KDTreeIndexParams : public IndexParams {
KDTreeIndexParams(int trees_ = 4) : IndexParams(KDTREE), trees(trees_) {};
int trees; // number of randomized trees to use (for kdtree)
flann_algorithm_t getIndexType() const { return algorithm; }
void print() const
{
logger.info("Index type: %d\n",(int)algorithm);
logger.info("Trees: %d\n", trees);
}
};
/**
* Randomized kd-tree index
*
* Contains the k-d trees and other information for indexing a set of points
* for nearest-neighbor matching.
*/
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
class KDTreeIndex : public NNIndex<ELEM_TYPE>
{
enum {
/**
* To improve efficiency, only SAMPLE_MEAN random values are used to
* compute the mean and variance at each level when building a tree.
* A value of 100 seems to perform as well as using all values.
*/
SAMPLE_MEAN = 100,
/**
* Top random dimensions to consider
*
* When creating random trees, the dimension on which to subdivide is
* selected at random from among the top RAND_DIM dimensions with the
* highest variance. A value of 5 works well.
*/
RAND_DIM=5
};
/**
* Number of randomized trees that are used
*/
int numTrees;
/**
* Array of indices to vectors in the dataset.
*/
int* vind;
/**
* The dataset used by this index
*/
const Matrix<ELEM_TYPE> dataset;
const IndexParams& index_params;
size_t size_;
size_t veclen_;
DIST_TYPE* mean;
DIST_TYPE* var;
/*--------------------- Internal Data Structures --------------------------*/
/**
* A node of the binary k-d tree.
*
* This is All nodes that have vec[divfeat] < divval are placed in the
* child1 subtree, else child2., A leaf node is indicated if both children are NULL.
*/
struct TreeSt {
/**
* Index of the vector feature used for subdivision.
* If this is a leaf node (both children are NULL) then
* this holds vector index for this leaf.
*/
int divfeat;
/**
* The value used for subdivision.
*/
DIST_TYPE divval;
/**
* The child nodes.
*/
TreeSt *child1, *child2;
};
typedef TreeSt* Tree;
/**
* Array of k-d trees used to find neighbours.
*/
Tree* trees;
typedef BranchStruct<Tree> BranchSt;
typedef BranchSt* Branch;
/**
* Pooled memory allocator.
*
* Using a pooled memory allocator is more efficient
* than allocating memory directly when there is a large
* number small of memory allocations.
*/
PooledAllocator pool;
public:
flann_algorithm_t getType() const
{
return KDTREE;
}
/**
* KDTree constructor
*
* Params:
* inputData = dataset with the input features
* params = parameters passed to the kdtree algorithm
*/
KDTreeIndex(const Matrix<ELEM_TYPE>& inputData, const KDTreeIndexParams& params = KDTreeIndexParams() ) :
dataset(inputData), index_params(params)
{
size_ = dataset.rows;
veclen_ = dataset.cols;
numTrees = params.trees;
trees = new Tree[numTrees];
// get the parameters
// if (params.find("trees") != params.end()) {
// numTrees = (int)params["trees"];
// trees = new Tree[numTrees];
// }
// else {
// numTrees = -1;
// trees = NULL;
// }
// Create a permutable array of indices to the input vectors.
vind = new int[size_];
for (size_t i = 0; i < size_; i++) {
vind[i] = i;
}
mean = new DIST_TYPE[veclen_];
var = new DIST_TYPE[veclen_];
}
/**
* Standard destructor
*/
~KDTreeIndex()
{
delete[] vind;
if (trees!=NULL) {
delete[] trees;
}
delete[] mean;
delete[] var;
}
/**
* Builds the index
*/
void buildIndex()
{
/* Construct the randomized trees. */
for (int i = 0; i < numTrees; i++) {
/* Randomize the order of vectors to allow for unbiased sampling. */
for (int j = size_; j > 0; --j) {
int rnd = rand_int(j);
swap(vind[j-1], vind[rnd]);
}
trees[i] = divideTree(0, size_ - 1);
}
}
void saveIndex(FILE* stream)
{
save_value(stream, numTrees);
for (int i=0;i<numTrees;++i) {
save_tree(stream, trees[i]);
}
}
void loadIndex(FILE* stream)
{
load_value(stream, numTrees);
if (trees!=NULL) {
delete[] trees;
}
trees = new Tree[numTrees];
for (int i=0;i<numTrees;++i) {
load_tree(stream,trees[i]);
}
}
/**
* Returns size of index.
*/
size_t size() const
{
return size_;
}
/**
* Returns the length of an index feature.
*/
size_t veclen() const
{
return veclen_;
}
/**
* Computes the inde memory usage
* Returns: memory used by the index
*/
int usedMemory() const
{
return pool.usedMemory+pool.wastedMemory+dataset.rows*sizeof(int); // pool memory and vind array memory
}
/**
* Find set of nearest neighbors to vec. Their indices are stored inside
* the result object.
*
* Params:
* result = the result object in which the indices of the nearest-neighbors are stored
* vec = the vector for which to search the nearest neighbors
* maxCheck = the maximum number of restarts (in a best-bin-first manner)
*/
void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams)
{
int maxChecks = searchParams.checks;
if (maxChecks<0) {
getExactNeighbors(result, vec);
} else {
getNeighbors(result, vec, maxChecks);
}
}
const IndexParams* getParameters() const
{
return &index_params;
}
private:
void save_tree(FILE* stream, Tree tree)
{
save_value(stream, *tree);
if (tree->child1!=NULL) {
save_tree(stream, tree->child1);
}
if (tree->child2!=NULL) {
save_tree(stream, tree->child2);
}
}
void load_tree(FILE* stream, Tree& tree)
{
tree = pool.allocate<TreeSt>();
load_value(stream, *tree);
if (tree->child1!=NULL) {
load_tree(stream, tree->child1);
}
if (tree->child2!=NULL) {
load_tree(stream, tree->child2);
}
}
/**
* Create a tree node that subdivides the list of vecs from vind[first]
* to vind[last]. The routine is called recursively on each sublist.
* Place a pointer to this new tree node in the location pTree.
*
* Params: pTree = the new node to create
* first = index of the first vector
* last = index of the last vector
*/
Tree divideTree(int first, int last)
{
Tree node = pool.allocate<TreeSt>(); // allocate memory
/* If only one exemplar remains, then make this a leaf node. */
if (first == last) {
node->child1 = node->child2 = NULL; /* Mark as leaf node. */
node->divfeat = vind[first]; /* Store index of this vec. */
}
else {
chooseDivision(node, first, last);
subdivide(node, first, last);
}
return node;
}
/**
* Choose which feature to use in order to subdivide this set of vectors.
* Make a random choice among those with the highest variance, and use
* its variance as the threshold value.
*/
void chooseDivision(Tree node, int first, int last)
{
memset(mean,0,veclen_*sizeof(DIST_TYPE));
memset(var,0,veclen_*sizeof(DIST_TYPE));
/* Compute mean values. Only the first SAMPLE_MEAN values need to be
sampled to get a good estimate.
*/
int end = min(first + SAMPLE_MEAN, last);
for (int j = first; j <= end; ++j) {
ELEM_TYPE* v = dataset[vind[j]];
for (size_t k=0; k<veclen_; ++k) {
mean[k] += v[k];
}
}
for (size_t k=0; k<veclen_; ++k) {
mean[k] /= (end - first + 1);
}
/* Compute variances (no need to divide by count). */
for (int j = first; j <= end; ++j) {
ELEM_TYPE* v = dataset[vind[j]];
for (size_t k=0; k<veclen_; ++k) {
DIST_TYPE dist = v[k] - mean[k];
var[k] += dist * dist;
}
}
/* Select one of the highest variance indices at random. */
node->divfeat = selectDivision(var);
node->divval = mean[node->divfeat];
}
/**
* Select the top RAND_DIM largest values from v and return the index of
* one of these selected at random.
*/
int selectDivision(DIST_TYPE* v)
{
int num = 0;
int topind[RAND_DIM];
/* Create a list of the indices of the top RAND_DIM values. */
for (size_t i = 0; i < veclen_; ++i) {
if (num < RAND_DIM || v[i] > v[topind[num-1]]) {
/* Put this element at end of topind. */
if (num < RAND_DIM) {
topind[num++] = i; /* Add to list. */
}
else {
topind[num-1] = i; /* Replace last element. */
}
/* Bubble end value down to right location by repeated swapping. */
int j = num - 1;
while (j > 0 && v[topind[j]] > v[topind[j-1]]) {
swap(topind[j], topind[j-1]);
--j;
}
}
}
/* Select a random integer in range [0,num-1], and return that index. */
int rnd = rand_int(num);
return topind[rnd];
}
/**
* Subdivide the list of exemplars using the feature and division
* value given in this node. Call divideTree recursively on each list.
*/
void subdivide(Tree node, int first, int last)
{
/* Move vector indices for left subtree to front of list. */
int i = first;
int j = last;
while (i <= j) {
int ind = vind[i];
ELEM_TYPE val = dataset[ind][node->divfeat];
if (val < node->divval) {
++i;
} else {
/* Move to end of list by swapping vind i and j. */
swap(vind[i], vind[j]);
--j;
}
}
/* If either list is empty, it means we have hit the unlikely case
in which all remaining features are identical. Split in the middle
to maintain a balanced tree.
*/
if ( (i == first) || (i == last+1)) {
i = (first+last+1)/2;
}
node->child1 = divideTree(first, i - 1);
node->child2 = divideTree(i, last);
}
/**
* Performs an exact nearest neighbor search. The exact search performs a full
* traversal of the tree.
*/
void getExactNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec)
{
// checkID -= 1; /* Set a different unique ID for each search. */
if (numTrees > 1) {
fprintf(stderr,"It doesn't make any sense to use more than one tree for exact search");
}
if (numTrees>0) {
searchLevelExact(result, vec, trees[0], 0.0);
}
assert(result.full());
}
/**
* Performs the approximate nearest-neighbor search. The search is approximate
* because the tree traversal is abandoned after a given number of descends in
* the tree.
*/
void getNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, int maxCheck)
{
int i;
BranchSt branch;
int checkCount = 0;
Heap<BranchSt>* heap = new Heap<BranchSt>(size_);
vector<bool> checked(size_,false);
/* Search once through each tree down to root. */
for (i = 0; i < numTrees; ++i) {
searchLevel(result, vec, trees[i], 0.0, checkCount, maxCheck, heap, checked);
}
/* Keep searching other branches from heap until finished. */
while ( heap->popMin(branch) && (checkCount < maxCheck || !result.full() )) {
searchLevel(result, vec, branch.node, branch.mindistsq, checkCount, maxCheck, heap, checked);
}
delete heap;
assert(result.full());
}
/**
* Search starting from a given node of the tree. Based on any mismatches at
* higher levels, all exemplars below this level must have a distance of
* at least "mindistsq".
*/
void searchLevel(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, Tree node, float mindistsq, int& checkCount, int maxCheck,
Heap<BranchSt>* heap, vector<bool>& checked)
{
if (result.worstDist()<mindistsq) {
// printf("Ignoring branch, too far\n");
return;
}
/* If this is a leaf node, then do check and return. */
if (node->child1 == NULL && node->child2 == NULL) {
/* Do not check same node more than once when searching multiple trees.
Once a vector is checked, we set its location in vind to the
current checkID.
*/
if (checked[node->divfeat] == true || checkCount>=maxCheck) {
if (result.full()) return;
}
checkCount++;
checked[node->divfeat] = true;
result.addPoint(dataset[node->divfeat],node->divfeat);
return;
}
/* Which child branch should be taken first? */
ELEM_TYPE val = vec[node->divfeat];
DIST_TYPE diff = val - node->divval;
Tree bestChild = (diff < 0) ? node->child1 : node->child2;
Tree otherChild = (diff < 0) ? node->child2 : node->child1;
/* Create a branch record for the branch not taken. Add distance
of this feature boundary (we don't attempt to correct for any
use of this feature in a parent node, which is unlikely to
happen and would have only a small effect). Don't bother
adding more branches to heap after halfway point, as cost of
adding exceeds their value.
*/
DIST_TYPE new_distsq = flann_dist(&val, &val+1, &node->divval, mindistsq);
// if (2 * checkCount < maxCheck || !result.full()) {
if (new_distsq < result.worstDist() || !result.full()) {
heap->insert( BranchSt::make_branch(otherChild, new_distsq) );
}
/* Call recursively to search next level down. */
searchLevel(result, vec, bestChild, mindistsq, checkCount, maxCheck, heap, checked);
}
/**
* Performs an exact search in the tree starting from a node.
*/
void searchLevelExact(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, Tree node, float mindistsq)
{
if (mindistsq>result.worstDist()) {
return;
}
/* If this is a leaf node, then do check and return. */
if (node->child1 == NULL && node->child2 == NULL) {
/* Do not check same node more than once when searching multiple trees.
Once a vector is checked, we set its location in vind to the
current checkID.
*/
// if (vind[node->divfeat] == checkID)
// return;
// vind[node->divfeat] = checkID;
result.addPoint(dataset[node->divfeat],node->divfeat);
return;
}
/* Which child branch should be taken first? */
ELEM_TYPE val = vec[node->divfeat];
DIST_TYPE diff = val - node->divval;
Tree bestChild = (diff < 0) ? node->child1 : node->child2;
Tree otherChild = (diff < 0) ? node->child2 : node->child1;
/* Call recursively to search next level down. */
searchLevelExact(result, vec, bestChild, mindistsq);
DIST_TYPE new_distsq = flann_dist(&val, &val+1, &node->divval, mindistsq);
searchLevelExact(result, vec, otherChild, new_distsq);
}
}; // class KDTree
} // namespace cvflann
#endif //KDTREE_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef LINEARSEARCH_H
#define LINEARSEARCH_H
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
namespace cvflann
{
struct LinearIndexParams : public IndexParams {
LinearIndexParams() : IndexParams(LINEAR) {};
flann_algorithm_t getIndexType() const { return algorithm; }
void print() const
{
logger.info("Index type: %d\n",(int)algorithm);
}
};
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
class LinearIndex : public NNIndex<ELEM_TYPE>
{
const Matrix<ELEM_TYPE> dataset;
const LinearIndexParams& index_params;
public:
LinearIndex(const Matrix<ELEM_TYPE>& inputData, const LinearIndexParams& params = LinearIndexParams() ) :
dataset(inputData), index_params(params)
{
}
flann_algorithm_t getType() const
{
return LINEAR;
}
size_t size() const
{
return dataset.rows;
}
size_t veclen() const
{
return dataset.cols;
}
int usedMemory() const
{
return 0;
}
void buildIndex()
{
/* nothing to do here for linear search */
}
void saveIndex(FILE* stream)
{
/* nothing to do here for linear search */
}
void loadIndex(FILE* stream)
{
/* nothing to do here for linear search */
}
void findNeighbors(ResultSet<ELEM_TYPE>& resultSet, const ELEM_TYPE* vec, const SearchParams& searchParams)
{
for (size_t i=0;i<dataset.rows;++i) {
resultSet.addPoint(dataset[i],i);
}
}
const IndexParams* getParameters() const
{
return &index_params;
}
};
} // namespace cvflann
#endif // LINEARSEARCH_H

View File

@@ -0,0 +1,91 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef LOGGER_H
#define LOGGER_H
#include <cstdio>
#include "opencv2/flann/general.h"
using namespace std;
namespace cvflann
{
class Logger
{
FILE* stream;
int logLevel;
public:
Logger() : stream(stdout), logLevel(LOG_WARN) {};
~Logger()
{
if (stream!=NULL && stream!=stdout) {
fclose(stream);
}
}
void setDestination(const char* name)
{
if (name==NULL) {
stream = stdout;
}
else {
stream = fopen(name,"w");
if (stream == NULL) {
stream = stdout;
}
}
}
void setLevel(int level) { logLevel = level; }
int log(int level, const char* fmt, ...);
int log(int level, const char* fmt, va_list arglist);
int fatal(const char* fmt, ...);
int error(const char* fmt, ...);
int warn(const char* fmt, ...);
int info(const char* fmt, ...);
};
extern Logger logger;
} // namespace cvflann
#endif //LOGGER_H

View File

@@ -0,0 +1,118 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef DATASET_H
#define DATASET_H
#include <stdio.h>
#include "opencv2/flann/general.h"
namespace cvflann
{
/**
* Class that implements a simple rectangular matrix stored in a memory buffer and
* provides convenient matrix-like access using the [] operators.
*/
template <typename T>
class Matrix {
public:
size_t rows;
size_t cols;
T* data;
Matrix() : rows(0), cols(0), data(NULL)
{
}
Matrix(T* data_, long rows_, long cols_) :
rows(rows_), cols(cols_), data(data_)
{
}
/**
* Convenience function for deallocating the storage data.
*/
void free()
{
if (data!=NULL) delete[] data;
}
~Matrix()
{
}
/**
* Operator that return a (pointer to a) row of the data.
*/
T* operator[](size_t index)
{
return data+index*cols;
}
T* operator[](size_t index) const
{
return data+index*cols;
}
};
class UntypedMatrix
{
public:
size_t rows;
size_t cols;
void* data;
flann_datatype_t type;
UntypedMatrix(void* data_, long rows_, long cols_) :
rows(rows_), cols(cols_), data(data_)
{
}
~UntypedMatrix()
{
}
template<typename T>
Matrix<T> as()
{
return Matrix<T>((T*)data, rows, cols);
}
};
} // namespace cvflann
#endif //DATASET_H

View File

@@ -0,0 +1,108 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef NNINDEX_H
#define NNINDEX_H
#include <string>
#include "opencv2/flann/general.h"
#include "opencv2/flann/matrix.h"
using namespace std;
namespace cvflann
{
template <typename ELEM_TYPE>
class ResultSet;
/**
* Nearest-neighbour index base class
*/
template <typename ELEM_TYPE>
class NNIndex
{
public:
virtual ~NNIndex() {};
/**
Method responsible with building the index.
*/
virtual void buildIndex() = 0;
/**
Saves the index to a stream
*/
virtual void saveIndex(FILE* stream) = 0;
/**
Loads the index from a stream
*/
virtual void loadIndex(FILE* stream) = 0;
/**
Method that searches for nearest-neighbors
*/
virtual void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams) = 0;
/**
Number of features in this index.
*/
virtual size_t size() const = 0;
/**
The length of each vector in this index.
*/
virtual size_t veclen() const = 0;
/**
The amount of memory (in bytes) this index uses.
*/
virtual int usedMemory() const = 0;
/**
* Algorithm name
*/
virtual flann_algorithm_t getType() const = 0;
/**
* Returns the parameters used for the index
*/
virtual const IndexParams* getParameters() const = 0;
};
} // namespace cvflann
#endif //NNINDEX_H

View File

@@ -0,0 +1,93 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef OBJECT_FACTORY_H_
#define OBJECT_FACTORY_H_
#include <map>
namespace cvflann
{
template<typename BaseClass, typename DerivedClass>
BaseClass* createObject()
{
return new DerivedClass();
}
template<typename BaseClass, typename UniqueIdType>
class ObjectFactory
{
typedef BaseClass* (*CreateObjectFunc)();
std::map<UniqueIdType, CreateObjectFunc> object_registry;
// singleton class, private constructor
ObjectFactory() {};
public:
typedef typename std::map<UniqueIdType, CreateObjectFunc>::iterator Iterator;
template<typename DerivedClass>
bool register_(UniqueIdType id)
{
if (object_registry.find(id) != object_registry.end())
return false;
object_registry[id] = &createObject<BaseClass, DerivedClass>;
return true;
}
bool unregister(UniqueIdType id)
{
return (object_registry.erase(id) == 1);
}
BaseClass* create(UniqueIdType id)
{
Iterator iter = object_registry.find(id);
if (iter == object_registry.end())
return NULL;
return ((*iter).second)();
}
static ObjectFactory<BaseClass,UniqueIdType>& instance()
{
static ObjectFactory<BaseClass,UniqueIdType> the_factory;
return the_factory;
}
};
} // namespace cvflann
#endif /* OBJECT_FACTORY_H_ */

View File

@@ -0,0 +1,134 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef RANDOM_H
#define RANDOM_H
#include <algorithm>
#include <cstdlib>
#include <cassert>
using namespace std;
namespace cvflann
{
/**
* Seeds the random number generator
*/
void seed_random(unsigned int seed);
/*
* Generates a random double value.
*/
double rand_double(double high = 1.0, double low=0);
/*
* Generates a random integer value.
*/
int rand_int(int high = RAND_MAX, int low = 0);
/**
* Random number generator that returns a distinct number from
* the [0,n) interval each time.
*
* TODO: improve on this to use a generator function instead of an
* array of randomly permuted numbers
*/
class UniqueRandom
{
int* vals;
int size;
int counter;
public:
/**
* Constructor.
* Params:
* n = the size of the interval from which to generate
* random numbers.
*/
UniqueRandom(int n) : vals(NULL) {
init(n);
}
~UniqueRandom()
{
delete[] vals;
}
/**
* Initializes the number generator.
* Params:
* n = the size of the interval from which to generate
* random numbers.
*/
void init(int n)
{
// create and initialize an array of size n
if (vals == NULL || n!=size) {
delete[] vals;
size = n;
vals = new int[size];
}
for(int i=0;i<size;++i) {
vals[i] = i;
}
// shuffle the elements in the array
// Fisher-Yates shuffle
for (int i=size;i>0;--i) {
// int rand = cast(int) (drand48() * n);
int rnd = rand_int(i);
assert(rnd >=0 && rnd < i);
swap(vals[i-1], vals[rnd]);
}
counter = 0;
}
/**
* Return a distinct random integer in greater or equal to 0 and less
* than 'n' on each call. It should be called maximum 'n' times.
* Returns: a random integer
*/
int next() {
if (counter==size) {
return -1;
} else {
return vals[counter++];
}
}
};
} // namespace cvflann
#endif //RANDOM_H

View File

@@ -0,0 +1,320 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef RESULTSET_H
#define RESULTSET_H
#include <algorithm>
#include <limits>
#include <vector>
#include "opencv2/flann/dist.h"
using namespace std;
namespace cvflann
{
/* This record represents a branch point when finding neighbors in
the tree. It contains a record of the minimum distance to the query
point, as well as the node at which the search resumes.
*/
template <typename T>
struct BranchStruct {
T node; /* Tree node at which search resumes */
float mindistsq; /* Minimum distance to query for all nodes below. */
bool operator<(const BranchStruct<T>& rhs)
{
return mindistsq<rhs.mindistsq;
}
static BranchStruct<T> make_branch(const T& aNode, float dist)
{
BranchStruct<T> branch;
branch.node = aNode;
branch.mindistsq = dist;
return branch;
}
};
template <typename ELEM_TYPE>
class ResultSet
{
protected:
public:
virtual ~ResultSet() {};
virtual void init(const ELEM_TYPE* target_, int veclen_) = 0;
virtual int* getNeighbors() = 0;
virtual float* getDistances() = 0;
virtual size_t size() const = 0;
virtual bool full() const = 0;
virtual bool addPoint(const ELEM_TYPE* point, int index) = 0;
virtual float worstDist() const = 0;
};
template <typename ELEM_TYPE>
class KNNResultSet : public ResultSet<ELEM_TYPE>
{
const ELEM_TYPE* target;
const ELEM_TYPE* target_end;
int veclen;
int* indices;
float* dists;
int capacity;
int count;
public:
KNNResultSet(int capacity_, ELEM_TYPE* target_ = NULL, int veclen_ = 0 ) :
target(target_), veclen(veclen_), capacity(capacity_), count(0)
{
target_end = target + veclen;
indices = new int[capacity_];
dists = new float[capacity_];
}
~KNNResultSet()
{
delete[] indices;
delete[] dists;
}
void init(const ELEM_TYPE* target_, int veclen_)
{
target = target_;
veclen = veclen_;
target_end = target + veclen;
count = 0;
}
int* getNeighbors()
{
return indices;
}
float* getDistances()
{
return dists;
}
size_t size() const
{
return count;
}
bool full() const
{
return count == capacity;
}
bool addPoint(const ELEM_TYPE* point, int index)
{
for (int i=0;i<count;++i) {
if (indices[i]==index) return false;
}
float dist = flann_dist(target, target_end, point);
if (count<capacity) {
indices[count] = index;
dists[count] = dist;
++count;
}
else if (dist < dists[count-1] || (dist == dists[count-1] && index < indices[count-1])) {
// else if (dist < dists[count-1]) {
indices[count-1] = index;
dists[count-1] = dist;
}
else {
return false;
}
int i = count-1;
// bubble up
while (i>=1 && (dists[i]<dists[i-1] || (dists[i]==dists[i-1] && indices[i]<indices[i-1]) ) ) {
// while (i>=1 && (dists[i]<dists[i-1]) ) {
swap(indices[i],indices[i-1]);
swap(dists[i],dists[i-1]);
i--;
}
return true;
}
float worstDist() const
{
return (count<capacity) ? numeric_limits<float>::max() : dists[count-1];
}
};
/**
* A result-set class used when performing a radius based search.
*/
template <typename ELEM_TYPE>
class RadiusResultSet : public ResultSet<ELEM_TYPE>
{
const ELEM_TYPE* target;
const ELEM_TYPE* target_end;
int veclen;
struct Item {
int index;
float dist;
bool operator<(Item rhs) {
return dist<rhs.dist;
}
};
vector<Item> items;
float radius;
bool sorted;
int* indices;
float* dists;
size_t count;
private:
void resize_vecs()
{
if (items.size()>count) {
if (indices!=NULL) delete[] indices;
if (dists!=NULL) delete[] dists;
count = items.size();
indices = new int[count];
dists = new float[count];
}
}
public:
RadiusResultSet(float radius_) :
radius(radius_), indices(NULL), dists(NULL)
{
sorted = false;
items.reserve(16);
count = 0;
}
~RadiusResultSet()
{
if (indices!=NULL) delete[] indices;
if (dists!=NULL) delete[] dists;
}
void init(const ELEM_TYPE* target_, int veclen_)
{
target = target_;
veclen = veclen_;
target_end = target + veclen;
items.clear();
sorted = false;
}
int* getNeighbors()
{
if (!sorted) {
sorted = true;
sort_heap(items.begin(), items.end());
}
resize_vecs();
for (size_t i=0;i<items.size();++i) {
indices[i] = items[i].index;
}
return indices;
}
float* getDistances()
{
if (!sorted) {
sorted = true;
sort_heap(items.begin(), items.end());
}
resize_vecs();
for (size_t i=0;i<items.size();++i) {
dists[i] = items[i].dist;
}
return dists;
}
size_t size() const
{
return items.size();
}
bool full() const
{
return true;
}
bool addPoint(const ELEM_TYPE* point, int index)
{
Item it;
it.index = index;
it.dist = flann_dist(target, target_end, point);
if (it.dist<=radius) {
items.push_back(it);
push_heap(items.begin(), items.end());
return true;
}
return false;
}
float worstDist() const
{
return radius;
}
};
} // namespace cvflann
#endif //RESULTSET_H

View File

@@ -0,0 +1,94 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef SAMPLING_H_
#define SAMPLING_H_
#include "opencv2/flann/matrix.h"
#include "opencv2/flann/random.h"
namespace cvflann
{
template<typename T>
Matrix<T> random_sample(Matrix<T>& srcMatrix, long size, bool remove = false)
{
UniqueRandom rand(srcMatrix.rows);
Matrix<T> newSet(new T[size * srcMatrix.cols], size,srcMatrix.cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = newSet[i];
src = srcMatrix[r];
for (size_t j=0;j<srcMatrix.cols;++j) {
dest[j] = src[j];
}
if (remove) {
dest = srcMatrix[srcMatrix.rows-i-1];
src = srcMatrix[r];
for (size_t j=0;j<srcMatrix.cols;++j) {
swap(*src,*dest);
src++;
dest++;
}
}
}
if (remove) {
srcMatrix.rows -= size;
}
return newSet;
}
template<typename T>
Matrix<T> random_sample(const Matrix<T>& srcMatrix, size_t size)
{
UniqueRandom rand(srcMatrix.rows);
Matrix<T> newSet(new T[size * srcMatrix.cols], size,srcMatrix.cols);
T *src,*dest;
for (size_t i=0;i<size;++i) {
long r = rand.next();
dest = newSet[i];
src = srcMatrix[r];
for (size_t j=0;j<srcMatrix.cols;++j) {
dest[j] = src[j];
}
}
return newSet;
}
} // namespace cvflann
#endif /* SAMPLING_H_ */

View File

@@ -0,0 +1,115 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE NNIndexGOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef SAVING_H_
#define SAVING_H_
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
#include <cstdio>
#include <cstring>
namespace cvflann
{
template <typename T> struct Datatype {};
template<> struct Datatype<char> { static flann_datatype_t type() { return INT8; } };
template<> struct Datatype<short> { static flann_datatype_t type() { return INT16; } };
template<> struct Datatype<int> { static flann_datatype_t type() { return INT32; } };
template<> struct Datatype<unsigned char> { static flann_datatype_t type() { return UINT8; } };
template<> struct Datatype<unsigned short> { static flann_datatype_t type() { return UINT16; } };
template<> struct Datatype<unsigned int> { static flann_datatype_t type() { return UINT32; } };
template<> struct Datatype<float> { static flann_datatype_t type() { return FLOAT32; } };
template<> struct Datatype<double> { static flann_datatype_t type() { return FLOAT64; } };
extern const char FLANN_SIGNATURE[];
extern const char FLANN_VERSION[];
/**
* Structure representing the index header.
*/
struct IndexHeader
{
char signature[16];
char version[16];
flann_datatype_t data_type;
flann_algorithm_t index_type;
int rows;
int cols;
};
/**
* Saves index header to stream
*
* @param stream - Stream to save to
* @param index - The index to save
*/
template<typename ELEM_TYPE>
void save_header(FILE* stream, const NNIndex<ELEM_TYPE>& index)
{
IndexHeader header;
memset(header.signature, 0 , sizeof(header.signature));
strcpy(header.signature, FLANN_SIGNATURE);
memset(header.version, 0 , sizeof(header.version));
strcpy(header.version, FLANN_VERSION);
header.data_type = Datatype<ELEM_TYPE>::type();
header.index_type = index.getType();
header.rows = index.size();
header.cols = index.veclen();
std::fwrite(&header, sizeof(header),1,stream);
}
/**
*
* @param stream - Stream to load from
* @return Index header
*/
IndexHeader load_header(FILE* stream);
template<typename T>
void save_value(FILE* stream, const T& value, int count = 1)
{
fwrite(&value, sizeof(value),count, stream);
}
template<typename T>
void load_value(FILE* stream, T& value, int count = 1)
{
int read_cnt = fread(&value, sizeof(value),count, stream);
if (read_cnt!=count) {
throw FLANNException("Cannot read from file");
}
}
} // namespace cvflann
#endif /* SAVING_H_ */

View File

@@ -0,0 +1,186 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef SIMPLEX_DOWNHILL_H
#define SIMPLEX_DOWNHILL_H
namespace cvflann
{
/**
Adds val to array vals (and point to array points) and keeping the arrays sorted by vals.
*/
template <typename T>
void addValue(int pos, float val, float* vals, T* point, T* points, int n)
{
vals[pos] = val;
for (int i=0;i<n;++i) {
points[pos*n+i] = point[i];
}
// bubble down
int j=pos;
while (j>0 && vals[j]<vals[j-1]) {
swap(vals[j],vals[j-1]);
for (int i=0;i<n;++i) {
swap(points[j*n+i],points[(j-1)*n+i]);
}
--j;
}
}
/**
Simplex downhill optimization function.
Preconditions: points is a 2D mattrix of size (n+1) x n
func is the cost function taking n an array of n params and returning float
vals is the cost function in the n+1 simplex points, if NULL it will be computed
Postcondition: returns optimum value and points[0..n] are the optimum parameters
*/
template <typename T, typename F>
float optimizeSimplexDownhill(T* points, int n, F func, float* vals = NULL )
{
const int MAX_ITERATIONS = 10;
assert(n>0);
T* p_o = new T[n];
T* p_r = new T[n];
T* p_e = new T[n];
int alpha = 1;
int iterations = 0;
bool ownVals = false;
if (vals == NULL) {
ownVals = true;
vals = new float[n+1];
for (int i=0;i<n+1;++i) {
float val = func(points+i*n);
addValue(i, val, vals, points+i*n, points, n);
}
}
int nn = n*n;
while (true) {
if (iterations++ > MAX_ITERATIONS) break;
// compute average of simplex points (except the highest point)
for (int j=0;j<n;++j) {
p_o[j] = 0;
for (int i=0;i<n;++i) {
p_o[i] += points[j*n+i];
}
}
for (int i=0;i<n;++i) {
p_o[i] /= n;
}
bool converged = true;
for (int i=0;i<n;++i) {
if (p_o[i] != points[nn+i]) {
converged = false;
}
}
if (converged) break;
// trying a reflection
for (int i=0;i<n;++i) {
p_r[i] = p_o[i] + alpha*(p_o[i]-points[nn+i]);
}
float val_r = func(p_r);
if (val_r>=vals[0] && val_r<vals[n]) {
// reflection between second highest and lowest
// add it to the simplex
logger.info("Choosing reflection\n");
addValue(n, val_r,vals, p_r, points, n);
continue;
}
if (val_r<vals[0]) {
// value is smaller than smalest in simplex
// expand some more to see if it drops further
for (int i=0;i<n;++i) {
p_e[i] = 2*p_r[i]-p_o[i];
}
float val_e = func(p_e);
if (val_e<val_r) {
logger.info("Choosing reflection and expansion\n");
addValue(n, val_e,vals,p_e,points,n);
}
else {
logger.info("Choosing reflection\n");
addValue(n, val_r,vals,p_r,points,n);
}
continue;
}
if (val_r>=vals[n]) {
for (int i=0;i<n;++i) {
p_e[i] = (p_o[i]+points[nn+i])/2;
}
float val_e = func(p_e);
if (val_e<vals[n]) {
logger.info("Choosing contraction\n");
addValue(n,val_e,vals,p_e,points,n);
continue;
}
}
{
logger.info("Full contraction\n");
for (int j=1;j<=n;++j) {
for (int i=0;i<n;++i) {
points[j*n+i] = (points[j*n+i]+points[i])/2;
}
float val = func(points+j*n);
addValue(j,val,vals,points+j*n,points,n);
}
}
}
float bestVal = vals[0];
delete[] p_r;
delete[] p_o;
delete[] p_e;
if (ownVals) delete[] vals;
return bestVal;
}
} // namespace cvflann
#endif //SIMPLEX_DOWNHILL_H

View File

@@ -0,0 +1,90 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef TIMER_H
#define TIMER_H
#include <time.h>
namespace cvflann
{
/**
* A start-stop timer class.
*
* Can be used to time portions of code.
*/
class StartStopTimer
{
clock_t startTime;
public:
/**
* Value of the timer.
*/
double value;
/**
* Constructor.
*/
StartStopTimer()
{
reset();
}
/**
* Starts the timer.
*/
void start() {
startTime = clock();
}
/**
* Stops the timer and updates timer value.
*/
void stop() {
clock_t stopTime = clock();
value += ( (double)stopTime - startTime) / CLOCKS_PER_SEC;
}
/**
* Resets the timer value to 0.
*/
void reset() {
value = 0;
}
};
}// namespace cvflann
#endif // TIMER_H

222
modules/flann/src/flann.cpp Normal file
View File

@@ -0,0 +1,222 @@
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#include <cstdio>
#include <cstdarg>
#include <sstream>
#include "opencv2/flann/dist.h"
#include "opencv2/flann/index_testing.h"
#include "opencv2/flann/logger.h"
#include "opencv2/flann/logger.h"
#include "opencv2/flann/saving.h"
#include "opencv2/flann/general.h"
// index types
#include "opencv2/flann/all_indices.h"
namespace cvflann
{
// ----------------------- dist.cpp ---------------------------
/** 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;
double euclidean_dist(const unsigned char* first1, const unsigned char* last1, unsigned char* first2, double acc)
{
double distsq = acc;
double diff0, diff1, diff2, diff3;
const unsigned char* lastgroup = last1 - 3;
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;
}
while (first1 < last1) {
diff0 = *first1++ - *first2++;
distsq += diff0 * diff0;
}
return distsq;
}
// ----------------------- index_testing.cpp ---------------------------
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;
}
// ----------------------- logger.cpp ---------------------------
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)
// ----------------------- random.cpp ---------------------------
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)));
}
// ----------------------- saving.cpp ---------------------------
const char FLANN_SIGNATURE[] = "FLANN_INDEX";
const char FLANN_VERSION[] = "1.5.0";
IndexHeader load_header(FILE* stream)
{
IndexHeader header;
int read_size = 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;
}
// ----------------------- flann.cpp ---------------------------
void log_verbosity(int level)
{
if (level>=0) {
logger.setLevel(level);
}
}
void set_distance_type(flann_distance_t distance_type, int order)
{
flann_distance_type = distance_type;
flann_minkowski_order = order;
}
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;
} // namespace cvflann

View File

View File

@@ -9,6 +9,7 @@ include_directories(
"${CMAKE_SOURCE_DIR}/modules/highgui/include"
"${CMAKE_SOURCE_DIR}/modules/video/include"
"${CMAKE_SOURCE_DIR}/modules/features2d/include"
"${CMAKE_SOURCE_DIR}/modules/flann/include"
"${CMAKE_SOURCE_DIR}/modules/calib3d/include"
"${CMAKE_SOURCE_DIR}/modules/legacy/include"
)

View File

@@ -1 +1 @@
define_opencv_module(legacy opencv_core opencv_imgproc opencv_calib3d opencv_features2d opencv_highgui opencv_video)
define_opencv_module(legacy opencv_core opencv_imgproc opencv_calib3d opencv_features2d opencv_highgui opencv_video opencv_flann)

View File

@@ -12,6 +12,7 @@ include_directories(
"${CMAKE_SOURCE_DIR}/modules/highgui/include"
"${CMAKE_SOURCE_DIR}/modules/ml/include"
"${CMAKE_SOURCE_DIR}/modules/features2d/include"
"${CMAKE_SOURCE_DIR}/modules/flann/include"
"${CMAKE_SOURCE_DIR}/modules/calib3d/include"
"${CMAKE_SOURCE_DIR}/modules/objdetect/include"
"${CMAKE_SOURCE_DIR}/modules/legacy/include"

View File

@@ -9,6 +9,7 @@ include_directories(
"${CMAKE_SOURCE_DIR}/modules/highgui/include"
"${CMAKE_SOURCE_DIR}/modules/video/include"
"${CMAKE_SOURCE_DIR}/modules/features2d/include"
"${CMAKE_SOURCE_DIR}/modules/flann/include"
"${CMAKE_SOURCE_DIR}/modules/calib3d/include"
"${CMAKE_SOURCE_DIR}/modules/legacy/include"
)