a LOT of obsolete stuff has been moved to the legacy module.
This commit is contained in:
@@ -1,63 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2009, Xavier Delacour, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
// 2009-01-09, Xavier Delacour <xavier.delacour@gmail.com>
|
||||
|
||||
#ifndef __opencv_featuretree_h__
|
||||
#define __opencv_featuretree_h__
|
||||
|
||||
struct CvFeatureTree {
|
||||
CvFeatureTree(const CvFeatureTree& x);
|
||||
CvFeatureTree& operator= (const CvFeatureTree& rhs);
|
||||
|
||||
CvFeatureTree() {}
|
||||
virtual ~CvFeatureTree() {}
|
||||
virtual void FindFeatures(const CvMat* d, int k, int emax, CvMat* results, CvMat* dist) = 0;
|
||||
virtual int FindOrthoRange(CvMat* /*bounds_min*/, CvMat* /*bounds_max*/,CvMat* /*results*/) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __cv_featuretree_h__
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
@@ -1,47 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef _CV_IMG_PROC_H_
|
||||
#define _CV_IMG_PROC_H_
|
||||
|
||||
|
||||
|
||||
#endif /*_CV_INTERNAL_H_*/
|
||||
@@ -1,467 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2008, Xavier Delacour, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
// 2008-05-13, Xavier Delacour <xavier.delacour@gmail.com>
|
||||
|
||||
#ifndef __cv_kdtree_h__
|
||||
#define __cv_kdtree_h__
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
#include "assert.h"
|
||||
#include "math.h"
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
#pragma warning(disable: 4512) // suppress "assignment operator could not be generated"
|
||||
#endif
|
||||
|
||||
// J.S. Beis and D.G. Lowe. Shape indexing using approximate nearest-neighbor search
|
||||
// in highdimensional spaces. In Proc. IEEE Conf. Comp. Vision Patt. Recog.,
|
||||
// pages 1000--1006, 1997. http://citeseer.ist.psu.edu/beis97shape.html
|
||||
#undef __deref
|
||||
#undef __valuetype
|
||||
|
||||
template < class __valuetype, class __deref >
|
||||
class CvKDTree {
|
||||
public:
|
||||
typedef __deref deref_type;
|
||||
typedef typename __deref::scalar_type scalar_type;
|
||||
typedef typename __deref::accum_type accum_type;
|
||||
|
||||
private:
|
||||
struct node {
|
||||
int dim; // split dimension; >=0 for nodes, -1 for leaves
|
||||
__valuetype value; // if leaf, value of leaf
|
||||
int left, right; // node indices of left and right branches
|
||||
scalar_type boundary; // left if deref(value,dim)<=boundary, otherwise right
|
||||
};
|
||||
typedef std::vector < node > node_array;
|
||||
|
||||
__deref deref; // requires operator() (__valuetype lhs,int dim)
|
||||
|
||||
node_array nodes; // node storage
|
||||
int point_dim; // dimension of points (the k in kd-tree)
|
||||
int root_node; // index of root node, -1 if empty tree
|
||||
|
||||
// for given set of point indices, compute dimension of highest variance
|
||||
template < class __instype, class __valuector >
|
||||
int dimension_of_highest_variance(__instype * first, __instype * last,
|
||||
__valuector ctor) {
|
||||
assert(last - first > 0);
|
||||
|
||||
accum_type maxvar = -std::numeric_limits < accum_type >::max();
|
||||
int maxj = -1;
|
||||
for (int j = 0; j < point_dim; ++j) {
|
||||
accum_type mean = 0;
|
||||
for (__instype * k = first; k < last; ++k)
|
||||
mean += deref(ctor(*k), j);
|
||||
mean /= last - first;
|
||||
accum_type var = 0;
|
||||
for (__instype * k = first; k < last; ++k) {
|
||||
accum_type diff = accum_type(deref(ctor(*k), j)) - mean;
|
||||
var += diff * diff;
|
||||
}
|
||||
var /= last - first;
|
||||
|
||||
assert(maxj != -1 || var >= maxvar);
|
||||
|
||||
if (var >= maxvar) {
|
||||
maxvar = var;
|
||||
maxj = j;
|
||||
}
|
||||
}
|
||||
|
||||
return maxj;
|
||||
}
|
||||
|
||||
// given point indices and dimension, find index of median; (almost) modifies [first,last)
|
||||
// such that points_in[first,median]<=point[median], points_in(median,last)>point[median].
|
||||
// implemented as partial quicksort; expected linear perf.
|
||||
template < class __instype, class __valuector >
|
||||
__instype * median_partition(__instype * first, __instype * last,
|
||||
int dim, __valuector ctor) {
|
||||
assert(last - first > 0);
|
||||
__instype *k = first + (last - first) / 2;
|
||||
median_partition(first, last, k, dim, ctor);
|
||||
return k;
|
||||
}
|
||||
|
||||
template < class __instype, class __valuector >
|
||||
struct median_pr {
|
||||
const __instype & pivot;
|
||||
int dim;
|
||||
__deref deref;
|
||||
__valuector ctor;
|
||||
median_pr(const __instype & _pivot, int _dim, __deref _deref, __valuector _ctor)
|
||||
: pivot(_pivot), dim(_dim), deref(_deref), ctor(_ctor) {
|
||||
}
|
||||
bool operator() (const __instype & lhs) const {
|
||||
return deref(ctor(lhs), dim) <= deref(ctor(pivot), dim);
|
||||
}
|
||||
};
|
||||
|
||||
template < class __instype, class __valuector >
|
||||
void median_partition(__instype * first, __instype * last,
|
||||
__instype * k, int dim, __valuector ctor) {
|
||||
int pivot = (int)((last - first) / 2);
|
||||
|
||||
std::swap(first[pivot], last[-1]);
|
||||
__instype *middle = std::partition(first, last - 1,
|
||||
median_pr < __instype, __valuector >
|
||||
(last[-1], dim, deref, ctor));
|
||||
std::swap(*middle, last[-1]);
|
||||
|
||||
if (middle < k)
|
||||
median_partition(middle + 1, last, k, dim, ctor);
|
||||
else if (middle > k)
|
||||
median_partition(first, middle, k, dim, ctor);
|
||||
}
|
||||
|
||||
// insert given points into the tree; return created node
|
||||
template < class __instype, class __valuector >
|
||||
int insert(__instype * first, __instype * last, __valuector ctor) {
|
||||
if (first == last)
|
||||
return -1;
|
||||
else {
|
||||
|
||||
int dim = dimension_of_highest_variance(first, last, ctor);
|
||||
__instype *median = median_partition(first, last, dim, ctor);
|
||||
|
||||
__instype *split = median;
|
||||
for (; split != last && deref(ctor(*split), dim) ==
|
||||
deref(ctor(*median), dim); ++split);
|
||||
|
||||
if (split == last) { // leaf
|
||||
int nexti = -1;
|
||||
for (--split; split >= first; --split) {
|
||||
int i = (int)nodes.size();
|
||||
node & n = *nodes.insert(nodes.end(), node());
|
||||
n.dim = -1;
|
||||
n.value = ctor(*split);
|
||||
n.left = -1;
|
||||
n.right = nexti;
|
||||
nexti = i;
|
||||
}
|
||||
|
||||
return nexti;
|
||||
} else { // node
|
||||
int i = (int)nodes.size();
|
||||
// note that recursive insert may invalidate this ref
|
||||
node & n = *nodes.insert(nodes.end(), node());
|
||||
|
||||
n.dim = dim;
|
||||
n.boundary = deref(ctor(*median), dim);
|
||||
|
||||
int left = insert(first, split, ctor);
|
||||
nodes[i].left = left;
|
||||
int right = insert(split, last, ctor);
|
||||
nodes[i].right = right;
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run to leaf; linear search for p;
|
||||
// if found, remove paths to empty leaves on unwind
|
||||
bool remove(int *i, const __valuetype & p) {
|
||||
if (*i == -1)
|
||||
return false;
|
||||
node & n = nodes[*i];
|
||||
bool r;
|
||||
|
||||
if (n.dim >= 0) { // node
|
||||
if (deref(p, n.dim) <= n.boundary) // left
|
||||
r = remove(&n.left, p);
|
||||
else // right
|
||||
r = remove(&n.right, p);
|
||||
|
||||
// if terminal, remove this node
|
||||
if (n.left == -1 && n.right == -1)
|
||||
*i = -1;
|
||||
|
||||
return r;
|
||||
} else { // leaf
|
||||
if (n.value == p) {
|
||||
*i = n.right;
|
||||
return true;
|
||||
} else
|
||||
return remove(&n.right, p);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
struct identity_ctor {
|
||||
const __valuetype & operator() (const __valuetype & rhs) const {
|
||||
return rhs;
|
||||
}
|
||||
};
|
||||
|
||||
// initialize an empty tree
|
||||
CvKDTree(__deref _deref = __deref())
|
||||
: deref(_deref), root_node(-1) {
|
||||
}
|
||||
// given points, initialize a balanced tree
|
||||
CvKDTree(__valuetype * first, __valuetype * last, int _point_dim,
|
||||
__deref _deref = __deref())
|
||||
: deref(_deref) {
|
||||
set_data(first, last, _point_dim, identity_ctor());
|
||||
}
|
||||
// given points, initialize a balanced tree
|
||||
template < class __instype, class __valuector >
|
||||
CvKDTree(__instype * first, __instype * last, int _point_dim,
|
||||
__valuector ctor, __deref _deref = __deref())
|
||||
: deref(_deref) {
|
||||
set_data(first, last, _point_dim, ctor);
|
||||
}
|
||||
|
||||
void set_deref(__deref _deref) {
|
||||
deref = _deref;
|
||||
}
|
||||
|
||||
void set_data(__valuetype * first, __valuetype * last, int _point_dim) {
|
||||
set_data(first, last, _point_dim, identity_ctor());
|
||||
}
|
||||
template < class __instype, class __valuector >
|
||||
void set_data(__instype * first, __instype * last, int _point_dim,
|
||||
__valuector ctor) {
|
||||
point_dim = _point_dim;
|
||||
nodes.clear();
|
||||
nodes.reserve(last - first);
|
||||
root_node = insert(first, last, ctor);
|
||||
}
|
||||
|
||||
int dims() const {
|
||||
return point_dim;
|
||||
}
|
||||
|
||||
// remove the given point
|
||||
bool remove(const __valuetype & p) {
|
||||
return remove(&root_node, p);
|
||||
}
|
||||
|
||||
void print() const {
|
||||
print(root_node);
|
||||
}
|
||||
void print(int i, int indent = 0) const {
|
||||
if (i == -1)
|
||||
return;
|
||||
for (int j = 0; j < indent; ++j)
|
||||
std::cout << " ";
|
||||
const node & n = nodes[i];
|
||||
if (n.dim >= 0) {
|
||||
std::cout << "node " << i << ", left " << nodes[i].left << ", right " <<
|
||||
nodes[i].right << ", dim " << nodes[i].dim << ", boundary " <<
|
||||
nodes[i].boundary << std::endl;
|
||||
print(n.left, indent + 3);
|
||||
print(n.right, indent + 3);
|
||||
} else
|
||||
std::cout << "leaf " << i << ", value = " << nodes[i].value << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// bbf search
|
||||
public:
|
||||
struct bbf_nn { // info on found neighbors (approx k nearest)
|
||||
const __valuetype *p; // nearest neighbor
|
||||
accum_type dist; // distance from d to query point
|
||||
bbf_nn(const __valuetype & _p, accum_type _dist)
|
||||
: p(&_p), dist(_dist) {
|
||||
}
|
||||
bool operator<(const bbf_nn & rhs) const {
|
||||
return dist < rhs.dist;
|
||||
}
|
||||
};
|
||||
typedef std::vector < bbf_nn > bbf_nn_pqueue;
|
||||
private:
|
||||
struct bbf_node { // info on branches not taken
|
||||
int node; // corresponding node
|
||||
accum_type dist; // minimum distance from bounds to query point
|
||||
bbf_node(int _node, accum_type _dist)
|
||||
: node(_node), dist(_dist) {
|
||||
}
|
||||
bool operator<(const bbf_node & rhs) const {
|
||||
return dist > rhs.dist;
|
||||
}
|
||||
};
|
||||
typedef std::vector < bbf_node > bbf_pqueue;
|
||||
mutable bbf_pqueue tmp_pq;
|
||||
|
||||
// called for branches not taken, as bbf walks to leaf;
|
||||
// construct bbf_node given minimum distance to bounds of alternate branch
|
||||
void pq_alternate(int alt_n, bbf_pqueue & pq, scalar_type dist) const {
|
||||
if (alt_n == -1)
|
||||
return;
|
||||
|
||||
// add bbf_node for alternate branch in priority queue
|
||||
pq.push_back(bbf_node(alt_n, dist));
|
||||
std::push_heap(pq.begin(), pq.end());
|
||||
}
|
||||
|
||||
// called by bbf to walk to leaf;
|
||||
// takes one step down the tree towards query point d
|
||||
template < class __desctype >
|
||||
int bbf_branch(int i, const __desctype * d, bbf_pqueue & pq) const {
|
||||
const node & n = nodes[i];
|
||||
// push bbf_node with bounds of alternate branch, then branch
|
||||
if (d[n.dim] <= n.boundary) { // left
|
||||
pq_alternate(n.right, pq, n.boundary - d[n.dim]);
|
||||
return n.left;
|
||||
} else { // right
|
||||
pq_alternate(n.left, pq, d[n.dim] - n.boundary);
|
||||
return n.right;
|
||||
}
|
||||
}
|
||||
|
||||
// compute euclidean distance between two points
|
||||
template < class __desctype >
|
||||
accum_type distance(const __desctype * d, const __valuetype & p) const {
|
||||
accum_type dist = 0;
|
||||
for (int j = 0; j < point_dim; ++j) {
|
||||
accum_type diff = accum_type(d[j]) - accum_type(deref(p, j));
|
||||
dist += diff * diff;
|
||||
} return (accum_type) sqrt(dist);
|
||||
}
|
||||
|
||||
// called per candidate nearest neighbor; constructs new bbf_nn for
|
||||
// candidate and adds it to priority queue of all candidates; if
|
||||
// queue len exceeds k, drops the point furthest from query point d.
|
||||
template < class __desctype >
|
||||
void bbf_new_nn(bbf_nn_pqueue & nn_pq, int k,
|
||||
const __desctype * d, const __valuetype & p) const {
|
||||
bbf_nn nn(p, distance(d, p));
|
||||
if ((int) nn_pq.size() < k) {
|
||||
nn_pq.push_back(nn);
|
||||
std::push_heap(nn_pq.begin(), nn_pq.end());
|
||||
} else if (nn_pq[0].dist > nn.dist) {
|
||||
std::pop_heap(nn_pq.begin(), nn_pq.end());
|
||||
nn_pq.end()[-1] = nn;
|
||||
std::push_heap(nn_pq.begin(), nn_pq.end());
|
||||
}
|
||||
assert(nn_pq.size() < 2 || nn_pq[0].dist >= nn_pq[1].dist);
|
||||
}
|
||||
|
||||
public:
|
||||
// finds (with high probability) the k nearest neighbors of d,
|
||||
// searching at most emax leaves/bins.
|
||||
// ret_nn_pq is an array containing the (at most) k nearest neighbors
|
||||
// (see bbf_nn structure def above).
|
||||
template < class __desctype >
|
||||
int find_nn_bbf(const __desctype * d,
|
||||
int k, int emax,
|
||||
bbf_nn_pqueue & ret_nn_pq) const {
|
||||
assert(k > 0);
|
||||
ret_nn_pq.clear();
|
||||
|
||||
if (root_node == -1)
|
||||
return 0;
|
||||
|
||||
// add root_node to bbf_node priority queue;
|
||||
// iterate while queue non-empty and emax>0
|
||||
tmp_pq.clear();
|
||||
tmp_pq.push_back(bbf_node(root_node, 0));
|
||||
while (tmp_pq.size() && emax > 0) {
|
||||
|
||||
// from node nearest query point d, run to leaf
|
||||
std::pop_heap(tmp_pq.begin(), tmp_pq.end());
|
||||
bbf_node bbf(tmp_pq.end()[-1]);
|
||||
tmp_pq.erase(tmp_pq.end() - 1);
|
||||
|
||||
int i;
|
||||
for (i = bbf.node;
|
||||
i != -1 && nodes[i].dim >= 0;
|
||||
i = bbf_branch(i, d, tmp_pq));
|
||||
|
||||
if (i != -1) {
|
||||
|
||||
// add points in leaf/bin to ret_nn_pq
|
||||
do {
|
||||
bbf_new_nn(ret_nn_pq, k, d, nodes[i].value);
|
||||
} while (-1 != (i = nodes[i].right));
|
||||
|
||||
--emax;
|
||||
}
|
||||
}
|
||||
|
||||
tmp_pq.clear();
|
||||
return (int)ret_nn_pq.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// orthogonal range search
|
||||
private:
|
||||
void find_ortho_range(int i, scalar_type * bounds_min,
|
||||
scalar_type * bounds_max,
|
||||
std::vector < __valuetype > &inbounds) const {
|
||||
if (i == -1)
|
||||
return;
|
||||
const node & n = nodes[i];
|
||||
if (n.dim >= 0) { // node
|
||||
if (bounds_min[n.dim] <= n.boundary)
|
||||
find_ortho_range(n.left, bounds_min, bounds_max, inbounds);
|
||||
if (bounds_max[n.dim] > n.boundary)
|
||||
find_ortho_range(n.right, bounds_min, bounds_max, inbounds);
|
||||
} else { // leaf
|
||||
do {
|
||||
inbounds.push_back(nodes[i].value);
|
||||
} while (-1 != (i = nodes[i].right));
|
||||
}
|
||||
}
|
||||
public:
|
||||
// return all points that lie within the given bounds; inbounds is cleared
|
||||
int find_ortho_range(scalar_type * bounds_min,
|
||||
scalar_type * bounds_max,
|
||||
std::vector < __valuetype > &inbounds) const {
|
||||
inbounds.clear();
|
||||
find_ortho_range(root_node, bounds_min, bounds_max, inbounds);
|
||||
return (int)inbounds.size();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __cv_kdtree_h__
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
@@ -1,64 +0,0 @@
|
||||
//M*//////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "_featuretree.h"
|
||||
|
||||
void cvReleaseFeatureTree(CvFeatureTree* tr)
|
||||
{
|
||||
delete tr;
|
||||
}
|
||||
|
||||
// desc is m x d set of candidate points.
|
||||
// results is m x k set of row indices of matching points.
|
||||
// dist is m x k distance to matching points.
|
||||
void cvFindFeatures(CvFeatureTree* tr, const CvMat* desc,
|
||||
CvMat* results, CvMat* dist, int k, int emax)
|
||||
{
|
||||
tr->FindFeatures(desc, k, emax, results, dist);
|
||||
}
|
||||
|
||||
int cvFindFeaturesBoxed(CvFeatureTree* tr,
|
||||
CvMat* bounds_min, CvMat* bounds_max,
|
||||
CvMat* results)
|
||||
{
|
||||
return tr->FindOrthoRange(bounds_min, bounds_max, results);
|
||||
}
|
||||
@@ -108,22 +108,6 @@ icvIntersectLines( double x1, double dx1, double y1, double dy1,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
icvCreateCenterNormalLine( CvSubdiv2DEdge edge, double *_a, double *_b, double *_c )
|
||||
{
|
||||
CvPoint2D32f org = cvSubdiv2DEdgeOrg( edge )->pt;
|
||||
CvPoint2D32f dst = cvSubdiv2DEdgeDst( edge )->pt;
|
||||
|
||||
double a = dst.x - org.x;
|
||||
double b = dst.y - org.y;
|
||||
double c = -(a * (dst.x + org.x) + b * (dst.y + org.y));
|
||||
|
||||
*_a = a + a;
|
||||
*_b = b + b;
|
||||
*_c = c;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
icvIntersectLines3( double *a0, double *b0, double *c0,
|
||||
double *a1, double *b1, double *c1, CvPoint2D32f * point )
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2008, Xavier Delacour, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
// 2008-05-13, Xavier Delacour <xavier.delacour@gmail.com>
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#if !defined _MSC_VER || defined __ICL || _MSC_VER >= 1300
|
||||
|
||||
#include "_kdtree.hpp"
|
||||
#include "_featuretree.h"
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
#pragma warning(disable:4996) // suppress "function call with parameters may be unsafe" in std::copy
|
||||
#endif
|
||||
|
||||
class CvKDTreeWrap : public CvFeatureTree {
|
||||
template <class __scalartype, int __cvtype>
|
||||
struct deref {
|
||||
typedef __scalartype scalar_type;
|
||||
typedef double accum_type;
|
||||
|
||||
CvMat* mat;
|
||||
deref(CvMat* _mat) : mat(_mat) {
|
||||
assert(CV_ELEM_SIZE1(__cvtype) == sizeof(__scalartype));
|
||||
}
|
||||
scalar_type operator() (int i, int j) const {
|
||||
return *((scalar_type*)(mat->data.ptr + i * mat->step) + j);
|
||||
}
|
||||
};
|
||||
|
||||
#define dispatch_cvtype(mat, c) \
|
||||
switch (CV_MAT_DEPTH((mat)->type)) { \
|
||||
case CV_32F: \
|
||||
{ typedef CvKDTree<int, deref<float, CV_32F> > tree_type; c; break; } \
|
||||
case CV_64F: \
|
||||
{ typedef CvKDTree<int, deref<double, CV_64F> > tree_type; c; break; } \
|
||||
default: assert(0); \
|
||||
}
|
||||
|
||||
CvMat* mat;
|
||||
void* data;
|
||||
|
||||
template <class __treetype>
|
||||
void find_nn(const CvMat* d, int k, int emax, CvMat* results, CvMat* dist) {
|
||||
__treetype* tr = (__treetype*) data;
|
||||
const uchar* dptr = d->data.ptr;
|
||||
uchar* resultsptr = results->data.ptr;
|
||||
uchar* distptr = dist->data.ptr;
|
||||
typename __treetype::bbf_nn_pqueue nn;
|
||||
|
||||
assert(d->cols == tr->dims());
|
||||
assert(results->rows == d->rows);
|
||||
assert(results->rows == dist->rows);
|
||||
assert(results->cols == k);
|
||||
assert(dist->cols == k);
|
||||
|
||||
for (int j = 0; j < d->rows; ++j) {
|
||||
const typename __treetype::scalar_type* dj =
|
||||
(const typename __treetype::scalar_type*) dptr;
|
||||
|
||||
int* resultsj = (int*) resultsptr;
|
||||
double* distj = (double*) distptr;
|
||||
tr->find_nn_bbf(dj, k, emax, nn);
|
||||
|
||||
assert((int)nn.size() <= k);
|
||||
for (unsigned int j = 0; j < nn.size(); ++j) {
|
||||
*resultsj++ = *nn[j].p;
|
||||
*distj++ = nn[j].dist;
|
||||
}
|
||||
std::fill(resultsj, resultsj + k - nn.size(), -1);
|
||||
std::fill(distj, distj + k - nn.size(), 0);
|
||||
|
||||
dptr += d->step;
|
||||
resultsptr += results->step;
|
||||
distptr += dist->step;
|
||||
}
|
||||
}
|
||||
|
||||
template <class __treetype>
|
||||
int find_ortho_range(CvMat* bounds_min, CvMat* bounds_max,
|
||||
CvMat* results) {
|
||||
int rn = results->rows * results->cols;
|
||||
std::vector<int> inbounds;
|
||||
dispatch_cvtype(mat, ((__treetype*)data)->
|
||||
find_ortho_range((typename __treetype::scalar_type*)bounds_min->data.ptr,
|
||||
(typename __treetype::scalar_type*)bounds_max->data.ptr,
|
||||
inbounds));
|
||||
std::copy(inbounds.begin(),
|
||||
inbounds.begin() + std::min((int)inbounds.size(), rn),
|
||||
(int*) results->data.ptr);
|
||||
return (int)inbounds.size();
|
||||
}
|
||||
|
||||
CvKDTreeWrap(const CvKDTreeWrap& x);
|
||||
CvKDTreeWrap& operator= (const CvKDTreeWrap& rhs);
|
||||
public:
|
||||
CvKDTreeWrap(CvMat* _mat) : mat(_mat) {
|
||||
// * a flag parameter should tell us whether
|
||||
// * (a) user ensures *mat outlives *this and is unchanged,
|
||||
// * (b) we take reference and user ensures mat is unchanged,
|
||||
// * (c) we copy data, (d) we own and release data.
|
||||
|
||||
std::vector<int> tmp(mat->rows);
|
||||
for (unsigned int j = 0; j < tmp.size(); ++j)
|
||||
tmp[j] = j;
|
||||
|
||||
dispatch_cvtype(mat, data = new tree_type
|
||||
(&tmp[0], &tmp[0] + tmp.size(), mat->cols,
|
||||
tree_type::deref_type(mat)));
|
||||
}
|
||||
~CvKDTreeWrap() {
|
||||
dispatch_cvtype(mat, delete (tree_type*) data);
|
||||
}
|
||||
|
||||
int dims() {
|
||||
int d = 0;
|
||||
dispatch_cvtype(mat, d = ((tree_type*) data)->dims());
|
||||
return d;
|
||||
}
|
||||
int type() {
|
||||
return mat->type;
|
||||
}
|
||||
|
||||
void FindFeatures(const CvMat* desc, int k, int emax, CvMat* results, CvMat* dist) {
|
||||
cv::Ptr<CvMat> tmp_desc;
|
||||
|
||||
if (desc->cols != dims())
|
||||
CV_Error(CV_StsUnmatchedSizes, "desc columns be equal feature dimensions");
|
||||
if (results->rows != desc->rows && results->cols != k)
|
||||
CV_Error(CV_StsUnmatchedSizes, "results and desc must be same height");
|
||||
if (dist->rows != desc->rows && dist->cols != k)
|
||||
CV_Error(CV_StsUnmatchedSizes, "dist and desc must be same height");
|
||||
if (CV_MAT_TYPE(results->type) != CV_32SC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "results must be CV_32SC1");
|
||||
if (CV_MAT_TYPE(dist->type) != CV_64FC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "dist must be CV_64FC1");
|
||||
|
||||
if (CV_MAT_TYPE(type()) != CV_MAT_TYPE(desc->type)) {
|
||||
tmp_desc = cvCreateMat(desc->rows, desc->cols, type());
|
||||
cvConvert(desc, tmp_desc);
|
||||
desc = tmp_desc;
|
||||
}
|
||||
|
||||
assert(CV_MAT_TYPE(desc->type) == CV_MAT_TYPE(mat->type));
|
||||
assert(CV_MAT_TYPE(dist->type) == CV_64FC1);
|
||||
assert(CV_MAT_TYPE(results->type) == CV_32SC1);
|
||||
|
||||
dispatch_cvtype(mat, find_nn<tree_type>
|
||||
(desc, k, emax, results, dist));
|
||||
}
|
||||
int FindOrthoRange(CvMat* bounds_min, CvMat* bounds_max,
|
||||
CvMat* results) {
|
||||
bool free_bounds = false;
|
||||
int count = -1;
|
||||
|
||||
if (bounds_min->cols * bounds_min->rows != dims() ||
|
||||
bounds_max->cols * bounds_max->rows != dims())
|
||||
CV_Error(CV_StsUnmatchedSizes, "bounds_{min,max} must 1 x dims or dims x 1");
|
||||
if (CV_MAT_TYPE(bounds_min->type) != CV_MAT_TYPE(bounds_max->type))
|
||||
CV_Error(CV_StsUnmatchedFormats, "bounds_{min,max} must have same type");
|
||||
if (CV_MAT_TYPE(results->type) != CV_32SC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "results must be CV_32SC1");
|
||||
|
||||
if (CV_MAT_TYPE(bounds_min->type) != CV_MAT_TYPE(type())) {
|
||||
free_bounds = true;
|
||||
|
||||
CvMat* old_bounds_min = bounds_min;
|
||||
bounds_min = cvCreateMat(bounds_min->rows, bounds_min->cols, type());
|
||||
cvConvert(old_bounds_min, bounds_min);
|
||||
|
||||
CvMat* old_bounds_max = bounds_max;
|
||||
bounds_max = cvCreateMat(bounds_max->rows, bounds_max->cols, type());
|
||||
cvConvert(old_bounds_max, bounds_max);
|
||||
}
|
||||
|
||||
assert(CV_MAT_TYPE(bounds_min->type) == CV_MAT_TYPE(mat->type));
|
||||
assert(CV_MAT_TYPE(bounds_min->type) == CV_MAT_TYPE(bounds_max->type));
|
||||
assert(bounds_min->rows * bounds_min->cols == dims());
|
||||
assert(bounds_max->rows * bounds_max->cols == dims());
|
||||
|
||||
dispatch_cvtype(mat, count = find_ortho_range<tree_type>
|
||||
(bounds_min, bounds_max,results));
|
||||
|
||||
if (free_bounds) {
|
||||
cvReleaseMat(&bounds_min);
|
||||
cvReleaseMat(&bounds_max);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
CvFeatureTree* cvCreateKDTree(CvMat* desc) {
|
||||
|
||||
if (CV_MAT_TYPE(desc->type) != CV_32FC1 &&
|
||||
CV_MAT_TYPE(desc->type) != CV_64FC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "descriptors must be either CV_32FC1 or CV_64FC1");
|
||||
|
||||
return new CvKDTreeWrap(desc);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,454 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2009, Xavier Delacour, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
// 2009-01-12, Xavier Delacour <xavier.delacour@gmail.com>
|
||||
|
||||
|
||||
// * hash perf could be improved
|
||||
// * in particular, implement integer only (converted fixed from float input)
|
||||
|
||||
// * number of hash functions could be reduced (andoni paper)
|
||||
|
||||
// * redundant distance computations could be suppressed
|
||||
|
||||
// * rework CvLSHOperations interface-- move some of the loops into it to
|
||||
// * allow efficient async storage
|
||||
|
||||
|
||||
// Datar, M., Immorlica, N., Indyk, P., and Mirrokni, V. S. 2004. Locality-sensitive hashing
|
||||
// scheme based on p-stable distributions. In Proceedings of the Twentieth Annual Symposium on
|
||||
// Computational Geometry (Brooklyn, New York, USA, June 08 - 11, 2004). SCG '04. ACM, New York,
|
||||
// NY, 253-262. DOI= http://doi.acm.org/10.1145/997817.997857
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
template <class T>
|
||||
class memory_hash_ops : public CvLSHOperations {
|
||||
int d;
|
||||
std::vector<T> data;
|
||||
std::vector<int> free_data;
|
||||
struct node {
|
||||
int i, h2, next;
|
||||
};
|
||||
std::vector<node> nodes;
|
||||
std::vector<int> free_nodes;
|
||||
std::vector<int> bins;
|
||||
|
||||
public:
|
||||
memory_hash_ops(int _d, int n) : d(_d) {
|
||||
bins.resize(n, -1);
|
||||
}
|
||||
|
||||
virtual int vector_add(const void* _p) {
|
||||
const T* p = (const T*)_p;
|
||||
int i;
|
||||
if (free_data.empty()) {
|
||||
i = (int)data.size();
|
||||
data.insert(data.end(), d, 0);
|
||||
} else {
|
||||
i = free_data.end()[-1];
|
||||
free_data.pop_back();
|
||||
}
|
||||
std::copy(p, p + d, data.begin() + i);
|
||||
return i / d;
|
||||
}
|
||||
virtual void vector_remove(int i) {
|
||||
free_data.push_back(i * d);
|
||||
}
|
||||
virtual const void* vector_lookup(int i) {
|
||||
return &data[i * d];
|
||||
}
|
||||
virtual void vector_reserve(int n) {
|
||||
data.reserve(n * d);
|
||||
}
|
||||
virtual unsigned int vector_count() {
|
||||
return (unsigned)(data.size() / d - free_data.size());
|
||||
}
|
||||
|
||||
virtual void hash_insert(lsh_hash h, int /*l*/, int i) {
|
||||
int ii;
|
||||
if (free_nodes.empty()) {
|
||||
ii = (int)nodes.size();
|
||||
nodes.push_back(node());
|
||||
} else {
|
||||
ii = free_nodes.end()[-1];
|
||||
free_nodes.pop_back();
|
||||
}
|
||||
node& n = nodes[ii];
|
||||
int h1 = (int)(h.h1 % bins.size());
|
||||
n.i = i;
|
||||
n.h2 = h.h2;
|
||||
n.next = bins[h1];
|
||||
bins[h1] = ii;
|
||||
}
|
||||
virtual void hash_remove(lsh_hash h, int /*l*/, int i) {
|
||||
int h1 = (int)(h.h1 % bins.size());
|
||||
for (int ii = bins[h1], iin, iip = -1; ii != -1; iip = ii, ii = iin) {
|
||||
iin = nodes[ii].next;
|
||||
if (nodes[ii].h2 == h.h2 && nodes[ii].i == i) {
|
||||
free_nodes.push_back(ii);
|
||||
if (iip == -1)
|
||||
bins[h1] = iin;
|
||||
else
|
||||
nodes[iip].next = iin;
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual int hash_lookup(lsh_hash h, int /*l*/, int* ret_i, int ret_i_max) {
|
||||
int h1 = (int)(h.h1 % bins.size());
|
||||
int k = 0;
|
||||
for (int ii = bins[h1]; ii != -1 && k < ret_i_max; ii = nodes[ii].next)
|
||||
if (nodes[ii].h2 == h.h2)
|
||||
ret_i[k++] = nodes[ii].i;
|
||||
return k;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T,int cvtype>
|
||||
class pstable_l2_func {
|
||||
CvMat *a, *b, *r1, *r2;
|
||||
int d, k;
|
||||
double r;
|
||||
pstable_l2_func(const pstable_l2_func& x);
|
||||
pstable_l2_func& operator= (const pstable_l2_func& rhs);
|
||||
public:
|
||||
typedef T scalar_type;
|
||||
typedef T accum_type;
|
||||
pstable_l2_func(int _d, int _k, double _r, CvRNG& rng)
|
||||
: d(_d), k(_k), r(_r) {
|
||||
assert(sizeof(T) == CV_ELEM_SIZE1(cvtype));
|
||||
a = cvCreateMat(k, d, cvtype);
|
||||
b = cvCreateMat(k, 1, cvtype);
|
||||
r1 = cvCreateMat(k, 1, CV_32SC1);
|
||||
r2 = cvCreateMat(k, 1, CV_32SC1);
|
||||
cvRandArr(&rng, a, CV_RAND_NORMAL, cvScalar(0), cvScalar(1));
|
||||
cvRandArr(&rng, b, CV_RAND_UNI, cvScalar(0), cvScalar(r));
|
||||
cvRandArr(&rng, r1, CV_RAND_UNI,
|
||||
cvScalar(std::numeric_limits<int>::min()),
|
||||
cvScalar(std::numeric_limits<int>::max()));
|
||||
cvRandArr(&rng, r2, CV_RAND_UNI,
|
||||
cvScalar(std::numeric_limits<int>::min()),
|
||||
cvScalar(std::numeric_limits<int>::max()));
|
||||
}
|
||||
~pstable_l2_func() {
|
||||
cvReleaseMat(&a);
|
||||
cvReleaseMat(&b);
|
||||
cvReleaseMat(&r1);
|
||||
cvReleaseMat(&r2);
|
||||
}
|
||||
|
||||
// * factor all L functions into this (reduces number of matrices to 4 total;
|
||||
// * simpler syntax in lsh_table). give parameter l here that tells us which
|
||||
// * row to use etc.
|
||||
|
||||
lsh_hash operator() (const T* x) const {
|
||||
const T* aj = (const T*)a->data.ptr;
|
||||
const T* bj = (const T*)b->data.ptr;
|
||||
|
||||
lsh_hash h;
|
||||
h.h1 = h.h2 = 0;
|
||||
for (int j = 0; j < k; ++j) {
|
||||
accum_type s = 0;
|
||||
for (int jj = 0; jj < d; ++jj)
|
||||
s += aj[jj] * x[jj];
|
||||
s += *bj;
|
||||
s = accum_type(s/r);
|
||||
int si = int(s);
|
||||
h.h1 += r1->data.i[j] * si;
|
||||
h.h2 += r2->data.i[j] * si;
|
||||
|
||||
aj += d;
|
||||
bj++;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
accum_type distance(const T* p, const T* q) const {
|
||||
accum_type s = 0;
|
||||
for (int j = 0; j < d; ++j) {
|
||||
accum_type d1 = p[j] - q[j];
|
||||
s += d1 * d1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
template <class H>
|
||||
class lsh_table {
|
||||
public:
|
||||
typedef typename H::scalar_type scalar_type;
|
||||
typedef typename H::accum_type accum_type;
|
||||
private:
|
||||
std::vector<H*> g;
|
||||
CvLSHOperations* ops;
|
||||
int d, L, k;
|
||||
double r;
|
||||
|
||||
static accum_type comp_dist(const std::pair<int,accum_type>& x,
|
||||
const std::pair<int,accum_type>& y) {
|
||||
return x.second < y.second;
|
||||
}
|
||||
|
||||
lsh_table(const lsh_table& x);
|
||||
lsh_table& operator= (const lsh_table& rhs);
|
||||
public:
|
||||
lsh_table(CvLSHOperations* _ops, int _d, int Lval, int _k, double _r, CvRNG& rng)
|
||||
: ops(_ops), d(_d), L(Lval), k(_k), r(_r) {
|
||||
g.resize(L);
|
||||
for (int j = 0; j < L; ++j)
|
||||
g[j] = new H(d, k, r, rng);
|
||||
}
|
||||
~lsh_table() {
|
||||
for (int j = 0; j < L; ++j)
|
||||
delete g[j];
|
||||
delete ops;
|
||||
}
|
||||
|
||||
int dims() const {
|
||||
return d;
|
||||
}
|
||||
unsigned int size() const {
|
||||
return ops->vector_count();
|
||||
}
|
||||
|
||||
void add(const scalar_type* data, int n, int* ret_indices = 0) {
|
||||
for (int j=0;j<n;++j) {
|
||||
const scalar_type* x = data+j*d;
|
||||
int i = ops->vector_add(x);
|
||||
if (ret_indices)
|
||||
ret_indices[j] = i;
|
||||
|
||||
for (int l = 0; l < L; ++l) {
|
||||
lsh_hash h = (*g[l])(x);
|
||||
ops->hash_insert(h, l, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
void remove(const int* indices, int n) {
|
||||
for (int j = 0; j < n; ++j) {
|
||||
int i = indices[n];
|
||||
const scalar_type* x = (const scalar_type*)ops->vector_lookup(i);
|
||||
|
||||
for (int l = 0; l < L; ++l) {
|
||||
lsh_hash h = (*g[l])(x);
|
||||
ops->hash_remove(h, l, i);
|
||||
}
|
||||
ops->vector_remove(i);
|
||||
}
|
||||
}
|
||||
void query(const scalar_type* q, int k0, int emax, double* dist, int* results) {
|
||||
cv::AutoBuffer<int> tmp(emax);
|
||||
typedef std::pair<int, accum_type> dr_type; // * swap int and accum_type here, for naming consistency
|
||||
cv::AutoBuffer<dr_type> dr(k0);
|
||||
int k1 = 0;
|
||||
|
||||
// * handle k0 >= emax, in which case don't track max distance
|
||||
|
||||
for (int l = 0; l < L && emax > 0; ++l) {
|
||||
lsh_hash h = (*g[l])(q);
|
||||
int m = ops->hash_lookup(h, l, tmp, emax);
|
||||
for (int j = 0; j < m && emax > 0; ++j, --emax) {
|
||||
int i = tmp[j];
|
||||
const scalar_type* p = (const scalar_type*)ops->vector_lookup(i);
|
||||
accum_type pd = (*g[l]).distance(p, q);
|
||||
if (k1 < k0) {
|
||||
dr[k1++] = std::make_pair(i, pd);
|
||||
std::push_heap(&dr[0], &dr[k1], comp_dist);
|
||||
} else if (pd < dr[0].second) {
|
||||
std::pop_heap(&dr[0], &dr[k0], comp_dist);
|
||||
dr[k0 - 1] = std::make_pair(i, pd);
|
||||
std::push_heap(&dr[0], &dr[k0], comp_dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < k1; ++j)
|
||||
dist[j] = dr[j].second, results[j] = dr[j].first;
|
||||
std::fill(dist + k1, dist + k0, 0);
|
||||
std::fill(results + k1, results + k0, -1);
|
||||
}
|
||||
void query(const scalar_type* data, int n, int k0, int emax, double* dist, int* results) {
|
||||
for (int j = 0; j < n; ++j) {
|
||||
query(data, k0, emax, dist, results);
|
||||
data += d; // * this may not agree with step for some scalar_types
|
||||
dist += k0;
|
||||
results += k0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef lsh_table<pstable_l2_func<float, CV_32FC1> > lsh_pstable_l2_32f;
|
||||
typedef lsh_table<pstable_l2_func<double, CV_64FC1> > lsh_pstable_l2_64f;
|
||||
|
||||
struct CvLSH {
|
||||
int type;
|
||||
union {
|
||||
lsh_pstable_l2_32f* lsh_32f;
|
||||
lsh_pstable_l2_64f* lsh_64f;
|
||||
} u;
|
||||
};
|
||||
|
||||
CvLSH* cvCreateLSH(CvLSHOperations* ops, int d, int L, int k, int type, double r, int64 seed) {
|
||||
CvLSH* lsh = 0;
|
||||
CvRNG rng = cvRNG(seed);
|
||||
|
||||
if (type != CV_32FC1 && type != CV_64FC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "vectors must be either CV_32FC1 or CV_64FC1");
|
||||
lsh = new CvLSH;
|
||||
lsh->type = type;
|
||||
switch (type) {
|
||||
case CV_32FC1: lsh->u.lsh_32f = new lsh_pstable_l2_32f(ops, d, L, k, r, rng); break;
|
||||
case CV_64FC1: lsh->u.lsh_64f = new lsh_pstable_l2_64f(ops, d, L, k, r, rng); break;
|
||||
}
|
||||
|
||||
return lsh;
|
||||
}
|
||||
|
||||
CvLSH* cvCreateMemoryLSH(int d, int n, int L, int k, int type, double r, int64 seed) {
|
||||
CvLSHOperations* ops = 0;
|
||||
|
||||
switch (type) {
|
||||
case CV_32FC1: ops = new memory_hash_ops<float>(d,n); break;
|
||||
case CV_64FC1: ops = new memory_hash_ops<double>(d,n); break;
|
||||
}
|
||||
return cvCreateLSH(ops, d, L, k, type, r, seed);
|
||||
}
|
||||
|
||||
void cvReleaseLSH(CvLSH** lsh) {
|
||||
switch ((*lsh)->type) {
|
||||
case CV_32FC1: delete (*lsh)->u.lsh_32f; break;
|
||||
case CV_64FC1: delete (*lsh)->u.lsh_64f; break;
|
||||
default: assert(0);
|
||||
}
|
||||
delete *lsh;
|
||||
*lsh = 0;
|
||||
}
|
||||
|
||||
unsigned int LSHSize(CvLSH* lsh) {
|
||||
switch (lsh->type) {
|
||||
case CV_32FC1: return lsh->u.lsh_32f->size(); break;
|
||||
case CV_64FC1: return lsh->u.lsh_64f->size(); break;
|
||||
default: assert(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void cvLSHAdd(CvLSH* lsh, const CvMat* data, CvMat* indices) {
|
||||
int dims, n;
|
||||
int* ret_indices = 0;
|
||||
|
||||
switch (lsh->type) {
|
||||
case CV_32FC1: dims = lsh->u.lsh_32f->dims(); break;
|
||||
case CV_64FC1: dims = lsh->u.lsh_64f->dims(); break;
|
||||
default: assert(0); return;
|
||||
}
|
||||
|
||||
n = data->rows;
|
||||
|
||||
if (dims != data->cols)
|
||||
CV_Error(CV_StsBadSize, "data must be n x d, where d is what was used to construct LSH");
|
||||
|
||||
if (CV_MAT_TYPE(data->type) != lsh->type)
|
||||
CV_Error(CV_StsUnsupportedFormat, "type of data and constructed LSH must agree");
|
||||
if (indices) {
|
||||
if (CV_MAT_TYPE(indices->type) != CV_32SC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "indices must be CV_32SC1");
|
||||
if (indices->rows * indices->cols != n)
|
||||
CV_Error(CV_StsBadSize, "indices must be n x 1 or 1 x n for n x d data");
|
||||
ret_indices = indices->data.i;
|
||||
}
|
||||
|
||||
switch (lsh->type) {
|
||||
case CV_32FC1: lsh->u.lsh_32f->add(data->data.fl, n, ret_indices); break;
|
||||
case CV_64FC1: lsh->u.lsh_64f->add(data->data.db, n, ret_indices); break;
|
||||
default: assert(0); return;
|
||||
}
|
||||
}
|
||||
|
||||
void cvLSHRemove(CvLSH* lsh, const CvMat* indices) {
|
||||
int n;
|
||||
|
||||
if (CV_MAT_TYPE(indices->type) != CV_32SC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "indices must be CV_32SC1");
|
||||
n = indices->rows * indices->cols;
|
||||
switch (lsh->type) {
|
||||
case CV_32FC1: lsh->u.lsh_32f->remove(indices->data.i, n); break;
|
||||
case CV_64FC1: lsh->u.lsh_64f->remove(indices->data.i, n); break;
|
||||
default: assert(0); return;
|
||||
}
|
||||
}
|
||||
|
||||
void cvLSHQuery(CvLSH* lsh, const CvMat* data, CvMat* indices, CvMat* dist, int k, int emax) {
|
||||
int dims;
|
||||
|
||||
switch (lsh->type) {
|
||||
case CV_32FC1: dims = lsh->u.lsh_32f->dims(); break;
|
||||
case CV_64FC1: dims = lsh->u.lsh_64f->dims(); break;
|
||||
default: assert(0); return;
|
||||
}
|
||||
|
||||
if (k<1)
|
||||
CV_Error(CV_StsOutOfRange, "k must be positive");
|
||||
if (CV_MAT_TYPE(data->type) != lsh->type)
|
||||
CV_Error(CV_StsUnsupportedFormat, "type of data and constructed LSH must agree");
|
||||
if (dims != data->cols)
|
||||
CV_Error(CV_StsBadSize, "data must be n x d, where d is what was used to construct LSH");
|
||||
if (dist->rows != data->rows || dist->cols != k)
|
||||
CV_Error(CV_StsBadSize, "dist must be n x k for n x d data");
|
||||
if (dist->rows != indices->rows || dist->cols != indices->cols)
|
||||
CV_Error(CV_StsBadSize, "dist and indices must be same size");
|
||||
if (CV_MAT_TYPE(dist->type) != CV_64FC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "dist must be CV_64FC1");
|
||||
if (CV_MAT_TYPE(indices->type) != CV_32SC1)
|
||||
CV_Error(CV_StsUnsupportedFormat, "indices must be CV_32SC1");
|
||||
|
||||
switch (lsh->type) {
|
||||
case CV_32FC1: lsh->u.lsh_32f->query(data->data.fl, data->rows,
|
||||
k, emax, dist->data.db, indices->data.i); break;
|
||||
case CV_64FC1: lsh->u.lsh_64f->query(data->data.db, data->rows,
|
||||
k, emax, dist->data.db, indices->data.i); break;
|
||||
default: assert(0); return;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,498 +0,0 @@
|
||||
/* Original code has been submitted by Liu Liu.
|
||||
----------------------------------------------------------------------------------
|
||||
* Spill-Tree for Approximate KNN Search
|
||||
* Author: Liu Liu
|
||||
* mailto: liuliu.1987+opencv@gmail.com
|
||||
* Refer to Paper:
|
||||
* An Investigation of Practical Approximate Nearest Neighbor Algorithms
|
||||
* cvMergeSpillTree TBD
|
||||
*
|
||||
* 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.
|
||||
* The name of Contributor may not be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE 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 "_featuretree.h"
|
||||
|
||||
struct CvSpillTreeNode
|
||||
{
|
||||
bool leaf; // is leaf or not (leaf is the point that have no more child)
|
||||
bool spill; // is not a non-overlapping point (defeatist search)
|
||||
CvSpillTreeNode* lc; // left child (<)
|
||||
CvSpillTreeNode* rc; // right child (>)
|
||||
int cc; // child count
|
||||
CvMat* u; // projection vector
|
||||
CvMat* center; // center
|
||||
int i; // original index
|
||||
double r; // radius of remaining feature point
|
||||
double ub; // upper bound
|
||||
double lb; // lower bound
|
||||
double mp; // mean point
|
||||
double p; // projection value
|
||||
};
|
||||
|
||||
struct CvSpillTree
|
||||
{
|
||||
CvSpillTreeNode* root;
|
||||
CvMat** refmat; // leaf ref matrix
|
||||
int total; // total leaves
|
||||
int naive; // under this value, we perform naive search
|
||||
int type; // mat type
|
||||
double rho; // under this value, it is a spill tree
|
||||
double tau; // the overlapping buffer ratio
|
||||
};
|
||||
|
||||
struct CvResult
|
||||
{
|
||||
int index;
|
||||
double distance;
|
||||
};
|
||||
|
||||
// find the farthest node in the "list" from "node"
|
||||
static inline CvSpillTreeNode*
|
||||
icvFarthestNode( CvSpillTreeNode* node,
|
||||
CvSpillTreeNode* list,
|
||||
int total )
|
||||
{
|
||||
double farthest = -1.;
|
||||
CvSpillTreeNode* result = NULL;
|
||||
for ( int i = 0; i < total; i++ )
|
||||
{
|
||||
double norm = cvNorm( node->center, list->center );
|
||||
if ( norm > farthest )
|
||||
{
|
||||
farthest = norm;
|
||||
result = list;
|
||||
}
|
||||
list = list->rc;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// clone a new tree node
|
||||
static inline CvSpillTreeNode*
|
||||
icvCloneSpillTreeNode( CvSpillTreeNode* node )
|
||||
{
|
||||
CvSpillTreeNode* result = (CvSpillTreeNode*)cvAlloc( sizeof(CvSpillTreeNode) );
|
||||
memcpy( result, node, sizeof(CvSpillTreeNode) );
|
||||
return result;
|
||||
}
|
||||
|
||||
// append the link-list of a tree node
|
||||
static inline void
|
||||
icvAppendSpillTreeNode( CvSpillTreeNode* node,
|
||||
CvSpillTreeNode* append )
|
||||
{
|
||||
if ( node->lc == NULL )
|
||||
{
|
||||
node->lc = node->rc = append;
|
||||
node->lc->lc = node->rc->rc = NULL;
|
||||
} else {
|
||||
append->lc = node->rc;
|
||||
append->rc = NULL;
|
||||
node->rc->rc = append;
|
||||
node->rc = append;
|
||||
}
|
||||
node->cc++;
|
||||
}
|
||||
|
||||
#define _dispatch_mat_ptr(x, step) (CV_MAT_DEPTH((x)->type) == CV_32F ? (void*)((x)->data.fl+(step)) : (CV_MAT_DEPTH((x)->type) == CV_64F ? (void*)((x)->data.db+(step)) : (void*)(0)))
|
||||
|
||||
static void
|
||||
icvDFSInitSpillTreeNode( const CvSpillTree* tr,
|
||||
const int d,
|
||||
CvSpillTreeNode* node )
|
||||
{
|
||||
if ( node->cc <= tr->naive )
|
||||
{
|
||||
// already get to a leaf, terminate the recursion.
|
||||
node->leaf = true;
|
||||
node->spill = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// random select a node, then find a farthest node from this one, then find a farthest from that one...
|
||||
// to approximate the farthest node-pair
|
||||
static CvRNG rng_state = cvRNG(0xdeadbeef);
|
||||
int rn = cvRandInt( &rng_state ) % node->cc;
|
||||
CvSpillTreeNode* lnode = NULL;
|
||||
CvSpillTreeNode* rnode = node->lc;
|
||||
for ( int i = 0; i < rn; i++ )
|
||||
rnode = rnode->rc;
|
||||
lnode = icvFarthestNode( rnode, node->lc, node->cc );
|
||||
rnode = icvFarthestNode( lnode, node->lc, node->cc );
|
||||
|
||||
// u is the projection vector
|
||||
node->u = cvCreateMat( 1, d, tr->type );
|
||||
cvSub( lnode->center, rnode->center, node->u );
|
||||
cvNormalize( node->u, node->u );
|
||||
|
||||
// find the center of node in hyperspace
|
||||
node->center = cvCreateMat( 1, d, tr->type );
|
||||
cvZero( node->center );
|
||||
CvSpillTreeNode* it = node->lc;
|
||||
for ( int i = 0; i < node->cc; i++ )
|
||||
{
|
||||
cvAdd( it->center, node->center, node->center );
|
||||
it = it->rc;
|
||||
}
|
||||
cvConvertScale( node->center, node->center, 1./node->cc );
|
||||
|
||||
// project every node to "u", and find the mean point "mp"
|
||||
it = node->lc;
|
||||
node->r = -1.;
|
||||
node->mp = 0;
|
||||
for ( int i = 0; i < node->cc; i++ )
|
||||
{
|
||||
node->mp += ( it->p = cvDotProduct( it->center, node->u ) );
|
||||
double norm = cvNorm( node->center, it->center );
|
||||
if ( norm > node->r )
|
||||
node->r = norm;
|
||||
it = it->rc;
|
||||
}
|
||||
node->mp = node->mp / node->cc;
|
||||
|
||||
// overlapping buffer and upper bound, lower bound
|
||||
double ob = (lnode->p-rnode->p)*tr->tau*.5;
|
||||
node->ub = node->mp+ob;
|
||||
node->lb = node->mp-ob;
|
||||
int sl = 0, l = 0;
|
||||
int sr = 0, r = 0;
|
||||
it = node->lc;
|
||||
for ( int i = 0; i < node->cc; i++ )
|
||||
{
|
||||
if ( it->p <= node->ub )
|
||||
sl++;
|
||||
if ( it->p >= node->lb )
|
||||
sr++;
|
||||
if ( it->p < node->mp )
|
||||
l++;
|
||||
else
|
||||
r++;
|
||||
it = it->rc;
|
||||
}
|
||||
// precision problem, return the node as it is.
|
||||
if (( l == 0 )||( r == 0 ))
|
||||
{
|
||||
cvReleaseMat( &(node->u) );
|
||||
cvReleaseMat( &(node->center) );
|
||||
node->leaf = true;
|
||||
node->spill = false;
|
||||
return;
|
||||
}
|
||||
CvSpillTreeNode* lc = (CvSpillTreeNode*)cvAlloc( sizeof(CvSpillTreeNode) );
|
||||
memset(lc, 0, sizeof(CvSpillTreeNode));
|
||||
CvSpillTreeNode* rc = (CvSpillTreeNode*)cvAlloc( sizeof(CvSpillTreeNode) );
|
||||
memset(rc, 0, sizeof(CvSpillTreeNode));
|
||||
lc->lc = lc->rc = rc->lc = rc->rc = NULL;
|
||||
lc->cc = rc->cc = 0;
|
||||
int undo = cvRound(node->cc*tr->rho);
|
||||
if (( sl >= undo )||( sr >= undo ))
|
||||
{
|
||||
// it is not a spill point (defeatist search disabled)
|
||||
it = node->lc;
|
||||
for ( int i = 0; i < node->cc; i++ )
|
||||
{
|
||||
CvSpillTreeNode* next = it->rc;
|
||||
if ( it->p < node->mp )
|
||||
icvAppendSpillTreeNode( lc, it );
|
||||
else
|
||||
icvAppendSpillTreeNode( rc, it );
|
||||
it = next;
|
||||
}
|
||||
node->spill = false;
|
||||
} else {
|
||||
// a spill point
|
||||
it = node->lc;
|
||||
for ( int i = 0; i < node->cc; i++ )
|
||||
{
|
||||
CvSpillTreeNode* next = it->rc;
|
||||
if ( it->p < node->lb )
|
||||
icvAppendSpillTreeNode( lc, it );
|
||||
else if ( it->p > node->ub )
|
||||
icvAppendSpillTreeNode( rc, it );
|
||||
else {
|
||||
CvSpillTreeNode* cit = icvCloneSpillTreeNode( it );
|
||||
icvAppendSpillTreeNode( lc, it );
|
||||
icvAppendSpillTreeNode( rc, cit );
|
||||
}
|
||||
it = next;
|
||||
}
|
||||
node->spill = true;
|
||||
}
|
||||
node->lc = lc;
|
||||
node->rc = rc;
|
||||
|
||||
// recursion process
|
||||
icvDFSInitSpillTreeNode( tr, d, node->lc );
|
||||
icvDFSInitSpillTreeNode( tr, d, node->rc );
|
||||
}
|
||||
|
||||
static CvSpillTree*
|
||||
icvCreateSpillTree( const CvMat* raw_data,
|
||||
const int naive,
|
||||
const double rho,
|
||||
const double tau )
|
||||
{
|
||||
int n = raw_data->rows;
|
||||
int d = raw_data->cols;
|
||||
|
||||
CvSpillTree* tr = (CvSpillTree*)cvAlloc( sizeof(CvSpillTree) );
|
||||
tr->root = (CvSpillTreeNode*)cvAlloc( sizeof(CvSpillTreeNode) );
|
||||
memset(tr->root, 0, sizeof(CvSpillTreeNode));
|
||||
tr->refmat = (CvMat**)cvAlloc( sizeof(CvMat*)*n );
|
||||
tr->total = n;
|
||||
tr->naive = naive;
|
||||
tr->rho = rho;
|
||||
tr->tau = tau;
|
||||
tr->type = raw_data->type;
|
||||
|
||||
// tie a link-list to the root node
|
||||
tr->root->lc = (CvSpillTreeNode*)cvAlloc( sizeof(CvSpillTreeNode) );
|
||||
memset(tr->root->lc, 0, sizeof(CvSpillTreeNode));
|
||||
tr->root->lc->center = cvCreateMatHeader( 1, d, tr->type );
|
||||
cvSetData( tr->root->lc->center, _dispatch_mat_ptr(raw_data, 0), raw_data->step );
|
||||
tr->refmat[0] = tr->root->lc->center;
|
||||
tr->root->lc->lc = NULL;
|
||||
tr->root->lc->leaf = true;
|
||||
tr->root->lc->i = 0;
|
||||
CvSpillTreeNode* node = tr->root->lc;
|
||||
for ( int i = 1; i < n; i++ )
|
||||
{
|
||||
CvSpillTreeNode* newnode = (CvSpillTreeNode*)cvAlloc( sizeof(CvSpillTreeNode) );
|
||||
memset(newnode, 0, sizeof(CvSpillTreeNode));
|
||||
newnode->center = cvCreateMatHeader( 1, d, tr->type );
|
||||
cvSetData( newnode->center, _dispatch_mat_ptr(raw_data, i*d), raw_data->step );
|
||||
tr->refmat[i] = newnode->center;
|
||||
newnode->lc = node;
|
||||
newnode->i = i;
|
||||
newnode->leaf = true;
|
||||
newnode->rc = NULL;
|
||||
node->rc = newnode;
|
||||
node = newnode;
|
||||
}
|
||||
tr->root->rc = node;
|
||||
tr->root->cc = n;
|
||||
icvDFSInitSpillTreeNode( tr, d, tr->root );
|
||||
return tr;
|
||||
}
|
||||
|
||||
static void
|
||||
icvSpillTreeNodeHeapify( CvResult * heap,
|
||||
int i,
|
||||
const int k )
|
||||
{
|
||||
if ( heap[i].index == -1 )
|
||||
return;
|
||||
int l, r, largest = i;
|
||||
CvResult inp;
|
||||
do {
|
||||
i = largest;
|
||||
r = (i+1)<<1;
|
||||
l = r-1;
|
||||
if (( l < k )&&( heap[l].index == -1 ))
|
||||
largest = l;
|
||||
else if (( r < k )&&( heap[r].index == -1 ))
|
||||
largest = r;
|
||||
else {
|
||||
if (( l < k )&&( heap[l].distance > heap[i].distance ))
|
||||
largest = l;
|
||||
if (( r < k )&&( heap[r].distance > heap[largest].distance ))
|
||||
largest = r;
|
||||
}
|
||||
if ( largest != i )
|
||||
CV_SWAP( heap[largest], heap[i], inp );
|
||||
} while ( largest != i );
|
||||
}
|
||||
|
||||
static void
|
||||
icvSpillTreeDFSearch( CvSpillTree* tr,
|
||||
CvSpillTreeNode* node,
|
||||
CvResult* heap,
|
||||
int* es,
|
||||
const CvMat* desc,
|
||||
const int k,
|
||||
const int emax,
|
||||
bool * cache)
|
||||
{
|
||||
if ((emax > 0)&&( *es >= emax ))
|
||||
return;
|
||||
double dist, p=0;
|
||||
double distance;
|
||||
while ( node->spill )
|
||||
{
|
||||
// defeatist search
|
||||
if ( !node->leaf )
|
||||
p = cvDotProduct( node->u, desc );
|
||||
if ( p < node->lb && node->lc->cc >= k ) // check the number of children larger than k otherwise you'll skip over better neighbor
|
||||
node = node->lc;
|
||||
else if ( p > node->ub && node->rc->cc >= k )
|
||||
node = node->rc;
|
||||
else
|
||||
break;
|
||||
if ( NULL == node )
|
||||
return;
|
||||
}
|
||||
if ( node->leaf )
|
||||
{
|
||||
// a leaf, naive search
|
||||
CvSpillTreeNode* it = node->lc;
|
||||
for ( int i = 0; i < node->cc; i++ )
|
||||
{
|
||||
if ( !cache[it->i] )
|
||||
{
|
||||
distance = cvNorm( it->center, desc );
|
||||
cache[it->i] = true;
|
||||
if (( heap[0].index == -1)||( distance < heap[0].distance ))
|
||||
{
|
||||
CvResult current_result;
|
||||
current_result.index = it->i;
|
||||
current_result.distance = distance;
|
||||
heap[0] = current_result;
|
||||
icvSpillTreeNodeHeapify( heap, 0, k );
|
||||
(*es)++;
|
||||
}
|
||||
}
|
||||
it = it->rc;
|
||||
}
|
||||
return;
|
||||
}
|
||||
dist = cvNorm( node->center, desc );
|
||||
// impossible case, skip
|
||||
if (( heap[0].index != -1 )&&( dist-node->r > heap[0].distance ))
|
||||
return;
|
||||
p = cvDotProduct( node->u, desc );
|
||||
// guided dfs
|
||||
if ( p < node->mp )
|
||||
{
|
||||
icvSpillTreeDFSearch( tr, node->lc, heap, es, desc, k, emax, cache );
|
||||
icvSpillTreeDFSearch( tr, node->rc, heap, es, desc, k, emax, cache );
|
||||
} else {
|
||||
icvSpillTreeDFSearch( tr, node->rc, heap, es, desc, k, emax, cache );
|
||||
icvSpillTreeDFSearch( tr, node->lc, heap, es, desc, k, emax, cache );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
icvFindSpillTreeFeatures( CvSpillTree* tr,
|
||||
const CvMat* desc,
|
||||
CvMat* results,
|
||||
CvMat* dist,
|
||||
const int k,
|
||||
const int emax )
|
||||
{
|
||||
assert( desc->type == tr->type );
|
||||
CvResult* heap = (CvResult*)cvAlloc( k*sizeof(heap[0]) );
|
||||
bool* cache = (bool*)cvAlloc( sizeof(bool)*tr->total );
|
||||
for ( int j = 0; j < desc->rows; j++ )
|
||||
{
|
||||
CvMat _desc = cvMat( 1, desc->cols, desc->type, _dispatch_mat_ptr(desc, j*desc->cols) );
|
||||
for ( int i = 0; i < k; i++ ) {
|
||||
CvResult current;
|
||||
current.index=-1;
|
||||
current.distance=-1;
|
||||
heap[i] = current;
|
||||
}
|
||||
memset( cache, 0, sizeof(bool)*tr->total );
|
||||
int es = 0;
|
||||
icvSpillTreeDFSearch( tr, tr->root, heap, &es, &_desc, k, emax, cache );
|
||||
CvResult inp;
|
||||
for ( int i = k-1; i > 0; i-- )
|
||||
{
|
||||
CV_SWAP( heap[i], heap[0], inp );
|
||||
icvSpillTreeNodeHeapify( heap, 0, i );
|
||||
}
|
||||
int* rs = results->data.i+j*results->cols;
|
||||
double* dt = dist->data.db+j*dist->cols;
|
||||
for ( int i = 0; i < k; i++, rs++, dt++ )
|
||||
if ( heap[i].index != -1 )
|
||||
{
|
||||
*rs = heap[i].index;
|
||||
*dt = heap[i].distance;
|
||||
} else
|
||||
*rs = -1;
|
||||
}
|
||||
cvFree( &heap );
|
||||
cvFree( &cache );
|
||||
}
|
||||
|
||||
static void
|
||||
icvDFSReleaseSpillTreeNode( CvSpillTreeNode* node )
|
||||
{
|
||||
if ( node->leaf )
|
||||
{
|
||||
CvSpillTreeNode* it = node->lc;
|
||||
for ( int i = 0; i < node->cc; i++ )
|
||||
{
|
||||
CvSpillTreeNode* s = it;
|
||||
it = it->rc;
|
||||
cvFree( &s );
|
||||
}
|
||||
} else {
|
||||
cvReleaseMat( &node->u );
|
||||
cvReleaseMat( &node->center );
|
||||
icvDFSReleaseSpillTreeNode( node->lc );
|
||||
icvDFSReleaseSpillTreeNode( node->rc );
|
||||
}
|
||||
cvFree( &node );
|
||||
}
|
||||
|
||||
static void
|
||||
icvReleaseSpillTree( CvSpillTree** tr )
|
||||
{
|
||||
for ( int i = 0; i < (*tr)->total; i++ )
|
||||
cvReleaseMat( &((*tr)->refmat[i]) );
|
||||
cvFree( &((*tr)->refmat) );
|
||||
icvDFSReleaseSpillTreeNode( (*tr)->root );
|
||||
cvFree( tr );
|
||||
}
|
||||
|
||||
class CvSpillTreeWrap : public CvFeatureTree {
|
||||
CvSpillTree* tr;
|
||||
public:
|
||||
CvSpillTreeWrap(const CvMat* raw_data,
|
||||
const int naive,
|
||||
const double rho,
|
||||
const double tau) {
|
||||
tr = icvCreateSpillTree(raw_data, naive, rho, tau);
|
||||
}
|
||||
~CvSpillTreeWrap() {
|
||||
icvReleaseSpillTree(&tr);
|
||||
}
|
||||
|
||||
void FindFeatures(const CvMat* desc, int k, int emax, CvMat* results, CvMat* dist) {
|
||||
icvFindSpillTreeFeatures(tr, desc, results, dist, k, emax);
|
||||
}
|
||||
};
|
||||
|
||||
CvFeatureTree* cvCreateSpillTree( const CvMat* raw_data,
|
||||
const int naive,
|
||||
const double rho,
|
||||
const double tau ) {
|
||||
return new CvSpillTreeWrap(raw_data, naive, rho, tau);
|
||||
}
|
||||
@@ -40,675 +40,6 @@
|
||||
//M*/
|
||||
#include "precomp.hpp"
|
||||
|
||||
CV_IMPL CvSubdiv2D *
|
||||
cvCreateSubdiv2D( int subdiv_type, int header_size,
|
||||
int vtx_size, int quadedge_size, CvMemStorage * storage )
|
||||
{
|
||||
if( !storage )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
if( header_size < (int)sizeof( CvSubdiv2D ) ||
|
||||
quadedge_size < (int)sizeof( CvQuadEdge2D ) ||
|
||||
vtx_size < (int)sizeof( CvSubdiv2DPoint ))
|
||||
CV_Error( CV_StsBadSize, "" );
|
||||
|
||||
return (CvSubdiv2D *)cvCreateGraph( subdiv_type, header_size,
|
||||
vtx_size, quadedge_size, storage );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************\
|
||||
* Quad Edge algebra *
|
||||
\****************************************************************************************/
|
||||
|
||||
static CvSubdiv2DEdge
|
||||
cvSubdiv2DMakeEdge( CvSubdiv2D * subdiv )
|
||||
{
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
CvQuadEdge2D* edge = (CvQuadEdge2D*)cvSetNew( (CvSet*)subdiv->edges );
|
||||
memset( edge->pt, 0, sizeof( edge->pt ));
|
||||
CvSubdiv2DEdge edgehandle = (CvSubdiv2DEdge) edge;
|
||||
|
||||
edge->next[0] = edgehandle;
|
||||
edge->next[1] = edgehandle + 3;
|
||||
edge->next[2] = edgehandle + 2;
|
||||
edge->next[3] = edgehandle + 1;
|
||||
|
||||
subdiv->quad_edges++;
|
||||
return edgehandle;
|
||||
}
|
||||
|
||||
|
||||
static CvSubdiv2DPoint *
|
||||
cvSubdiv2DAddPoint( CvSubdiv2D * subdiv, CvPoint2D32f pt, int is_virtual )
|
||||
{
|
||||
CvSubdiv2DPoint* subdiv_point = (CvSubdiv2DPoint*)cvSetNew( (CvSet*)subdiv );
|
||||
if( subdiv_point )
|
||||
{
|
||||
memset( subdiv_point, 0, subdiv->elem_size );
|
||||
subdiv_point->pt = pt;
|
||||
subdiv_point->first = 0;
|
||||
subdiv_point->flags |= is_virtual ? CV_SUBDIV2D_VIRTUAL_POINT_FLAG : 0;
|
||||
subdiv_point->id = -1;
|
||||
}
|
||||
|
||||
return subdiv_point;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cvSubdiv2DSplice( CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
|
||||
{
|
||||
CvSubdiv2DEdge *a_next = &CV_SUBDIV2D_NEXT_EDGE( edgeA );
|
||||
CvSubdiv2DEdge *b_next = &CV_SUBDIV2D_NEXT_EDGE( edgeB );
|
||||
CvSubdiv2DEdge a_rot = cvSubdiv2DRotateEdge( *a_next, 1 );
|
||||
CvSubdiv2DEdge b_rot = cvSubdiv2DRotateEdge( *b_next, 1 );
|
||||
CvSubdiv2DEdge *a_rot_next = &CV_SUBDIV2D_NEXT_EDGE( a_rot );
|
||||
CvSubdiv2DEdge *b_rot_next = &CV_SUBDIV2D_NEXT_EDGE( b_rot );
|
||||
CvSubdiv2DEdge t;
|
||||
|
||||
CV_SWAP( *a_next, *b_next, t );
|
||||
CV_SWAP( *a_rot_next, *b_rot_next, t );
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cvSubdiv2DSetEdgePoints( CvSubdiv2DEdge edge,
|
||||
CvSubdiv2DPoint * org_pt, CvSubdiv2DPoint * dst_pt )
|
||||
{
|
||||
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
|
||||
|
||||
if( !quadedge )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
quadedge->pt[edge & 3] = org_pt;
|
||||
quadedge->pt[(edge + 2) & 3] = dst_pt;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cvSubdiv2DDeleteEdge( CvSubdiv2D * subdiv, CvSubdiv2DEdge edge )
|
||||
{
|
||||
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
|
||||
|
||||
if( !subdiv || !quadedge )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG ));
|
||||
|
||||
CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
|
||||
cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG ));
|
||||
|
||||
cvSetRemoveByPtr( (CvSet*)(subdiv->edges), quadedge );
|
||||
subdiv->quad_edges--;
|
||||
}
|
||||
|
||||
|
||||
static CvSubdiv2DEdge
|
||||
cvSubdiv2DConnectEdges( CvSubdiv2D * subdiv, CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
|
||||
{
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
CvSubdiv2DEdge new_edge = cvSubdiv2DMakeEdge( subdiv );
|
||||
|
||||
cvSubdiv2DSplice( new_edge, cvSubdiv2DGetEdge( edgeA, CV_NEXT_AROUND_LEFT ));
|
||||
cvSubdiv2DSplice( cvSubdiv2DSymEdge( new_edge ), edgeB );
|
||||
|
||||
CvSubdiv2DPoint* dstA = cvSubdiv2DEdgeDst( edgeA );
|
||||
CvSubdiv2DPoint* orgB = cvSubdiv2DEdgeOrg( edgeB );
|
||||
cvSubdiv2DSetEdgePoints( new_edge, dstA, orgB );
|
||||
|
||||
return new_edge;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cvSubdiv2DSwapEdges( CvSubdiv2DEdge edge )
|
||||
{
|
||||
CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
|
||||
CvSubdiv2DEdge a = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG );
|
||||
CvSubdiv2DEdge b = cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG );
|
||||
CvSubdiv2DPoint *dstB, *dstA;
|
||||
|
||||
cvSubdiv2DSplice( edge, a );
|
||||
cvSubdiv2DSplice( sym_edge, b );
|
||||
|
||||
dstA = cvSubdiv2DEdgeDst( a );
|
||||
dstB = cvSubdiv2DEdgeDst( b );
|
||||
cvSubdiv2DSetEdgePoints( edge, dstA, dstB );
|
||||
|
||||
cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( a, CV_NEXT_AROUND_LEFT ));
|
||||
cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( b, CV_NEXT_AROUND_LEFT ));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
icvIsRightOf( CvPoint2D32f& pt, CvSubdiv2DEdge edge )
|
||||
{
|
||||
CvSubdiv2DPoint *org = cvSubdiv2DEdgeOrg(edge), *dst = cvSubdiv2DEdgeDst(edge);
|
||||
double cw_area = cvTriangleArea( pt, dst->pt, org->pt );
|
||||
|
||||
return (cw_area > 0) - (cw_area < 0);
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL CvSubdiv2DPointLocation
|
||||
cvSubdiv2DLocate( CvSubdiv2D * subdiv, CvPoint2D32f pt,
|
||||
CvSubdiv2DEdge * _edge, CvSubdiv2DPoint ** _point )
|
||||
{
|
||||
CvSubdiv2DPoint *point = 0;
|
||||
int right_of_curr = 0;
|
||||
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
if( !CV_IS_SUBDIV2D(subdiv) )
|
||||
CV_Error( CV_StsBadFlag, "" );
|
||||
|
||||
int i, max_edges = subdiv->quad_edges * 4;
|
||||
CvSubdiv2DEdge edge = subdiv->recent_edge;
|
||||
|
||||
if( max_edges == 0 )
|
||||
CV_Error( CV_StsBadSize, "" );
|
||||
CV_Assert(edge != 0);
|
||||
|
||||
if( pt.x < subdiv->topleft.x || pt.y < subdiv->topleft.y ||
|
||||
pt.x >= subdiv->bottomright.x || pt.y >= subdiv->bottomright.y )
|
||||
CV_Error( CV_StsOutOfRange, "" );
|
||||
|
||||
CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
|
||||
|
||||
right_of_curr = icvIsRightOf( pt, edge );
|
||||
if( right_of_curr > 0 )
|
||||
{
|
||||
edge = cvSubdiv2DSymEdge( edge );
|
||||
right_of_curr = -right_of_curr;
|
||||
}
|
||||
|
||||
for( i = 0; i < max_edges; i++ )
|
||||
{
|
||||
CvSubdiv2DEdge onext_edge = cvSubdiv2DNextEdge( edge );
|
||||
CvSubdiv2DEdge dprev_edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_DST );
|
||||
|
||||
int right_of_onext = icvIsRightOf( pt, onext_edge );
|
||||
int right_of_dprev = icvIsRightOf( pt, dprev_edge );
|
||||
|
||||
if( right_of_dprev > 0 )
|
||||
{
|
||||
if( right_of_onext > 0 || (right_of_onext == 0 && right_of_curr == 0) )
|
||||
{
|
||||
location = CV_PTLOC_INSIDE;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
right_of_curr = right_of_onext;
|
||||
edge = onext_edge;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( right_of_onext > 0 )
|
||||
{
|
||||
if( right_of_dprev == 0 && right_of_curr == 0 )
|
||||
{
|
||||
location = CV_PTLOC_INSIDE;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
right_of_curr = right_of_dprev;
|
||||
edge = dprev_edge;
|
||||
}
|
||||
}
|
||||
else if( right_of_curr == 0 &&
|
||||
icvIsRightOf( cvSubdiv2DEdgeDst( onext_edge )->pt, edge ) >= 0 )
|
||||
{
|
||||
edge = cvSubdiv2DSymEdge( edge );
|
||||
}
|
||||
else
|
||||
{
|
||||
right_of_curr = right_of_onext;
|
||||
edge = onext_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
exit:
|
||||
|
||||
subdiv->recent_edge = edge;
|
||||
|
||||
if( location == CV_PTLOC_INSIDE )
|
||||
{
|
||||
double t1, t2, t3;
|
||||
CvPoint2D32f org_pt = cvSubdiv2DEdgeOrg( edge )->pt;
|
||||
CvPoint2D32f dst_pt = cvSubdiv2DEdgeDst( edge )->pt;
|
||||
|
||||
t1 = fabs( pt.x - org_pt.x );
|
||||
t1 += fabs( pt.y - org_pt.y );
|
||||
t2 = fabs( pt.x - dst_pt.x );
|
||||
t2 += fabs( pt.y - dst_pt.y );
|
||||
t3 = fabs( org_pt.x - dst_pt.x );
|
||||
t3 += fabs( org_pt.y - dst_pt.y );
|
||||
|
||||
if( t1 < FLT_EPSILON )
|
||||
{
|
||||
location = CV_PTLOC_VERTEX;
|
||||
point = cvSubdiv2DEdgeOrg( edge );
|
||||
edge = 0;
|
||||
}
|
||||
else if( t2 < FLT_EPSILON )
|
||||
{
|
||||
location = CV_PTLOC_VERTEX;
|
||||
point = cvSubdiv2DEdgeDst( edge );
|
||||
edge = 0;
|
||||
}
|
||||
else if( (t1 < t3 || t2 < t3) &&
|
||||
fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
|
||||
{
|
||||
location = CV_PTLOC_ON_EDGE;
|
||||
point = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( location == CV_PTLOC_ERROR )
|
||||
{
|
||||
edge = 0;
|
||||
point = 0;
|
||||
}
|
||||
|
||||
if( _edge )
|
||||
*_edge = edge;
|
||||
if( _point )
|
||||
*_point = point;
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
|
||||
CV_INLINE int
|
||||
icvIsPtInCircle3( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c )
|
||||
{
|
||||
const double eps = FLT_EPSILON*0.125;
|
||||
double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt );
|
||||
val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt );
|
||||
val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt );
|
||||
val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c );
|
||||
|
||||
return val > eps ? 1 : val < -eps ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL CvSubdiv2DPoint *
|
||||
cvSubdivDelaunay2DInsert( CvSubdiv2D * subdiv, CvPoint2D32f pt )
|
||||
{
|
||||
CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
|
||||
|
||||
CvSubdiv2DPoint *curr_point = 0, *first_point = 0;
|
||||
CvSubdiv2DEdge curr_edge = 0, deleted_edge = 0, base_edge = 0;
|
||||
int i, max_edges;
|
||||
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
if( !CV_IS_SUBDIV2D(subdiv) )
|
||||
CV_Error( CV_StsBadFlag, "" );
|
||||
|
||||
location = cvSubdiv2DLocate( subdiv, pt, &curr_edge, &curr_point );
|
||||
|
||||
switch (location)
|
||||
{
|
||||
case CV_PTLOC_ERROR:
|
||||
CV_Error( CV_StsBadSize, "" );
|
||||
|
||||
case CV_PTLOC_OUTSIDE_RECT:
|
||||
CV_Error( CV_StsOutOfRange, "" );
|
||||
|
||||
case CV_PTLOC_VERTEX:
|
||||
break;
|
||||
|
||||
case CV_PTLOC_ON_EDGE:
|
||||
deleted_edge = curr_edge;
|
||||
subdiv->recent_edge = curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
|
||||
cvSubdiv2DDeleteEdge( subdiv, deleted_edge );
|
||||
/* no break */
|
||||
|
||||
case CV_PTLOC_INSIDE:
|
||||
|
||||
assert( curr_edge != 0 );
|
||||
subdiv->is_geometry_valid = 0;
|
||||
|
||||
curr_point = cvSubdiv2DAddPoint( subdiv, pt, 0 );
|
||||
base_edge = cvSubdiv2DMakeEdge( subdiv );
|
||||
first_point = cvSubdiv2DEdgeOrg( curr_edge );
|
||||
cvSubdiv2DSetEdgePoints( base_edge, first_point, curr_point );
|
||||
cvSubdiv2DSplice( base_edge, curr_edge );
|
||||
|
||||
do
|
||||
{
|
||||
base_edge = cvSubdiv2DConnectEdges( subdiv, curr_edge,
|
||||
cvSubdiv2DSymEdge( base_edge ));
|
||||
curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
|
||||
}
|
||||
while( cvSubdiv2DEdgeDst( curr_edge ) != first_point );
|
||||
|
||||
curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
|
||||
|
||||
max_edges = subdiv->quad_edges * 4;
|
||||
|
||||
for( i = 0; i < max_edges; i++ )
|
||||
{
|
||||
CvSubdiv2DPoint *temp_dst = 0, *curr_org = 0, *curr_dst = 0;
|
||||
CvSubdiv2DEdge temp_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
|
||||
|
||||
temp_dst = cvSubdiv2DEdgeDst( temp_edge );
|
||||
curr_org = cvSubdiv2DEdgeOrg( curr_edge );
|
||||
curr_dst = cvSubdiv2DEdgeDst( curr_edge );
|
||||
|
||||
if( icvIsRightOf( temp_dst->pt, curr_edge ) > 0 &&
|
||||
icvIsPtInCircle3( curr_org->pt, temp_dst->pt,
|
||||
curr_dst->pt, curr_point->pt ) < 0 )
|
||||
{
|
||||
cvSubdiv2DSwapEdges( curr_edge );
|
||||
curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
|
||||
}
|
||||
else if( curr_org == first_point )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_edge = cvSubdiv2DGetEdge( cvSubdiv2DNextEdge( curr_edge ),
|
||||
CV_PREV_AROUND_LEFT );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CV_Error_(CV_StsError, ("cvSubdiv2DLocate returned invalid location = %d", location) );
|
||||
}
|
||||
|
||||
return curr_point;
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL void
|
||||
cvInitSubdivDelaunay2D( CvSubdiv2D * subdiv, CvRect rect )
|
||||
{
|
||||
float big_coord = 3.f * MAX( rect.width, rect.height );
|
||||
CvPoint2D32f ppA, ppB, ppC;
|
||||
CvSubdiv2DPoint *pA, *pB, *pC;
|
||||
CvSubdiv2DEdge edge_AB, edge_BC, edge_CA;
|
||||
float rx = (float) rect.x;
|
||||
float ry = (float) rect.y;
|
||||
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
cvClearSet( (CvSet *) (subdiv->edges) );
|
||||
cvClearSet( (CvSet *) subdiv );
|
||||
|
||||
subdiv->quad_edges = 0;
|
||||
subdiv->recent_edge = 0;
|
||||
subdiv->is_geometry_valid = 0;
|
||||
|
||||
subdiv->topleft = cvPoint2D32f( rx, ry );
|
||||
subdiv->bottomright = cvPoint2D32f( rx + rect.width, ry + rect.height );
|
||||
|
||||
ppA = cvPoint2D32f( rx + big_coord, ry );
|
||||
ppB = cvPoint2D32f( rx, ry + big_coord );
|
||||
ppC = cvPoint2D32f( rx - big_coord, ry - big_coord );
|
||||
|
||||
pA = cvSubdiv2DAddPoint( subdiv, ppA, 0 );
|
||||
pB = cvSubdiv2DAddPoint( subdiv, ppB, 0 );
|
||||
pC = cvSubdiv2DAddPoint( subdiv, ppC, 0 );
|
||||
|
||||
edge_AB = cvSubdiv2DMakeEdge( subdiv );
|
||||
edge_BC = cvSubdiv2DMakeEdge( subdiv );
|
||||
edge_CA = cvSubdiv2DMakeEdge( subdiv );
|
||||
|
||||
cvSubdiv2DSetEdgePoints( edge_AB, pA, pB );
|
||||
cvSubdiv2DSetEdgePoints( edge_BC, pB, pC );
|
||||
cvSubdiv2DSetEdgePoints( edge_CA, pC, pA );
|
||||
|
||||
cvSubdiv2DSplice( edge_AB, cvSubdiv2DSymEdge( edge_CA ));
|
||||
cvSubdiv2DSplice( edge_BC, cvSubdiv2DSymEdge( edge_AB ));
|
||||
cvSubdiv2DSplice( edge_CA, cvSubdiv2DSymEdge( edge_BC ));
|
||||
|
||||
subdiv->recent_edge = edge_AB;
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL void
|
||||
cvClearSubdivVoronoi2D( CvSubdiv2D * subdiv )
|
||||
{
|
||||
int elem_size;
|
||||
int i, total;
|
||||
CvSeqReader reader;
|
||||
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
/* clear pointers to voronoi points */
|
||||
total = subdiv->edges->total;
|
||||
elem_size = subdiv->edges->elem_size;
|
||||
|
||||
cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
|
||||
|
||||
for( i = 0; i < total; i++ )
|
||||
{
|
||||
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) reader.ptr;
|
||||
|
||||
quadedge->pt[1] = quadedge->pt[3] = 0;
|
||||
CV_NEXT_SEQ_ELEM( elem_size, reader );
|
||||
}
|
||||
|
||||
/* remove voronoi points */
|
||||
total = subdiv->total;
|
||||
elem_size = subdiv->elem_size;
|
||||
|
||||
cvStartReadSeq( (CvSeq *) subdiv, &reader, 0 );
|
||||
|
||||
for( i = 0; i < total; i++ )
|
||||
{
|
||||
CvSubdiv2DPoint *pt = (CvSubdiv2DPoint *) reader.ptr;
|
||||
|
||||
/* check for virtual point. it is also check that the point exists */
|
||||
if( pt->flags & CV_SUBDIV2D_VIRTUAL_POINT_FLAG )
|
||||
{
|
||||
cvSetRemoveByPtr( (CvSet*)subdiv, pt );
|
||||
}
|
||||
CV_NEXT_SEQ_ELEM( elem_size, reader );
|
||||
}
|
||||
|
||||
subdiv->is_geometry_valid = 0;
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL void
|
||||
cvCalcSubdivVoronoi2D( CvSubdiv2D * subdiv )
|
||||
{
|
||||
CvSeqReader reader;
|
||||
int i, total, elem_size;
|
||||
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
/* check if it is already calculated */
|
||||
if( subdiv->is_geometry_valid )
|
||||
return;
|
||||
|
||||
total = subdiv->edges->total;
|
||||
elem_size = subdiv->edges->elem_size;
|
||||
|
||||
cvClearSubdivVoronoi2D( subdiv );
|
||||
|
||||
cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
|
||||
|
||||
if( total <= 3 )
|
||||
return;
|
||||
|
||||
/* skip first three edges (bounding triangle) */
|
||||
for( i = 0; i < 3; i++ )
|
||||
CV_NEXT_SEQ_ELEM( elem_size, reader );
|
||||
|
||||
/* loop through all quad-edges */
|
||||
for( ; i < total; i++ )
|
||||
{
|
||||
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (reader.ptr);
|
||||
|
||||
if( CV_IS_SET_ELEM( quadedge ))
|
||||
{
|
||||
CvSubdiv2DEdge edge0 = (CvSubdiv2DEdge) quadedge, edge1, edge2;
|
||||
double a0, b0, c0, a1, b1, c1;
|
||||
CvPoint2D32f virt_point;
|
||||
CvSubdiv2DPoint *voronoi_point;
|
||||
|
||||
if( !quadedge->pt[3] )
|
||||
{
|
||||
edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_LEFT );
|
||||
edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_LEFT );
|
||||
|
||||
icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
|
||||
icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
|
||||
|
||||
icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
|
||||
if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
|
||||
fabs( virt_point.y ) < FLT_MAX * 0.5 )
|
||||
{
|
||||
voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
|
||||
|
||||
quadedge->pt[3] =
|
||||
((CvQuadEdge2D *) (edge1 & ~3))->pt[3 - (edge1 & 2)] =
|
||||
((CvQuadEdge2D *) (edge2 & ~3))->pt[3 - (edge2 & 2)] = voronoi_point;
|
||||
}
|
||||
}
|
||||
|
||||
if( !quadedge->pt[1] )
|
||||
{
|
||||
edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_RIGHT );
|
||||
edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_RIGHT );
|
||||
|
||||
icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
|
||||
icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
|
||||
|
||||
icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
|
||||
|
||||
if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
|
||||
fabs( virt_point.y ) < FLT_MAX * 0.5 )
|
||||
{
|
||||
voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
|
||||
|
||||
quadedge->pt[1] =
|
||||
((CvQuadEdge2D *) (edge1 & ~3))->pt[1 + (edge1 & 2)] =
|
||||
((CvQuadEdge2D *) (edge2 & ~3))->pt[1 + (edge2 & 2)] = voronoi_point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CV_NEXT_SEQ_ELEM( elem_size, reader );
|
||||
}
|
||||
|
||||
subdiv->is_geometry_valid = 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
icvIsRightOf2( const CvPoint2D32f& pt, const CvPoint2D32f& org, const CvPoint2D32f& diff )
|
||||
{
|
||||
double cw_area = ((double)org.x - pt.x)*diff.y - ((double)org.y - pt.y)*diff.x;
|
||||
return (cw_area > 0) - (cw_area < 0);
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL CvSubdiv2DPoint*
|
||||
cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt )
|
||||
{
|
||||
CvSubdiv2DPoint* point = 0;
|
||||
CvPoint2D32f start;
|
||||
CvPoint2D32f diff;
|
||||
CvSubdiv2DPointLocation loc;
|
||||
CvSubdiv2DEdge edge;
|
||||
int i;
|
||||
|
||||
if( !subdiv )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
if( !CV_IS_SUBDIV2D( subdiv ))
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
if( subdiv->edges->active_count <= 3 )
|
||||
return 0;
|
||||
|
||||
if( !subdiv->is_geometry_valid )
|
||||
cvCalcSubdivVoronoi2D( subdiv );
|
||||
|
||||
loc = cvSubdiv2DLocate( subdiv, pt, &edge, &point );
|
||||
|
||||
switch( loc )
|
||||
{
|
||||
case CV_PTLOC_ON_EDGE:
|
||||
case CV_PTLOC_INSIDE:
|
||||
break;
|
||||
default:
|
||||
return point;
|
||||
}
|
||||
|
||||
point = 0;
|
||||
|
||||
start = cvSubdiv2DEdgeOrg( edge )->pt;
|
||||
diff.x = pt.x - start.x;
|
||||
diff.y = pt.y - start.y;
|
||||
|
||||
edge = cvSubdiv2DRotateEdge( edge, 1 );
|
||||
|
||||
for( i = 0; i < subdiv->total; i++ )
|
||||
{
|
||||
CvPoint2D32f t;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
assert( cvSubdiv2DEdgeDst( edge ));
|
||||
|
||||
t = cvSubdiv2DEdgeDst( edge )->pt;
|
||||
if( icvIsRightOf2( t, start, diff ) >= 0 )
|
||||
break;
|
||||
|
||||
edge = cvSubdiv2DGetEdge( edge, CV_NEXT_AROUND_LEFT );
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
assert( cvSubdiv2DEdgeOrg( edge ));
|
||||
|
||||
t = cvSubdiv2DEdgeOrg( edge )->pt;
|
||||
if( icvIsRightOf2( t, start, diff ) < 0 )
|
||||
break;
|
||||
|
||||
edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_LEFT );
|
||||
}
|
||||
|
||||
{
|
||||
CvPoint2D32f tempDiff = cvSubdiv2DEdgeDst( edge )->pt;
|
||||
t = cvSubdiv2DEdgeOrg( edge )->pt;
|
||||
tempDiff.x -= t.x;
|
||||
tempDiff.y -= t.y;
|
||||
|
||||
if( icvIsRightOf2( pt, t, tempDiff ) >= 0 )
|
||||
{
|
||||
point = cvSubdiv2DEdgeOrg( cvSubdiv2DRotateEdge( edge, 3 ));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
edge = cvSubdiv2DSymEdge( edge );
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
@@ -879,17 +210,21 @@ void Subdiv2D::swapEdges( int edge )
|
||||
splice(sedge, getEdge(b, NEXT_AROUND_LEFT));
|
||||
}
|
||||
|
||||
static double triangleArea( Point2f a, Point2f b, Point2f c )
|
||||
{
|
||||
return ((double)b.x - a.x) * ((double)c.y - a.y) - ((double)b.y - a.y) * ((double)c.x - a.x);
|
||||
}
|
||||
|
||||
int Subdiv2D::isRightOf(Point2f pt, int edge) const
|
||||
{
|
||||
Point2f org, dst;
|
||||
edgeOrg(edge, &org);
|
||||
edgeDst(edge, &dst);
|
||||
double cw_area = cvTriangleArea( pt, dst, org );
|
||||
double cw_area = triangleArea( pt, dst, org );
|
||||
|
||||
return (cw_area > 0) - (cw_area < 0);
|
||||
}
|
||||
|
||||
|
||||
int Subdiv2D::newEdge()
|
||||
{
|
||||
if( freeQEdge <= 0 )
|
||||
@@ -1039,7 +374,7 @@ int Subdiv2D::locate(Point2f pt, int& _edge, int& _vertex)
|
||||
edge = 0;
|
||||
}
|
||||
else if( (t1 < t3 || t2 < t3) &&
|
||||
fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
|
||||
fabs( triangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
|
||||
{
|
||||
location = PTLOC_ON_EDGE;
|
||||
vertex = 0;
|
||||
@@ -1063,10 +398,10 @@ inline int
|
||||
isPtInCircle3( Point2f pt, Point2f a, Point2f b, Point2f c)
|
||||
{
|
||||
const double eps = FLT_EPSILON*0.125;
|
||||
double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt );
|
||||
val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt );
|
||||
val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt );
|
||||
val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c );
|
||||
double val = ((double)a.x * a.x + (double)a.y * a.y) * triangleArea( b, c, pt );
|
||||
val -= ((double)b.x * b.x + (double)b.y * b.y) * triangleArea( a, c, pt );
|
||||
val += ((double)c.x * c.x + (double)c.y * c.y) * triangleArea( a, b, pt );
|
||||
val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * triangleArea( a, b, c );
|
||||
|
||||
return val > eps ? 1 : val < -eps ? -1 : 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user