提交 562914e3 编写于 作者: V Vadim Pisarevsky

upgraded to FLANN 1.6. Added miniflann interface, which is now used in the...

upgraded to FLANN 1.6. Added miniflann interface, which is now used in the rest of OpenCV. Added Python bindings for FLANN.
上级 4e42bf63
......@@ -44,7 +44,7 @@
#define __OPENCV_FEATURES_2D_HPP__
#include "opencv2/core/core.hpp"
#include "opencv2/flann/flann.hpp"
#include "opencv2/flann/miniflann.hpp"
#ifdef __cplusplus
#include <limits>
......
......@@ -603,7 +603,7 @@ void FlannBasedMatcher::radiusMatchImpl( const Mat& queryDescriptors, vector<vec
Mat queryDescriptorsRow = queryDescriptors.row(qIdx);
Mat indicesRow = indices.row(qIdx);
Mat distsRow = dists.row(qIdx);
flannIndex->radiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, *searchParams );
flannIndex->radiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, count, *searchParams );
}
convertToDMatches( mergedDescriptors, indices, dists, matches );
......
......@@ -405,14 +405,14 @@ int CV_FlannTest::radiusSearch( Mat& points, Mat& neighbors )
// 1st way
Mat p( 1, points.cols, CV_32FC1, points.ptr<float>(i) ),
n( 1, neighbors.cols, CV_32SC1, neighbors.ptr<int>(i) );
index->radiusSearch( p, n, dist, radius, SearchParams() );
index->radiusSearch( p, n, dist, radius, neighbors.cols, SearchParams() );
// 2nd way
float* fltPtr = points.ptr<float>(i);
vector<float> query( fltPtr, fltPtr + points.cols );
vector<int> indices( neighbors1.cols, 0 );
vector<float> dists( dist.cols, 0 );
index->radiusSearch( query, indices, dists, radius, SearchParams() );
index->radiusSearch( query, indices, dists, radius, neighbors.cols, SearchParams() );
vector<int>::const_iterator it = indices.begin();
for( j = 0; it != indices.end(); ++it, j++ )
neighbors1.at<int>(i,j) = *it;
......
......@@ -27,50 +27,129 @@
*************************************************************************/
#ifndef _OPENCV_ALL_INDICES_H_
#define _OPENCV_ALL_INDICES_H_
#ifndef OPENCV_FLANN_ALL_INDICES_H_
#define OPENCV_FLANN_ALL_INDICES_H_
#include "opencv2/flann/general.h"
#include "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"
#include "nn_index.h"
#include "kdtree_index.h"
#include "kdtree_single_index.h"
#include "kmeans_index.h"
#include "composite_index.h"
#include "linear_index.h"
#include "hierarchical_clustering_index.h"
#include "lsh_index.h"
#include "autotuned_index.h"
namespace cvflann
namespace cvflann
{
template<typename KDTreeCapability, typename VectorSpace, typename Distance>
struct index_creator
{
static NNIndex<Distance>* create(const Matrix<typename Distance::ElementType>& dataset, const IndexParams& params, const Distance& distance)
{
flann_algorithm_t index_type = get_param<flann_algorithm_t>(params, "algorithm");
NNIndex<Distance>* nnIndex;
switch (index_type) {
case FLANN_INDEX_LINEAR:
nnIndex = new LinearIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_KDTREE_SINGLE:
nnIndex = new KDTreeSingleIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_KDTREE:
nnIndex = new KDTreeIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_KMEANS:
nnIndex = new KMeansIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_COMPOSITE:
nnIndex = new CompositeIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_AUTOTUNED:
nnIndex = new AutotunedIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_HIERARCHICAL:
nnIndex = new HierarchicalClusteringIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_LSH:
nnIndex = new LshIndex<Distance>(dataset, params, distance);
break;
default:
throw FLANNException("Unknown index type");
}
return nnIndex;
}
};
template<typename VectorSpace, typename Distance>
struct index_creator<False,VectorSpace,Distance>
{
static NNIndex<Distance>* create(const Matrix<typename Distance::ElementType>& dataset, const IndexParams& params, const Distance& distance)
{
flann_algorithm_t index_type = get_param<flann_algorithm_t>(params, "algorithm");
template<typename T>
NNIndex<T>* create_index_by_type(const Matrix<T>& dataset, const IndexParams& params)
NNIndex<Distance>* nnIndex;
switch (index_type) {
case FLANN_INDEX_LINEAR:
nnIndex = new LinearIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_KMEANS:
nnIndex = new KMeansIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_HIERARCHICAL:
nnIndex = new HierarchicalClusteringIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_LSH:
nnIndex = new LshIndex<Distance>(dataset, params, distance);
break;
default:
throw FLANNException("Unknown index type");
}
return nnIndex;
}
};
template<typename Distance>
struct index_creator<False,False,Distance>
{
flann_algorithm_t index_type = params.getIndexType();
NNIndex<T>* nnIndex;
switch (index_type) {
case FLANN_INDEX_LINEAR:
nnIndex = new LinearIndex<T>(dataset, (const LinearIndexParams&)params);
break;
case FLANN_INDEX_KDTREE:
nnIndex = new KDTreeIndex<T>(dataset, (const KDTreeIndexParams&)params);
break;
case FLANN_INDEX_KMEANS:
nnIndex = new KMeansIndex<T>(dataset, (const KMeansIndexParams&)params);
break;
case FLANN_INDEX_COMPOSITE:
nnIndex = new CompositeIndex<T>(dataset, (const CompositeIndexParams&) params);
break;
case FLANN_INDEX_AUTOTUNED:
nnIndex = new AutotunedIndex<T>(dataset, (const AutotunedIndexParams&) params);
break;
default:
throw FLANNException("Unknown index type");
}
return nnIndex;
static NNIndex<Distance>* create(const Matrix<typename Distance::ElementType>& dataset, const IndexParams& params, const Distance& distance)
{
flann_algorithm_t index_type = get_param<flann_algorithm_t>(params, "algorithm");
NNIndex<Distance>* nnIndex;
switch (index_type) {
case FLANN_INDEX_LINEAR:
nnIndex = new LinearIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_HIERARCHICAL:
nnIndex = new HierarchicalClusteringIndex<Distance>(dataset, params, distance);
break;
case FLANN_INDEX_LSH:
nnIndex = new LshIndex<Distance>(dataset, params, distance);
break;
default:
throw FLANNException("Unknown index type");
}
return nnIndex;
}
};
template<typename Distance>
NNIndex<Distance>* create_index_by_type(const Matrix<typename Distance::ElementType>& dataset, const IndexParams& params, const Distance& distance)
{
return index_creator<typename Distance::is_kdtree_distance,
typename Distance::is_vector_space_distance,
Distance>::create(dataset, params,distance);
}
} //namespace cvflann
}
#endif /* _OPENCV_ALL_INDICES_H_ */
#endif /* OPENCV_FLANN_ALL_INDICES_H_ */
......@@ -28,12 +28,13 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef _OPENCV_ALLOCATOR_H_
#define _OPENCV_ALLOCATOR_H_
#ifndef OPENCV_FLANN_ALLOCATOR_H_
#define OPENCV_FLANN_ALLOCATOR_H_
#include <stdlib.h>
#include <stdio.h>
namespace cvflann
{
......@@ -47,8 +48,8 @@ namespace cvflann
template <typename T>
T* allocate(size_t count = 1)
{
T* mem = (T*) ::malloc(sizeof(T)*count);
return mem;
T* mem = (T*) ::malloc(sizeof(T)*count);
return mem;
}
......@@ -70,118 +71,118 @@ T* allocate(size_t count = 1)
const size_t WORDSIZE=16;
const size_t BLOCKSIZE=8192;
class CV_EXPORTS PooledAllocator
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. */
/* 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;
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* allocateBytes(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) {
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* allocateMemory(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
*/
return NULL;
}
/* 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->allocateBytes((int)(sizeof(T)*count));
return mem;
}
T* allocate(size_t count = 1)
{
T* mem = (T*) this->allocateMemory((int)(sizeof(T)*count));
return mem;
}
};
} // namespace cvflann
}
#endif //_OPENCV_ALLOCATOR_H_
#endif //OPENCV_FLANN_ALLOCATOR_H_
#ifndef OPENCV_FLANN_ANY_H_
#define OPENCV_FLANN_ANY_H_
/*
* (C) Copyright Christopher Diggins 2005-2011
* (C) Copyright Pablo Aguilar 2005
* (C) Copyright Kevlin Henney 2001
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt
*
* Adapted for FLANN by Marius Muja
*/
#include <stdexcept>
#include <ostream>
#include <typeinfo>
namespace cdiggins
{
namespace anyimpl
{
struct bad_any_cast
{
};
struct empty_any
{
};
struct base_any_policy
{
virtual void static_delete(void** x) = 0;
virtual void copy_from_value(void const* src, void** dest) = 0;
virtual void clone(void* const* src, void** dest) = 0;
virtual void move(void* const* src, void** dest) = 0;
virtual void* get_value(void** src) = 0;
virtual size_t get_size() = 0;
virtual const std::type_info& type() = 0;
virtual void print(std::ostream& out, void* const* src) = 0;
};
template<typename T>
struct typed_base_any_policy : base_any_policy
{
virtual size_t get_size() { return sizeof(T); }
virtual const std::type_info& type() { return typeid(T); }
};
template<typename T>
struct small_any_policy : typed_base_any_policy<T>
{
virtual void static_delete(void**) { }
virtual void copy_from_value(void const* src, void** dest)
{
new (dest) T(* reinterpret_cast<T const*>(src));
}
virtual void clone(void* const* src, void** dest) { *dest = *src; }
virtual void move(void* const* src, void** dest) { *dest = *src; }
virtual void* get_value(void** src) { return reinterpret_cast<void*>(src); }
virtual void print(std::ostream& out, void* const* src) { out << *reinterpret_cast<T const*>(src); }
};
template<typename T>
struct big_any_policy : typed_base_any_policy<T>
{
virtual void static_delete(void** x)
{
if (* x) delete (* reinterpret_cast<T**>(x)); *x = NULL;
}
virtual void copy_from_value(void const* src, void** dest)
{
*dest = new T(*reinterpret_cast<T const*>(src));
}
virtual void clone(void* const* src, void** dest)
{
*dest = new T(**reinterpret_cast<T* const*>(src));
}
virtual void move(void* const* src, void** dest)
{
(*reinterpret_cast<T**>(dest))->~T();
**reinterpret_cast<T**>(dest) = **reinterpret_cast<T* const*>(src);
}
virtual void* get_value(void** src) { return *src; }
virtual void print(std::ostream& out, void* const* src) { out << *reinterpret_cast<T const*>(*src); }
};
template<typename T>
struct choose_policy
{
typedef big_any_policy<T> type;
};
template<typename T>
struct choose_policy<T*>
{
typedef small_any_policy<T*> type;
};
struct any;
/// Choosing the policy for an any type is illegal, but should never happen.
/// This is designed to throw a compiler error.
template<>
struct choose_policy<any>
{
typedef void type;
};
/// Specializations for small types.
#define SMALL_POLICY(TYPE) \
template<> \
struct choose_policy<TYPE> { typedef small_any_policy<TYPE> type; \
};
SMALL_POLICY(signed char);
SMALL_POLICY(unsigned char);
SMALL_POLICY(signed short);
SMALL_POLICY(unsigned short);
SMALL_POLICY(signed int);
SMALL_POLICY(unsigned int);
SMALL_POLICY(signed long);
SMALL_POLICY(unsigned long);
SMALL_POLICY(float);
SMALL_POLICY(bool);
#undef SMALL_POLICY
/// This function will return a different policy for each type.
template<typename T>
base_any_policy* get_policy()
{
static typename choose_policy<T>::type policy;
return &policy;
}
} // namespace anyimpl
struct any
{
private:
// fields
anyimpl::base_any_policy* policy;
void* object;
public:
/// Initializing constructor.
template <typename T>
any(const T& x)
: policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
{
assign(x);
}
/// Empty constructor.
any()
: policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
{ }
/// Special initializing constructor for string literals.
any(const char* x)
: policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
{
assign(x);
}
/// Copy constructor.
any(const any& x)
: policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
{
assign(x);
}
/// Destructor.
~any()
{
policy->static_delete(&object);
}
/// Assignment function from another any.
any& assign(const any& x)
{
reset();
policy = x.policy;
policy->clone(&x.object, &object);
return *this;
}
/// Assignment function.
template <typename T>
any& assign(const T& x)
{
reset();
policy = anyimpl::get_policy<T>();
policy->copy_from_value(&x, &object);
return *this;
}
/// Assignment operator.
template<typename T>
any& operator=(const T& x)
{
return assign(x);
}
/// Assignment operator, specialed for literal strings.
/// They have types like const char [6] which don't work as expected.
any& operator=(const char* x)
{
return assign(x);
}
/// Utility functions
any& swap(any& x)
{
std::swap(policy, x.policy);
std::swap(object, x.object);
return *this;
}
/// Cast operator. You can only cast to the original type.
template<typename T>
T& cast()
{
if (policy->type() != typeid(T)) throw anyimpl::bad_any_cast();
T* r = reinterpret_cast<T*>(policy->get_value(&object));
return *r;
}
/// Cast operator. You can only cast to the original type.
template<typename T>
const T& cast() const
{
if (policy->type() != typeid(T)) throw anyimpl::bad_any_cast();
void* obj = const_cast<void*>(object);
T* r = reinterpret_cast<T*>(policy->get_value(&obj));
return *r;
}
/// Returns true if the any contains no value.
bool empty() const
{
return policy->type() == typeid(anyimpl::empty_any);
}
/// Frees any allocated memory, and sets the value to NULL.
void reset()
{
policy->static_delete(&object);
policy = anyimpl::get_policy<anyimpl::empty_any>();
}
/// Returns true if the two types are the same.
bool compatible(const any& x) const
{
return policy->type() == x.policy->type();
}
/// Returns if the type is compatible with the policy
template<typename T>
bool has_type()
{
return policy->type() == typeid(T);
}
const std::type_info& type() const
{
return policy->type();
}
friend std::ostream& operator <<(std::ostream& out, const any& any_val);
};
inline std::ostream& operator <<(std::ostream& out, const any& any_val)
{
any_val.policy->print(out,&any_val.object);
return out;
}
}
#endif // OPENCV_FLANN_ANY_H_
......@@ -28,135 +28,167 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef _OPENCV_COMPOSITETREE_H_
#define _OPENCV_COMPOSITETREE_H_
#ifndef OPENCV_FLANN_COMPOSITE_INDEX_H_
#define OPENCV_FLANN_COMPOSITE_INDEX_H_
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
#include "general.h"
#include "nn_index.h"
#include "kdtree_index.h"
#include "kmeans_index.h"
namespace cvflann
{
struct CompositeIndexParams : public IndexParams {
CompositeIndexParams(int trees_ = 4, int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = FLANN_CENTERS_RANDOM, float cb_index_ = 0.2 ) :
IndexParams(FLANN_INDEX_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
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);
}
/**
* Index parameters for the CompositeIndex.
*/
struct CompositeIndexParams : public IndexParams
{
CompositeIndexParams(int trees = 4, int branching = 32, int iterations = 11,
flann_centers_init_t centers_init = FLANN_CENTERS_RANDOM, float cb_index = 0.2 )
{
(*this)["algorithm"] = FLANN_INDEX_KMEANS;
// number of randomized trees to use (for kdtree)
(*this)["trees"] = trees;
// branching factor
(*this)["branching"] = branching;
// max iterations to perform in one kmeans clustering (kmeans tree)
(*this)["iterations"] = iterations;
// algorithm used for picking the initial cluster centers for kmeans tree
(*this)["centers_init"] = centers_init;
// cluster boundary index. Used when searching the kmeans tree
(*this)["cb_index"] = cb_index;
}
};
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
class CompositeIndex : public NNIndex<ELEM_TYPE>
/**
* This index builds a kd-tree index and a k-means index and performs nearest
* neighbour search both indexes. This gives a slight boost in search performance
* as some of the neighbours that are missed by one index are found by the other.
*/
template <typename Distance>
class CompositeIndex : public NNIndex<Distance>
{
KMeansIndex<ELEM_TYPE, DIST_TYPE>* kmeans;
KDTreeIndex<ELEM_TYPE, DIST_TYPE>* kdtree;
const Matrix<ELEM_TYPE> dataset;
const IndexParams& index_params;
CompositeIndex& operator=(const CompositeIndex&);
CompositeIndex(const CompositeIndex&);
public:
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
/**
* Index constructor
* @param inputData dataset containing the points to index
* @param params Index parameters
* @param d Distance functor
* @return
*/
CompositeIndex(const Matrix<ElementType>& inputData, const IndexParams& params = CompositeIndexParams(),
Distance d = Distance()) : index_params_(params)
{
kdtree_index_ = new KDTreeIndex<Distance>(inputData, params, d);
kmeans_index_ = new KMeansIndex<Distance>(inputData, params, d);
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;
}
CompositeIndex(const CompositeIndex&);
CompositeIndex& operator=(const CompositeIndex&);
virtual ~CompositeIndex()
{
delete kdtree_index_;
delete kmeans_index_;
}
/**
* @return The index type
*/
flann_algorithm_t getType() const
{
return FLANN_INDEX_COMPOSITE;
}
/**
* @return Size of the index
*/
size_t size() const
{
return dataset.rows;
}
size_t veclen() const
{
return dataset.cols;
}
{
return kdtree_index_->size();
}
int usedMemory() const
{
return kmeans->usedMemory()+kdtree->usedMemory();
}
/**
* \returns The dimensionality of the features in this index.
*/
size_t veclen() const
{
return kdtree_index_->veclen();
}
void buildIndex()
{
logger().info("Building kmeans tree...\n");
kmeans->buildIndex();
logger().info("Building kdtree tree...\n");
kdtree->buildIndex();
}
/**
* \returns The amount of memory (in bytes) used by the index.
*/
int usedMemory() const
{
return kmeans_index_->usedMemory() + kdtree_index_->usedMemory();
}
/**
* \brief Builds the index
*/
void buildIndex()
{
Logger::info("Building kmeans tree...\n");
kmeans_index_->buildIndex();
Logger::info("Building kdtree tree...\n");
kdtree_index_->buildIndex();
}
/**
* \brief Saves the index to a stream
* \param stream The stream to save the index to
*/
void saveIndex(FILE* stream)
{
kmeans->saveIndex(stream);
kdtree->saveIndex(stream);
kmeans_index_->saveIndex(stream);
kdtree_index_->saveIndex(stream);
}
/**
* \brief Loads the index from a stream
* \param stream The stream from which the index is loaded
*/
void loadIndex(FILE* stream)
{
kmeans->loadIndex(stream);
kdtree->loadIndex(stream);
kmeans_index_->loadIndex(stream);
kdtree_index_->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);
}
/**
* \returns The index parameters
*/
IndexParams getParameters() const
{
return index_params_;
}
/**
* \brief Method that searches for nearest-neighbours
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
{
kmeans_index_->findNeighbors(result, vec, searchParams);
kdtree_index_->findNeighbors(result, vec, searchParams);
}
const IndexParams* getParameters() const
{
return &index_params;
}
private:
/** The k-means index */
KMeansIndex<Distance>* kmeans_index_;
/** The kd-tree index */
KDTreeIndex<Distance>* kdtree_index_;
/** The index parameters */
const IndexParams index_params_;
};
} // namespace cvflann
}
#endif //_OPENCV_COMPOSITETREE_H_
#endif //OPENCV_FLANN_COMPOSITE_INDEX_H_
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2011 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2011 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 OPENCV_FLANN_CONFIG_H_
#define OPENCV_FLANN_CONFIG_H_
#define FLANN_VERSION "1.6.10"
#endif /* OPENCV_FLANN_CONFIG_H_ */
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2011 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2011 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 OPENCV_FLANN_DEFINES_H_
#define OPENCV_FLANN_DEFINES_H_
#include "config.h"
#ifdef WIN32
/* win32 dll export/import directives */
#ifdef FLANN_EXPORTS
#define FLANN_EXPORT __declspec(dllexport)
#elif defined(FLANN_STATIC)
#define FLANN_EXPORT
#else
#define FLANN_EXPORT __declspec(dllimport)
#endif
#else
/* unix needs nothing */
#define FLANN_EXPORT
#endif
#ifdef __GNUC__
#define FLANN_DEPRECATED __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define FLANN_DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement FLANN_DEPRECATED for this compiler")
#define FLANN_DEPRECATED
#endif
#if __amd64__ || __x86_64__ || _WIN64 || _M_X64
#define FLANN_PLATFORM_64_BIT
#else
#define FLANN_PLATFORM_32_BIT
#endif
#define FLANN_ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
/* Nearest neighbour index algorithms */
enum flann_algorithm_t
{
FLANN_INDEX_LINEAR = 0,
FLANN_INDEX_KDTREE = 1,
FLANN_INDEX_KMEANS = 2,
FLANN_INDEX_COMPOSITE = 3,
FLANN_INDEX_KDTREE_SINGLE = 4,
FLANN_INDEX_HIERARCHICAL = 5,
FLANN_INDEX_LSH = 6,
FLANN_INDEX_SAVED = 254,
FLANN_INDEX_AUTOTUNED = 255,
// deprecated constants, should use the FLANN_INDEX_* ones instead
LINEAR = 0,
KDTREE = 1,
KMEANS = 2,
COMPOSITE = 3,
KDTREE_SINGLE = 4,
SAVED = 254,
AUTOTUNED = 255
};
enum flann_centers_init_t
{
FLANN_CENTERS_RANDOM = 0,
FLANN_CENTERS_GONZALES = 1,
FLANN_CENTERS_KMEANSPP = 2,
// deprecated constants, should use the FLANN_CENTERS_* ones instead
CENTERS_RANDOM = 0,
CENTERS_GONZALES = 1,
CENTERS_KMEANSPP = 2
};
enum flann_log_level_t
{
FLANN_LOG_NONE = 0,
FLANN_LOG_FATAL = 1,
FLANN_LOG_ERROR = 2,
FLANN_LOG_WARN = 3,
FLANN_LOG_INFO = 4,
};
enum flann_distance_t
{
FLANN_DIST_EUCLIDEAN = 1,
FLANN_DIST_L2 = 1,
FLANN_DIST_MANHATTAN = 2,
FLANN_DIST_L1 = 2,
FLANN_DIST_MINKOWSKI = 3,
FLANN_DIST_MAX = 4,
FLANN_DIST_HIST_INTERSECT = 5,
FLANN_DIST_HELLINGER = 6,
FLANN_DIST_CHI_SQUARE = 7,
FLANN_DIST_CS = 7,
FLANN_DIST_KULLBACK_LEIBLER = 8,
FLANN_DIST_KL = 8,
// deprecated constants, should use the FLANN_DIST_* ones instead
EUCLIDEAN = 1,
MANHATTAN = 2,
MINKOWSKI = 3,
MAX_DIST = 4,
HIST_INTERSECT = 5,
HELLINGER = 6,
CS = 7,
KL = 8,
KULLBACK_LEIBLER = 8
};
enum flann_datatype_t
{
FLANN_INT8 = 0,
FLANN_INT16 = 1,
FLANN_INT32 = 2,
FLANN_INT64 = 3,
FLANN_UINT8 = 4,
FLANN_UINT16 = 5,
FLANN_UINT32 = 6,
FLANN_UINT64 = 7,
FLANN_FLOAT32 = 8,
FLANN_FLOAT64 = 9
};
enum
{
FLANN_CHECKS_UNLIMITED = -1,
FLANN_CHECKS_AUTOTUNED = -2
};
#endif /* OPENCV_FLANN_DEFINES_H_ */
#ifndef OPENCV_FLANN_DUMMY_H_
#define OPENCV_FLANN_DUMMY_H_
namespace cvflann
{
#if (defined WIN32 || defined _WIN32 || defined WINCE) && defined CVAPI_EXPORTS
__declspec(dllexport)
#endif
void dummyfunc();
}
#endif /* OPENCV_FLANN_DUMMY_H_ */
/***********************************************************************
* 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.
*************************************************************************/
/***********************************************************************
* Author: Vincent Rabaud
*************************************************************************/
#ifndef OPENCV_FLANN_DYNAMIC_BITSET_H_
#define OPENCV_FLANN_DYNAMIC_BITSET_H_
//#define FLANN_USE_BOOST 1
#if FLANN_USE_BOOST
#include <boost/dynamic_bitset.hpp>
typedef boost::dynamic_bitset<> DynamicBitset;
#else
#include <limits.h>
#include "dist.h"
/** Class re-implementing the boost version of it
* This helps not depending on boost, it also does not do the bound checks
* and has a way to reset a block for speed
*/
class DynamicBitset
{
public:
/** @param default constructor
*/
DynamicBitset()
{
}
/** @param only constructor we use in our code
* @param the size of the bitset (in bits)
*/
DynamicBitset(size_t size)
{
resize(size);
reset();
}
/** Sets all the bits to 0
*/
void clear()
{
std::fill(bitset_.begin(), bitset_.end(), 0);
}
/** @brief checks if the bitset is empty
* @return true if the bitset is empty
*/
bool empty() const
{
return bitset_.empty();
}
/** @param set all the bits to 0
*/
void reset()
{
std::fill(bitset_.begin(), bitset_.end(), 0);
}
/** @brief set one bit to 0
* @param
*/
void reset(size_t index)
{
bitset_[index / cell_bit_size_] &= ~(size_t(1) << (index % cell_bit_size_));
}
/** @brief sets a specific bit to 0, and more bits too
* This function is useful when resetting a given set of bits so that the
* whole bitset ends up being 0: if that's the case, we don't care about setting
* other bits to 0
* @param
*/
void reset_block(size_t index)
{
bitset_[index / cell_bit_size_] = 0;
}
/** @param resize the bitset so that it contains at least size bits
* @param size
*/
void resize(size_t size)
{
size_ = size;
bitset_.resize(size / cell_bit_size_ + 1);
}
/** @param set a bit to true
* @param index the index of the bit to set to 1
*/
void set(size_t index)
{
bitset_[index / cell_bit_size_] |= size_t(1) << (index % cell_bit_size_);
}
/** @param gives the number of contained bits
*/
size_t size() const
{
return size_;
}
/** @param check if a bit is set
* @param index the index of the bit to check
* @return true if the bit is set
*/
bool test(size_t index) const
{
return (bitset_[index / cell_bit_size_] & (size_t(1) << (index % cell_bit_size_))) != 0;
}
private:
std::vector<size_t> bitset_;
size_t size_;
static const unsigned int cell_bit_size_ = CHAR_BIT * sizeof(size_t);
};
#endif
#endif // OPENCV_FLANN_DYNAMIC_BITSET_H_
......@@ -45,7 +45,17 @@
#ifdef __cplusplus
#include "opencv2/core/types_c.h"
#include "opencv2/core/core.hpp"
#include "opencv2/flann/flann_base.hpp"
#include "opencv2/flann/miniflann.hpp"
namespace cvflann
{
CV_EXPORTS flann_distance_t flann_distance_type();
FLANN_DEPRECATED CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order);
}
namespace cv
{
......@@ -61,132 +71,345 @@ 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; } };
// bring the flann parameters into this namespace
using ::cvflann::get_param;
using ::cvflann::print_params;
// bring the flann distances into this namespace
using ::cvflann::L2_Simple;
using ::cvflann::L2;
using ::cvflann::L1;
using ::cvflann::MinkowskiDistance;
using ::cvflann::MaxDistance;
using ::cvflann::HammingLUT;
using ::cvflann::Hamming;
using ::cvflann::Hamming2;
using ::cvflann::HistIntersectionDistance;
using ::cvflann::HellingerDistance;
using ::cvflann::ChiSquareDistance;
using ::cvflann::KL_Divergence;
template <typename Distance>
class GenericIndex
{
public:
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
GenericIndex(const Mat& features, const IndexParams& params, Distance distance = Distance());
~GenericIndex();
void knnSearch(const vector<ElementType>& query, vector<int>& indices,
vector<DistanceType>& dists, int knn, const SearchParams& params);
void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& params);
int radiusSearch(const vector<ElementType>& query, vector<int>& indices,
vector<DistanceType>& dists, DistanceType radius, const SearchParams& params);
int radiusSearch(const Mat& query, Mat& indices, Mat& dists,
DistanceType radius, const SearchParams& params);
void save(std::string filename) { nnIndex->save(filename); }
int veclen() const { return nnIndex->veclen(); }
int size() const { return nnIndex->size(); }
IndexParams getParameters() { return nnIndex->getParameters(); }
FLANN_DEPRECATED const IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); }
private:
::cvflann::Index<Distance>* nnIndex;
};
#define FLANN_DISTANCE_CHECK \
if ( ::cvflann::flann_distance_type() != FLANN_DIST_L2) { \
printf("[WARNING] You are using cv::flann::Index (or cv::flann::GenericIndex) and have also changed "\
"the distance using cvflann::set_distance_type. This is no longer working as expected "\
"(cv::flann::Index always uses L2). You should create the index templated on the distance, "\
"for example for L1 distance use: GenericIndex< L1<float> > \n"); \
}
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 Distance>
GenericIndex<Distance>::GenericIndex(const Mat& dataset, const IndexParams& params, Distance distance)
{
CV_Assert(dataset.type() == CvType<ElementType>::type());
CV_Assert(dataset.isContinuous());
::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);
nnIndex = new ::cvflann::Index<Distance>(m_dataset, params, distance);
FLANN_DISTANCE_CHECK
nnIndex->buildIndex();
}
template <typename Distance>
GenericIndex<Distance>::~GenericIndex()
{
delete nnIndex;
}
template <typename T>
class CV_EXPORTS Index_ {
::cvflann::Index<T>* nnIndex;
template <typename Distance>
void GenericIndex<Distance>::knnSearch(const vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& dists, int knn, const SearchParams& searchParams)
{
::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
FLANN_DISTANCE_CHECK
nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
}
template <typename Distance>
void GenericIndex<Distance>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const SearchParams& searchParams)
{
CV_Assert(queries.type() == CvType<ElementType>::type());
CV_Assert(queries.isContinuous());
::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(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() == CvType<DistanceType>::type());
CV_Assert(dists.isContinuous());
::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
FLANN_DISTANCE_CHECK
nnIndex->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
}
template <typename Distance>
int GenericIndex<Distance>::radiusSearch(const vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& dists, DistanceType radius, const SearchParams& searchParams)
{
::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
FLANN_DISTANCE_CHECK
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
}
template <typename Distance>
int GenericIndex<Distance>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const SearchParams& searchParams)
{
CV_Assert(query.type() == CvType<ElementType>::type());
CV_Assert(query.isContinuous());
::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(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() == CvType<DistanceType>::type());
CV_Assert(dists.isContinuous());
::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
FLANN_DISTANCE_CHECK
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
}
/**
* @deprecated Use GenericIndex class instead
*/
template <typename T>
class FLANN_DEPRECATED Index_ {
public:
typedef typename L2<T>::ElementType ElementType;
typedef typename L2<T>::ResultType DistanceType;
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 vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& 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);
int radiusSearch(const vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& dists, DistanceType radius, const SearchParams& params);
int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const SearchParams& params);
void save(std::string filename)
{
if (nnIndex_L1) nnIndex_L1->save(filename);
if (nnIndex_L2) nnIndex_L2->save(filename);
}
void save(std::string filename) { nnIndex->save(filename); }
int veclen() const
{
if (nnIndex_L1) return nnIndex_L1->veclen();
if (nnIndex_L2) return nnIndex_L2->veclen();
}
int veclen() const { return nnIndex->veclen(); }
int size() const
{
if (nnIndex_L1) return nnIndex_L1->size();
if (nnIndex_L2) return nnIndex_L2->size();
}
int size() const { return nnIndex->size(); }
IndexParams getParameters()
{
if (nnIndex_L1) return nnIndex_L1->getParameters();
if (nnIndex_L2) return nnIndex_L2->getParameters();
}
const IndexParams* getIndexParameters() { return nnIndex->getIndexParameters(); }
FLANN_DEPRECATED const IndexParams* getIndexParameters()
{
if (nnIndex_L1) return nnIndex_L1->getIndexParameters();
if (nnIndex_L2) return nnIndex_L2->getIndexParameters();
}
private:
// providing backwards compatibility for L2 and L1 distances (most common)
::cvflann::Index< L2<ElementType> >* nnIndex_L2;
::cvflann::Index< L1<ElementType> >* nnIndex_L1;
};
template <typename T>
Index_<T>::Index_(const Mat& dataset, const IndexParams& params)
{
CV_Assert(dataset.type() == CvType<T>::type());
printf("[WARNING] The cv::flann::Index_<T> class is deperecated, use cv::flann::GenericIndex<Distance> instead\n");
CV_Assert(dataset.type() == CvType<ElementType>::type());
CV_Assert(dataset.isContinuous());
::cvflann::Matrix<T> m_dataset((T*)dataset.ptr<T>(0), dataset.rows, dataset.cols);
::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);
nnIndex = new ::cvflann::Index<T>(m_dataset, params);
nnIndex->buildIndex();
if ( ::cvflann::flann_distance_type() == FLANN_DIST_L2 ) {
nnIndex_L1 = NULL;
nnIndex_L2 = new ::cvflann::Index< L2<ElementType> >(m_dataset, params);
}
else if ( ::cvflann::flann_distance_type() == FLANN_DIST_L1 ) {
nnIndex_L1 = new ::cvflann::Index< L1<ElementType> >(m_dataset, params);
nnIndex_L2 = NULL;
}
else {
printf("[ERROR] cv::flann::Index_<T> only provides backwards compatibility for the L1 and L2 distances. "
"For other distance types you must use cv::flann::GenericIndex<Distance>\n");
CV_Assert(0);
}
if (nnIndex_L1) nnIndex_L1->buildIndex();
if (nnIndex_L2) nnIndex_L2->buildIndex();
}
template <typename T>
Index_<T>::~Index_()
{
delete nnIndex;
if (nnIndex_L1) delete nnIndex_L1;
if (nnIndex_L2) delete nnIndex_L2;
}
template <typename T>
void Index_<T>::knnSearch(const vector<T>& query, vector<int>& indices, vector<float>& dists, int knn, const SearchParams& searchParams)
void Index_<T>::knnSearch(const vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& 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());
::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
nnIndex->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
if (nnIndex_L2) nnIndex_L2->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.type() == CvType<ElementType>::type());
CV_Assert(queries.isContinuous());
::cvflann::Matrix<T> m_queries((T*)queries.ptr<T>(0), queries.rows, queries.cols);
::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(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.type() == CvType<DistanceType>::type());
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);
::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
if (nnIndex_L2) nnIndex_L2->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)
int Index_<T>::radiusSearch(const vector<ElementType>& query, vector<int>& indices, vector<DistanceType>& dists, DistanceType 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());
::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
if (nnIndex_L2) return nnIndex_L2->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)
int Index_<T>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const SearchParams& searchParams)
{
CV_Assert(query.type() == CvType<T>::type());
CV_Assert(query.type() == CvType<ElementType>::type());
CV_Assert(query.isContinuous());
::cvflann::Matrix<T> m_query((T*)query.ptr<T>(0), query.rows, query.cols);
::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(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.type() == CvType<DistanceType>::type());
CV_Assert(dists.isContinuous());
::cvflann::Matrix<float> m_dists((float*)dists.ptr<float>(0), dists.rows, dists.cols);
::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
return nnIndex->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
if (nnIndex_L2) return nnIndex_L2->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)
template <typename Distance>
int hierarchicalClustering(const Mat& features, Mat& centers, const KMeansIndexParams& params,
Distance d = Distance())
{
CV_Assert(features.type() == CvType<ELEM_TYPE>::type());
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
CV_Assert(features.type() == CvType<ElementType>::type());
CV_Assert(features.isContinuous());
::cvflann::Matrix<ELEM_TYPE> m_features((ELEM_TYPE*)features.ptr<ELEM_TYPE>(0), features.rows, features.cols);
::cvflann::Matrix<ElementType> m_features((ElementType*)features.ptr<ElementType>(0), features.rows, features.cols);
CV_Assert(centers.type() == CvType<DIST_TYPE>::type());
CV_Assert(centers.type() == CvType<DistanceType>::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);
::cvflann::Matrix<DistanceType> m_centers((DistanceType*)centers.ptr<DistanceType>(0), centers.rows, centers.cols);
return ::cvflann::hierarchicalClustering<Distance>(m_features, m_centers, params, d);
}
template <typename ELEM_TYPE, typename DIST_TYPE>
FLANN_DEPRECATED int hierarchicalClustering(const Mat& features, Mat& centers, const KMeansIndexParams& params)
{
printf("[WARNING] cv::flann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE> is deprecated, use "
"cv::flann::hierarchicalClustering<Distance> instead\n");
if ( ::cvflann::flann_distance_type() == FLANN_DIST_L2 ) {
return hierarchicalClustering< L2<ELEM_TYPE> >(features, centers, params);
}
else if ( ::cvflann::flann_distance_type() == FLANN_DIST_L1 ) {
return hierarchicalClustering< L1<ELEM_TYPE> >(features, centers, params);
}
else {
printf("[ERROR] cv::flann::hierarchicalClustering<ELEM_TYPE,DIST_TYPE> only provides backwards "
"compatibility for the L1 and L2 distances. "
"For other distance types you must use cv::flann::hierarchicalClustering<Distance>\n");
CV_Assert(0);
}
}
} } // namespace cv::flann
......
......@@ -28,232 +28,264 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef _OPENCV_FLANN_BASE_HPP_
#define _OPENCV_FLANN_BASE_HPP_
#ifndef FLANN_BASE_HPP_
#define FLANN_BASE_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 "general.h"
#include "matrix.h"
#include "params.h"
#include "saving.h"
#include "opencv2/flann/all_indices.h"
#include "all_indices.h"
namespace cvflann
{
/**
Sets the log level used for all flann functions
Params:
level = verbosity level
*/
CV_EXPORTS void log_verbosity(int level);
* Sets the log level used for all flann functions
* @param level Verbosity level
*/
inline void log_verbosity(int level)
{
if (level >= 0) {
Logger::setLevel(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.
* (Deprecated) Index parameters for creating a saved index.
*/
CV_EXPORTS void set_distance_type(flann_distance_t distance_type, int order);
struct CV_EXPORTS SavedIndexParams : public IndexParams {
SavedIndexParams(std::string filename_) : IndexParams(FLANN_INDEX_SAVED), filename(filename_) {}
std::string filename; // filename of the stored index
void print() const
{
logger().info("Index type: %d\n",(int)algorithm);
logger().info("Filename: %s\n", filename.c_str());
}
};
template<typename T>
class CV_EXPORTS 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(); }
struct SavedIndexParams : public IndexParams
{
SavedIndexParams(std::string filename)
{
(* this)["algorithm"] = FLANN_INDEX_SAVED;
(*this)["filename"] = filename;
}
};
template<typename T>
NNIndex<T>* load_saved_index(const Matrix<T>& dataset, const std::string& filename)
template<typename Distance>
NNIndex<Distance>* load_saved_index(const Matrix<typename Distance::ElementType>& dataset, const std::string& filename, Distance distance)
{
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;
}
typedef typename Distance::ElementType ElementType;
FILE* fin = fopen(filename.c_str(), "rb");
if (fin == NULL) {
return NULL;
}
IndexHeader header = load_header(fin);
if (header.data_type != Datatype<ElementType>::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");
}
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==FLANN_INDEX_SAVED) {
nnIndex = load_saved_index(dataset, ((const SavedIndexParams&)params).filename);
built = true;
}
else {
nnIndex = create_index_by_type(dataset, params);
}
}
IndexParams params;
params["algorithm"] = header.index_type;
NNIndex<Distance>* nnIndex = create_index_by_type<Distance>(dataset, params, distance);
nnIndex->loadIndex(fin);
fclose(fin);
template<typename T>
Index<T>::~Index()
{
delete nnIndex;
return 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)
template<typename Distance>
class Index : public NNIndex<Distance>
{
if (!built) {
throw FLANNException("You must build the index before searching.");
public:
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
Index(const Matrix<ElementType>& features, const IndexParams& params, Distance distance = Distance() )
: index_params_(params)
{
flann_algorithm_t index_type = get_param<flann_algorithm_t>(params,"algorithm");
loaded_ = false;
if (index_type == FLANN_INDEX_SAVED) {
nnIndex_ = load_saved_index<Distance>(features, get_param<std::string>(params,"filename"), distance);
loaded_ = true;
}
else {
nnIndex_ = create_index_by_type<Distance>(features, params, distance);
}
}
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);
~Index()
{
delete nnIndex_;
}
for (size_t i = 0; i < queries.rows; i++) {
T* target = queries[i];
resultSet.init(target, (int)queries.cols);
/**
* Builds the index.
*/
void buildIndex()
{
if (!loaded_) {
nnIndex_->buildIndex();
}
}
nnIndex->findNeighbors(resultSet, target, searchParams);
void save(std::string filename)
{
FILE* fout = fopen(filename.c_str(), "wb");
if (fout == NULL) {
throw FLANNException("Cannot open file");
}
save_header(fout, *nnIndex_);
saveIndex(fout);
fclose(fout);
}
int* neighbors = resultSet.getNeighbors();
float* distances = resultSet.getDistances();
memcpy(indices[i], neighbors, knn*sizeof(int));
memcpy(dists[i], distances, knn*sizeof(float));
/**
* \brief Saves the index to a stream
* \param stream The stream to save the index to
*/
virtual void saveIndex(FILE* stream)
{
nnIndex_->saveIndex(stream);
}
}
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.");
/**
* \brief Loads the index from a stream
* \param stream The stream from which the index is loaded
*/
virtual void loadIndex(FILE* stream)
{
nnIndex_->loadIndex(stream);
}
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, (int)query.cols);
nnIndex->findNeighbors(resultSet,query.data,searchParams);
/**
* \returns number of features in this index.
*/
size_t veclen() const
{
return nnIndex_->veclen();
}
// TODO: optimise here
int* neighbors = resultSet.getNeighbors();
float* distances = resultSet.getDistances();
size_t count_nn = std::min(resultSet.size(), indices.cols);
/**
* \returns The dimensionality of the features in this index.
*/
size_t size() const
{
return nnIndex_->size();
}
assert (dists.cols>=count_nn);
/**
* \returns The index type (kdtree, kmeans,...)
*/
flann_algorithm_t getType() const
{
return nnIndex_->getType();
}
for (size_t i=0;i<count_nn;++i) {
indices[0][i] = neighbors[i];
dists[0][i] = distances[i];
}
/**
* \returns The amount of memory (in bytes) used by the index.
*/
virtual int usedMemory() const
{
return nnIndex_->usedMemory();
}
return (int)count_nn;
}
/**
* \returns The index parameters
*/
IndexParams getParameters() const
{
return nnIndex_->getParameters();
}
template<typename T>
void Index<T>::save(std::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);
}
/**
* \brief Perform k-nearest neighbor search
* \param[in] queries The query points for which to find the nearest neighbors
* \param[out] indices The indices of the nearest neighbors found
* \param[out] dists Distances to the nearest neighbors found
* \param[in] knn Number of nearest neighbors to return
* \param[in] params Search parameters
*/
void knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& params)
{
nnIndex_->knnSearch(queries, indices, dists, knn, params);
}
/**
* \brief Perform radius search
* \param[in] query The query point
* \param[out] indices The indinces of the neighbors found within the given radius
* \param[out] dists The distances to the nearest neighbors found
* \param[in] radius The radius used for search
* \param[in] params Search parameters
* \returns Number of neighbors found
*/
int radiusSearch(const Matrix<ElementType>& query, Matrix<int>& indices, Matrix<DistanceType>& dists, float radius, const SearchParams& params)
{
return nnIndex_->radiusSearch(query, indices, dists, radius, params);
}
template<typename T>
int Index<T>::size() const
{
return nnIndex->size();
}
/**
* \brief Method that searches for nearest-neighbours
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
{
nnIndex_->findNeighbors(result, vec, searchParams);
}
template<typename T>
int Index<T>::veclen() const
{
return nnIndex->veclen();
}
/**
* \brief Returns actual index
*/
FLANN_DEPRECATED NNIndex<Distance>* getIndex()
{
return nnIndex_;
}
/**
* \brief Returns index parameters.
* \deprecated use getParameters() instead.
*/
FLANN_DEPRECATED const IndexParams* getIndexParameters()
{
return &index_params_;
}
private:
/** Pointer to actual index class */
NNIndex<Distance>* nnIndex_;
/** Indices if the index was loaded from a file */
bool loaded_;
/** Parameters passed to the index */
IndexParams index_params_;
};
template <typename ELEM_TYPE, typename DIST_TYPE>
int hierarchicalClustering(const Matrix<ELEM_TYPE>& features, Matrix<DIST_TYPE>& centers, const KMeansIndexParams& params)
/**
* Performs a hierarchical clustering of the points passed as argument and then takes a cut in the
* the clustering tree to return a flat clustering.
* @param[in] points Points to be clustered
* @param centers The computed cluster centres. Matrix should be preallocated and centers.rows is the
* number of clusters requested.
* @param params Clustering parameters (The same as for cvflann::KMeansIndex)
* @param d Distance to be used for clustering (eg: cvflann::L2)
* @return number of clusters computed (can be different than clusters.rows and is the highest number
* of the form (branching-1)*K+1 smaller than clusters.rows).
*/
template <typename Distance>
int hierarchicalClustering(const Matrix<typename Distance::ElementType>& points, Matrix<typename Distance::ResultType>& centers,
const KMeansIndexParams& params, Distance d = Distance())
{
KMeansIndex<ELEM_TYPE, DIST_TYPE> kmeans(features, params);
kmeans.buildIndex();
KMeansIndex<Distance> kmeans(points, params, d);
kmeans.buildIndex();
int clusterNum = kmeans.getClusterCenters(centers);
return clusterNum;
return clusterNum;
}
} // namespace cvflann
#endif /* _OPENCV_FLANN_BASE_HPP_ */
}
#endif /* FLANN_BASE_HPP_ */
......@@ -28,119 +28,25 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef _OPENCV_GENERAL_H_
#define _OPENCV_GENERAL_H_
#ifdef __cplusplus
#ifndef OPENCV_FLANN_GENERAL_H_
#define OPENCV_FLANN_GENERAL_H_
#include "defines.h"
#include <stdexcept>
#include <cassert>
#include "opencv2/flann/object_factory.h"
#include "opencv2/flann/logger.h"
namespace cvflann {
#undef ARRAY_LEN
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
/* Nearest neighbour index algorithms */
enum flann_algorithm_t {
FLANN_INDEX_LINEAR = 0,
FLANN_INDEX_KDTREE = 1,
FLANN_INDEX_KMEANS = 2,
FLANN_INDEX_COMPOSITE = 3,
FLANN_INDEX_SAVED = 254,
FLANN_INDEX_AUTOTUNED = 255
};
enum flann_centers_init_t {
FLANN_CENTERS_RANDOM = 0,
FLANN_CENTERS_GONZALES = 1,
FLANN_CENTERS_KMEANSPP = 2
};
enum flann_distance_t {
FLANN_DIST_EUCLIDEAN = 1,
FLANN_DIST_L2 = 1,
FLANN_DIST_MANHATTAN = 2,
FLANN_DIST_L1 = 2,
FLANN_DIST_MINKOWSKI = 3,
FLANN_DIST_MAX = 4,
FLANN_DIST_HIST_INTERSECT = 5,
FLANN_DIST_HELLINGER = 6,
FLANN_DIST_CHI_SQUARE = 7,
FLANN_DIST_CS = 7,
FLANN_DIST_KULLBACK_LEIBLER = 8,
FLANN_DIST_KL = 8
};
enum flann_datatype_t {
FLANN_INT8 = 0,
FLANN_INT16 = 1,
FLANN_INT32 = 2,
FLANN_INT64 = 3,
FLANN_UINT8 = 4,
FLANN_UINT16 = 5,
FLANN_UINT32 = 6,
FLANN_UINT64 = 7,
FLANN_FLOAT32 = 8,
FLANN_FLOAT64 = 9
};
template <typename ELEM_TYPE>
struct DistType
{
typedef ELEM_TYPE type;
};
template <>
struct DistType<unsigned char>
namespace cvflann
{
typedef float type;
};
template <>
struct DistType<int>
class FLANNException : public std::runtime_error
{
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 CV_EXPORTS IndexParams {
protected:
IndexParams(flann_algorithm_t algorithm_) : algorithm(algorithm_) {};
public:
virtual ~IndexParams() {}
virtual flann_algorithm_t getIndexType() const { return algorithm; }
virtual void print() const = 0;
flann_algorithm_t algorithm;
};
typedef ObjectFactory<IndexParams, flann_algorithm_t> ParamsFactory;
CV_EXPORTS ParamsFactory& ParamsFactory_instance();
struct CV_EXPORTS SearchParams {
SearchParams(int checks_ = 32) :
checks(checks_) {};
FLANNException(const char* message) : std::runtime_error(message) { }
int checks;
FLANNException(const std::string& message) : std::runtime_error(message) { }
};
} // namespace cvflann
}
#endif
#endif /* _OPENCV_GENERAL_H_ */
#endif /* OPENCV_FLANN_GENERAL_H_ */
......@@ -28,39 +28,41 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef _OPENCV_GROUND_TRUTH_H_
#define _OPENCV_GROUND_TRUTH_H_
#ifndef OPENCV_FLANN_GROUND_TRUTH_H_
#define OPENCV_FLANN_GROUND_TRUTH_H_
#include "dist.h"
#include "matrix.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)
template <typename Distance>
void find_nearest(const Matrix<typename Distance::ElementType>& dataset, typename Distance::ElementType* query, int* matches, int nn,
int skip = 0, Distance distance = Distance())
{
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
int n = nn + skip;
T* query_end = query + dataset.cols;
long* match = new long[n];
T* dists = new T[n];
int* match = new int[n];
DistanceType* dists = new DistanceType[n];
dists[0] = (float)flann_dist(query, query_end, dataset[0]);
dists[0] = distance(dataset[0], query, dataset.cols);
match[0] = 0;
int dcnt = 1;
for (size_t i=1;i<dataset.rows;++i) {
T tmp = (T)flann_dist(query, query_end, dataset[i]);
for (size_t i=1; i<dataset.rows; ++i) {
DistanceType tmp = distance(dataset[i], query, dataset.cols);
if (dcnt<n) {
match[dcnt] = (long)i;
match[dcnt] = i;
dists[dcnt++] = tmp;
}
else if (tmp < dists[dcnt-1]) {
dists[dcnt-1] = tmp;
match[dcnt-1] = (long)i;
match[dcnt-1] = i;
}
int j = dcnt-1;
......@@ -72,7 +74,7 @@ void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int
}
}
for (int i=0;i<nn;++i) {
for (int i=0; i<nn; ++i) {
matches[i] = match[i+skip];
}
......@@ -81,15 +83,16 @@ void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int
}
template <typename T>
void compute_ground_truth(const Matrix<T>& dataset, const Matrix<T>& testset, Matrix<int>& matches, int skip=0)
template <typename Distance>
void compute_ground_truth(const Matrix<typename Distance::ElementType>& dataset, const Matrix<typename Distance::ElementType>& testset, Matrix<int>& matches,
int skip=0, Distance d = Distance())
{
for (size_t i=0;i<testset.rows;++i) {
find_nearest(dataset, testset[i], matches[i], (int)matches.cols, skip);
for (size_t i=0; i<testset.rows; ++i) {
find_nearest<Distance>(dataset, testset[i], matches[i], (int)matches.cols, skip, d);
}
}
} // namespace cvflann
}
#endif //_OPENCV_GROUND_TRUTH_H_
#endif //OPENCV_FLANN_GROUND_TRUTH_H_
......@@ -27,137 +27,207 @@
*************************************************************************/
#ifndef _OPENCV_HDF5_H_
#define _OPENCV_HDF5_H_
#ifndef OPENCV_FLANN_HDF5_H_
#define OPENCV_FLANN_HDF5_H_
#include <H5Cpp.h>
#include <hdf5.h>
#include "opencv2/flann/matrix.h"
#include "matrix.h"
namespace cvflann
{
#ifndef H5_NO_NAMESPACE
using namespace H5;
#endif
namespace
{
namespace cvflann
template<typename T>
hid_t get_hdf5_type()
{
throw FLANNException("Unsupported type for IO operations");
}
template<>
hid_t get_hdf5_type<char>() { return H5T_NATIVE_CHAR; }
template<>
hid_t get_hdf5_type<unsigned char>() { return H5T_NATIVE_UCHAR; }
template<>
hid_t get_hdf5_type<short int>() { return H5T_NATIVE_SHORT; }
template<>
hid_t get_hdf5_type<unsigned short int>() { return H5T_NATIVE_USHORT; }
template<>
hid_t get_hdf5_type<int>() { return H5T_NATIVE_INT; }
template<>
hid_t get_hdf5_type<unsigned int>() { return H5T_NATIVE_UINT; }
template<>
hid_t get_hdf5_type<long>() { return H5T_NATIVE_LONG; }
template<>
hid_t get_hdf5_type<unsigned long>() { return H5T_NATIVE_ULONG; }
template<>
hid_t get_hdf5_type<float>() { return H5T_NATIVE_FLOAT; }
template<>
hid_t get_hdf5_type<double>() { return H5T_NATIVE_DOUBLE; }
template<>
hid_t get_hdf5_type<long double>() { return H5T_NATIVE_LDOUBLE; }
}
namespace {
#define CHECK_ERROR(x,y) if ((x)<0) throw FLANNException((y));
template<typename T>
PredType get_hdf5_type()
void save_to_file(const cvflann::Matrix<T>& dataset, const std::string& filename, const std::string& name)
{
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; }
#if H5Eset_auto_vers == 2
H5Eset_auto( H5E_DEFAULT, NULL, NULL );
#else
H5Eset_auto( NULL, NULL );
#endif
herr_t status;
hid_t file_id;
file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
if (file_id < 0) {
file_id = H5Fcreate(filename.c_str(), H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT);
}
CHECK_ERROR(file_id,"Error creating hdf5 file.");
hsize_t dimsf[2]; // dataset dimensions
dimsf[0] = dataset.rows;
dimsf[1] = dataset.cols;
hid_t space_id = H5Screate_simple(2, dimsf, NULL);
hid_t memspace_id = H5Screate_simple(2, dimsf, NULL);
hid_t dataset_id;
#if H5Dcreate_vers == 2
dataset_id = H5Dcreate2(file_id, name.c_str(), get_hdf5_type<T>(), space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
#else
dataset_id = H5Dcreate(file_id, name.c_str(), get_hdf5_type<T>(), space_id, H5P_DEFAULT);
#endif
if (dataset_id<0) {
#if H5Dopen_vers == 2
dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT);
#else
dataset_id = H5Dopen(file_id, name.c_str());
#endif
}
CHECK_ERROR(dataset_id,"Error creating or opening dataset in file.");
status = H5Dwrite(dataset_id, get_hdf5_type<T>(), memspace_id, space_id, H5P_DEFAULT, dataset.data );
CHECK_ERROR(status, "Error writing to dataset");
H5Sclose(memspace_id);
H5Sclose(space_id);
H5Dclose(dataset_id);
H5Fclose(file_id);
}
template<typename T>
void save_to_file(const cvflann::Matrix<T>& flann_dataset, const std::string& filename, const std::string& name)
void load_from_file(cvflann::Matrix<T>& 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());
}
herr_t status;
hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
CHECK_ERROR(file_id,"Error opening hdf5 file.");
hid_t dataset_id;
#if H5Dopen_vers == 2
dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT);
#else
dataset_id = H5Dopen(file_id, name.c_str());
#endif
CHECK_ERROR(dataset_id,"Error opening dataset in file.");
hid_t space_id = H5Dget_space(dataset_id);
hsize_t dims_out[2];
H5Sget_simple_extent_dims(space_id, dims_out, NULL);
dataset = cvflann::Matrix<T>(new T[dims_out[0]*dims_out[1]], dims_out[0], dims_out[1]);
status = H5Dread(dataset_id, get_hdf5_type<T>(), H5S_ALL, H5S_ALL, H5P_DEFAULT, dataset[0]);
CHECK_ERROR(status, "Error reading dataset");
H5Sclose(space_id);
H5Dclose(dataset_id);
H5Fclose(file_id);
}
#ifdef HAVE_MPI
namespace mpi
{
/**
* Loads a the hyperslice corresponding to this processor from a hdf5 file.
* @param flann_dataset Dataset where the data is loaded
* @param filename HDF5 file name
* @param name Name of dataset inside file
*/
template<typename T>
void load_from_file(cvflann::Matrix<T>& flann_dataset, const std::string& filename, const std::string& name)
void load_from_file(cvflann::Matrix<T>& 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());
}
}
MPI_Comm comm = MPI_COMM_WORLD;
MPI_Info info = MPI_INFO_NULL;
int mpi_size, mpi_rank;
MPI_Comm_size(comm, &mpi_size);
MPI_Comm_rank(comm, &mpi_rank);
herr_t status;
hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS);
H5Pset_fapl_mpio(plist_id, comm, info);
hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, plist_id);
CHECK_ERROR(file_id,"Error opening hdf5 file.");
H5Pclose(plist_id);
hid_t dataset_id;
#if H5Dopen_vers == 2
dataset_id = H5Dopen2(file_id, name.c_str(), H5P_DEFAULT);
#else
dataset_id = H5Dopen(file_id, name.c_str());
#endif
CHECK_ERROR(dataset_id,"Error opening dataset in file.");
hid_t space_id = H5Dget_space(dataset_id);
hsize_t dims[2];
H5Sget_simple_extent_dims(space_id, dims, NULL);
hsize_t count[2];
hsize_t offset[2];
} // namespace cvflann
hsize_t item_cnt = dims[0]/mpi_size+(dims[0]%mpi_size==0 ? 0 : 1);
hsize_t cnt = (mpi_rank<mpi_size-1 ? item_cnt : dims[0]-item_cnt*(mpi_size-1));
count[0] = cnt;
count[1] = dims[1];
offset[0] = mpi_rank*item_cnt;
offset[1] = 0;
hid_t memspace_id = H5Screate_simple(2,count,NULL);
H5Sselect_hyperslab(space_id, H5S_SELECT_SET, offset, NULL, count, NULL);
dataset.rows = count[0];
dataset.cols = count[1];
dataset.data = new T[dataset.rows*dataset.cols];
plist_id = H5Pcreate(H5P_DATASET_XFER);
H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);
status = H5Dread(dataset_id, get_hdf5_type<T>(), memspace_id, space_id, plist_id, dataset.data);
CHECK_ERROR(status, "Error reading dataset");
H5Pclose(plist_id);
H5Sclose(space_id);
H5Sclose(memspace_id);
H5Dclose(dataset_id);
H5Fclose(file_id);
}
}
#endif // HAVE_MPI
} // namespace cvflann::mpi
#endif /* _OPENCV_HDF5_H_ */
#endif /* OPENCV_FLANN_HDF5_H_ */
......@@ -28,41 +28,40 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef _OPENCV_LINEARSEARCH_H_
#define _OPENCV_LINEARSEARCH_H_
#include "opencv2/flann/general.h"
#include "opencv2/flann/nn_index.h"
#ifndef OPENCV_FLANN_LINEAR_INDEX_H_
#define OPENCV_FLANN_LINEAR_INDEX_H_
#include "general.h"
#include "nn_index.h"
namespace cvflann
{
struct CV_EXPORTS LinearIndexParams : public IndexParams {
LinearIndexParams() : IndexParams(FLANN_INDEX_LINEAR) {};
void print() const
{
logger().info("Index type: %d\n",(int)algorithm);
}
struct LinearIndexParams : public IndexParams
{
LinearIndexParams()
{
(* this)["algorithm"] = FLANN_INDEX_LINEAR;
}
};
template <typename ELEM_TYPE, typename DIST_TYPE = typename DistType<ELEM_TYPE>::type >
class LinearIndex : public NNIndex<ELEM_TYPE>
template <typename Distance>
class LinearIndex : public NNIndex<Distance>
{
const Matrix<ELEM_TYPE> dataset;
const LinearIndexParams& index_params;
public:
LinearIndex(const LinearIndex&);
LinearIndex& operator=(const LinearIndex&);
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
public:
LinearIndex(const Matrix<ELEM_TYPE>& inputData, const LinearIndexParams& params = LinearIndexParams() ) :
dataset(inputData), index_params(params)
{
}
LinearIndex(const Matrix<ElementType>& inputData, const IndexParams& params = LinearIndexParams(),
Distance d = Distance()) :
dataset_(inputData), index_params_(params), distance_(d)
{
}
LinearIndex(const LinearIndex&);
LinearIndex& operator=(const LinearIndex&);
flann_algorithm_t getType() const
{
......@@ -70,52 +69,64 @@ public:
}
size_t size() const
{
return dataset.rows;
}
size_t size() const
{
return dataset_.rows;
}
size_t veclen() const
{
return dataset.cols;
}
size_t veclen() const
{
return dataset_.cols;
}
int usedMemory() const
{
return 0;
}
int usedMemory() const
{
return 0;
}
void buildIndex()
{
/* nothing to do here for linear search */
}
void buildIndex()
{
/* nothing to do here for linear search */
}
void saveIndex(FILE*)
{
/* nothing to do here for linear search */
/* nothing to do here for linear search */
}
void loadIndex(FILE*)
{
/* nothing to do here for linear search */
/* nothing to do here for linear search */
index_params_["algorithm"] = getType();
}
void findNeighbors(ResultSet<DistanceType>& resultSet, const ElementType* vec, const SearchParams& /*searchParams*/)
{
ElementType* data = dataset_.data;
for (size_t i = 0; i < dataset_.rows; ++i, data += dataset_.cols) {
DistanceType dist = distance_(data, vec, dataset_.cols);
resultSet.addPoint(dist, i);
}
}
void findNeighbors(ResultSet<ELEM_TYPE>& resultSet, const ELEM_TYPE*, const SearchParams&)
{
for (size_t i=0;i<dataset.rows;++i) {
resultSet.addPoint(dataset[i],(int)i);
}
}
IndexParams getParameters() const
{
return index_params_;
}
const IndexParams* getParameters() const
{
return &index_params;
}
private:
/** The dataset */
const Matrix<ElementType> dataset_;
/** Index parameters */
IndexParams index_params_;
/** Index distance */
Distance distance_;
};
} // namespace cvflann
}
#endif // _OPENCV_LINEARSEARCH_H_
#endif // OPENCV_FLANN_LINEAR_INDEX_H_
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -28,8 +28,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef _OPENCV_TIMER_H_
#define _OPENCV_TIMER_H_
#ifndef FLANN_TIMER_H
#define FLANN_TIMER_H
#include <time.h>
......@@ -42,7 +42,7 @@ namespace cvflann
*
* Can be used to time portions of code.
*/
class CV_EXPORTS StartStopTimer
class StartStopTimer
{
clock_t startTime;
......@@ -64,14 +64,16 @@ public:
/**
* Starts the timer.
*/
void start() {
void start()
{
startTime = clock();
}
/**
* Stops the timer and updates timer value.
*/
void stop() {
void stop()
{
clock_t stopTime = clock();
value += ( (double)stopTime - startTime) / CLOCKS_PER_SEC;
}
......@@ -79,12 +81,13 @@ public:
/**
* Resets the timer value to 0.
*/
void reset() {
void reset()
{
value = 0;
}
};
}// namespace cvflann
}
#endif // _OPENCV_TIMER_H_
#endif // FLANN_TIMER_H
此差异已折叠。
此差异已折叠。
......@@ -5,10 +5,13 @@
#include <cstdarg>
#include <sstream>
#include "opencv2/flann/miniflann.hpp"
#include "opencv2/flann/dist.h"
#include "opencv2/flann/index_testing.h"
#include "opencv2/flann/params.h"
#include "opencv2/flann/saving.h"
#include "opencv2/flann/general.h"
#include "opencv2/flann/dummy.h"
// index types
#include "opencv2/flann/all_indices.h"
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册