| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 | /*********************************************************************** * 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 OPENCV_FLANN_RESULTSET_H#define OPENCV_FLANN_RESULTSET_H#include <algorithm>#include <cstring>#include <iostream>#include <limits>#include <set>#include <vector>namespace cvflann{/* This record represents a branch point when finding neighbors in    the tree.  It contains a record of the minimum distance to the query    point, as well as the node at which the search resumes. */template <typename T, typename DistanceType>struct BranchStruct{    T node;           /* Tree node at which search resumes */    DistanceType mindist;     /* Minimum distance to query for all nodes below. */    BranchStruct() {}    BranchStruct(const T& aNode, DistanceType dist) : node(aNode), mindist(dist) {}    bool operator<(const BranchStruct<T, DistanceType>& rhs) const    {        return mindist<rhs.mindist;    }};template <typename DistanceType>class ResultSet{public:    virtual ~ResultSet() {}    virtual bool full() const = 0;    virtual void addPoint(DistanceType dist, int index) = 0;    virtual DistanceType worstDist() const = 0;};/** * KNNSimpleResultSet does not ensure that the element it holds are unique. * Is used in those cases where the nearest neighbour algorithm used does not * attempt to insert the same element multiple times. */template <typename DistanceType>class KNNSimpleResultSet : public ResultSet<DistanceType>{    int* indices;    DistanceType* dists;    int capacity;    int count;    DistanceType worst_distance_;public:    KNNSimpleResultSet(int capacity_) : capacity(capacity_), count(0)    {    }    void init(int* indices_, DistanceType* dists_)    {        indices = indices_;        dists = dists_;        count = 0;        worst_distance_ = (std::numeric_limits<DistanceType>::max)();        dists[capacity-1] = worst_distance_;    }    size_t size() const    {        return count;    }    bool full() const    {        return count == capacity;    }    void addPoint(DistanceType dist, int index)    {        if (dist >= worst_distance_) return;        int i;        for (i=count; i>0; --i) {#ifdef FLANN_FIRST_MATCH            if ( (dists[i-1]>dist) || ((dist==dists[i-1])&&(indices[i-1]>index)) )#else            if (dists[i-1]>dist)#endif            {                if (i<capacity) {                    dists[i] = dists[i-1];                    indices[i] = indices[i-1];                }            }            else break;        }        if (count < capacity) ++count;        dists[i] = dist;        indices[i] = index;        worst_distance_ = dists[capacity-1];    }    DistanceType worstDist() const    {        return worst_distance_;    }};/** * K-Nearest neighbour result set. Ensures that the elements inserted are unique */template <typename DistanceType>class KNNResultSet : public ResultSet<DistanceType>{    int* indices;    DistanceType* dists;    int capacity;    int count;    DistanceType worst_distance_;public:    KNNResultSet(int capacity_) : capacity(capacity_), count(0)    {    }    void init(int* indices_, DistanceType* dists_)    {        indices = indices_;        dists = dists_;        count = 0;        worst_distance_ = (std::numeric_limits<DistanceType>::max)();        dists[capacity-1] = worst_distance_;    }    size_t size() const    {        return count;    }    bool full() const    {        return count == capacity;    }    void addPoint(DistanceType dist, int index)    {        if (dist >= worst_distance_) return;        int i;        for (i = count; i > 0; --i) {#ifdef FLANN_FIRST_MATCH            if ( (dists[i-1]<=dist) && ((dist!=dists[i-1])||(indices[i-1]<=index)) )#else            if (dists[i-1]<=dist)#endif            {                // Check for duplicate indices                int j = i - 1;                while ((j >= 0) && (dists[j] == dist)) {                    if (indices[j] == index) {                        return;                    }                    --j;                }                break;            }        }        if (count < capacity) ++count;        for (int j = count-1; j > i; --j) {            dists[j] = dists[j-1];            indices[j] = indices[j-1];        }        dists[i] = dist;        indices[i] = index;        worst_distance_ = dists[capacity-1];    }    DistanceType worstDist() const    {        return worst_distance_;    }};/** * A result-set class used when performing a radius based search. */template <typename DistanceType>class RadiusResultSet : public ResultSet<DistanceType>{    DistanceType radius;    int* indices;    DistanceType* dists;    size_t capacity;    size_t count;public:    RadiusResultSet(DistanceType radius_, int* indices_, DistanceType* dists_, int capacity_) :        radius(radius_), indices(indices_), dists(dists_), capacity(capacity_)    {        init();    }    ~RadiusResultSet()    {    }    void init()    {        count = 0;    }    size_t size() const    {        return count;    }    bool full() const    {        return true;    }    void addPoint(DistanceType dist, int index)    {        if (dist<radius) {            if ((capacity>0)&&(count < capacity)) {                dists[count] = dist;                indices[count] = index;            }            count++;        }    }    DistanceType worstDist() const    {        return radius;    }};/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////** Class that holds the k NN neighbors * Faster than KNNResultSet as it uses a binary heap and does not maintain two arrays */template<typename DistanceType>class UniqueResultSet : public ResultSet<DistanceType>{public:    struct DistIndex    {        DistIndex(DistanceType dist, unsigned int index) :            dist_(dist), index_(index)        {        }        bool operator<(const DistIndex dist_index) const        {            return (dist_ < dist_index.dist_) || ((dist_ == dist_index.dist_) && index_ < dist_index.index_);        }        DistanceType dist_;        unsigned int index_;    };    /** Default cosntructor */    UniqueResultSet() :        is_full_(false), worst_distance_(std::numeric_limits<DistanceType>::max())    {    }    /** Check the status of the set     * @return true if we have k NN     */    inline bool full() const    {        return is_full_;    }    /** Remove all elements in the set     */    virtual void clear() = 0;    /** Copy the set to two C arrays     * @param indices pointer to a C array of indices     * @param dist pointer to a C array of distances     * @param n_neighbors the number of neighbors to copy     */    virtual void copy(int* indices, DistanceType* dist, int n_neighbors = -1) const    {        if (n_neighbors < 0) {            for (typename std::set<DistIndex>::const_iterator dist_index = dist_indices_.begin(), dist_index_end =                     dist_indices_.end(); dist_index != dist_index_end; ++dist_index, ++indices, ++dist) {                *indices = dist_index->index_;                *dist = dist_index->dist_;            }        }        else {            int i = 0;            for (typename std::set<DistIndex>::const_iterator dist_index = dist_indices_.begin(), dist_index_end =                     dist_indices_.end(); (dist_index != dist_index_end) && (i < n_neighbors); ++dist_index, ++indices, ++dist, ++i) {                *indices = dist_index->index_;                *dist = dist_index->dist_;            }        }    }    /** Copy the set to two C arrays but sort it according to the distance first     * @param indices pointer to a C array of indices     * @param dist pointer to a C array of distances     * @param n_neighbors the number of neighbors to copy     */    virtual void sortAndCopy(int* indices, DistanceType* dist, int n_neighbors = -1) const    {        copy(indices, dist, n_neighbors);    }    /** The number of neighbors in the set     * @return     */    size_t size() const    {        return dist_indices_.size();    }    /** The distance of the furthest neighbor     * If we don't have enough neighbors, it returns the max possible value     * @return     */    inline DistanceType worstDist() const    {        return worst_distance_;    }protected:    /** Flag to say if the set is full */    bool is_full_;    /** The worst distance found so far */    DistanceType worst_distance_;    /** The best candidates so far */    std::set<DistIndex> dist_indices_;};/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////** Class that holds the k NN neighbors * Faster than KNNResultSet as it uses a binary heap and does not maintain two arrays */template<typename DistanceType>class KNNUniqueResultSet : public UniqueResultSet<DistanceType>{public:    /** Constructor     * @param capacity the number of neighbors to store at max     */    KNNUniqueResultSet(unsigned int capacity) : capacity_(capacity)    {        this->is_full_ = false;        this->clear();    }    /** Add a possible candidate to the best neighbors     * @param dist distance for that neighbor     * @param index index of that neighbor     */    inline void addPoint(DistanceType dist, int index)    {        // Don't do anything if we are worse than the worst        if (dist >= worst_distance_) return;        dist_indices_.insert(DistIndex(dist, index));        if (is_full_) {            if (dist_indices_.size() > capacity_) {                dist_indices_.erase(*dist_indices_.rbegin());                worst_distance_ = dist_indices_.rbegin()->dist_;            }        }        else if (dist_indices_.size() == capacity_) {            is_full_ = true;            worst_distance_ = dist_indices_.rbegin()->dist_;        }    }    /** Remove all elements in the set     */    void clear()    {        dist_indices_.clear();        worst_distance_ = std::numeric_limits<DistanceType>::max();        is_full_ = false;    }protected:    typedef typename UniqueResultSet<DistanceType>::DistIndex DistIndex;    using UniqueResultSet<DistanceType>::is_full_;    using UniqueResultSet<DistanceType>::worst_distance_;    using UniqueResultSet<DistanceType>::dist_indices_;    /** The number of neighbors to keep */    unsigned int capacity_;};/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////** Class that holds the radius nearest neighbors * It is more accurate than RadiusResult as it is not limited in the number of neighbors */template<typename DistanceType>class RadiusUniqueResultSet : public UniqueResultSet<DistanceType>{public:    /** Constructor     * @param radius the maximum distance of a neighbor     */    RadiusUniqueResultSet(DistanceType radius) :        radius_(radius)    {        is_full_ = true;    }    /** Add a possible candidate to the best neighbors     * @param dist distance for that neighbor     * @param index index of that neighbor     */    void addPoint(DistanceType dist, int index)    {        if (dist <= radius_) dist_indices_.insert(DistIndex(dist, index));    }    /** Remove all elements in the set     */    inline void clear()    {        dist_indices_.clear();    }    /** Check the status of the set     * @return alwys false     */    inline bool full() const    {        return true;    }    /** The distance of the furthest neighbor     * If we don't have enough neighbors, it returns the max possible value     * @return     */    inline DistanceType worstDist() const    {        return radius_;    }private:    typedef typename UniqueResultSet<DistanceType>::DistIndex DistIndex;    using UniqueResultSet<DistanceType>::dist_indices_;    using UniqueResultSet<DistanceType>::is_full_;    /** The furthest distance a neighbor can be */    DistanceType radius_;};/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////** Class that holds the k NN neighbors within a radius distance */template<typename DistanceType>class KNNRadiusUniqueResultSet : public KNNUniqueResultSet<DistanceType>{public:    /** Constructor     * @param capacity the number of neighbors to store at max     * @param radius the maximum distance of a neighbor     */    KNNRadiusUniqueResultSet(unsigned int capacity, DistanceType radius)    {        this->capacity_ = capacity;        this->radius_ = radius;        this->dist_indices_.reserve(capacity_);        this->clear();    }    /** Remove all elements in the set     */    void clear()    {        dist_indices_.clear();        worst_distance_ = radius_;        is_full_ = false;    }private:    using KNNUniqueResultSet<DistanceType>::dist_indices_;    using KNNUniqueResultSet<DistanceType>::is_full_;    using KNNUniqueResultSet<DistanceType>::worst_distance_;    /** The maximum number of neighbors to consider */    unsigned int capacity_;    /** The maximum distance of a neighbor */    DistanceType radius_;};}#endif //OPENCV_FLANN_RESULTSET_H
 |