Commit 16b1f61c authored by Marius Muja's avatar Marius Muja

Updated FLANN to version 1.5

parent 3230073b
...@@ -2,7 +2,6 @@ if(ANDROID) ...@@ -2,7 +2,6 @@ if(ANDROID)
configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk") configure_file("${CMAKE_SOURCE_DIR}/Android.mk.modules.in" "${CMAKE_CURRENT_BINARY_DIR}/Android.mk")
endif() endif()
add_subdirectory(flann)
add_subdirectory(lapack) add_subdirectory(lapack)
add_subdirectory(zlib) add_subdirectory(zlib)
if(WITH_JASPER AND NOT JASPER_FOUND) if(WITH_JASPER AND NOT JASPER_FOUND)
......
if(ANDROID)
file(GLOB_RECURSE flann_sources_cpp *.cpp)
define_android_manual(flann "${flann_sources_cpp}" "$(LOCAL_PATH)/../include $(LOCAL_PATH)/../include/flann")
else(ANDROID)
if (DEFINED OPENCV_VERSION)
# ----------------------------------------------------------------------------
# CMake file for libflann. See root CMakeLists.txt
#
# ----------------------------------------------------------------------------
project(flann)
# List of C++ files:
#set(CMAKE_BUILD_TYPE Debug)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/../include/flann"
)
# The .cpp files:
file(GLOB flann_sources *.cpp *.h *.hpp)
file(GLOB flann_h "${CMAKE_CURRENT_SOURCE_DIR}/../include/flann/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/../include/flann/*.hpp")
source_group("Src" FILES ${flann_sources})
source_group("Include" FILES ${flann_h})
set(flann_sources ${flann_sources} ${flann_h})
# ----------------------------------------------------------------------------------
# Define the library target:
# ----------------------------------------------------------------------------------
set(the_target "flann")
add_library(${the_target} STATIC ${flann_sources})
add_definitions(-Dflann_EXPORTS)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3")
add_definitions(-DJAS_WIN_MSVC_BUILD)
endif()
if(UNIX)
if(CMAKE_COMPILER_IS_GNUCXX OR CV_ICC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif()
endif()
set_target_properties(${the_target}
PROPERTIES
OUTPUT_NAME "${the_target}"
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/3rdparty/lib"
)
ELSE()
INCLUDE_DIRECTORIES(algorithms util nn .)
ADD_SUBDIRECTORY( tests )
file(GLOB_RECURSE SOURCES *.cpp)
#SET(SOURCES flann.cpp util/Random.cpp nn/Testing.cpp algorithms/NNIndex.cpp algorithms/dist.cpp util/Logger.cpp util/Saving.cpp)
ADD_LIBRARY(flann ${SOURCES})
#ADD_LIBRARY(flann SHARED ${SOURCES}) #JL: Why the two versions??
#ADD_LIBRARY(flann_s STATIC ${SOURCES})
IF(WIN32)
INSTALL (
TARGETS flann
RUNTIME DESTINATION matlab
)
INSTALL (
TARGETS flann
RUNTIME DESTINATION python/pyflann/bindings
)
ELSE(WIN32)
INSTALL (
TARGETS flann
LIBRARY DESTINATION python/pyflann/bindings
)
ENDIF(WIN32)
INSTALL (
TARGETS flann # flann_s
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
# INSTALL (
# TARGETS flann flann_s
# ARCHIVE DESTINATION ${PROJECT_SOURCE_DIR}/python
# LIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/python
# )
INSTALL (
FILES flann.h constants.h
DESTINATION include
)
ENDIF()
endif(ANDROID)#android
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef COMMOM_H
#define COMMOM_H
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
#include <stdexcept>
namespace cvflann
{
class FLANNException : public std::runtime_error {
public:
FLANNException(const char* message) : std::runtime_error(message) { }
};
}
#endif //COMMOM_H
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#include "dist.h"
namespace cvflann
{
/** Global variable indicating the distance metric
* to be used.
*/
flann_distance_t flann_distance_type = EUCLIDEAN;
/**
* Zero iterator that emulates a zero feature.
*/
ZeroIterator<float> zero;
/**
* Order of Minkowski distance to use.
*/
int flann_minkowski_order;
}
This diff is collapsed.
This diff is collapsed.
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef FLANN_HPP_
#define FLANN_HPP_
#include <vector>
#include <string>
#include "constants.h"
#include "common.h"
#include "matrix.h"
#include "flann.h"
namespace cvflann
{
class NNIndex;
class IndexFactory
{
public:
virtual ~IndexFactory() {}
virtual NNIndex* createIndex(const Matrix<float>& dataset) const = 0;
};
struct IndexParams : public IndexFactory {
protected:
IndexParams() {};
public:
static IndexParams* createFromParameters(const FLANNParameters& p);
virtual void fromParameters(const FLANNParameters&) {};
virtual void toParameters(FLANNParameters&) { };
};
struct LinearIndexParams : public IndexParams {
LinearIndexParams() {};
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct KDTreeIndexParams : public IndexParams {
KDTreeIndexParams(int trees_ = 4) : trees(trees_) {};
int trees; // number of randomized trees to use (for kdtree)
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KDTREE;
p.trees = trees;
};
};
struct KMeansIndexParams : public IndexParams {
KMeansIndexParams(int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
branching(branching_),
iterations(iterations_),
centers_init(centers_init_),
cb_index(cb_index_) {};
int branching; // branching factor (for kmeans tree)
int iterations; // max iterations to perform in one kmeans clustering (kmeans tree)
flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree
float cb_index; // cluster boundary index. Used when searching the kmeans tree
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KMEANS;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
struct CompositeIndexParams : public IndexParams {
CompositeIndexParams(int trees_ = 4, int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
trees(trees_),
branching(branching_),
iterations(iterations_),
centers_init(centers_init_),
cb_index(cb_index_) {};
int trees; // number of randomized trees to use (for kdtree)
int branching; // branching factor (for kmeans tree)
int iterations; // max iterations to perform in one kmeans clustering (kmeans tree)
flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree
float cb_index; // cluster boundary index. Used when searching the kmeans tree
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = COMPOSITE;
p.trees = trees;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
struct AutotunedIndexParams : public IndexParams {
AutotunedIndexParams( float target_precision_ = 0.9, float build_weight_ = 0.01,
float memory_weight_ = 0, float sample_fraction_ = 0.1) :
target_precision(target_precision_),
build_weight(build_weight_),
memory_weight(memory_weight_),
sample_fraction(sample_fraction_) {};
float target_precision; // precision desired (used for autotuning, -1 otherwise)
float build_weight; // build tree time weighting factor
float memory_weight; // index memory weighting factor
float sample_fraction; // what fraction of the dataset to use for autotuning
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
target_precision = p.target_precision;
build_weight = p.build_weight;
memory_weight = p.memory_weight;
sample_fraction = p.sample_fraction;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = AUTOTUNED;
p.target_precision = target_precision;
p.build_weight = build_weight;
p.memory_weight = memory_weight;
p.sample_fraction = sample_fraction;
};
};
struct SavedIndexParams : public IndexParams {
SavedIndexParams() {
throw FLANNException("I don't know which index to load");
}
SavedIndexParams(std::string filename_) : filename(filename_) {}
std::string filename; // filename of the stored index
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct SearchParams {
SearchParams(int checks_ = 32) :
checks(checks_) {};
int checks;
};
class Index {
NNIndex* nnIndex;
public:
Index(const Matrix<float>& features, const IndexParams& params);
~Index();
void knnSearch(const Matrix<float>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& params);
int radiusSearch(const Matrix<float>& query, Matrix<int> indices, Matrix<float> dists, float radius, const SearchParams& params);
void save(std::string filename);
int veclen() const;
int size() const;
};
int hierarchicalClustering(const Matrix<float>& features, Matrix<float>& centers, const KMeansIndexParams& params);
}
#endif /* FLANN_HPP_ */
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef TESTING_H
#define TESTING_H
#include "nn_index.h"
#include "matrix.h"
using namespace std;
namespace cvflann
{
void search_for_neighbors(NNIndex& index, const Matrix<float>& testset, Matrix<int>& result, Matrix<float>& dists, const SearchParams &searchParams, int skip = 0);
float test_index_checks(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
int checks, float& precision, int nn = 1, int skipMatches = 0);
float test_index_precision(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
float precision, int& checks, int nn = 1, int skipMatches = 0);
float test_index_precisions(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches,
float* precisions, int precisions_length, int nn = 1, int skipMatches = 0, float maxTime = 0);
}
#endif //TESTING_H
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef DATASET_H
#define DATASET_H
#include <stdio.h>
#include <random.h>
namespace cvflann
{
/**
* Class implementing a generic rectangular dataset.
*/
template <typename T>
class Matrix {
/**
* Flag showing if the class owns its data storage.
*/
bool ownData;
void shallow_copy(const Matrix& rhs)
{
data = rhs.data;
rows = rhs.rows;
cols = rhs.cols;
ownData = false;
}
public:
long rows;
long cols;
T* data;
Matrix(long rows_, long cols_, T* data_ = NULL) :
ownData(false), rows(rows_), cols(cols_), data(data_)
{
if (data_==NULL) {
data = new T[rows*cols];
ownData = true;
}
}
Matrix(const Matrix& d)
{
shallow_copy(d);
}
const Matrix& operator=(const Matrix& rhs)
{
if (this!=&rhs) {
shallow_copy(rhs);
}
return *this;
}
~Matrix()
{
if (ownData) {
delete[] data;
}
}
/**
* Operator that return a (pointer to a) row of the data.
*/
T* operator[](long index)
{
return data+index*cols;
}
T* operator[](long index) const
{
return data+index*cols;
}
Matrix<T>* sample(long size, bool remove = false)
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
if (remove) {
dest = (*this)[rows-i-1];
src = (*this)[r];
for (long j=0;j<cols;++j) {
swap(*src,*dest);
src++;
dest++;
}
}
}
if (remove) {
rows -= size;
}
return newSet;
}
Matrix<T>* sample(long size) const
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
}
return newSet;
}
};
}
#endif //DATASET_H
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#include "random.h"
namespace cvflann
{
void seed_random(unsigned int seed)
{
srand(seed);
}
double rand_double(double high, double low)
{
return low + ((high-low) * (std::rand() / (RAND_MAX + 1.0)));
}
int rand_int(int high, int low)
{
return low + (int) ( double(high-low) * (std::rand() / (RAND_MAX + 1.0)));
}
}
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef RANDOM_H
#define RANDOM_H
#include <algorithm>
#include <cstdlib>
#include <cassert>
using namespace std;
namespace cvflann
{
/**
* Seeds the random number generator
*/
void seed_random(unsigned int seed);
/*
* Generates a random double value.
*/
double rand_double(double high = 1.0, double low=0);
/*
* Generates a random integer value.
*/
int rand_int(int high = RAND_MAX, int low = 0);
/**
* Random number generator that returns a distinct number from
* the [0,n) interval each time.
*
* TODO: improve on this to use a generator function instead of an
* array of randomly permuted numbers
*/
class UniqueRandom
{
int* vals;
int size;
int counter;
public:
/**
* Constructor.
* Params:
* n = the size of the interval from which to generate
* random numbers.
*/
UniqueRandom(int n) : vals(NULL) {
init(n);
}
~UniqueRandom()
{
delete[] vals;
}
/**
* Initializes the number generator.
* Params:
* n = the size of the interval from which to generate
* random numbers.
*/
void init(int n)
{
// create and initialize an array of size n
if (vals == NULL || n!=size) {
delete[] vals;
size = n;
vals = new int[size];
}
for(int i=0;i<size;++i) {
vals[i] = i;
}
// shuffle the elements in the array
// Fisher-Yates shuffle
for (int i=size;i>0;--i) {
// int rand = cast(int) (drand48() * n);
int rnd = rand_int(i);
assert(rnd >=0 && rnd < i);
swap(vals[i-1], vals[rnd]);
}
counter = 0;
}
/**
* Return a distinct random integer in greater or equal to 0 and less
* than 'n' on each call. It should be called maximum 'n' times.
* Returns: a random integer
*/
int next() {
if (counter==size) {
return -1;
} else {
return vals[counter++];
}
}
};
}
#endif //RANDOM_H
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef COMMOM_H
#define COMMOM_H
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
#include <stdexcept>
namespace cvflann
{
class FLANNException : public std::runtime_error {
public:
FLANNException(const char* message) : std::runtime_error(message) { }
};
}
#endif //COMMOM_H
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef CONSTANTS_H
#define CONSTANTS_H
const double FLANN_VERSION = 1.20;
/* Nearest neighbor index algorithms */
enum flann_algorithm_t {
LINEAR = 0,
KDTREE = 1,
KMEANS = 2,
COMPOSITE = 3,
SAVED = 254,
AUTOTUNED = 255,
};
enum flann_centers_init_t {
CENTERS_RANDOM = 0,
CENTERS_GONZALES = 1,
CENTERS_KMEANSPP = 2
};
enum flann_log_level_t {
LOG_NONE = 0,
LOG_FATAL = 1,
LOG_ERROR = 2,
LOG_WARN = 3,
LOG_INFO = 4
};
enum flann_distance_t {
EUCLIDEAN = 1,
MANHATTAN = 2,
MINKOWSKI = 3
};
#endif // CONSTANTS_H
This diff is collapsed.
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef FLANN_HPP_
#define FLANN_HPP_
#include <vector>
#include <string>
#include "constants.h"
#include "common.h"
#include "matrix.h"
#include "flann.h"
namespace cvflann
{
class NNIndex;
class IndexFactory
{
public:
virtual ~IndexFactory() {}
virtual NNIndex* createIndex(const Matrix<float>& dataset) const = 0;
};
struct IndexParams : public IndexFactory {
protected:
IndexParams() {};
public:
static IndexParams* createFromParameters(const FLANNParameters& p);
void fromParameters(const FLANNParameters&) {};
void toParameters(FLANNParameters&) { };
};
struct LinearIndexParams : public IndexParams {
LinearIndexParams() {};
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct KDTreeIndexParams : public IndexParams {
KDTreeIndexParams(int trees_ = 4) : trees(trees_) {};
int trees; // number of randomized trees to use (for kdtree)
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KDTREE;
p.trees = trees;
};
};
struct KMeansIndexParams : public IndexParams {
KMeansIndexParams(int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
branching(branching_),
iterations(iterations_),
centers_init(centers_init_),
cb_index(cb_index_) {};
int branching; // branching factor (for kmeans tree)
int iterations; // max iterations to perform in one kmeans clustering (kmeans tree)
flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree
float cb_index; // cluster boundary index. Used when searching the kmeans tree
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = KMEANS;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
struct CompositeIndexParams : public IndexParams {
CompositeIndexParams(int trees_ = 4, int branching_ = 32, int iterations_ = 11,
flann_centers_init_t centers_init_ = CENTERS_RANDOM, float cb_index_ = 0.2 ) :
trees(trees_),
branching(branching_),
iterations(iterations_),
centers_init(centers_init_),
cb_index(cb_index_) {};
int trees; // number of randomized trees to use (for kdtree)
int branching; // branching factor (for kmeans tree)
int iterations; // max iterations to perform in one kmeans clustering (kmeans tree)
flann_centers_init_t centers_init; // algorithm used for picking the initial cluster centers for kmeans tree
float cb_index; // cluster boundary index. Used when searching the kmeans tree
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
trees = p.trees;
branching = p.branching;
iterations = p.iterations;
centers_init = p.centers_init;
cb_index = p.cb_index;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = COMPOSITE;
p.trees = trees;
p.branching = branching;
p.iterations = iterations;
p.centers_init = centers_init;
p.cb_index = cb_index;
};
};
struct AutotunedIndexParams : public IndexParams {
AutotunedIndexParams( float target_precision_ = 0.9, float build_weight_ = 0.01,
float memory_weight_ = 0, float sample_fraction_ = 0.1) :
target_precision(target_precision_),
build_weight(build_weight_),
memory_weight(memory_weight_),
sample_fraction(sample_fraction_) {};
float target_precision; // precision desired (used for autotuning, -1 otherwise)
float build_weight; // build tree time weighting factor
float memory_weight; // index memory weighting factor
float sample_fraction; // what fraction of the dataset to use for autotuning
NNIndex* createIndex(const Matrix<float>& dataset) const;
void fromParameters(const FLANNParameters& p)
{
target_precision = p.target_precision;
build_weight = p.build_weight;
memory_weight = p.memory_weight;
sample_fraction = p.sample_fraction;
}
void toParameters(FLANNParameters& p)
{
p.algorithm = AUTOTUNED;
p.target_precision = target_precision;
p.build_weight = build_weight;
p.memory_weight = memory_weight;
p.sample_fraction = sample_fraction;
};
};
struct SavedIndexParams : public IndexParams {
SavedIndexParams() {
throw FLANNException("I don't know which index to load");
}
SavedIndexParams(std::string filename_) : filename(filename_) {}
std::string filename; // filename of the stored index
NNIndex* createIndex(const Matrix<float>& dataset) const;
};
struct SearchParams {
SearchParams(int checks_ = 32) :
checks(checks_) {};
int checks;
};
class Index {
NNIndex* nnIndex;
public:
Index(const Matrix<float>& features, const IndexParams& params);
~Index();
void knnSearch(const Matrix<float>& queries, Matrix<int>& indices, Matrix<float>& dists, int knn, const SearchParams& params);
int radiusSearch(const Matrix<float>& query, Matrix<int> indices, Matrix<float> dists, float radius, const SearchParams& params);
void save(std::string filename);
int veclen() const;
int size() const;
};
int hierarchicalClustering(const Matrix<float>& features, Matrix<float>& centers, const KMeansIndexParams& params);
}
#endif /* FLANN_HPP_ */
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef DATASET_H
#define DATASET_H
#include <stdio.h>
#include "random.h"
namespace cvflann
{
/**
* Class implementing a generic rectangular dataset.
*/
template <typename T>
class Matrix {
/**
* Flag showing if the class owns its data storage.
*/
bool ownData;
void shallow_copy(const Matrix& rhs)
{
data = rhs.data;
rows = rhs.rows;
cols = rhs.cols;
ownData = false;
}
public:
long rows;
long cols;
T* data;
Matrix(long rows_, long cols_, T* data_ = NULL) :
ownData(false), rows(rows_), cols(cols_), data(data_)
{
if (data_==NULL) {
data = new T[rows*cols];
ownData = true;
}
}
Matrix(const Matrix& d)
{
shallow_copy(d);
}
const Matrix& operator=(const Matrix& rhs)
{
if (this!=&rhs) {
shallow_copy(rhs);
}
return *this;
}
~Matrix()
{
if (ownData) {
delete[] data;
}
}
/**
* Operator that return a (pointer to a) row of the data.
*/
T* operator[](long index)
{
return data+index*cols;
}
T* operator[](long index) const
{
return data+index*cols;
}
Matrix<T>* sample(long size, bool remove = false)
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
if (remove) {
dest = (*this)[rows-i-1];
src = (*this)[r];
for (long j=0;j<cols;++j) {
swap(*src,*dest);
src++;
dest++;
}
}
}
if (remove) {
rows -= size;
}
return newSet;
}
Matrix<T>* sample(long size) const
{
UniqueRandom rand(rows);
Matrix<T> *newSet = new Matrix<T>(size,cols);
T *src,*dest;
for (long i=0;i<size;++i) {
long r = rand.next();
dest = (*newSet)[i];
src = (*this)[r];
for (long j=0;j<cols;++j) {
dest[j] = src[j];
}
}
return newSet;
}
};
}
#endif //DATASET_H
...@@ -293,18 +293,23 @@ This section documents OpenCV's interface to the FLANN\footnote{http://people.cs ...@@ -293,18 +293,23 @@ This section documents OpenCV's interface to the FLANN\footnote{http://people.cs
contains a collection of algorithms optimized for fast nearest neighbor search in large datasets and for high dimensional features. More contains a collection of algorithms optimized for fast nearest neighbor search in large datasets and for high dimensional features. More
information about FLANN can be found in \cite{muja_flann_2009}. information about FLANN can be found in \cite{muja_flann_2009}.
\cvclass{cvflann::Index} \cvclass{cv::flann::Index_}
The FLANN nearest neighbor index class. The FLANN nearest neighbor index class. This class is templated with the type of elements for which the index is built.
\begin{lstlisting} \begin{lstlisting}
namespace cvflann namespace cv
{ {
class Index namespace flann
{
template <typename T>
class Index_
{ {
public: public:
Index(const Mat& features, const IndexParams& params); Index_(const Mat& features, const IndexParams& params);
~Index_();
void knnSearch(const vector<float>& query, void knnSearch(const vector<T>& query,
vector<int>& indices, vector<int>& indices,
vector<float>& dists, vector<float>& dists,
int knn, int knn,
...@@ -315,7 +320,7 @@ namespace cvflann ...@@ -315,7 +320,7 @@ namespace cvflann
int knn, int knn,
const SearchParams& params); const SearchParams& params);
int radiusSearch(const vector<float>& query, int radiusSearch(const vector<T>& query,
vector<int>& indices, vector<int>& indices,
vector<float>& dists, vector<float>& dists,
float radius, float radius,
...@@ -331,16 +336,22 @@ namespace cvflann ...@@ -331,16 +336,22 @@ namespace cvflann
int veclen() const; int veclen() const;
int size() const; int size() const;
const IndexParams* getIndexParameters();
}; };
}
typedef Index_<float> Index;
} } // namespace cv::flann
\end{lstlisting} \end{lstlisting}
\cvCppFunc{cvflann::Index::Index} \cvCppFunc{cv::flann::Index_<T>::Index_}
Constructs a nearest neighbor search index for a given dataset. Constructs a nearest neighbor search index for a given dataset.
\cvdefCpp{Index::Index(const Mat\& features, const IndexParams\& params);} \cvdefCpp{Index_<T>::Index_(const Mat\& features, const IndexParams\& params);}
\begin{description} \begin{description}
\cvarg{features}{ Matrix of type CV\_32F containing the features(points) to index. The size of the matrix is num\_features x feature\_dimensionality.} \cvarg{features}{ Matrix of containing the features(points) to index. The size of the matrix is num\_features x feature\_dimensionality and
the data type of the elements in the matrix must coincide with the type of the index.}
\cvarg{params}{Structure containing the index parameters. The type of index that will be constructed depends on the type of this parameter. \cvarg{params}{Structure containing the index parameters. The type of index that will be constructed depends on the type of this parameter.
The possible parameter types are:} The possible parameter types are:}
...@@ -428,9 +439,9 @@ struct SavedIndexParams : public IndexParams ...@@ -428,9 +439,9 @@ struct SavedIndexParams : public IndexParams
\end{description} \end{description}
\end{description} \end{description}
\cvCppFunc{cvflann::Index::knnSearch} \cvCppFunc{cv::flann::Index_<T>::knnSearch}
Performs a K-nearest neighbor search for a given query point using the index. Performs a K-nearest neighbor search for a given query point using the index.
\cvdefCpp{void Index::knnSearch(const vector<float>\& query, \par \cvdefCpp{void Index_<T>::knnSearch(const vector<T>\& query, \par
vector<int>\& indices, \par vector<int>\& indices, \par
vector<float>\& dists, \par vector<float>\& dists, \par
int knn, \par int knn, \par
...@@ -451,15 +462,15 @@ Performs a K-nearest neighbor search for a given query point using the index. ...@@ -451,15 +462,15 @@ Performs a K-nearest neighbor search for a given query point using the index.
\end{description} \end{description}
\end{description} \end{description}
\cvCppFunc{cvflann::Index::knnSearch} \cvCppFunc{cv::flann::Index_<T>::knnSearch}
Performs a K-nearest neighbor search for multiple query points. Performs a K-nearest neighbor search for multiple query points.
\cvdefCpp{void Index::knnSearch(const Mat\& queries,\par \cvdefCpp{void Index_<T>::knnSearch(const Mat\& queries,\par
Mat\& indices, Mat\& dists,\par Mat\& indices, Mat\& dists,\par
int knn, const SearchParams\& params);} int knn, const SearchParams\& params);}
\begin{description} \begin{description}
\cvarg{queries}{The query points, one per row} \cvarg{queries}{The query points, one per row. The type of queries must match the index type.}
\cvarg{indices}{Indices of the nearest neighbors found } \cvarg{indices}{Indices of the nearest neighbors found }
\cvarg{dists}{Distances to the nearest neighbors found} \cvarg{dists}{Distances to the nearest neighbors found}
\cvarg{knn}{Number of nearest neighbors to search for} \cvarg{knn}{Number of nearest neighbors to search for}
...@@ -467,9 +478,9 @@ Performs a K-nearest neighbor search for multiple query points. ...@@ -467,9 +478,9 @@ Performs a K-nearest neighbor search for multiple query points.
\end{description} \end{description}
\cvCppFunc{cvflann::Index::radiusSearch} \cvCppFunc{cv::flann::Index_<T>::radiusSearch}
Performs a radius nearest neighbor search for a given query point. Performs a radius nearest neighbor search for a given query point.
\cvdefCpp{int Index::radiusSearch(const vector<float>\& query, \par \cvdefCpp{int Index_<T>::radiusSearch(const vector<T>\& query, \par
vector<int>\& indices, \par vector<int>\& indices, \par
vector<float>\& dists, \par vector<float>\& dists, \par
float radius, \par float radius, \par
...@@ -483,9 +494,9 @@ Performs a radius nearest neighbor search for a given query point. ...@@ -483,9 +494,9 @@ Performs a radius nearest neighbor search for a given query point.
\end{description} \end{description}
\cvCppFunc{cvflann::Index::radiusSearch} \cvCppFunc{cv::flann::Index_<T>::radiusSearch}
Performs a radius nearest neighbor search for multiple query points. Performs a radius nearest neighbor search for multiple query points.
\cvdefCpp{int Index::radiusSearch(const Mat\& query, \par \cvdefCpp{int Index_<T>::radiusSearch(const Mat\& query, \par
Mat\& indices, \par Mat\& indices, \par
Mat\& dists, \par Mat\& dists, \par
float radius, \par float radius, \par
...@@ -499,21 +510,25 @@ Performs a radius nearest neighbor search for multiple query points. ...@@ -499,21 +510,25 @@ Performs a radius nearest neighbor search for multiple query points.
\end{description} \end{description}
\cvCppFunc{cvflann::Index::save} \cvCppFunc{cv::flann::Index_<T>::save}
Saves the index to a file. Saves the index to a file.
\cvdefCpp{void Index::save(std::string filename);} \cvdefCpp{void Index_<T>::save(std::string filename);}
\begin{description} \begin{description}
\cvarg{filename}{The file to save the index to} \cvarg{filename}{The file to save the index to}
\end{description} \end{description}
\cvCppFunc{cv::flann::Index_<T>::getIndexParameters}
Returns the index paramreters. This is usefull in case of autotuned indices, when the parameters computed can be retrived using this method.
\cvdefCpp{const IndexParams* Index_<T>::getIndexParameters();}
\cvCppFunc{cvflann::hierarchicalClustering} \cvCppFunc{cv::flann::hierarchicalClustering<ET,DT>}
Clusters the given points by constructing a hierarchical k-means tree and choosing a cut in the tree that minimizes the cluster's variance. Clusters the given points by constructing a hierarchical k-means tree and choosing a cut in the tree that minimizes the cluster's variance.
\cvdefCpp{int hierarchicalClustering(const Mat\& features, Mat\& centers,\par \cvdefCpp{int hierarchicalClustering<ET,DT>(const Mat\& features, Mat\& centers,\par
const KMeansIndexParams\& params);} const KMeansIndexParams\& params);}
\begin{description} \begin{description}
\cvarg{features}{The points to be clustered} \cvarg{features}{The points to be clustered. The matrix must have elements of type ET.}
\cvarg{centers}{The centers of the clusters obtained. The number of rows in this matrix represents the number of clusters desired, however, because of the way the cut in the hierarchical tree is chosen, the number of clusters computed will be the highest number of the form \texttt{(branching-1)*k+1} that's lower than the number of clusters desired, where \texttt{branching} is the tree's branching factor (see description of the KMeansIndexParams).} \cvarg{centers}{The centers of the clusters obtained. The matrix must have type DT. The number of rows in this matrix represents the number of clusters desired, however, because of the way the cut in the hierarchical tree is chosen, the number of clusters computed will be the highest number of the form \texttt{(branching-1)*k+1} that's lower than the number of clusters desired, where \texttt{branching} is the tree's branching factor (see description of the KMeansIndexParams).}
\cvarg{params}{Parameters used in the construction of the hierarchical k-means tree} \cvarg{params}{Parameters used in the construction of the hierarchical k-means tree}
\end{description} \end{description}
The function returns the number of clusters computed. The function returns the number of clusters computed.
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/video/tracking.hpp" #include "opencv2/video/tracking.hpp"
#include "opencv2/features2d/features2d.hpp" #include "opencv2/features2d/features2d.hpp"
#include "opencv2/flann/flann.hpp"
#include "opencv2/calib3d/calib3d.hpp" #include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/objdetect/objdetect.hpp" #include "opencv2/objdetect/objdetect.hpp"
......
...@@ -5,6 +5,7 @@ endif() ...@@ -5,6 +5,7 @@ endif()
add_subdirectory(calib3d) add_subdirectory(calib3d)
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(features2d) add_subdirectory(features2d)
add_subdirectory(flann)
if(MSVC OR MINGW) if(MSVC OR MINGW)
if(NOT CMAKE_CL_64) if(NOT CMAKE_CL_64)
......
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)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/include") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/include")
set(deps opencv_lapack zlib flann) set(deps opencv_lapack zlib)
define_opencv_module(core ${deps}) define_opencv_module(core ${deps})
...@@ -3985,6 +3985,5 @@ public: ...@@ -3985,6 +3985,5 @@ public:
#include "opencv2/core/operations.hpp" #include "opencv2/core/operations.hpp"
#include "opencv2/core/mat.hpp" #include "opencv2/core/mat.hpp"
#include "opencv2/core/flann.hpp" // FLANN (Fast Library for Approximate Nearest Neighbors)
#endif /*__OPENCV_CORE_HPP__*/ #endif /*__OPENCV_CORE_HPP__*/
/*********************************************************************
* 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));
}
}
}
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)
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#define __OPENCV_FEATURES_2D_HPP__ #define __OPENCV_FEATURES_2D_HPP__
#include "opencv2/core/core.hpp" #include "opencv2/core/core.hpp"
#include "opencv2/flann/flann.hpp"
#ifdef __cplusplus #ifdef __cplusplus
#include <limits> #include <limits>
......
define_opencv_module(flann opencv_core)
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. * 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. * 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 * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
...@@ -28,60 +26,51 @@ ...@@ -28,60 +26,51 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/ *************************************************************************/
#ifndef SAVING_H_
#define SAVING_H_
#include "constants.h" #ifndef ALL_INDICES_H_
#include "nn_index.h" #define ALL_INDICES_H_
#include "opencv2/flann/general.h"
namespace cvflann #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
* Structure representing the index header.
*/
struct IndexHeader
{ {
char signature[16];
int flann_version;
flann_algorithm_t index_type;
int rows;
int cols;
};
/**
* Saves index header to stream
*
* @param stream - Stream to save to
* @param index - The index to save
*/
void save_header(FILE* stream, const NNIndex& index);
/**
*
* @param stream - Stream to load from
* @return Index header
*/
IndexHeader load_header(FILE* stream);
template<typename T> template<typename T>
void save_value(FILE* stream, const T& value, int count = 1) NNIndex<T>* create_index_by_type(const Matrix<T>& dataset, const IndexParams& params)
{ {
fwrite(&value, sizeof(value),count, stream); flann_algorithm_t index_type = params.getIndexType();
}
NNIndex<T>* nnIndex;
template<typename T> switch (index_type) {
void load_value(FILE* stream, T& value, int count = 1) case LINEAR:
{ nnIndex = new LinearIndex<T>(dataset, (const LinearIndexParams&)params);
int read_cnt = (int)fread(&value, sizeof(value),count, stream); break;
if (read_cnt!=count) { case KDTREE:
throw FLANNException("Cannot read from file"); 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;
} }
}
#endif /* SAVING_H_ */ } //namespace cvflann
#endif /* ALL_INDICES_H_ */
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
namespace cvflann namespace cvflann
{ {
...@@ -144,7 +143,7 @@ public: ...@@ -144,7 +143,7 @@ public:
// use the standard C malloc to allocate memory // use the standard C malloc to allocate memory
void* m = ::malloc(blocksize); void* m = ::malloc(blocksize);
if (!m) { if (!m) {
fprintf(stderr,"Failed to allocate memory."); fprintf(stderr,"Failed to allocate memory.\n");
exit(1); exit(1);
} }
...@@ -177,12 +176,12 @@ public: ...@@ -177,12 +176,12 @@ public:
template <typename T> template <typename T>
T* allocate(size_t count = 1) T* allocate(size_t count = 1)
{ {
T* mem = (T*) this->malloc((int)(sizeof(T)*count)); T* mem = (T*) this->malloc(sizeof(T)*count);
return mem; return mem;
} }
}; };
} } // namespace cvflann
#endif //ALLOCATOR_H #endif //ALLOCATOR_H
...@@ -31,29 +31,65 @@ ...@@ -31,29 +31,65 @@
#ifndef COMPOSITETREE_H #ifndef COMPOSITETREE_H
#define COMPOSITETREE_H #define COMPOSITETREE_H
#include "constants.h" #include "opencv2/flann/general.h"
#include "nn_index.h" #include "opencv2/flann/nn_index.h"
namespace cvflann namespace cvflann
{ {
class CompositeIndex : public NNIndex
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* kmeans; KMeansIndex<ELEM_TYPE, DIST_TYPE>* kmeans;
KDTreeIndex* kdtree; KDTreeIndex<ELEM_TYPE, DIST_TYPE>* kdtree;
const Matrix<float> dataset; const Matrix<ELEM_TYPE> dataset;
const IndexParams& index_params;
public: public:
CompositeIndex(const Matrix<float>& inputData, const CompositeIndexParams& params = CompositeIndexParams() ) : dataset(inputData) CompositeIndex(const Matrix<ELEM_TYPE>& inputData, const CompositeIndexParams& params = CompositeIndexParams() ) :
dataset(inputData), index_params(params)
{ {
KDTreeIndexParams kdtree_params(params.trees); KDTreeIndexParams kdtree_params(params.trees);
KMeansIndexParams kmeans_params(params.branching, params.iterations, params.centers_init, params.cb_index); KMeansIndexParams kmeans_params(params.branching, params.iterations, params.centers_init, params.cb_index);
kdtree = new KDTreeIndex(inputData,kdtree_params); kdtree = new KDTreeIndex<ELEM_TYPE, DIST_TYPE>(inputData,kdtree_params);
kmeans = new KMeansIndex(inputData,kmeans_params); kmeans = new KMeansIndex<ELEM_TYPE, DIST_TYPE>(inputData,kmeans_params);
} }
...@@ -70,12 +106,12 @@ public: ...@@ -70,12 +106,12 @@ public:
} }
int size() const size_t size() const
{ {
return dataset.rows; return dataset.rows;
} }
int veclen() const size_t veclen() const
{ {
return dataset.cols; return dataset.cols;
} }
...@@ -95,34 +131,33 @@ public: ...@@ -95,34 +131,33 @@ public:
} }
void saveIndex(FILE* /*stream*/) void saveIndex(FILE* stream)
{ {
kmeans->saveIndex(stream);
kdtree->saveIndex(stream);
} }
void loadIndex(FILE* /*stream*/) void loadIndex(FILE* stream)
{ {
kmeans->loadIndex(stream);
kdtree->loadIndex(stream);
} }
void findNeighbors(ResultSet& result, const float* vec, const SearchParams& searchParams) void findNeighbors(ResultSet<ELEM_TYPE>& result, const ELEM_TYPE* vec, const SearchParams& searchParams)
{ {
kmeans->findNeighbors(result,vec,searchParams); kmeans->findNeighbors(result,vec,searchParams);
kdtree->findNeighbors(result,vec,searchParams); kdtree->findNeighbors(result,vec,searchParams);
} }
const IndexParams* getParameters() const
// Params estimateSearchParams(float precision, Dataset<float>* testset = NULL) {
// { return &index_params;
// Params params; }
//
// return params;
// }
}; };
} } // namespace cvflann
#endif //COMPOSITETREE_H #endif //COMPOSITETREE_H
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include <cmath> #include <cmath>
using namespace std; using namespace std;
#include "constants.h" #include "opencv2/flann/general.h"
namespace cvflann namespace cvflann
{ {
...@@ -82,6 +82,9 @@ double euclidean_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, doubl ...@@ -82,6 +82,9 @@ double euclidean_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, doubl
return distsq; 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. * Compute the Manhattan (L_1) distance between two vectors.
* *
...@@ -152,6 +155,142 @@ double minkowski_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, doubl ...@@ -152,6 +155,142 @@ double minkowski_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, doubl
} }
// L_infinity distance (NOT A VALID KD-TREE DISTANCE - NOT DIMENSIONWISE ADDITIVE)
template <typename Iterator1, typename Iterator2>
double max_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double dist = acc;
Iterator1 lastgroup = last1 - 3;
double diff0, diff1, diff2, diff3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
diff0 = fabs(first1[0] - first2[0]);
diff1 = fabs(first1[1] - first2[1]);
diff2 = fabs(first1[2] - first2[2]);
diff3 = fabs(first1[3] - first2[3]);
if (diff0 > dist) dist = diff0;
if (diff1 > dist) dist = diff1;
if (diff2 > dist) dist = diff2;
if (diff3 > dist) dist = diff3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
diff0 = fabs(*first1++ - *first2++);
dist = (diff0 > dist) ? diff0 : dist;
}
return dist;
}
template <typename Iterator1, typename Iterator2>
double hist_intersection_kernel(Iterator1 first1, Iterator1 last1, Iterator2 first2)
{
double kernel = 0;
Iterator1 lastgroup = last1 - 3;
double min0, min1, min2, min3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
min0 = first1[0] < first2[0] ? first1[0] : first2[0];
min1 = first1[1] < first2[1] ? first1[1] : first2[1];
min2 = first1[2] < first2[2] ? first1[2] : first2[2];
min3 = first1[3] < first2[3] ? first1[3] : first2[3];
kernel += min0 + min1 + min2 + min3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
min0 = first1[0] < first2[0] ? first1[0] : first2[0];
kernel += min0;
first1++;
first2++;
}
return kernel;
}
template <typename Iterator1, typename Iterator2>
double hist_intersection_dist_sq(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double dist_sq = acc - 2 * hist_intersection_kernel(first1, last1, first2);
while (first1 < last1) {
dist_sq += *first1 + *first2;
first1++;
first2++;
}
return dist_sq;
}
// Hellinger distance
template <typename Iterator1, typename Iterator2>
double hellinger_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double distsq = acc;
double diff0, diff1, diff2, diff3;
Iterator1 lastgroup = last1 - 3;
/* Process 4 items with each loop for efficiency. */
while (first1 < lastgroup) {
diff0 = sqrt(first1[0]) - sqrt(first2[0]);
diff1 = sqrt(first1[1]) - sqrt(first2[1]);
diff2 = sqrt(first1[2]) - sqrt(first2[2]);
diff3 = sqrt(first1[3]) - sqrt(first2[3]);
distsq += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
first1 += 4;
first2 += 4;
}
/* Process last 0-3 pixels. Not needed for standard vector lengths. */
while (first1 < last1) {
diff0 = sqrt(*first1++) - sqrt(*first2++);
distsq += diff0 * diff0;
}
return distsq;
}
// chi-dsquare distance
template <typename Iterator1, typename Iterator2>
double chi_square_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double dist = acc;
while (first1 < last1) {
double sum = *first1 + *first2;
if (sum > 0) {
double diff = *first1 - *first2;
dist += diff * diff / sum;
}
first1++;
first2++;
}
return dist;
}
// Kullback–Leibler divergence (NOT SYMMETRIC)
template <typename Iterator1, typename Iterator2>
double kl_divergence(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{
double div = acc;
while (first1 < last1) {
if (*first2 != 0) {
double ratio = *first1 / *first2;
if (ratio > 0) {
div += *first1 * log(ratio);
}
}
first1++;
first2++;
}
return div;
}
extern flann_distance_t flann_distance_type; extern flann_distance_t flann_distance_type;
...@@ -163,17 +302,27 @@ extern flann_distance_t flann_distance_type; ...@@ -163,17 +302,27 @@ extern flann_distance_t flann_distance_type;
* of this argument. * of this argument.
*/ */
template <typename Iterator1, typename Iterator2> template <typename Iterator1, typename Iterator2>
float custom_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0) double custom_dist(Iterator1 first1, Iterator1 last1, Iterator2 first2, double acc = 0)
{ {
switch (flann_distance_type) { switch (flann_distance_type) {
case EUCLIDEAN: case EUCLIDEAN:
return (float)euclidean_dist(first1, last1, first2, acc); return euclidean_dist(first1, last1, first2, acc);
case MANHATTAN: case MANHATTAN:
return (float)manhattan_dist(first1, last1, first2, acc); return manhattan_dist(first1, last1, first2, acc);
case MINKOWSKI: case MINKOWSKI:
return (float)minkowski_dist(first1, last1, first2, acc); 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: default:
return (float)euclidean_dist(first1, last1, first2, acc); return euclidean_dist(first1, last1, first2, acc);
} }
} }
...@@ -191,7 +340,7 @@ struct ZeroIterator { ...@@ -191,7 +340,7 @@ struct ZeroIterator {
return 0; return 0;
} }
T operator[](int /*index*/) { T operator[](int index) {
return 0; return 0;
} }
...@@ -206,6 +355,6 @@ struct ZeroIterator { ...@@ -206,6 +355,6 @@ struct ZeroIterator {
}; };
extern ZeroIterator<float> zero; extern ZeroIterator<float> zero;
} } // namespace cvflann
#endif //DIST_H #endif //DIST_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.
*************************************************************************/
#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_ */
...@@ -31,17 +31,18 @@ ...@@ -31,17 +31,18 @@
#ifndef CONSTANTS_H #ifndef CONSTANTS_H
#define CONSTANTS_H #define CONSTANTS_H
#define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
const double FLANN_VERSION = 1.20;
/* Nearest neighbor index algorithms */
/* Nearest neighbour index algorithms */
enum flann_algorithm_t { enum flann_algorithm_t {
LINEAR = 0, LINEAR = 0,
KDTREE = 1, KDTREE = 1,
KMEANS = 2, KMEANS = 2,
COMPOSITE = 3, COMPOSITE = 3,
SAVED = 254, SAVED = 254,
AUTOTUNED = 255, AUTOTUNED = 255
}; };
enum flann_centers_init_t { enum flann_centers_init_t {
...@@ -50,7 +51,6 @@ enum flann_centers_init_t { ...@@ -50,7 +51,6 @@ enum flann_centers_init_t {
CENTERS_KMEANSPP = 2 CENTERS_KMEANSPP = 2
}; };
enum flann_log_level_t { enum flann_log_level_t {
LOG_NONE = 0, LOG_NONE = 0,
LOG_FATAL = 1, LOG_FATAL = 1,
...@@ -62,7 +62,92 @@ enum flann_log_level_t { ...@@ -62,7 +62,92 @@ enum flann_log_level_t {
enum flann_distance_t { enum flann_distance_t {
EUCLIDEAN = 1, EUCLIDEAN = 1,
MANHATTAN = 2, MANHATTAN = 2,
MINKOWSKI = 3 MINKOWSKI = 3,
MAX_DIST = 4,
HIK = 5,
HELLINGER = 6,
CS = 7,
CHI_SQUARE = 7,
KL = 8,
KULLBACK_LEIBLER = 8
}; };
#endif // CONSTANTS_H 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 */
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
#ifndef GROUND_TRUTH_H #ifndef GROUND_TRUTH_H
#define GROUND_TRUTH_H #define GROUND_TRUTH_H
#include "matrix.h" #include "opencv2/flann/dist.h"
#include "dist.h" #include "opencv2/flann/matrix.h"
namespace cvflann namespace cvflann
{ {
...@@ -51,7 +51,7 @@ void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int ...@@ -51,7 +51,7 @@ void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int
match[0] = 0; match[0] = 0;
int dcnt = 1; int dcnt = 1;
for (int i=1;i<dataset.rows;++i) { for (size_t i=1;i<dataset.rows;++i) {
T tmp = flann_dist(query, query_end, dataset[i]); T tmp = flann_dist(query, query_end, dataset[i]);
if (dcnt<n) { if (dcnt<n) {
...@@ -84,12 +84,12 @@ void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int ...@@ -84,12 +84,12 @@ void find_nearest(const Matrix<T>& dataset, T* query, int* matches, int nn, int
template <typename T> template <typename T>
void compute_ground_truth(const Matrix<T>& dataset, const Matrix<T>& testset, Matrix<int>& matches, int skip=0) void compute_ground_truth(const Matrix<T>& dataset, const Matrix<T>& testset, Matrix<int>& matches, int skip=0)
{ {
for (int i=0;i<testset.rows;++i) { for (size_t i=0;i<testset.rows;++i) {
find_nearest(dataset, testset[i], matches[i], matches.cols, skip); find_nearest(dataset, testset[i], matches[i], matches.cols, skip);
} }
} }
} } // namespace cvflann
#endif //GROUND_TRUTH_H #endif //GROUND_TRUTH_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.
*
* 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_ */
...@@ -204,6 +204,6 @@ public: ...@@ -204,6 +204,6 @@ public:
}; };
} } // namespace cvflann
#endif //HEAP_H #endif //HEAP_H
...@@ -28,51 +28,40 @@ ...@@ -28,51 +28,40 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/ *************************************************************************/
#include "index_testing.h" #ifndef TESTING_H
#include "result_set.h" #define TESTING_H
#include "timer.h"
#include "logger.h" #include <cstring>
#include "dist.h" #include <cassert>
#include "common.h"
#include "opencv2/flann/matrix.h"
#include <algorithm> #include "opencv2/flann/nn_index.h"
#include <math.h> #include "opencv2/flann/result_set.h"
#include <string.h> #include "opencv2/flann/logger.h"
#include <stdlib.h> #include "opencv2/flann/timer.h"
namespace cvflann
{
const float SEARCH_EPS = 0.001f; using namespace std;
int countCorrectMatches(int* neighbors, int* groundTruth, int n) namespace cvflann
{ {
int count = 0;
for (int i=0;i<n;++i) { int countCorrectMatches(int* neighbors, int* groundTruth, int n);
for (int k=0;k<n;++k) {
if (neighbors[i]==groundTruth[k]) {
count++;
break;
}
}
}
return count;
}
float computeDistanceRaport(const Matrix<float>& inputData, float* target, int* neighbors, int* groundTruth, int veclen, int n) template <typename ELEM_TYPE>
float computeDistanceRaport(const Matrix<ELEM_TYPE>& inputData, ELEM_TYPE* target, int* neighbors, int* groundTruth, int veclen, int n)
{ {
float* target_end = target + veclen; ELEM_TYPE* target_end = target + veclen;
float ret = 0; float ret = 0;
for (int i=0;i<n;++i) { for (int i=0;i<n;++i) {
float den = (float)flann_dist(target,target_end, inputData[groundTruth[i]]); float den = flann_dist(target,target_end, inputData[groundTruth[i]]);
float num = (float)flann_dist(target,target_end, inputData[neighbors[i]]); float num = flann_dist(target,target_end, inputData[neighbors[i]]);
// printf("den=%g,num=%g\n",den,num);
if (den==0 && num==0) { if (den==0 && num==0) {
ret += 1; ret += 1;
} else { }
else {
ret += num/den; ret += num/den;
} }
} }
...@@ -80,19 +69,20 @@ float computeDistanceRaport(const Matrix<float>& inputData, float* target, int* ...@@ -80,19 +69,20 @@ float computeDistanceRaport(const Matrix<float>& inputData, float* target, int*
return ret; return ret;
} }
float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches, int nn, int checks, float& time, float& dist, int skipMatches) 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<nn) { if (matches.cols<size_t(nn)) {
logger.info("matches.cols=%d, nn=%d\n",matches.cols,nn); logger.info("matches.cols=%d, nn=%d\n",matches.cols,nn);
throw FLANNException("Ground truth is not computed for as many neighbors as requested"); throw FLANNException("Ground truth is not computed for as many neighbors as requested");
} }
KNNResultSet resultSet(nn+skipMatches); KNNResultSet<ELEM_TYPE> resultSet(nn+skipMatches);
SearchParams searchParams(checks); SearchParams searchParams(checks);
int correct = 0; int correct;
float distR = 0; float distR;
StartStopTimer t; StartStopTimer t;
int repeats = 0; int repeats = 0;
while (t.value<0.2) { while (t.value<0.2) {
...@@ -100,8 +90,8 @@ float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, c ...@@ -100,8 +90,8 @@ float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, c
t.start(); t.start();
correct = 0; correct = 0;
distR = 0; distR = 0;
for (int i = 0; i < testData.rows; i++) { for (size_t i = 0; i < testData.rows; i++) {
float* target = testData[i]; ELEM_TYPE* target = testData[i];
resultSet.init(target, testData.cols); resultSet.init(target, testData.cols);
index.findNeighbors(resultSet,target, searchParams); index.findNeighbors(resultSet,target, searchParams);
int* neighbors = resultSet.getNeighbors(); int* neighbors = resultSet.getNeighbors();
...@@ -112,7 +102,7 @@ float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, c ...@@ -112,7 +102,7 @@ float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, c
} }
t.stop(); t.stop();
} }
time = (float)(t.value/repeats); time = t.value/repeats;
float precicion = (float)correct/(nn*testData.rows); float precicion = (float)correct/(nn*testData.rows);
...@@ -125,29 +115,10 @@ float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, c ...@@ -125,29 +115,10 @@ float search_with_ground_truth(NNIndex& index, const Matrix<float>& inputData, c
return precicion; return precicion;
} }
void search_for_neighbors(NNIndex& index, const Matrix<float>& testset, Matrix<int>& result, Matrix<float>& dists, const SearchParams& searchParams, int skip)
{
assert(testset.rows == result.rows);
int nn = result.cols;
KNNResultSet resultSet(nn+skip);
for (int i = 0; i < testset.rows; i++) {
float* target = testset[i];
resultSet.init(target, testset.cols);
index.findNeighbors(resultSet,target, searchParams);
int* neighbors = resultSet.getNeighbors();
float* distances = resultSet.getDistances();
memcpy(result[i], neighbors+skip, nn*sizeof(int));
memcpy(dists[i], distances+skip, nn*sizeof(float));
}
}
float test_index_checks(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches, int checks, float& precision, int nn, int skipMatches) 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(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n");
logger.info("---------------------------------------------------------\n"); logger.info("---------------------------------------------------------\n");
...@@ -159,10 +130,12 @@ float test_index_checks(NNIndex& index, const Matrix<float>& inputData, const Ma ...@@ -159,10 +130,12 @@ float test_index_checks(NNIndex& index, const Matrix<float>& inputData, const Ma
return time; return time;
} }
template <typename ELEM_TYPE>
float test_index_precision(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches, 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, int skipMatches) 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(" Nodes Precision(%) Time(s) Time/vec(ms) Mean dist\n");
logger.info("---------------------------------------------------------\n"); logger.info("---------------------------------------------------------\n");
...@@ -227,9 +200,12 @@ float test_index_precision(NNIndex& index, const Matrix<float>& inputData, const ...@@ -227,9 +200,12 @@ float test_index_precision(NNIndex& index, const Matrix<float>& inputData, const
} }
float test_index_precisions(NNIndex& index, const Matrix<float>& inputData, const Matrix<float>& testData, const Matrix<int>& matches, template <typename ELEM_TYPE>
float* precisions, int precisions_length, int nn, int skipMatches, float maxTime) 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 // make sure precisions array is sorted
sort(precisions, precisions+precisions_length); sort(precisions, precisions+precisions_length);
...@@ -311,4 +287,6 @@ float test_index_precisions(NNIndex& index, const Matrix<float>& inputData, cons ...@@ -311,4 +287,6 @@ float test_index_precisions(NNIndex& index, const Matrix<float>& inputData, cons
return time; return time;
} }
} } // namespace cvflann
#endif //TESTING_H
...@@ -31,19 +31,35 @@ ...@@ -31,19 +31,35 @@
#ifndef LINEARSEARCH_H #ifndef LINEARSEARCH_H
#define LINEARSEARCH_H #define LINEARSEARCH_H
#include "constants.h" #include "opencv2/flann/general.h"
#include "nn_index.h" #include "opencv2/flann/nn_index.h"
namespace cvflann namespace cvflann
{ {
class LinearIndex : public NNIndex { 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);
}
};
const Matrix<float> dataset; 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: public:
LinearIndex(const Matrix<float>& inputData, const LinearIndexParams& params = LinearIndexParams() ) : dataset(inputData) LinearIndex(const Matrix<ELEM_TYPE>& inputData, const LinearIndexParams& params = LinearIndexParams() ) :
dataset(inputData), index_params(params)
{ {
} }
...@@ -53,12 +69,12 @@ public: ...@@ -53,12 +69,12 @@ public:
} }
int size() const size_t size() const
{ {
return dataset.rows; return dataset.rows;
} }
int veclen() const size_t veclen() const
{ {
return dataset.cols; return dataset.cols;
} }
...@@ -74,32 +90,31 @@ public: ...@@ -74,32 +90,31 @@ public:
/* nothing to do here for linear search */ /* nothing to do here for linear search */
} }
void saveIndex(FILE* /*stream*/) void saveIndex(FILE* stream)
{ {
/* nothing to do here for linear search */ /* nothing to do here for linear search */
} }
void loadIndex(FILE* /*stream*/) void loadIndex(FILE* stream)
{ {
/* nothing to do here for linear search */ /* nothing to do here for linear search */
} }
void findNeighbors(ResultSet& resultSet, const float* /*vec*/, const SearchParams& /*searchParams*/) void findNeighbors(ResultSet<ELEM_TYPE>& resultSet, const ELEM_TYPE* vec, const SearchParams& searchParams)
{ {
for (int i=0;i<dataset.rows;++i) { for (size_t i=0;i<dataset.rows;++i) {
resultSet.addPoint(dataset[i],i); resultSet.addPoint(dataset[i],i);
} }
} }
// Params estimateSearchParams(float precision, Matrix<float>* testset = NULL) const IndexParams* getParameters() const
// { {
// Params params; return &index_params;
// return params; }
// }
}; };
} } // namespace cvflann
#endif // LINEARSEARCH_H #endif // LINEARSEARCH_H
...@@ -33,9 +33,7 @@ ...@@ -33,9 +33,7 @@
#include <cstdio> #include <cstdio>
#include <stdarg.h> #include "opencv2/flann/general.h"
#include "common.h"
#include "flann.h"
using namespace std; using namespace std;
...@@ -88,6 +86,6 @@ public: ...@@ -88,6 +86,6 @@ public:
extern Logger logger; extern Logger logger;
} } // namespace cvflann
#endif //LOGGER_H #endif //LOGGER_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.
*************************************************************************/
#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
This diff is collapsed.
This diff is collapsed.
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)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment