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