"atomic bomb" commit. Reorganized OpenCV directory structure

This commit is contained in:
Vadim Pisarevsky
2010-05-11 17:44:00 +00:00
commit 127d6649a1
1761 changed files with 1766340 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
/*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:

View File

@@ -0,0 +1,72 @@
/*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_GEOM_H_
#define _CV_GEOM_H_
/* Finds distance between two points */
CV_INLINE float icvDistanceL2_32f( CvPoint2D32f pt1, CvPoint2D32f pt2 )
{
float dx = pt2.x - pt1.x;
float dy = pt2.y - pt1.y;
return std::sqrt( dx*dx + dy*dy );
}
int icvIntersectLines( double x1, double dx1, double y1, double dy1,
double x2, double dx2, double y2, double dy2,
double* t2 );
void icvCreateCenterNormalLine( CvSubdiv2DEdge edge, double* a, double* b, double* c );
void icvIntersectLines3( double* a0, double* b0, double* c0,
double* a1, double* b1, double* c1,
CvPoint2D32f* point );
/* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */
CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size, CvMemStorage* storage, int method );
#endif /*_IPCVGEOM_H_*/
/* End of file. */

View File

@@ -0,0 +1,47 @@
/*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_*/

View File

@@ -0,0 +1,467 @@
/*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));
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);
push_heap(nn_pq.begin(), nn_pq.end());
} else if (nn_pq[0].dist > nn.dist) {
pop_heap(nn_pq.begin(), nn_pq.end());
nn_pq.end()[-1] = nn;
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
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:

373
modules/imgproc/src/_list.h Normal file
View File

@@ -0,0 +1,373 @@
/*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_LIST_H_
#define _CV_LIST_H_
#include <stdlib.h>
#include <assert.h>
#define CV_FORCE_INLINE CV_INLINE
#if !defined(_LIST_INLINE)
#define _LIST_INLINE CV_FORCE_INLINE
#endif /*_LIST_INLINE*/
#if defined DECLARE_LIST
#if defined _MSC_VER && _MSC_VER >= 1200
#pragma warning("DECLARE_LIST macro is already defined!")
#endif
#endif /*DECLARE_LIST*/
static const long default_size = 10;
static const long default_inc_size = 10;
struct _pos
{
void* m_pos;
#ifdef _DEBUG
struct _list* m_list;
#endif /*_DEBUG*/
};
typedef struct _pos CVPOS;
struct _list
{
void* m_buffer;
void* m_first_buffer;
long m_buf_size; /* The size of the buffer */
long m_size; /* The number of elements */
CVPOS m_head;
CVPOS m_tail;
CVPOS m_head_free;
};
typedef struct _list _CVLIST;
#define DECLARE_LIST(type, prefix)\
/* Basic element of a list*/\
struct prefix##element_##type\
{\
struct prefix##element_##type* m_prev;\
struct prefix##element_##type* m_next;\
type m_data;\
};\
typedef struct prefix##element_##type ELEMENT_##type;\
/* Initialization and destruction*/\
_LIST_INLINE _CVLIST* prefix##create_list_##type(long);\
_LIST_INLINE void prefix##destroy_list_##type(_CVLIST*);\
/* Access functions*/\
_LIST_INLINE CVPOS prefix##get_head_pos_##type(_CVLIST*);\
_LIST_INLINE CVPOS prefix##get_tail_pos_##type(_CVLIST*);\
_LIST_INLINE type* prefix##get_next_##type(CVPOS*);\
_LIST_INLINE type* prefix##get_prev_##type(CVPOS*);\
/* Modification functions*/\
_LIST_INLINE void prefix##clear_list_##type(_CVLIST*);\
_LIST_INLINE CVPOS prefix##add_head_##type(_CVLIST*, type*);\
_LIST_INLINE CVPOS prefix##add_tail_##type(_CVLIST*, type*);\
_LIST_INLINE void prefix##remove_head_##type(_CVLIST*);\
_LIST_INLINE void prefix##remove_tail_##type(_CVLIST*);\
_LIST_INLINE CVPOS prefix##insert_before_##type(_CVLIST*, CVPOS, type*);\
_LIST_INLINE CVPOS prefix##insert_after_##type(_CVLIST*, CVPOS, type*);\
_LIST_INLINE void prefix##remove_at_##type(_CVLIST*, CVPOS);\
_LIST_INLINE void prefix##set_##type(CVPOS, type*);\
_LIST_INLINE type* prefix##get_##type(CVPOS);\
/* Statistics functions*/\
_LIST_INLINE int prefix##get_count_##type(_CVLIST*);
/* This macro finds a space for a new element and puts in into 'element' pointer */
#define INSERT_NEW(element_type, l, element)\
l->m_size++;\
if(l->m_head_free.m_pos != NULL)\
{\
element = (element_type*)(l->m_head_free.m_pos);\
if(element->m_next != NULL)\
{\
element->m_next->m_prev = NULL;\
l->m_head_free.m_pos = element->m_next;\
}\
else\
{\
l->m_head_free.m_pos = NULL;\
}\
}\
else\
{\
if(l->m_buf_size < l->m_size && l->m_head_free.m_pos == NULL)\
{\
*(void**)l->m_buffer = cvAlloc(l->m_buf_size*sizeof(element_type) + sizeof(void*));\
l->m_buffer = *(void**)l->m_buffer;\
*(void**)l->m_buffer = NULL;\
element = (element_type*)((char*)l->m_buffer + sizeof(void*));\
}\
else\
{\
element = (element_type*)((char*)l->m_buffer + sizeof(void*)) + l->m_size - 1;\
}\
}
/* This macro adds 'element' to the list of free elements*/
#define INSERT_FREE(element_type, l, element)\
if(l->m_head_free.m_pos != NULL)\
{\
((element_type*)l->m_head_free.m_pos)->m_prev = element;\
}\
element->m_next = ((element_type*)l->m_head_free.m_pos);\
l->m_head_free.m_pos = element;
/*#define GET_FIRST_FREE(l) ((ELEMENT_##type*)(l->m_head_free.m_pos))*/
#define IMPLEMENT_LIST(type, prefix)\
_CVLIST* prefix##create_list_##type(long size)\
{\
_CVLIST* pl = (_CVLIST*)cvAlloc(sizeof(_CVLIST));\
pl->m_buf_size = size > 0 ? size : default_size;\
pl->m_first_buffer = cvAlloc(pl->m_buf_size*sizeof(ELEMENT_##type) + sizeof(void*));\
pl->m_buffer = pl->m_first_buffer;\
*(void**)pl->m_buffer = NULL;\
pl->m_size = 0;\
pl->m_head.m_pos = NULL;\
pl->m_tail.m_pos = NULL;\
pl->m_head_free.m_pos = NULL;\
return pl;\
}\
void prefix##destroy_list_##type(_CVLIST* l)\
{\
void* cur = l->m_first_buffer;\
void* next;\
while(cur)\
{\
next = *(void**)cur;\
cvFree(&cur);\
cur = next;\
}\
cvFree(&l);\
}\
CVPOS prefix##get_head_pos_##type(_CVLIST* l)\
{\
return l->m_head;\
}\
CVPOS prefix##get_tail_pos_##type(_CVLIST* l)\
{\
return l->m_tail;\
}\
type* prefix##get_next_##type(CVPOS* pos)\
{\
if(pos->m_pos)\
{\
ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\
pos->m_pos = element->m_next;\
return &element->m_data;\
}\
else\
{\
return NULL;\
}\
}\
type* prefix##get_prev_##type(CVPOS* pos)\
{\
if(pos->m_pos)\
{\
ELEMENT_##type* element = (ELEMENT_##type*)(pos->m_pos);\
pos->m_pos = element->m_prev;\
return &element->m_data;\
}\
else\
{\
return NULL;\
}\
}\
int prefix##is_pos_##type(CVPOS pos)\
{\
return !!pos.m_pos;\
}\
void prefix##clear_list_##type(_CVLIST* l)\
{\
l->m_head.m_pos = NULL;\
l->m_tail.m_pos = NULL;\
l->m_size = 0;\
l->m_head_free.m_pos = NULL;\
}\
CVPOS prefix##add_head_##type(_CVLIST* l, type* data)\
{\
ELEMENT_##type* element;\
INSERT_NEW(ELEMENT_##type, l, element);\
element->m_prev = NULL;\
element->m_next = (ELEMENT_##type*)(l->m_head.m_pos);\
memcpy(&(element->m_data), data, sizeof(*data));\
if(element->m_next)\
{\
element->m_next->m_prev = element;\
}\
else\
{\
l->m_tail.m_pos = element;\
}\
l->m_head.m_pos = element;\
return l->m_head;\
}\
CVPOS prefix##add_tail_##type(_CVLIST* l, type* data)\
{\
ELEMENT_##type* element;\
INSERT_NEW(ELEMENT_##type, l, element);\
element->m_next = NULL;\
element->m_prev = (ELEMENT_##type*)(l->m_tail.m_pos);\
memcpy(&(element->m_data), data, sizeof(*data));\
if(element->m_prev)\
{\
element->m_prev->m_next = element;\
}\
else\
{\
l->m_head.m_pos = element;\
}\
l->m_tail.m_pos = element;\
return l->m_tail;\
}\
void prefix##remove_head_##type(_CVLIST* l)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_head.m_pos));\
if(element->m_next != NULL)\
{\
element->m_next->m_prev = NULL;\
}\
l->m_head.m_pos = element->m_next;\
INSERT_FREE(ELEMENT_##type, l, element);\
l->m_size--;\
}\
void prefix##remove_tail_##type(_CVLIST* l)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(l->m_tail.m_pos));\
if(element->m_prev != NULL)\
{\
element->m_prev->m_next = NULL;\
}\
l->m_tail.m_pos = element->m_prev;\
INSERT_FREE(ELEMENT_##type, l, element);\
l->m_size--;\
}\
CVPOS prefix##insert_after_##type(_CVLIST* l, CVPOS pos, type* data)\
{\
ELEMENT_##type* element;\
ELEMENT_##type* before;\
CVPOS newpos;\
INSERT_NEW(ELEMENT_##type, l, element);\
memcpy(&(element->m_data), data, sizeof(*data));\
before = (ELEMENT_##type*)pos.m_pos;\
element->m_prev = before;\
element->m_next = before->m_next;\
before->m_next = element;\
if(element->m_next != NULL)\
element->m_next->m_prev = element;\
else\
l->m_tail.m_pos = element;\
newpos.m_pos = element;\
return newpos;\
}\
CVPOS prefix##insert_before_##type(_CVLIST* l, CVPOS pos, type* data)\
{\
ELEMENT_##type* element;\
ELEMENT_##type* after;\
CVPOS newpos;\
INSERT_NEW(ELEMENT_##type, l, element);\
memcpy(&(element->m_data), data, sizeof(*data));\
after = (ELEMENT_##type*)pos.m_pos;\
element->m_prev = after->m_prev;\
element->m_next = after;\
after->m_prev = element;\
if(element->m_prev != NULL)\
element->m_prev->m_next = element;\
else\
l->m_head.m_pos = element;\
newpos.m_pos = element;\
return newpos;\
}\
void prefix##remove_at_##type(_CVLIST* l, CVPOS pos)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)pos.m_pos);\
if(element->m_prev != NULL)\
{\
element->m_prev->m_next = element->m_next;\
}\
else\
{\
l->m_head.m_pos = element->m_next;\
}\
if(element->m_next != NULL)\
{\
element->m_next->m_prev = element->m_prev;\
}\
else\
{\
l->m_tail.m_pos = element->m_prev;\
}\
INSERT_FREE(ELEMENT_##type, l, element);\
l->m_size--;\
}\
void prefix##set_##type(CVPOS pos, type* data)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\
memcpy(&(element->m_data), data, sizeof(data));\
}\
type* prefix##get_##type(CVPOS pos)\
{\
ELEMENT_##type* element = ((ELEMENT_##type*)(pos.m_pos));\
return &(element->m_data);\
}\
int prefix##get_count_##type(_CVLIST* list)\
{\
return list->m_size;\
}
#define DECLARE_AND_IMPLEMENT_LIST(type, prefix)\
DECLARE_LIST(type, prefix)\
IMPLEMENT_LIST(type, prefix)
typedef struct __index
{
int value;
float rho, theta;
}
_index;
DECLARE_LIST( _index, h_ )
#endif/*_CV_LIST_H_*/

View File

@@ -0,0 +1,638 @@
/*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.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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"
namespace cv
{
inline float sqr(uchar a) { return CV_8TO32F_SQR(a); }
inline float sqr(float a) { return a*a; }
inline double sqr(double a) { return a*a; }
inline Vec3f sqr(const Vec3b& a)
{
return Vec3f(CV_8TO32F_SQR(a[0]), CV_8TO32F_SQR(a[1]), CV_8TO32F_SQR(a[2]));
}
inline Vec3f sqr(const Vec3f& a)
{
return Vec3f(a[0]*a[0], a[1]*a[1], a[2]*a[2]);
}
inline Vec3d sqr(const Vec3d& a)
{
return Vec3d(a[0]*a[0], a[1]*a[1], a[2]*a[2]);
}
inline float multiply(uchar a, uchar b) { return CV_8TO32F(a)*CV_8TO32F(b); }
inline float multiply(float a, float b) { return a*b; }
inline double multiply(double a, double b) { return a*b; }
inline Vec3f multiply(const Vec3b& a, const Vec3b& b)
{
return Vec3f(
CV_8TO32F(a[0])*CV_8TO32F(b[0]),
CV_8TO32F(a[1])*CV_8TO32F(b[1]),
CV_8TO32F(a[2])*CV_8TO32F(b[2]));
}
inline Vec3f multiply(const Vec3f& a, const Vec3f& b)
{
return Vec3f(a[0]*b[0], a[1]*b[1], a[2]*b[2]);
}
inline Vec3d multiply(const Vec3d& a, const Vec3d& b)
{
return Vec3d(a[0]*b[0], a[1]*b[1], a[2]*b[2]);
}
inline float addw(uchar a, float alpha, float b, float beta)
{
return b*beta + CV_8TO32F(a)*alpha;
}
inline float addw(float a, float alpha, float b, float beta)
{
return b*beta + a*alpha;
}
inline double addw(uchar a, double alpha, double b, double beta)
{
return b*beta + CV_8TO32F(a)*alpha;
}
inline double addw(float a, double alpha, double b, double beta)
{
return b*beta + a*alpha;
}
inline double addw(double a, double alpha, double b, double beta)
{
return b*beta + a*alpha;
}
inline Vec3f addw(const Vec3b& a, float alpha, const Vec3f& b, float beta)
{
return Vec3f(b[0]*beta + CV_8TO32F(a[0])*alpha,
b[1]*beta + CV_8TO32F(a[1])*alpha,
b[2]*beta + CV_8TO32F(a[2])*alpha);
}
inline Vec3f addw(const Vec3f& a, float alpha, const Vec3f& b, float beta)
{
return Vec3f(b[0]*beta + a[0]*alpha, b[1]*beta + a[1]*alpha, b[2]*beta + a[2]*alpha);
}
inline Vec3d addw(const Vec3b& a, double alpha, const Vec3d& b, double beta)
{
return Vec3d(b[0]*beta + CV_8TO32F(a[0])*alpha,
b[1]*beta + CV_8TO32F(a[1])*alpha,
b[2]*beta + CV_8TO32F(a[2])*alpha);
}
inline Vec3d addw(const Vec3f& a, double alpha, const Vec3d& b, double beta)
{
return Vec3d(b[0]*beta + a[0]*alpha, b[1]*beta + a[1]*alpha, b[2]*beta + a[2]*alpha);
}
inline Vec3d addw(const Vec3d& a, double alpha, const Vec3d& b, double beta)
{
return Vec3d(b[0]*beta + a[0]*alpha, b[1]*beta + a[1]*alpha, b[2]*beta + a[2]*alpha);
}
template<typename T, typename AT> void
acc_( const Mat& _src, Mat& _dst )
{
Size size = _src.size();
size.width *= _src.channels();
if( _src.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src = (const T*)(_src.data + _src.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
for( j = 0; j <= size.width - 4; j += 4 )
{
AT t0 = dst[j] + src[j], t1 = dst[j+1] + src[j+1];
dst[j] = t0; dst[j+1] = t1;
t0 = dst[j+2] + src[j+2]; t1 = dst[j+3] + src[j+3];
dst[j+2] = t0; dst[j+3] = t1;
}
for( ; j < size.width; j++ )
dst[j] += src[j];
}
}
template<typename T, typename AT> void
accSqr_( const Mat& _src, Mat& _dst )
{
Size size = _src.size();
size.width *= _src.channels();
if( _src.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src = (const T*)(_src.data + _src.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
for( j = 0; j <= size.width - 4; j += 4 )
{
AT t0 = dst[j] + sqr(src[j]), t1 = dst[j+1] + sqr(src[j+1]);
dst[j] = t0; dst[j+1] = t1;
t0 = dst[j+2] + sqr(src[j+2]); t1 = dst[j+3] + sqr(src[j+3]);
dst[j+2] = t0; dst[j+3] = t1;
}
for( ; j < size.width; j++ )
dst[j] += sqr(src[j]);
}
}
template<typename T, typename AT> void
accProd_( const Mat& _src1, const Mat& _src2, Mat& _dst )
{
Size size = _src1.size();
size.width *= _src1.channels();
if( _src1.isContinuous() && _src2.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src1 = (const T*)(_src1.data + _src1.step*i);
const T* src2 = (const T*)(_src2.data + _src2.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
for( j = 0; j <= size.width - 4; j += 4 )
{
AT t0, t1;
t0 = dst[j] + multiply(src1[j], src2[j]);
t1 = dst[j+1] + multiply(src1[j+1], src2[j+1]);
dst[j] = t0; dst[j+1] = t1;
t0 = dst[j+2] + multiply(src1[j+2], src2[j+2]);
t1 = dst[j+3] + multiply(src1[j+3], src2[j+3]);
dst[j+2] = t0; dst[j+3] = t1;
}
for( ; j < size.width; j++ )
dst[j] += multiply(src1[j], src2[j]);
}
}
template<typename T, typename AT> void
accW_( const Mat& _src, Mat& _dst, double _alpha )
{
AT alpha = (AT)_alpha, beta = (AT)(1 - _alpha);
Size size = _src.size();
size.width *= _src.channels();
if( _src.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src = (const T*)(_src.data + _src.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
for( j = 0; j <= size.width - 4; j += 4 )
{
AT t0, t1;
t0 = addw(src[j], alpha, dst[j], beta);
t1 = addw(src[j+1], alpha, dst[j+1], beta);
dst[j] = t0; dst[j+1] = t1;
t0 = addw(src[j+2], alpha, dst[j+2], beta);
t1 = addw(src[j+3], alpha, dst[j+3], beta);
dst[j+2] = t0; dst[j+3] = t1;
}
for( ; j < size.width; j++ )
dst[j] = addw(src[j], alpha, dst[j], beta);
}
}
template<typename T, typename AT> void
accMask_( const Mat& _src, Mat& _dst, const Mat& _mask )
{
Size size = _src.size();
if( _src.isContinuous() && _dst.isContinuous() && _mask.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src = (const T*)(_src.data + _src.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
const uchar* mask = _mask.data + _mask.step*i;
for( j = 0; j < size.width; j++ )
if( mask[j] )
dst[j] += src[j];
}
}
template<typename T, typename AT> void
accSqrMask_( const Mat& _src, Mat& _dst, const Mat& _mask )
{
Size size = _src.size();
if( _src.isContinuous() && _dst.isContinuous() && _mask.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src = (const T*)(_src.data + _src.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
const uchar* mask = _mask.data + _mask.step*i;
for( j = 0; j < size.width; j++ )
if( mask[j] )
dst[j] += sqr(src[j]);
}
}
template<typename T, typename AT> void
accProdMask_( const Mat& _src1, const Mat& _src2, Mat& _dst, const Mat& _mask )
{
Size size = _src1.size();
if( _src1.isContinuous() && _src2.isContinuous() &&
_dst.isContinuous() && _mask.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src1 = (const T*)(_src1.data + _src1.step*i);
const T* src2 = (const T*)(_src2.data + _src2.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
const uchar* mask = _mask.data + _mask.step*i;
for( j = 0; j < size.width; j++ )
if( mask[j] )
dst[j] += multiply(src1[j], src2[j]);
}
}
template<typename T, typename AT> void
accWMask_( const Mat& _src, Mat& _dst, double _alpha, const Mat& _mask )
{
typedef typename DataType<AT>::channel_type AT1;
AT1 alpha = (AT1)_alpha, beta = (AT1)(1 - _alpha);
Size size = _src.size();
if( _src.isContinuous() && _dst.isContinuous() && _mask.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
int i, j;
for( i = 0; i < size.height; i++ )
{
const T* src = (const T*)(_src.data + _src.step*i);
AT* dst = (AT*)(_dst.data + _dst.step*i);
const uchar* mask = _mask.data + _mask.step*i;
for( j = 0; j < size.width; j++ )
if( mask[j] )
dst[j] = addw(src[j], alpha, dst[j], beta);
}
}
typedef void (*AccFunc)(const Mat&, Mat&);
typedef void (*AccMaskFunc)(const Mat&, Mat&, const Mat&);
typedef void (*AccProdFunc)(const Mat&, const Mat&, Mat&);
typedef void (*AccProdMaskFunc)(const Mat&, const Mat&, Mat&, const Mat&);
typedef void (*AccWFunc)(const Mat&, Mat&, double);
typedef void (*AccWMaskFunc)(const Mat&, Mat&, double, const Mat&);
void accumulate( const Mat& src, Mat& dst, const Mat& mask )
{
CV_Assert( dst.size() == src.size() && dst.channels() == src.channels() );
if( !mask.data )
{
AccFunc func = 0;
if( src.depth() == CV_8U && dst.depth() == CV_32F )
func = acc_<uchar, float>;
else if( src.depth() == CV_8U && dst.depth() == CV_64F )
func = acc_<uchar, double>;
else if( src.depth() == CV_32F && dst.depth() == CV_32F )
func = acc_<float, float>;
else if( src.depth() == CV_32F && dst.depth() == CV_64F )
func = acc_<float, double>;
else if( src.depth() == CV_64F && dst.depth() == CV_64F )
func = acc_<double, double>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src, dst );
}
else
{
CV_Assert( mask.size() == src.size() && mask.type() == CV_8UC1 );
AccMaskFunc func = 0;
if( src.type() == CV_8UC1 && dst.type() == CV_32FC1 )
func = accMask_<uchar, float>;
else if( src.type() == CV_8UC3 && dst.type() == CV_32FC3 )
func = accMask_<Vec3b, Vec3f>;
else if( src.type() == CV_8UC1 && dst.type() == CV_64FC1 )
func = accMask_<uchar, double>;
else if( src.type() == CV_8UC3 && dst.type() == CV_64FC3 )
func = accMask_<Vec3b, Vec3d>;
else if( src.type() == CV_32FC1 && dst.type() == CV_32FC1 )
func = accMask_<float, float>;
else if( src.type() == CV_32FC3 && dst.type() == CV_32FC3 )
func = accMask_<Vec3f, Vec3f>;
else if( src.type() == CV_32FC1 && dst.type() == CV_64FC1 )
func = accMask_<float, double>;
else if( src.type() == CV_32FC3 && dst.type() == CV_64FC3 )
func = accMask_<Vec3f, Vec3d>;
else if( src.type() == CV_64FC1 && dst.type() == CV_64FC1 )
func = accMask_<double, double>;
else if( src.type() == CV_64FC3 && dst.type() == CV_64FC3 )
func = accMask_<Vec3d, Vec3d>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src, dst, mask );
}
}
void accumulateSquare( const Mat& src, Mat& dst, const Mat& mask )
{
CV_Assert( dst.size() == src.size() && dst.channels() == src.channels() );
if( !mask.data )
{
AccFunc func = 0;
if( src.depth() == CV_8U && dst.depth() == CV_32F )
func = accSqr_<uchar, float>;
else if( src.depth() == CV_8U && dst.depth() == CV_64F )
func = accSqr_<uchar, double>;
else if( src.depth() == CV_32F && dst.depth() == CV_32F )
func = accSqr_<float, float>;
else if( src.depth() == CV_32F && dst.depth() == CV_64F )
func = accSqr_<float, double>;
else if( src.depth() == CV_64F && dst.depth() == CV_64F )
func = accSqr_<double, double>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src, dst );
}
else
{
CV_Assert( mask.size() == src.size() && mask.type() == CV_8UC1 );
AccMaskFunc func = 0;
if( src.type() == CV_8UC1 && dst.type() == CV_32FC1 )
func = accSqrMask_<uchar, float>;
else if( src.type() == CV_8UC3 && dst.type() == CV_32FC3 )
func = accSqrMask_<Vec3b, Vec3f>;
else if( src.type() == CV_8UC1 && dst.type() == CV_64FC1 )
func = accSqrMask_<uchar, double>;
else if( src.type() == CV_8UC3 && dst.type() == CV_64FC3 )
func = accSqrMask_<Vec3b, Vec3d>;
else if( src.type() == CV_32FC1 && dst.type() == CV_32FC1 )
func = accSqrMask_<float, float>;
else if( src.type() == CV_32FC3 && dst.type() == CV_32FC3 )
func = accSqrMask_<Vec3f, Vec3f>;
else if( src.type() == CV_32FC1 && dst.type() == CV_64FC1 )
func = accSqrMask_<float, double>;
else if( src.type() == CV_32FC3 && dst.type() == CV_64FC3 )
func = accSqrMask_<Vec3f, Vec3d>;
else if( src.type() == CV_64FC1 && dst.type() == CV_64FC1 )
func = accSqrMask_<double, double>;
else if( src.type() == CV_64FC3 && dst.type() == CV_64FC3 )
func = accSqrMask_<Vec3d, Vec3d>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src, dst, mask );
}
}
void accumulateProduct( const Mat& src1, const Mat& src2, Mat& dst, const Mat& mask )
{
CV_Assert( dst.size() == src1.size() && dst.channels() == src1.channels() &&
src1.size() == src2.size() && src1.type() == src2.type() );
if( !mask.data )
{
AccProdFunc func = 0;
if( src1.depth() == CV_8U && dst.depth() == CV_32F )
func = accProd_<uchar, float>;
else if( src1.depth() == CV_8U && dst.depth() == CV_64F )
func = accProd_<uchar, double>;
else if( src1.depth() == CV_32F && dst.depth() == CV_32F )
func = accProd_<float, float>;
else if( src1.depth() == CV_32F && dst.depth() == CV_64F )
func = accProd_<float, double>;
else if( src1.depth() == CV_64F && dst.depth() == CV_64F )
func = accProd_<double, double>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src1, src2, dst );
}
else
{
CV_Assert( mask.size() == src1.size() && mask.type() == CV_8UC1 );
AccProdMaskFunc func = 0;
if( src1.type() == CV_8UC1 && dst.type() == CV_32FC1 )
func = accProdMask_<uchar, float>;
else if( src1.type() == CV_8UC3 && dst.type() == CV_32FC3 )
func = accProdMask_<Vec3b, Vec3f>;
else if( src1.type() == CV_8UC1 && dst.type() == CV_64FC1 )
func = accProdMask_<uchar, double>;
else if( src1.type() == CV_8UC3 && dst.type() == CV_64FC3 )
func = accProdMask_<Vec3b, Vec3d>;
else if( src1.type() == CV_32FC1 && dst.type() == CV_32FC1 )
func = accProdMask_<float, float>;
else if( src1.type() == CV_32FC3 && dst.type() == CV_32FC3 )
func = accProdMask_<Vec3f, Vec3f>;
else if( src1.type() == CV_32FC1 && dst.type() == CV_64FC1 )
func = accProdMask_<float, double>;
else if( src1.type() == CV_32FC3 && dst.type() == CV_64FC3 )
func = accProdMask_<Vec3f, Vec3d>;
else if( src1.type() == CV_64FC1 && dst.type() == CV_64FC1 )
func = accProdMask_<double, double>;
else if( src1.type() == CV_64FC3 && dst.type() == CV_64FC3 )
func = accProdMask_<Vec3d, Vec3d>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src1, src2, dst, mask );
}
}
void accumulateWeighted( const Mat& src, Mat& dst, double alpha, const Mat& mask )
{
CV_Assert( dst.size() == src.size() && dst.channels() == src.channels() );
if( !mask.data )
{
AccWFunc func = 0;
if( src.depth() == CV_8U && dst.depth() == CV_32F )
func = accW_<uchar, float>;
else if( src.depth() == CV_8U && dst.depth() == CV_64F )
func = accW_<uchar, double>;
else if( src.depth() == CV_32F && dst.depth() == CV_32F )
func = accW_<float, float>;
else if( src.depth() == CV_32F && dst.depth() == CV_64F )
func = accW_<float, double>;
else if( src.depth() == CV_64F && dst.depth() == CV_64F )
func = accW_<double, double>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src, dst, alpha );
}
else
{
CV_Assert( mask.size() == src.size() && mask.type() == CV_8UC1 );
AccWMaskFunc func = 0;
if( src.type() == CV_8UC1 && dst.type() == CV_32FC1 )
func = accWMask_<uchar, float>;
else if( src.type() == CV_8UC3 && dst.type() == CV_32FC3 )
func = accWMask_<Vec3b, Vec3f>;
else if( src.type() == CV_8UC1 && dst.type() == CV_64FC1 )
func = accWMask_<uchar, double>;
else if( src.type() == CV_8UC3 && dst.type() == CV_64FC3 )
func = accWMask_<Vec3b, Vec3d>;
else if( src.type() == CV_32FC1 && dst.type() == CV_32FC1 )
func = accWMask_<float, float>;
else if( src.type() == CV_32FC3 && dst.type() == CV_32FC3 )
func = accWMask_<Vec3f, Vec3f>;
else if( src.type() == CV_32FC1 && dst.type() == CV_64FC1 )
func = accWMask_<float, double>;
else if( src.type() == CV_32FC3 && dst.type() == CV_64FC3 )
func = accWMask_<Vec3f, Vec3d>;
else if( src.type() == CV_64FC1 && dst.type() == CV_64FC1 )
func = accWMask_<double, double>;
else if( src.type() == CV_64FC3 && dst.type() == CV_64FC3 )
func = accWMask_<Vec3d, Vec3d>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src, dst, alpha, mask );
}
}
}
CV_IMPL void
cvAcc( const void* arr, void* sumarr, const void* maskarr )
{
cv::Mat src = cv::cvarrToMat(arr), dst = cv::cvarrToMat(sumarr), mask;
if( maskarr )
mask = cv::cvarrToMat(maskarr);
cv::accumulate( src, dst, mask );
}
CV_IMPL void
cvSquareAcc( const void* arr, void* sumarr, const void* maskarr )
{
cv::Mat src = cv::cvarrToMat(arr), dst = cv::cvarrToMat(sumarr), mask;
if( maskarr )
mask = cv::cvarrToMat(maskarr);
cv::accumulateSquare( src, dst, mask );
}
CV_IMPL void
cvMultiplyAcc( const void* arr1, const void* arr2,
void* sumarr, const void* maskarr )
{
cv::Mat src1 = cv::cvarrToMat(arr1), src2 = cv::cvarrToMat(arr2);
cv::Mat dst = cv::cvarrToMat(sumarr), mask;
if( maskarr )
mask = cv::cvarrToMat(maskarr);
cv::accumulateProduct( src1, src2, dst, mask );
}
CV_IMPL void
cvRunningAvg( const void* arr, void* sumarr, double alpha, const void* maskarr )
{
cv::Mat src = cv::cvarrToMat(arr), dst = cv::cvarrToMat(sumarr), mask;
if( maskarr )
mask = cv::cvarrToMat(maskarr);
cv::accumulateWeighted( src, dst, alpha, mask );
}
/* End of file. */

View File

@@ -0,0 +1,803 @@
/*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"
/****************************************************************************************\
* Chain Approximation *
\****************************************************************************************/
typedef struct _CvPtInfo
{
CvPoint pt;
int k; /* support region */
int s; /* curvature value */
struct _CvPtInfo *next;
}
_CvPtInfo;
/* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */
CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size,
CvMemStorage* storage, int method )
{
static const int abs_diff[] = { 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1 };
cv::AutoBuffer<_CvPtInfo> buf(chain->total + 8);
_CvPtInfo temp;
_CvPtInfo *array = buf, *first = 0, *current = 0, *prev_current = 0;
int i, j, i1, i2, s, len;
int count = chain->total;
CvChainPtReader reader;
CvSeqWriter writer;
CvPoint pt = chain->origin;
CV_Assert( CV_IS_SEQ_CHAIN_CONTOUR( chain ));
CV_Assert( header_size >= (int)sizeof(CvContour) );
cvStartWriteSeq( (chain->flags & ~CV_SEQ_ELTYPE_MASK) | CV_SEQ_ELTYPE_POINT,
header_size, sizeof( CvPoint ), storage, &writer );
if( chain->total == 0 )
{
CV_WRITE_SEQ_ELEM( pt, writer );
return cvEndWriteSeq( &writer );
}
cvStartReadChainPoints( chain, &reader );
temp.next = 0;
current = &temp;
/* Pass 0.
Restores all the digital curve points from the chain code.
Removes the points (from the resultant polygon)
that have zero 1-curvature */
for( i = 0; i < count; i++ )
{
int prev_code = *reader.prev_elem;
reader.prev_elem = reader.ptr;
CV_READ_CHAIN_POINT( pt, reader );
/* calc 1-curvature */
s = abs_diff[reader.code - prev_code + 7];
if( method <= CV_CHAIN_APPROX_SIMPLE )
{
if( method == CV_CHAIN_APPROX_NONE || s != 0 )
{
CV_WRITE_SEQ_ELEM( pt, writer );
}
}
else
{
if( s != 0 )
current = current->next = array + i;
array[i].s = s;
array[i].pt = pt;
}
}
//assert( pt.x == chain->origin.x && pt.y == chain->origin.y );
if( method <= CV_CHAIN_APPROX_SIMPLE )
return cvEndWriteSeq( &writer );
current->next = 0;
len = i;
current = temp.next;
assert( current );
/* Pass 1.
Determines support region for all the remained points */
do
{
CvPoint pt0;
int k, l = 0, d_num = 0;
i = (int)(current - array);
pt0 = array[i].pt;
/* determine support region */
for( k = 1;; k++ )
{
int lk, dk_num;
int dx, dy;
Cv32suf d;
assert( k <= len );
/* calc indices */
i1 = i - k;
i1 += i1 < 0 ? len : 0;
i2 = i + k;
i2 -= i2 >= len ? len : 0;
dx = array[i2].pt.x - array[i1].pt.x;
dy = array[i2].pt.y - array[i1].pt.y;
/* distance between p_(i - k) and p_(i + k) */
lk = dx * dx + dy * dy;
/* distance between p_i and the line (p_(i-k), p_(i+k)) */
dk_num = (pt0.x - array[i1].pt.x) * dy - (pt0.y - array[i1].pt.y) * dx;
d.f = (float) (((double) d_num) * lk - ((double) dk_num) * l);
if( k > 1 && (l >= lk || ((d_num > 0 && d.i <= 0) || (d_num < 0 && d.i >= 0))))
break;
d_num = dk_num;
l = lk;
}
current->k = --k;
/* determine cosine curvature if it should be used */
if( method == CV_CHAIN_APPROX_TC89_KCOS )
{
/* calc k-cosine curvature */
for( j = k, s = 0; j > 0; j-- )
{
double temp_num;
int dx1, dy1, dx2, dy2;
Cv32suf sk;
i1 = i - j;
i1 += i1 < 0 ? len : 0;
i2 = i + j;
i2 -= i2 >= len ? len : 0;
dx1 = array[i1].pt.x - pt0.x;
dy1 = array[i1].pt.y - pt0.y;
dx2 = array[i2].pt.x - pt0.x;
dy2 = array[i2].pt.y - pt0.y;
if( (dx1 | dy1) == 0 || (dx2 | dy2) == 0 )
break;
temp_num = dx1 * dx2 + dy1 * dy2;
temp_num =
(float) (temp_num /
sqrt( ((double)dx1 * dx1 + (double)dy1 * dy1) *
((double)dx2 * dx2 + (double)dy2 * dy2) ));
sk.f = (float) (temp_num + 1.1);
assert( 0 <= sk.f && sk.f <= 2.2 );
if( j < k && sk.i <= s )
break;
s = sk.i;
}
current->s = s;
}
current = current->next;
}
while( current != 0 );
prev_current = &temp;
current = temp.next;
/* Pass 2.
Performs non-maxima supression */
do
{
int k2 = current->k >> 1;
s = current->s;
i = (int)(current - array);
for( j = 1; j <= k2; j++ )
{
i2 = i - j;
i2 += i2 < 0 ? len : 0;
if( array[i2].s > s )
break;
i2 = i + j;
i2 -= i2 >= len ? len : 0;
if( array[i2].s > s )
break;
}
if( j <= k2 ) /* exclude point */
{
prev_current->next = current->next;
current->s = 0; /* "clear" point */
}
else
prev_current = current;
current = current->next;
}
while( current != 0 );
/* Pass 3.
Removes non-dominant points with 1-length support region */
current = temp.next;
assert( current );
prev_current = &temp;
do
{
if( current->k == 1 )
{
s = current->s;
i = (int)(current - array);
i1 = i - 1;
i1 += i1 < 0 ? len : 0;
i2 = i + 1;
i2 -= i2 >= len ? len : 0;
if( s <= array[i1].s || s <= array[i2].s )
{
prev_current->next = current->next;
current->s = 0;
}
else
prev_current = current;
}
else
prev_current = current;
current = current->next;
}
while( current != 0 );
if( method == CV_CHAIN_APPROX_TC89_KCOS )
goto copy_vect;
/* Pass 4.
Cleans remained couples of points */
assert( temp.next );
if( array[0].s != 0 && array[len - 1].s != 0 ) /* specific case */
{
for( i1 = 1; i1 < len && array[i1].s != 0; i1++ )
{
array[i1 - 1].s = 0;
}
if( i1 == len )
goto copy_vect; /* all points survived */
i1--;
for( i2 = len - 2; i2 > 0 && array[i2].s != 0; i2-- )
{
array[i2].next = 0;
array[i2 + 1].s = 0;
}
i2++;
if( i1 == 0 && i2 == len - 1 ) /* only two points */
{
i1 = (int)(array[0].next - array);
array[len] = array[0]; /* move to the end */
array[len].next = 0;
array[len - 1].next = array + len;
}
temp.next = array + i1;
}
current = temp.next;
first = prev_current = &temp;
count = 1;
/* do last pass */
do
{
if( current->next == 0 || current->next - current != 1 )
{
if( count >= 2 )
{
if( count == 2 )
{
int s1 = prev_current->s;
int s2 = current->s;
if( s1 > s2 || (s1 == s2 && prev_current->k <= current->k) )
/* remove second */
prev_current->next = current->next;
else
/* remove first */
first->next = current;
}
else
first->next->next = current;
}
first = current;
count = 1;
}
else
count++;
prev_current = current;
current = current->next;
}
while( current != 0 );
copy_vect:
// gather points
current = temp.next;
assert( current );
do
{
CV_WRITE_SEQ_ELEM( current->pt, writer );
current = current->next;
}
while( current != 0 );
return cvEndWriteSeq( &writer );
}
/*Applies some approximation algorithm to chain-coded contour(s) and
converts it/them to polygonal representation */
CV_IMPL CvSeq*
cvApproxChains( CvSeq* src_seq,
CvMemStorage* storage,
int method,
double /*parameter*/,
int minimal_perimeter,
int recursive )
{
CvSeq *prev_contour = 0, *parent = 0;
CvSeq *dst_seq = 0;
if( !src_seq || !storage )
CV_Error( CV_StsNullPtr, "" );
if( method > CV_CHAIN_APPROX_TC89_KCOS || method <= 0 || minimal_perimeter < 0 )
CV_Error( CV_StsOutOfRange, "" );
while( src_seq != 0 )
{
int len = src_seq->total;
if( len >= minimal_perimeter )
{
CvSeq *contour = 0;
switch( method )
{
case CV_CHAIN_APPROX_NONE:
case CV_CHAIN_APPROX_SIMPLE:
case CV_CHAIN_APPROX_TC89_L1:
case CV_CHAIN_APPROX_TC89_KCOS:
contour = icvApproximateChainTC89( (CvChain *) src_seq, sizeof( CvContour ), storage, method );
break;
default:
CV_Error( CV_StsOutOfRange, "" );
}
if( contour->total > 0 )
{
cvBoundingRect( contour, 1 );
contour->v_prev = parent;
contour->h_prev = prev_contour;
if( prev_contour )
prev_contour->h_next = contour;
else if( parent )
parent->v_next = contour;
prev_contour = contour;
if( !dst_seq )
dst_seq = prev_contour;
}
else /* if resultant contour has zero length, skip it */
{
len = -1;
}
}
if( !recursive )
break;
if( src_seq->v_next && len >= minimal_perimeter )
{
assert( prev_contour != 0 );
parent = prev_contour;
prev_contour = 0;
src_seq = src_seq->v_next;
}
else
{
while( src_seq->h_next == 0 )
{
src_seq = src_seq->v_prev;
if( src_seq == 0 )
break;
prev_contour = parent;
if( parent )
parent = parent->v_prev;
}
if( src_seq )
src_seq = src_seq->h_next;
}
}
return dst_seq;
}
/****************************************************************************************\
* Polygonal Approximation *
\****************************************************************************************/
/* Ramer-Douglas-Peucker algorithm for polygon simplification */
/* the version for integer point coordinates */
template<typename T> static CvSeq*
icvApproxPolyDP( CvSeq* src_contour, int header_size,
CvMemStorage* storage, double eps )
{
typedef cv::Point_<T> PT;
int init_iters = 3;
CvSlice slice = {0, 0}, right_slice = {0, 0};
CvSeqReader reader, reader2;
CvSeqWriter writer;
PT start_pt(-1000000, -1000000), end_pt(0, 0), pt(0,0);
int i = 0, j, count = src_contour->total, new_count;
int is_closed = CV_IS_SEQ_CLOSED( src_contour );
bool le_eps = false;
CvMemStorage* temp_storage = 0;
CvSeq* stack = 0;
CvSeq* dst_contour;
assert( CV_SEQ_ELTYPE(src_contour) == cv::DataType<PT>::type );
cvStartWriteSeq( src_contour->flags, header_size, sizeof(pt), storage, &writer );
if( src_contour->total == 0 )
return cvEndWriteSeq( &writer );
temp_storage = cvCreateChildMemStorage( storage );
assert( src_contour->first != 0 );
stack = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSlice), temp_storage );
eps *= eps;
cvStartReadSeq( src_contour, &reader, 0 );
if( !is_closed )
{
right_slice.start_index = count;
end_pt = *(PT*)(reader.ptr);
start_pt = *(PT*)cvGetSeqElem( src_contour, -1 );
if( start_pt.x != end_pt.x || start_pt.y != end_pt.y )
{
slice.start_index = 0;
slice.end_index = count - 1;
cvSeqPush( stack, &slice );
}
else
{
is_closed = 1;
init_iters = 1;
}
}
if( is_closed )
{
/* 1. Find approximately two farthest points of the contour */
right_slice.start_index = 0;
for( i = 0; i < init_iters; i++ )
{
double dist, max_dist = 0;
cvSetSeqReaderPos( &reader, right_slice.start_index, 1 );
CV_READ_SEQ_ELEM( start_pt, reader ); /* read the first point */
for( j = 1; j < count; j++ )
{
double dx, dy;
CV_READ_SEQ_ELEM( pt, reader );
dx = pt.x - start_pt.x;
dy = pt.y - start_pt.y;
dist = dx * dx + dy * dy;
if( dist > max_dist )
{
max_dist = dist;
right_slice.start_index = j;
}
}
le_eps = max_dist <= eps;
}
/* 2. initialize the stack */
if( !le_eps )
{
slice.start_index = cvGetSeqReaderPos( &reader );
slice.end_index = right_slice.start_index += slice.start_index;
right_slice.start_index -= right_slice.start_index >= count ? count : 0;
right_slice.end_index = slice.start_index;
if( right_slice.end_index < right_slice.start_index )
right_slice.end_index += count;
cvSeqPush( stack, &right_slice );
cvSeqPush( stack, &slice );
}
else
CV_WRITE_SEQ_ELEM( start_pt, writer );
}
/* 3. run recursive process */
while( stack->total != 0 )
{
cvSeqPop( stack, &slice );
cvSetSeqReaderPos( &reader, slice.end_index );
CV_READ_SEQ_ELEM( end_pt, reader );
cvSetSeqReaderPos( &reader, slice.start_index );
CV_READ_SEQ_ELEM( start_pt, reader );
if( slice.end_index > slice.start_index + 1 )
{
double dx, dy, dist, max_dist = 0;
dx = end_pt.x - start_pt.x;
dy = end_pt.y - start_pt.y;
assert( dx != 0 || dy != 0 );
for( i = slice.start_index + 1; i < slice.end_index; i++ )
{
CV_READ_SEQ_ELEM( pt, reader );
dist = abs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
if( dist > max_dist )
{
max_dist = dist;
right_slice.start_index = i;
}
}
le_eps = max_dist * max_dist <= eps * (dx * dx + dy * dy);
}
else
{
assert( slice.end_index > slice.start_index );
le_eps = true;
/* read starting point */
cvSetSeqReaderPos( &reader, slice.start_index );
CV_READ_SEQ_ELEM( start_pt, reader );
}
if( le_eps )
{
CV_WRITE_SEQ_ELEM( start_pt, writer );
}
else
{
right_slice.end_index = slice.end_index;
slice.end_index = right_slice.start_index;
cvSeqPush( stack, &right_slice );
cvSeqPush( stack, &slice );
}
}
is_closed = CV_IS_SEQ_CLOSED( src_contour );
if( !is_closed )
CV_WRITE_SEQ_ELEM( end_pt, writer );
dst_contour = cvEndWriteSeq( &writer );
// last stage: do final clean-up of the approximated contour -
// remove extra points on the [almost] stright lines.
cvStartReadSeq( dst_contour, &reader, is_closed );
CV_READ_SEQ_ELEM( start_pt, reader );
reader2 = reader;
CV_READ_SEQ_ELEM( pt, reader );
new_count = count = dst_contour->total;
for( i = !is_closed; i < count - !is_closed && new_count > 2; i++ )
{
double dx, dy, dist;
CV_READ_SEQ_ELEM( end_pt, reader );
dx = end_pt.x - start_pt.x;
dy = end_pt.y - start_pt.y;
dist = abs((pt.x - start_pt.x)*dy - (pt.y - start_pt.y)*dx);
if( dist * dist <= 0.5*eps*(dx*dx + dy*dy) && dx != 0 && dy != 0 )
{
new_count--;
*((PT*)reader2.ptr) = start_pt = end_pt;
CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 );
CV_READ_SEQ_ELEM( pt, reader );
i++;
continue;
}
*((PT*)reader2.ptr) = start_pt = pt;
CV_NEXT_SEQ_ELEM( sizeof(pt), reader2 );
pt = end_pt;
}
if( !is_closed )
*((PT*)reader2.ptr) = pt;
if( new_count < count )
cvSeqPopMulti( dst_contour, 0, count - new_count );
cvReleaseMemStorage( &temp_storage );
return dst_contour;
}
CV_IMPL CvSeq*
cvApproxPoly( const void* array, int header_size,
CvMemStorage* storage, int method,
double parameter, int parameter2 )
{
CvSeq* dst_seq = 0;
CvSeq *prev_contour = 0, *parent = 0;
CvContour contour_header;
CvSeq* src_seq = 0;
CvSeqBlock block;
int recursive = 0;
if( CV_IS_SEQ( array ))
{
src_seq = (CvSeq*)array;
if( !CV_IS_SEQ_POLYLINE( src_seq ))
CV_Error( CV_StsBadArg, "Unsupported sequence type" );
recursive = parameter2;
if( !storage )
storage = src_seq->storage;
}
else
{
src_seq = cvPointSeqFromMat(
CV_SEQ_KIND_CURVE | (parameter2 ? CV_SEQ_FLAG_CLOSED : 0),
array, &contour_header, &block );
}
if( !storage )
CV_Error( CV_StsNullPtr, "NULL storage pointer " );
if( header_size < 0 )
CV_Error( CV_StsOutOfRange, "header_size is negative. "
"Pass 0 to make the destination header_size == input header_size" );
if( header_size == 0 )
header_size = src_seq->header_size;
if( !CV_IS_SEQ_POLYLINE( src_seq ))
{
if( CV_IS_SEQ_CHAIN( src_seq ))
{
CV_Error( CV_StsBadArg, "Input curves are not polygonal. "
"Use cvApproxChains first" );
}
else
{
CV_Error( CV_StsBadArg, "Input curves have uknown type" );
}
}
if( header_size == 0 )
header_size = src_seq->header_size;
if( header_size < (int)sizeof(CvContour) )
CV_Error( CV_StsBadSize, "New header size must be non-less than sizeof(CvContour)" );
if( method != CV_POLY_APPROX_DP )
CV_Error( CV_StsOutOfRange, "Unknown approximation method" );
while( src_seq != 0 )
{
CvSeq *contour = 0;
switch (method)
{
case CV_POLY_APPROX_DP:
if( parameter < 0 )
CV_Error( CV_StsOutOfRange, "Accuracy must be non-negative" );
if( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 )
contour = icvApproxPolyDP<int>( src_seq, header_size, storage, parameter );
else
contour = icvApproxPolyDP<float>( src_seq, header_size, storage, parameter );
break;
default:
assert(0);
CV_Error( CV_StsBadArg, "Invalid approximation method" );
}
assert( contour );
if( header_size >= (int)sizeof(CvContour))
cvBoundingRect( contour, 1 );
contour->v_prev = parent;
contour->h_prev = prev_contour;
if( prev_contour )
prev_contour->h_next = contour;
else if( parent )
parent->v_next = contour;
prev_contour = contour;
if( !dst_seq )
dst_seq = prev_contour;
if( !recursive )
break;
if( src_seq->v_next )
{
assert( prev_contour != 0 );
parent = prev_contour;
prev_contour = 0;
src_seq = src_seq->v_next;
}
else
{
while( src_seq->h_next == 0 )
{
src_seq = src_seq->v_prev;
if( src_seq == 0 )
break;
prev_contour = parent;
if( parent )
parent = parent->v_prev;
}
if( src_seq )
src_seq = src_seq->h_next;
}
}
return dst_seq;
}
/* End of file. */

View File

@@ -0,0 +1,348 @@
/*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"
CV_IMPL void cvCanny( const void* srcarr, void* dstarr,
double low_thresh, double high_thresh,
int aperture_size )
{
cv::Ptr<CvMat> dx, dy;
cv::AutoBuffer<char> buffer;
std::vector<uchar*> stack;
uchar **stack_top = 0, **stack_bottom = 0;
CvMat srcstub, *src = cvGetMat( srcarr, &srcstub );
CvMat dststub, *dst = cvGetMat( dstarr, &dststub );
CvSize size;
int flags = aperture_size;
int low, high;
int* mag_buf[3];
uchar* map;
int mapstep, maxsize;
int i, j;
CvMat mag_row;
if( CV_MAT_TYPE( src->type ) != CV_8UC1 ||
CV_MAT_TYPE( dst->type ) != CV_8UC1 )
CV_Error( CV_StsUnsupportedFormat, "" );
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedSizes, "" );
if( low_thresh > high_thresh )
{
double t;
CV_SWAP( low_thresh, high_thresh, t );
}
aperture_size &= INT_MAX;
if( (aperture_size & 1) == 0 || aperture_size < 3 || aperture_size > 7 )
CV_Error( CV_StsBadFlag, "" );
size = cvGetMatSize( src );
dx = cvCreateMat( size.height, size.width, CV_16SC1 );
dy = cvCreateMat( size.height, size.width, CV_16SC1 );
cvSobel( src, dx, 1, 0, aperture_size );
cvSobel( src, dy, 0, 1, aperture_size );
/*if( icvCannyGetSize_p && icvCanny_16s8u_C1R_p && !(flags & CV_CANNY_L2_GRADIENT) )
{
int buf_size= 0;
IPPI_CALL( icvCannyGetSize_p( size, &buf_size ));
CV_CALL( buffer = cvAlloc( buf_size ));
IPPI_CALL( icvCanny_16s8u_C1R_p( (short*)dx->data.ptr, dx->step,
(short*)dy->data.ptr, dy->step,
dst->data.ptr, dst->step,
size, (float)low_thresh,
(float)high_thresh, buffer ));
EXIT;
}*/
if( flags & CV_CANNY_L2_GRADIENT )
{
Cv32suf ul, uh;
ul.f = (float)low_thresh;
uh.f = (float)high_thresh;
low = ul.i;
high = uh.i;
}
else
{
low = cvFloor( low_thresh );
high = cvFloor( high_thresh );
}
buffer.allocate( (size.width+2)*(size.height+2) + (size.width+2)*3*sizeof(int) );
mag_buf[0] = (int*)(char*)buffer;
mag_buf[1] = mag_buf[0] + size.width + 2;
mag_buf[2] = mag_buf[1] + size.width + 2;
map = (uchar*)(mag_buf[2] + size.width + 2);
mapstep = size.width + 2;
maxsize = MAX( 1 << 10, size.width*size.height/10 );
stack.resize( maxsize );
stack_top = stack_bottom = &stack[0];
memset( mag_buf[0], 0, (size.width+2)*sizeof(int) );
memset( map, 1, mapstep );
memset( map + mapstep*(size.height + 1), 1, mapstep );
/* sector numbers
(Top-Left Origin)
1 2 3
* * *
* * *
0*******0
* * *
* * *
3 2 1
*/
#define CANNY_PUSH(d) *(d) = (uchar)2, *stack_top++ = (d)
#define CANNY_POP(d) (d) = *--stack_top
mag_row = cvMat( 1, size.width, CV_32F );
// calculate magnitude and angle of gradient, perform non-maxima supression.
// fill the map with one of the following values:
// 0 - the pixel might belong to an edge
// 1 - the pixel can not belong to an edge
// 2 - the pixel does belong to an edge
for( i = 0; i <= size.height; i++ )
{
int* _mag = mag_buf[(i > 0) + 1] + 1;
float* _magf = (float*)_mag;
const short* _dx = (short*)(dx->data.ptr + dx->step*i);
const short* _dy = (short*)(dy->data.ptr + dy->step*i);
uchar* _map;
int x, y;
int magstep1, magstep2;
int prev_flag = 0;
if( i < size.height )
{
_mag[-1] = _mag[size.width] = 0;
if( !(flags & CV_CANNY_L2_GRADIENT) )
for( j = 0; j < size.width; j++ )
_mag[j] = abs(_dx[j]) + abs(_dy[j]);
/*else if( icvFilterSobelVert_8u16s_C1R_p != 0 ) // check for IPP
{
// use vectorized sqrt
mag_row.data.fl = _magf;
for( j = 0; j < size.width; j++ )
{
x = _dx[j]; y = _dy[j];
_magf[j] = (float)((double)x*x + (double)y*y);
}
cvPow( &mag_row, &mag_row, 0.5 );
}*/
else
{
for( j = 0; j < size.width; j++ )
{
x = _dx[j]; y = _dy[j];
_magf[j] = (float)std::sqrt((double)x*x + (double)y*y);
}
}
}
else
memset( _mag-1, 0, (size.width + 2)*sizeof(int) );
// at the very beginning we do not have a complete ring
// buffer of 3 magnitude rows for non-maxima suppression
if( i == 0 )
continue;
_map = map + mapstep*i + 1;
_map[-1] = _map[size.width] = 1;
_mag = mag_buf[1] + 1; // take the central row
_dx = (short*)(dx->data.ptr + dx->step*(i-1));
_dy = (short*)(dy->data.ptr + dy->step*(i-1));
magstep1 = (int)(mag_buf[2] - mag_buf[1]);
magstep2 = (int)(mag_buf[0] - mag_buf[1]);
if( (stack_top - stack_bottom) + size.width > maxsize )
{
int sz = (int)(stack_top - stack_bottom);
maxsize = MAX( maxsize * 3/2, maxsize + 8 );
stack.resize(maxsize);
stack_bottom = &stack[0];
stack_top = stack_bottom + sz;
}
for( j = 0; j < size.width; j++ )
{
#define CANNY_SHIFT 15
#define TG22 (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5)
x = _dx[j];
y = _dy[j];
int s = x ^ y;
int m = _mag[j];
x = abs(x);
y = abs(y);
if( m > low )
{
int tg22x = x * TG22;
int tg67x = tg22x + ((x + x) << CANNY_SHIFT);
y <<= CANNY_SHIFT;
if( y < tg22x )
{
if( m > _mag[j-1] && m >= _mag[j+1] )
{
if( m > high && !prev_flag && _map[j-mapstep] != 2 )
{
CANNY_PUSH( _map + j );
prev_flag = 1;
}
else
_map[j] = (uchar)0;
continue;
}
}
else if( y > tg67x )
{
if( m > _mag[j+magstep2] && m >= _mag[j+magstep1] )
{
if( m > high && !prev_flag && _map[j-mapstep] != 2 )
{
CANNY_PUSH( _map + j );
prev_flag = 1;
}
else
_map[j] = (uchar)0;
continue;
}
}
else
{
s = s < 0 ? -1 : 1;
if( m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s] )
{
if( m > high && !prev_flag && _map[j-mapstep] != 2 )
{
CANNY_PUSH( _map + j );
prev_flag = 1;
}
else
_map[j] = (uchar)0;
continue;
}
}
}
prev_flag = 0;
_map[j] = (uchar)1;
}
// scroll the ring buffer
_mag = mag_buf[0];
mag_buf[0] = mag_buf[1];
mag_buf[1] = mag_buf[2];
mag_buf[2] = _mag;
}
// now track the edges (hysteresis thresholding)
while( stack_top > stack_bottom )
{
uchar* m;
if( (stack_top - stack_bottom) + 8 > maxsize )
{
int sz = (int)(stack_top - stack_bottom);
maxsize = MAX( maxsize * 3/2, maxsize + 8 );
stack.resize(maxsize);
stack_bottom = &stack[0];
stack_top = stack_bottom + sz;
}
CANNY_POP(m);
if( !m[-1] )
CANNY_PUSH( m - 1 );
if( !m[1] )
CANNY_PUSH( m + 1 );
if( !m[-mapstep-1] )
CANNY_PUSH( m - mapstep - 1 );
if( !m[-mapstep] )
CANNY_PUSH( m - mapstep );
if( !m[-mapstep+1] )
CANNY_PUSH( m - mapstep + 1 );
if( !m[mapstep-1] )
CANNY_PUSH( m + mapstep - 1 );
if( !m[mapstep] )
CANNY_PUSH( m + mapstep );
if( !m[mapstep+1] )
CANNY_PUSH( m + mapstep + 1 );
}
// the final pass, form the final image
for( i = 0; i < size.height; i++ )
{
const uchar* _map = map + mapstep*(i+1) + 1;
uchar* _dst = dst->data.ptr + dst->step*i;
for( j = 0; j < size.width; j++ )
_dst[j] = (uchar)-(_map[j] >> 1);
}
}
void cv::Canny( const Mat& image, Mat& edges,
double threshold1, double threshold2,
int apertureSize, bool L2gradient )
{
Mat src = image;
edges.create(src.size(), CV_8U);
CvMat _src = src, _dst = edges;
cvCanny( &_src, &_dst, threshold1, threshold2,
apertureSize + (L2gradient ? CV_CANNY_L2_GRADIENT : 0));
}
/* End of file. */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,815 @@
/*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"
static int
icvSklansky_32s( CvPoint** array, int start, int end, int* stack, int nsign, int sign2 )
{
int incr = end > start ? 1 : -1;
/* prepare first triangle */
int pprev = start, pcur = pprev + incr, pnext = pcur + incr;
int stacksize = 3;
if( start == end ||
(array[start]->x == array[end]->x &&
array[start]->y == array[end]->y) )
{
stack[0] = start;
return 1;
}
stack[0] = pprev;
stack[1] = pcur;
stack[2] = pnext;
end += incr; /* make end = afterend */
while( pnext != end )
{
/* check the angle p1,p2,p3 */
int cury = array[pcur]->y;
int nexty = array[pnext]->y;
int by = nexty - cury;
if( CV_SIGN(by) != nsign )
{
int ax = array[pcur]->x - array[pprev]->x;
int bx = array[pnext]->x - array[pcur]->x;
int ay = cury - array[pprev]->y;
int convexity = ay*bx - ax*by;/* if >0 then convex angle */
if( CV_SIGN(convexity) == sign2 && (ax != 0 || ay != 0) )
{
pprev = pcur;
pcur = pnext;
pnext += incr;
stack[stacksize] = pnext;
stacksize++;
}
else
{
if( pprev == start )
{
pcur = pnext;
stack[1] = pcur;
pnext += incr;
stack[2] = pnext;
}
else
{
stack[stacksize-2] = pnext;
pcur = pprev;
pprev = stack[stacksize-4];
stacksize--;
}
}
}
else
{
pnext += incr;
stack[stacksize-1] = pnext;
}
}
return --stacksize;
}
static int
icvSklansky_32f( CvPoint2D32f** array, int start, int end, int* stack, int nsign, int sign2 )
{
int incr = end > start ? 1 : -1;
/* prepare first triangle */
int pprev = start, pcur = pprev + incr, pnext = pcur + incr;
int stacksize = 3;
if( start == end ||
(array[start]->x == array[end]->x &&
array[start]->y == array[end]->y) )
{
stack[0] = start;
return 1;
}
stack[0] = pprev;
stack[1] = pcur;
stack[2] = pnext;
end += incr; /* make end = afterend */
while( pnext != end )
{
/* check the angle p1,p2,p3 */
float cury = array[pcur]->y;
float nexty = array[pnext]->y;
float by = nexty - cury;
if( CV_SIGN( by ) != nsign )
{
float ax = array[pcur]->x - array[pprev]->x;
float bx = array[pnext]->x - array[pcur]->x;
float ay = cury - array[pprev]->y;
float convexity = ay*bx - ax*by;/* if >0 then convex angle */
if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) )
{
pprev = pcur;
pcur = pnext;
pnext += incr;
stack[stacksize] = pnext;
stacksize++;
}
else
{
if( pprev == start )
{
pcur = pnext;
stack[1] = pcur;
pnext += incr;
stack[2] = pnext;
}
else
{
stack[stacksize-2] = pnext;
pcur = pprev;
pprev = stack[stacksize-4];
stacksize--;
}
}
}
else
{
pnext += incr;
stack[stacksize-1] = pnext;
}
}
return --stacksize;
}
typedef int (*sklansky_func)( CvPoint** points, int start, int end,
int* stack, int sign, int sign2 );
#define cmp_pts( pt1, pt2 ) \
((pt1)->x < (pt2)->x || ((pt1)->x <= (pt2)->x && (pt1)->y < (pt2)->y))
static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32s, CvPoint*, cmp_pts )
static CV_IMPLEMENT_QSORT( icvSortPointsByPointers_32f, CvPoint2D32f*, cmp_pts )
static void
icvCalcAndWritePtIndices( CvPoint** pointer, int* stack, int start, int end,
CvSeq* ptseq, CvSeqWriter* writer )
{
int i, incr = start < end ? 1 : -1;
int idx, first_idx = ptseq->first->start_index;
for( i = start; i != end; i += incr )
{
CvPoint* ptr = (CvPoint*)pointer[stack[i]];
CvSeqBlock* block = ptseq->first;
while( (unsigned)(idx = (int)(ptr - (CvPoint*)block->data)) >= (unsigned)block->count )
{
block = block->next;
if( block == ptseq->first )
CV_Error( CV_StsError, "Internal error" );
}
idx += block->start_index - first_idx;
CV_WRITE_SEQ_ELEM( idx, *writer );
}
}
CV_IMPL CvSeq*
cvConvexHull2( const CvArr* array, void* hull_storage,
int orientation, int return_points )
{
union { CvContour* c; CvSeq* s; } hull;
cv::AutoBuffer<CvPoint*> _pointer;
CvPoint** pointer;
CvPoint2D32f** pointerf = 0;
cv::AutoBuffer<int> _stack;
int* stack;
hull.s = 0;
CvMat* mat = 0;
CvSeqReader reader;
CvSeqWriter writer;
CvContour contour_header;
union { CvContour c; CvSeq s; } hull_header;
CvSeqBlock block, hullblock;
CvSeq* ptseq = 0;
CvSeq* hullseq = 0;
int is_float;
int* t_stack;
int t_count;
int i, miny_ind = 0, maxy_ind = 0, total;
int hulltype;
int stop_idx;
sklansky_func sklansky;
if( CV_IS_SEQ( array ))
{
ptseq = (CvSeq*)array;
if( !CV_IS_SEQ_POINT_SET( ptseq ))
CV_Error( CV_StsBadArg, "Unsupported sequence type" );
if( hull_storage == 0 )
hull_storage = ptseq->storage;
}
else
{
ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block );
}
if( CV_IS_STORAGE( hull_storage ))
{
if( return_points )
{
hullseq = cvCreateSeq(
CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE(ptseq)|
CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
sizeof(CvContour), sizeof(CvPoint),(CvMemStorage*)hull_storage );
}
else
{
hullseq = cvCreateSeq(
CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE_PPOINT|
CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
sizeof(CvContour), sizeof(CvPoint*), (CvMemStorage*)hull_storage );
}
}
else
{
if( !CV_IS_MAT( hull_storage ))
CV_Error(CV_StsBadArg, "Destination must be valid memory storage or matrix");
mat = (CvMat*)hull_storage;
if( (mat->cols != 1 && mat->rows != 1) || !CV_IS_MAT_CONT(mat->type))
CV_Error( CV_StsBadArg,
"The hull matrix should be continuous and have a single row or a single column" );
if( mat->cols + mat->rows - 1 < ptseq->total )
CV_Error( CV_StsBadSize, "The hull matrix size might be not enough to fit the hull" );
if( CV_MAT_TYPE(mat->type) != CV_SEQ_ELTYPE(ptseq) &&
CV_MAT_TYPE(mat->type) != CV_32SC1 )
CV_Error( CV_StsUnsupportedFormat,
"The hull matrix must have the same type as input or 32sC1 (integers)" );
hullseq = cvMakeSeqHeaderForArray(
CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
sizeof(contour_header), CV_ELEM_SIZE(mat->type), mat->data.ptr,
mat->cols + mat->rows - 1, &hull_header.s, &hullblock );
cvClearSeq( hullseq );
}
total = ptseq->total;
if( total == 0 )
{
if( mat )
CV_Error( CV_StsBadSize,
"Point sequence can not be empty if the output is matrix" );
return hull.s;
}
cvStartAppendToSeq( hullseq, &writer );
is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2;
hulltype = CV_SEQ_ELTYPE(hullseq);
sklansky = !is_float ? (sklansky_func)icvSklansky_32s :
(sklansky_func)icvSklansky_32f;
_pointer.allocate( ptseq->total );
_stack.allocate( ptseq->total + 2);
pointer = _pointer;
pointerf = (CvPoint2D32f**)pointer;
stack = _stack;
cvStartReadSeq( ptseq, &reader );
for( i = 0; i < total; i++ )
{
pointer[i] = (CvPoint*)reader.ptr;
CV_NEXT_SEQ_ELEM( ptseq->elem_size, reader );
}
// sort the point set by x-coordinate, find min and max y
if( !is_float )
{
icvSortPointsByPointers_32s( pointer, total, 0 );
for( i = 1; i < total; i++ )
{
int y = pointer[i]->y;
if( pointer[miny_ind]->y > y )
miny_ind = i;
if( pointer[maxy_ind]->y < y )
maxy_ind = i;
}
}
else
{
icvSortPointsByPointers_32f( pointerf, total, 0 );
for( i = 1; i < total; i++ )
{
float y = pointerf[i]->y;
if( pointerf[miny_ind]->y > y )
miny_ind = i;
if( pointerf[maxy_ind]->y < y )
maxy_ind = i;
}
}
if( pointer[0]->x == pointer[total-1]->x &&
pointer[0]->y == pointer[total-1]->y )
{
if( hulltype == CV_SEQ_ELTYPE_PPOINT )
{
CV_WRITE_SEQ_ELEM( pointer[0], writer );
}
else if( hulltype == CV_SEQ_ELTYPE_INDEX )
{
int index = 0;
CV_WRITE_SEQ_ELEM( index, writer );
}
else
{
CvPoint pt = pointer[0][0];
CV_WRITE_SEQ_ELEM( pt, writer );
}
goto finish_hull;
}
/*upper half */
{
int *tl_stack = stack;
int tl_count = sklansky( pointer, 0, maxy_ind, tl_stack, -1, 1 );
int *tr_stack = tl_stack + tl_count;
int tr_count = sklansky( pointer, ptseq->total - 1, maxy_ind, tr_stack, -1, -1 );
/* gather upper part of convex hull to output */
if( orientation == CV_COUNTER_CLOCKWISE )
{
CV_SWAP( tl_stack, tr_stack, t_stack );
CV_SWAP( tl_count, tr_count, t_count );
}
if( hulltype == CV_SEQ_ELTYPE_PPOINT )
{
for( i = 0; i < tl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]], writer );
for( i = tr_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]], writer );
}
else if( hulltype == CV_SEQ_ELTYPE_INDEX )
{
icvCalcAndWritePtIndices( pointer, tl_stack, 0, tl_count-1, ptseq, &writer );
icvCalcAndWritePtIndices( pointer, tr_stack, tr_count-1, 0, ptseq, &writer );
}
else
{
for( i = 0; i < tl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[tl_stack[i]][0], writer );
for( i = tr_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[tr_stack[i]][0], writer );
}
stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
}
/* lower half */
{
int *bl_stack = stack;
int bl_count = sklansky( pointer, 0, miny_ind, bl_stack, 1, -1 );
int *br_stack = stack + bl_count;
int br_count = sklansky( pointer, ptseq->total - 1, miny_ind, br_stack, 1, 1 );
if( orientation != CV_COUNTER_CLOCKWISE )
{
CV_SWAP( bl_stack, br_stack, t_stack );
CV_SWAP( bl_count, br_count, t_count );
}
if( stop_idx >= 0 )
{
int check_idx = bl_count > 2 ? bl_stack[1] :
bl_count + br_count > 2 ? br_stack[2-bl_count] : -1;
if( check_idx == stop_idx || (check_idx >= 0 &&
pointer[check_idx]->x == pointer[stop_idx]->x &&
pointer[check_idx]->y == pointer[stop_idx]->y) )
{
/* if all the points lie on the same line, then
the bottom part of the convex hull is the mirrored top part
(except the exteme points).*/
bl_count = MIN( bl_count, 2 );
br_count = MIN( br_count, 2 );
}
}
if( hulltype == CV_SEQ_ELTYPE_PPOINT )
{
for( i = 0; i < bl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]], writer );
for( i = br_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[br_stack[i]], writer );
}
else if( hulltype == CV_SEQ_ELTYPE_INDEX )
{
icvCalcAndWritePtIndices( pointer, bl_stack, 0, bl_count-1, ptseq, &writer );
icvCalcAndWritePtIndices( pointer, br_stack, br_count-1, 0, ptseq, &writer );
}
else
{
for( i = 0; i < bl_count - 1; i++ )
CV_WRITE_SEQ_ELEM( pointer[bl_stack[i]][0], writer );
for( i = br_count - 1; i > 0; i-- )
CV_WRITE_SEQ_ELEM( pointer[br_stack[i]][0], writer );
}
}
finish_hull:
cvEndWriteSeq( &writer );
if( mat )
{
if( mat->rows > mat->cols )
mat->rows = hullseq->total;
else
mat->cols = hullseq->total;
}
else
{
hull.s = hullseq;
hull.c->rect = cvBoundingRect( ptseq,
ptseq->header_size < (int)sizeof(CvContour) ||
&ptseq->flags == &contour_header.flags );
/*if( ptseq != (CvSeq*)&contour_header )
hullseq->v_prev = ptseq;*/
}
return hull.s;
}
/* contour must be a simple polygon */
/* it must have more than 3 points */
CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array,
const CvArr* hullarray,
CvMemStorage* storage )
{
CvSeq* defects = 0;
int i, index;
CvPoint* hull_cur;
/* is orientation of hull different from contour one */
int rev_orientation;
CvContour contour_header;
union { CvContour c; CvSeq s; } hull_header;
CvSeqBlock block, hullblock;
CvSeq *ptseq = (CvSeq*)array, *hull = (CvSeq*)hullarray;
CvSeqReader hull_reader;
CvSeqReader ptseq_reader;
CvSeqWriter writer;
int is_index;
if( CV_IS_SEQ( ptseq ))
{
if( !CV_IS_SEQ_POINT_SET( ptseq ))
CV_Error( CV_StsUnsupportedFormat,
"Input sequence is not a sequence of points" );
if( !storage )
storage = ptseq->storage;
}
else
{
ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block );
}
if( CV_SEQ_ELTYPE( ptseq ) != CV_32SC2 )
CV_Error( CV_StsUnsupportedFormat, "Floating-point coordinates are not supported here" );
if( CV_IS_SEQ( hull ))
{
int hulltype = CV_SEQ_ELTYPE( hull );
if( hulltype != CV_SEQ_ELTYPE_PPOINT && hulltype != CV_SEQ_ELTYPE_INDEX )
CV_Error( CV_StsUnsupportedFormat,
"Convex hull must represented as a sequence "
"of indices or sequence of pointers" );
if( !storage )
storage = hull->storage;
}
else
{
CvMat* mat = (CvMat*)hull;
if( !CV_IS_MAT( hull ))
CV_Error(CV_StsBadArg, "Convex hull is neither sequence nor matrix");
if( (mat->cols != 1 && mat->rows != 1) ||
!CV_IS_MAT_CONT(mat->type) || CV_MAT_TYPE(mat->type) != CV_32SC1 )
CV_Error( CV_StsBadArg,
"The matrix should be 1-dimensional and continuous array of int's" );
if( mat->cols + mat->rows - 1 > ptseq->total )
CV_Error( CV_StsBadSize, "Convex hull is larger than the point sequence" );
hull = cvMakeSeqHeaderForArray(
CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
sizeof(CvContour), CV_ELEM_SIZE(mat->type), mat->data.ptr,
mat->cols + mat->rows - 1, &hull_header.s, &hullblock );
}
is_index = CV_SEQ_ELTYPE(hull) == CV_SEQ_ELTYPE_INDEX;
if( !storage )
CV_Error( CV_StsNullPtr, "NULL storage pointer" );
defects = cvCreateSeq( CV_SEQ_KIND_GENERIC, sizeof(CvSeq), sizeof(CvConvexityDefect), storage );
if( ptseq->total < 4 || hull->total < 3)
{
//CV_ERROR( CV_StsBadSize,
// "point seq size must be >= 4, convex hull size must be >= 3" );
return defects;
}
/* recognize co-orientation of ptseq and its hull */
{
int sign = 0;
int index1, index2, index3;
if( !is_index )
{
CvPoint* pos = *CV_SEQ_ELEM( hull, CvPoint*, 0 );
index1 = cvSeqElemIdx( ptseq, pos );
pos = *CV_SEQ_ELEM( hull, CvPoint*, 1 );
index2 = cvSeqElemIdx( ptseq, pos );
pos = *CV_SEQ_ELEM( hull, CvPoint*, 2 );
index3 = cvSeqElemIdx( ptseq, pos );
}
else
{
index1 = *CV_SEQ_ELEM( hull, int, 0 );
index2 = *CV_SEQ_ELEM( hull, int, 1 );
index3 = *CV_SEQ_ELEM( hull, int, 2 );
}
sign += (index2 > index1) ? 1 : 0;
sign += (index3 > index2) ? 1 : 0;
sign += (index1 > index3) ? 1 : 0;
rev_orientation = (sign == 2) ? 0 : 1;
}
cvStartReadSeq( ptseq, &ptseq_reader, 0 );
cvStartReadSeq( hull, &hull_reader, rev_orientation );
if( !is_index )
{
hull_cur = *(CvPoint**)hull_reader.prev_elem;
index = cvSeqElemIdx( ptseq, (char*)hull_cur, 0 );
}
else
{
index = *(int*)hull_reader.prev_elem;
hull_cur = CV_GET_SEQ_ELEM( CvPoint, ptseq, index );
}
cvSetSeqReaderPos( &ptseq_reader, index );
cvStartAppendToSeq( defects, &writer );
/* cycle through ptseq and hull with computing defects */
for( i = 0; i < hull->total; i++ )
{
CvConvexityDefect defect;
int is_defect = 0;
double dx0, dy0;
double depth = 0, scale;
CvPoint* hull_next;
if( !is_index )
hull_next = *(CvPoint**)hull_reader.ptr;
else
{
int t = *(int*)hull_reader.ptr;
hull_next = CV_GET_SEQ_ELEM( CvPoint, ptseq, t );
}
dx0 = (double)hull_next->x - (double)hull_cur->x;
dy0 = (double)hull_next->y - (double)hull_cur->y;
assert( dx0 != 0 || dy0 != 0 );
scale = 1./sqrt(dx0*dx0 + dy0*dy0);
defect.start = hull_cur;
defect.end = hull_next;
for(;;)
{
/* go through ptseq to achieve next hull point */
CV_NEXT_SEQ_ELEM( sizeof(CvPoint), ptseq_reader );
if( ptseq_reader.ptr == (schar*)hull_next )
break;
else
{
CvPoint* cur = (CvPoint*)ptseq_reader.ptr;
/* compute distance from current point to hull edge */
double dx = (double)cur->x - (double)hull_cur->x;
double dy = (double)cur->y - (double)hull_cur->y;
/* compute depth */
double dist = fabs(-dy0*dx + dx0*dy) * scale;
if( dist > depth )
{
depth = dist;
defect.depth_point = cur;
defect.depth = (float)depth;
is_defect = 1;
}
}
}
if( is_defect )
{
CV_WRITE_SEQ_ELEM( defect, writer );
}
hull_cur = hull_next;
if( rev_orientation )
{
CV_PREV_SEQ_ELEM( hull->elem_size, hull_reader );
}
else
{
CV_NEXT_SEQ_ELEM( hull->elem_size, hull_reader );
}
}
return cvEndWriteSeq( &writer );
}
CV_IMPL int
cvCheckContourConvexity( const CvArr* array )
{
int flag = -1;
int i;
int orientation = 0;
CvSeqReader reader;
CvContour contour_header;
CvSeqBlock block;
CvSeq* contour = (CvSeq*)array;
if( CV_IS_SEQ(contour) )
{
if( !CV_IS_SEQ_POINT_SET(contour))
CV_Error( CV_StsUnsupportedFormat,
"Input sequence must be polygon (closed 2d curve)" );
}
else
{
contour = cvPointSeqFromMat(CV_SEQ_KIND_CURVE|CV_SEQ_FLAG_CLOSED, array, &contour_header, &block );
}
if( contour->total == 0 )
return -1;
cvStartReadSeq( contour, &reader, 0 );
flag = 1;
if( CV_SEQ_ELTYPE( contour ) == CV_32SC2 )
{
CvPoint *prev_pt = (CvPoint*)reader.prev_elem;
CvPoint *cur_pt = (CvPoint*)reader.ptr;
int dx0 = cur_pt->x - prev_pt->x;
int dy0 = cur_pt->y - prev_pt->y;
for( i = 0; i < contour->total; i++ )
{
int dxdy0, dydx0;
int dx, dy;
/*int orient; */
CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
prev_pt = cur_pt;
cur_pt = (CvPoint *) reader.ptr;
dx = cur_pt->x - prev_pt->x;
dy = cur_pt->y - prev_pt->y;
dxdy0 = dx * dy0;
dydx0 = dy * dx0;
/* find orientation */
/*orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
if( orientation == 3 )
{
flag = 0;
break;
}
dx0 = dx;
dy0 = dy;
}
}
else
{
CV_Assert( CV_SEQ_ELTYPE(contour) == CV_32FC2 );
CvPoint2D32f *prev_pt = (CvPoint2D32f*)reader.prev_elem;
CvPoint2D32f *cur_pt = (CvPoint2D32f*)reader.ptr;
float dx0 = cur_pt->x - prev_pt->x;
float dy0 = cur_pt->y - prev_pt->y;
for( i = 0; i < contour->total; i++ )
{
float dxdy0, dydx0;
float dx, dy;
/*int orient; */
CV_NEXT_SEQ_ELEM( sizeof(CvPoint2D32f), reader );
prev_pt = cur_pt;
cur_pt = (CvPoint2D32f*) reader.ptr;
dx = cur_pt->x - prev_pt->x;
dy = cur_pt->y - prev_pt->y;
dxdy0 = dx * dy0;
dydx0 = dy * dx0;
/* find orientation */
/*orient = -dy0 * dx + dx0 * dy;
orientation |= (orient > 0) ? 1 : 2;
*/
orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
if( orientation == 3 )
{
flag = 0;
break;
}
dx0 = dx;
dy0 = dy;
}
}
return flag;
}
/* End of file. */

View File

@@ -0,0 +1,405 @@
/*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.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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 <stdio.h>
namespace cv
{
static void
calcMinEigenVal( const Mat& _cov, Mat& _dst )
{
int i, j;
Size size = _cov.size();
#if CV_SSE
volatile bool simd = checkHardwareSupport(CV_CPU_SSE);
#endif
if( _cov.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
for( i = 0; i < size.height; i++ )
{
const float* cov = (const float*)(_cov.data + _cov.step*i);
float* dst = (float*)(_dst.data + _dst.step*i);
j = 0;
#if CV_SSE
if( simd )
{
__m128 half = _mm_set1_ps(0.5f);
for( ; j <= size.width - 5; j += 4 )
{
__m128 t0 = _mm_loadu_ps(cov + j*3); // a0 b0 c0 x
__m128 t1 = _mm_loadu_ps(cov + j*3 + 3); // a1 b1 c1 x
__m128 t2 = _mm_loadu_ps(cov + j*3 + 6); // a2 b2 c2 x
__m128 t3 = _mm_loadu_ps(cov + j*3 + 9); // a3 b3 c3 x
__m128 a, b, c, t;
t = _mm_unpacklo_ps(t0, t1); // a0 a1 b0 b1
c = _mm_unpackhi_ps(t0, t1); // c0 c1 x x
b = _mm_unpacklo_ps(t2, t3); // a2 a3 b2 b3
c = _mm_movelh_ps(c, _mm_unpackhi_ps(t2, t3)); // c0 c1 c2 c3
a = _mm_movelh_ps(t, b);
b = _mm_movehl_ps(b, t);
a = _mm_mul_ps(a, half);
c = _mm_mul_ps(c, half);
t = _mm_sub_ps(a, c);
t = _mm_add_ps(_mm_mul_ps(t, t), _mm_mul_ps(b,b));
a = _mm_sub_ps(_mm_add_ps(a, c), _mm_sqrt_ps(t));
_mm_storeu_ps(dst + j, a);
}
}
#endif
for( ; j < size.width; j++ )
{
double a = cov[j*3]*0.5;
double b = cov[j*3+1];
double c = cov[j*3+2]*0.5;
dst[j] = (float)((a + c) - std::sqrt((a - c)*(a - c) + b*b));
}
}
}
static void
calcHarris( const Mat& _cov, Mat& _dst, double k )
{
int i, j;
Size size = _cov.size();
#if CV_SSE
volatile bool simd = checkHardwareSupport(CV_CPU_SSE);
#endif
if( _cov.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
for( i = 0; i < size.height; i++ )
{
const float* cov = (const float*)(_cov.data + _cov.step*i);
float* dst = (float*)(_dst.data + _dst.step*i);
j = 0;
#if CV_SSE
if( simd )
{
__m128 k4 = _mm_set1_ps((float)k);
for( ; j <= size.width - 5; j += 4 )
{
__m128 t0 = _mm_loadu_ps(cov + j*3); // a0 b0 c0 x
__m128 t1 = _mm_loadu_ps(cov + j*3 + 3); // a1 b1 c1 x
__m128 t2 = _mm_loadu_ps(cov + j*3 + 6); // a2 b2 c2 x
__m128 t3 = _mm_loadu_ps(cov + j*3 + 9); // a3 b3 c3 x
__m128 a, b, c, t;
t = _mm_unpacklo_ps(t0, t1); // a0 a1 b0 b1
c = _mm_unpackhi_ps(t0, t1); // c0 c1 x x
b = _mm_unpacklo_ps(t2, t3); // a2 a3 b2 b3
c = _mm_movelh_ps(c, _mm_unpackhi_ps(t2, t3)); // c0 c1 c2 c3
a = _mm_movelh_ps(t, b);
b = _mm_movehl_ps(b, t);
t = _mm_add_ps(a, c);
a = _mm_sub_ps(_mm_mul_ps(a, c), _mm_mul_ps(b, b));
t = _mm_mul_ps(_mm_mul_ps(t, t), k4);
a = _mm_sub_ps(a, t);
_mm_storeu_ps(dst + j, a);
}
}
#endif
for( ; j < size.width; j++ )
{
double a = cov[j*3];
double b = cov[j*3+1];
double c = cov[j*3+2];
dst[j] = (float)(a*c - b*b - k*(a + c)*(a + c));
}
}
}
static void
calcEigenValsVecs( const Mat& _cov, Mat& _dst )
{
int i, j;
Size size = _cov.size();
if( _cov.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
for( i = 0; i < size.height; i++ )
{
const float* cov = (const float*)(_cov.data + _cov.step*i);
float* dst = (float*)(_dst.data + _dst.step*i);
for( j = 0; j < size.width; j++ )
{
double a = cov[j*3];
double b = cov[j*3+1];
double c = cov[j*3+2];
double u = (a + c)*0.5;
double v = std::sqrt((a - c)*(a - c)*0.25 + b*b);
double l1 = u + v;
double l2 = u - v;
double x = b;
double y = l1 - a;
double e = fabs(x);
if( e + fabs(y) < 1e-4 )
{
y = b;
x = l1 - c;
e = fabs(x);
if( e + fabs(y) < 1e-4 )
{
e = 1./(e + fabs(y) + FLT_EPSILON);
x *= e, y *= e;
}
}
double d = 1./std::sqrt(x*x + y*y + DBL_EPSILON);
dst[6*j] = (float)l1;
dst[6*j + 2] = (float)(x*d);
dst[6*j + 3] = (float)(y*d);
x = b;
y = l2 - a;
e = fabs(x);
if( e + fabs(y) < 1e-4 )
{
y = b;
x = l2 - c;
e = fabs(x);
if( e + fabs(y) < 1e-4 )
{
e = 1./(e + fabs(y) + FLT_EPSILON);
x *= e, y *= e;
}
}
d = 1./std::sqrt(x*x + y*y + DBL_EPSILON);
dst[6*j + 1] = (float)l2;
dst[6*j + 4] = (float)(x*d);
dst[6*j + 5] = (float)(y*d);
}
}
}
enum { MINEIGENVAL=0, HARRIS=1, EIGENVALSVECS=2 };
static void
cornerEigenValsVecs( const Mat& src, Mat& eigenv, int block_size,
int aperture_size, int op_type, double k=0.,
int borderType=BORDER_DEFAULT )
{
int depth = src.depth();
double scale = (double)(1 << ((aperture_size > 0 ? aperture_size : 3) - 1)) * block_size;
if( aperture_size < 0 )
scale *= 2.;
if( depth == CV_8U )
scale *= 255.;
scale = 1./scale;
CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );
Mat Dx, Dy;
if( aperture_size > 0 )
{
Sobel( src, Dx, CV_32F, 1, 0, aperture_size, scale, 0, borderType );
Sobel( src, Dy, CV_32F, 0, 1, aperture_size, scale, 0, borderType );
}
else
{
Scharr( src, Dx, CV_32F, 1, 0, scale, 0, borderType );
Scharr( src, Dy, CV_32F, 0, 1, scale, 0, borderType );
}
Size size = src.size();
Mat cov( size, CV_32FC3 );
int i, j;
for( i = 0; i < size.height; i++ )
{
float* cov_data = (float*)(cov.data + i*cov.step);
const float* dxdata = (const float*)(Dx.data + i*Dx.step);
const float* dydata = (const float*)(Dy.data + i*Dy.step);
for( j = 0; j < size.width; j++ )
{
float dx = dxdata[j];
float dy = dydata[j];
cov_data[j*3] = dx*dx;
cov_data[j*3+1] = dx*dy;
cov_data[j*3+2] = dy*dy;
}
}
boxFilter(cov, cov, cov.depth(), Size(block_size, block_size),
Point(-1,-1), false, borderType );
if( op_type == MINEIGENVAL )
calcMinEigenVal( cov, eigenv );
else if( op_type == HARRIS )
calcHarris( cov, eigenv, k );
else if( op_type == EIGENVALSVECS )
calcEigenValsVecs( cov, eigenv );
}
void cornerMinEigenVal( const Mat& src, Mat& dst, int blockSize, int ksize, int borderType )
{
dst.create( src.size(), CV_32F );
cornerEigenValsVecs( src, dst, blockSize, ksize, MINEIGENVAL, 0, borderType );
}
void cornerHarris( const Mat& src, Mat& dst, int blockSize, int ksize, double k, int borderType )
{
dst.create( src.size(), CV_32F );
cornerEigenValsVecs( src, dst, blockSize, ksize, HARRIS, k, borderType );
}
void cornerEigenValsAndVecs( const Mat& src, Mat& dst, int blockSize, int ksize, int borderType )
{
if( dst.rows != src.rows || dst.cols*dst.channels() != src.cols*6 || dst.depth() != CV_32F )
dst.create( src.size(), CV_32FC(6) );
cornerEigenValsVecs( src, dst, blockSize, ksize, EIGENVALSVECS, 0, borderType );
}
void preCornerDetect( const Mat& src, Mat& dst, int ksize, int borderType )
{
Mat Dx, Dy, D2x, D2y, Dxy;
CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );
dst.create( src.size(), CV_32F );
Sobel( src, Dx, CV_32F, 1, 0, ksize, 1, 0, borderType );
Sobel( src, Dy, CV_32F, 0, 1, ksize, 1, 0, borderType );
Sobel( src, D2x, CV_32F, 2, 0, ksize, 1, 0, borderType );
Sobel( src, D2y, CV_32F, 0, 2, ksize, 1, 0, borderType );
Sobel( src, Dxy, CV_32F, 1, 1, ksize, 1, 0, borderType );
double factor = 1 << (ksize - 1);
if( src.depth() == CV_8U )
factor *= 255;
factor = 1./(factor * factor * factor);
Size size = src.size();
int i, j;
for( i = 0; i < size.height; i++ )
{
float* dstdata = (float*)(dst.data + i*dst.step);
const float* dxdata = (const float*)(Dx.data + i*Dx.step);
const float* dydata = (const float*)(Dy.data + i*Dy.step);
const float* d2xdata = (const float*)(D2x.data + i*D2x.step);
const float* d2ydata = (const float*)(D2y.data + i*D2y.step);
const float* dxydata = (const float*)(Dxy.data + i*Dxy.step);
for( j = 0; j < size.width; j++ )
{
double dx = dxdata[j];
double dy = dydata[j];
dstdata[j] = (float)(factor*(dx*dx*d2ydata[j] + dy*dy*d2xdata[j] - 2*dx*dy*dxydata[j]));
}
}
}
}
CV_IMPL void
cvCornerMinEigenVal( const CvArr* srcarr, CvArr* dstarr,
int block_size, int aperture_size )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 );
cv::cornerMinEigenVal( src, dst, block_size, aperture_size, cv::BORDER_REPLICATE );
}
CV_IMPL void
cvCornerHarris( const CvArr* srcarr, CvArr* dstarr,
int block_size, int aperture_size, double k )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 );
cv::cornerHarris( src, dst, block_size, aperture_size, k, cv::BORDER_REPLICATE );
}
CV_IMPL void
cvCornerEigenValsAndVecs( const void* srcarr, void* dstarr,
int block_size, int aperture_size )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.rows == dst.rows && src.cols*6 == dst.cols*dst.channels() && dst.depth() == CV_32F );
cv::cornerEigenValsAndVecs( src, dst, block_size, aperture_size, cv::BORDER_REPLICATE );
}
CV_IMPL void
cvPreCornerDetect( const void* srcarr, void* dstarr, int aperture_size )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.size() == dst.size() && dst.type() == CV_32FC1 );
cv::preCornerDetect( src, dst, aperture_size, cv::BORDER_REPLICATE );
}
/* End of file */

View File

@@ -0,0 +1,266 @@
/*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"
CV_IMPL void
cvFindCornerSubPix( const void* srcarr, CvPoint2D32f* corners,
int count, CvSize win, CvSize zeroZone,
CvTermCriteria criteria )
{
cv::AutoBuffer<float> buffer;
const int MAX_ITERS = 100;
const float drv_x[] = { -1.f, 0.f, 1.f };
const float drv_y[] = { 0.f, 0.5f, 0.f };
float *maskX;
float *maskY;
float *mask;
float *src_buffer;
float *gx_buffer;
float *gy_buffer;
int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1;
int win_rect_size = (win_w + 4) * (win_h + 4);
double coeff;
CvSize size, src_buf_size;
int i, j, k, pt_i;
int max_iters = 10;
double eps = 0;
CvMat stub, *src = (CvMat*)srcarr;
src = cvGetMat( srcarr, &stub );
if( CV_MAT_TYPE( src->type ) != CV_8UC1 )
CV_Error( CV_StsBadMask, "" );
if( !corners )
CV_Error( CV_StsNullPtr, "" );
if( count < 0 )
CV_Error( CV_StsBadSize, "" );
if( count == 0 )
return;
if( win.width <= 0 || win.height <= 0 )
CV_Error( CV_StsBadSize, "" );
size = cvGetMatSize( src );
if( size.width < win_w + 4 || size.height < win_h + 4 )
CV_Error( CV_StsBadSize, "" );
/* initialize variables, controlling loop termination */
switch( criteria.type )
{
case CV_TERMCRIT_ITER:
eps = 0.f;
max_iters = criteria.max_iter;
break;
case CV_TERMCRIT_EPS:
eps = criteria.epsilon;
max_iters = MAX_ITERS;
break;
case CV_TERMCRIT_ITER | CV_TERMCRIT_EPS:
eps = criteria.epsilon;
max_iters = criteria.max_iter;
break;
default:
assert( 0 );
CV_Error( CV_StsBadFlag, "" );
}
eps = MAX( eps, 0 );
eps *= eps; /* use square of error in comparsion operations. */
max_iters = MAX( max_iters, 1 );
max_iters = MIN( max_iters, MAX_ITERS );
buffer.allocate( win_rect_size * 5 + win_w + win_h + 32 );
/* assign pointers */
maskX = buffer;
maskY = maskX + win_w + 4;
mask = maskY + win_h + 4;
src_buffer = mask + win_w * win_h;
gx_buffer = src_buffer + win_rect_size;
gy_buffer = gx_buffer + win_rect_size;
coeff = 1. / (win.width * win.width);
/* calculate mask */
for( i = -win.width, k = 0; i <= win.width; i++, k++ )
{
maskX[k] = (float)exp( -i * i * coeff );
}
if( win.width == win.height )
{
maskY = maskX;
}
else
{
coeff = 1. / (win.height * win.height);
for( i = -win.height, k = 0; i <= win.height; i++, k++ )
{
maskY[k] = (float) exp( -i * i * coeff );
}
}
for( i = 0; i < win_h; i++ )
{
for( j = 0; j < win_w; j++ )
{
mask[i * win_w + j] = maskX[j] * maskY[i];
}
}
/* make zero_zone */
if( zeroZone.width >= 0 && zeroZone.height >= 0 &&
zeroZone.width * 2 + 1 < win_w && zeroZone.height * 2 + 1 < win_h )
{
for( i = win.height - zeroZone.height; i <= win.height + zeroZone.height; i++ )
{
for( j = win.width - zeroZone.width; j <= win.width + zeroZone.width; j++ )
{
mask[i * win_w + j] = 0;
}
}
}
/* set sizes of image rectangles, used in convolutions */
src_buf_size.width = win_w + 2;
src_buf_size.height = win_h + 2;
/* do optimization loop for all the points */
for( pt_i = 0; pt_i < count; pt_i++ )
{
CvPoint2D32f cT = corners[pt_i], cI = cT;
int iter = 0;
double err;
do
{
CvPoint2D32f cI2;
double a, b, c, bb1, bb2;
IPPI_CALL( icvGetRectSubPix_8u32f_C1R( (uchar*)src->data.ptr, src->step, size,
src_buffer, (win_w + 2) * sizeof( src_buffer[0] ),
cvSize( win_w + 2, win_h + 2 ), cI ));
/* calc derivatives */
icvSepConvSmall3_32f( src_buffer, src_buf_size.width * sizeof(src_buffer[0]),
gx_buffer, win_w * sizeof(gx_buffer[0]),
src_buf_size, drv_x, drv_y, buffer );
icvSepConvSmall3_32f( src_buffer, src_buf_size.width * sizeof(src_buffer[0]),
gy_buffer, win_w * sizeof(gy_buffer[0]),
src_buf_size, drv_y, drv_x, buffer );
a = b = c = bb1 = bb2 = 0;
/* process gradient */
for( i = 0, k = 0; i < win_h; i++ )
{
double py = i - win.height;
for( j = 0; j < win_w; j++, k++ )
{
double m = mask[k];
double tgx = gx_buffer[k];
double tgy = gy_buffer[k];
double gxx = tgx * tgx * m;
double gxy = tgx * tgy * m;
double gyy = tgy * tgy * m;
double px = j - win.width;
a += gxx;
b += gxy;
c += gyy;
bb1 += gxx * px + gxy * py;
bb2 += gxy * px + gyy * py;
}
}
{
double A[4];
double InvA[4];
CvMat matA, matInvA;
A[0] = a;
A[1] = A[2] = b;
A[3] = c;
cvInitMatHeader( &matA, 2, 2, CV_64F, A );
cvInitMatHeader( &matInvA, 2, 2, CV_64FC1, InvA );
cvInvert( &matA, &matInvA, CV_SVD );
cI2.x = (float)(cI.x + InvA[0]*bb1 + InvA[1]*bb2);
cI2.y = (float)(cI.y + InvA[2]*bb1 + InvA[3]*bb2);
}
err = (cI2.x - cI.x) * (cI2.x - cI.x) + (cI2.y - cI.y) * (cI2.y - cI.y);
cI = cI2;
}
while( ++iter < max_iters && err > eps );
/* if new point is too far from initial, it means poor convergence.
leave initial point as the result */
if( fabs( cI.x - cT.x ) > win.width || fabs( cI.y - cT.y ) > win.height )
{
cI = cT;
}
corners[pt_i] = cI; /* store result */
}
}
void cv::cornerSubPix( const Mat& image, vector<Point2f>& corners,
Size winSize, Size zeroZone,
TermCriteria criteria )
{
CvMat _image = image;
cvFindCornerSubPix(&_image, (CvPoint2D32f*)&corners[0], (int)corners.size(),
winSize, zeroZone, criteria );
}
/* End of file. */

View File

@@ -0,0 +1,367 @@
/*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"
/****************************************************************************************/
/* lightweight convolution with 3x3 kernel */
void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
CvSize src_size, const float* kx, const float* ky, float* buffer )
{
int dst_width, buffer_step = 0;
int x, y;
assert( src && dst && src_size.width > 2 && src_size.height > 2 &&
(src_step & 3) == 0 && (dst_step & 3) == 0 &&
(kx || ky) && (buffer || !kx || !ky));
src_step /= sizeof(src[0]);
dst_step /= sizeof(dst[0]);
dst_width = src_size.width - 2;
if( !kx )
{
/* set vars, so that vertical convolution
will write results into destination ROI and
horizontal convolution won't run */
src_size.width = dst_width;
buffer_step = dst_step;
buffer = dst;
dst_width = 0;
}
assert( src_step >= src_size.width && dst_step >= dst_width );
src_size.height -= 3;
if( !ky )
{
/* set vars, so that vertical convolution won't run and
horizontal convolution will write results into destination ROI */
src_size.height += 3;
buffer_step = src_step;
buffer = src;
src_size.width = 0;
}
for( y = 0; y <= src_size.height; y++, src += src_step,
dst += dst_step,
buffer += buffer_step )
{
float* src2 = src + src_step;
float* src3 = src + src_step*2;
for( x = 0; x < src_size.width; x++ )
{
buffer[x] = (float)(ky[0]*src[x] + ky[1]*src2[x] + ky[2]*src3[x]);
}
for( x = 0; x < dst_width; x++ )
{
dst[x] = (float)(kx[0]*buffer[x] + kx[1]*buffer[x+1] + kx[2]*buffer[x+2]);
}
}
}
/****************************************************************************************\
Sobel & Scharr Derivative Filters
\****************************************************************************************/
namespace cv
{
static void getScharrKernels( Mat& kx, Mat& ky, int dx, int dy, bool normalize, int ktype )
{
const int ksize = 3;
CV_Assert( ktype == CV_32F || ktype == CV_64F );
if( kx.cols != ksize || kx.rows != 1 || kx.type() != ktype )
kx.create( ksize, 1, ktype );
if( ky.cols != ksize || ky.rows != 1 || ky.type() != ktype )
ky.create( ksize, 1, ktype );
CV_Assert( dx >= 0 && dy >= 0 && dx+dy == 1 );
for( int k = 0; k < 2; k++ )
{
Mat* kernel = k == 0 ? &kx : &ky;
int order = k == 0 ? dx : dy;
int kerI[3];
if( order == 0 )
kerI[0] = 3, kerI[1] = 10, kerI[2] = 3;
else if( order == 1 )
kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);
double scale = !normalize || order == 1 ? 1. : 1./32;
temp.convertTo(*kernel, ktype, scale);
}
}
static void getSobelKernels( Mat& kx, Mat& ky, int dx, int dy, int _ksize, bool normalize, int ktype )
{
int i, j, ksizeX = _ksize, ksizeY = _ksize;
if( ksizeX == 1 && dx > 0 )
ksizeX = 3;
if( ksizeY == 1 && dy > 0 )
ksizeY = 3;
CV_Assert( ktype == CV_32F || ktype == CV_64F );
if( kx.cols != ksizeX || kx.rows != 1 || kx.type() != ktype )
kx.create( ksizeX, 1, ktype );
if( ky.cols != ksizeY || ky.rows != 1 || ky.type() != ktype )
ky.create( ksizeY, 1, ktype );
if( _ksize % 2 == 0 || _ksize > 31 )
CV_Error( CV_StsOutOfRange, "The kernel size must be odd and not larger than 31" );
vector<int> kerI(std::max(ksizeX, ksizeY) + 1);
CV_Assert( dx >= 0 && dy >= 0 && dx+dy > 0 );
for( int k = 0; k < 2; k++ )
{
Mat* kernel = k == 0 ? &kx : &ky;
int order = k == 0 ? dx : dy;
int ksize = k == 0 ? ksizeX : ksizeY;
CV_Assert( ksize > order );
if( ksize == 1 )
kerI[0] = 1;
else if( ksize == 3 )
{
if( order == 0 )
kerI[0] = 1, kerI[1] = 2, kerI[2] = 1;
else if( order == 1 )
kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
else
kerI[0] = 1, kerI[1] = -2, kerI[2] = 1;
}
else
{
int oldval, newval;
kerI[0] = 1;
for( i = 0; i < ksize; i++ )
kerI[i+1] = 0;
for( i = 0; i < ksize - order - 1; i++ )
{
oldval = kerI[0];
for( j = 1; j <= ksize; j++ )
{
newval = kerI[j]+kerI[j-1];
kerI[j-1] = oldval;
oldval = newval;
}
}
for( i = 0; i < order; i++ )
{
oldval = -kerI[0];
for( j = 1; j <= ksize; j++ )
{
newval = kerI[j-1] - kerI[j];
kerI[j-1] = oldval;
oldval = newval;
}
}
}
Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);
double scale = !normalize ? 1. : 1./(1 << (ksize-order-1));
temp.convertTo(*kernel, ktype, scale);
}
}
void getDerivKernels( Mat& kx, Mat& ky, int dx, int dy,
int ksize, bool normalize, int ktype )
{
if( ksize <= 0 )
getScharrKernels( kx, ky, dx, dy, normalize, ktype );
else
getSobelKernels( kx, ky, dx, dy, ksize, normalize, ktype );
}
Ptr<FilterEngine> createDerivFilter(int srcType, int dstType,
int dx, int dy, int ksize, int borderType )
{
Mat kx, ky;
getDerivKernels( kx, ky, dx, dy, ksize, false, CV_32F );
return createSeparableLinearFilter(srcType, dstType,
kx, ky, Point(-1,-1), 0, borderType );
}
void Sobel( const Mat& src, Mat& dst, int ddepth, int dx, int dy,
int ksize, double scale, double delta, int borderType )
{
int ktype = std::max(CV_32F, std::max(ddepth, src.depth()));
Mat kx, ky;
getDerivKernels( kx, ky, dx, dy, ksize, false, ktype );
if( scale != 1 )
{
// usually the smoothing part is the slowest to compute,
// so try to scale it instead of the faster differenciating part
if( dx == 0 )
kx *= scale;
else
ky *= scale;
}
sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType );
}
void Scharr( const Mat& src, Mat& dst, int ddepth, int dx, int dy,
double scale, double delta, int borderType )
{
int ktype = std::max(CV_32F, std::max(ddepth, src.depth()));
Mat kx, ky;
getScharrKernels( kx, ky, dx, dy, false, ktype );
if( scale != 1 )
{
// usually the smoothing part is the slowest to compute,
// so try to scale it instead of the faster differenciating part
if( dx == 0 )
kx *= scale;
else
ky *= scale;
}
sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType );
}
void Laplacian( const Mat& src, Mat& dst, int ddepth, int ksize,
double scale, double delta, int borderType )
{
if( ksize == 1 || ksize == 3 )
{
float K[2][9] =
{{0, 1, 0, 1, -4, 1, 0, 1, 0},
{2, 0, 2, 0, -8, 0, 2, 0, 2}};
Mat kernel(3, 3, CV_32F, K[ksize == 3]);
if( scale != 1 )
kernel *= scale;
filter2D( src, dst, ddepth, kernel, Point(-1,-1), delta, borderType );
}
else
{
const size_t STRIPE_SIZE = 1 << 14;
int depth = src.depth();
int ktype = std::max(CV_32F, std::max(ddepth, depth));
int wdepth = depth == CV_8U && ksize <= 5 ? CV_16S : depth <= CV_32F ? CV_32F : CV_64F;
int wtype = CV_MAKETYPE(wdepth, src.channels());
Mat kd, ks;
getSobelKernels( kd, ks, 2, 0, ksize, false, ktype );
if( ddepth < 0 )
ddepth = src.depth();
int dtype = CV_MAKETYPE(ddepth, src.channels());
dst.create( src.size(), dtype );
int dy0 = std::min(std::max((int)(STRIPE_SIZE/(getElemSize(src.type())*src.cols)), 1), src.rows);
Ptr<FilterEngine> fx = createSeparableLinearFilter(src.type(),
wtype, kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() );
Ptr<FilterEngine> fy = createSeparableLinearFilter(src.type(),
wtype, ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() );
int y = fx->start(src), dsty = 0, dy = 0;
fy->start(src);
const uchar* sptr = src.data + y*src.step;
Mat d2x( dy0 + kd.rows - 1, src.cols, wtype );
Mat d2y( dy0 + kd.rows - 1, src.cols, wtype );
for( ; dsty < src.rows; sptr += dy0*src.step, dsty += dy )
{
fx->proceed( sptr, (int)src.step, dy0, d2x.data, (int)d2x.step );
dy = fy->proceed( sptr, (int)src.step, dy0, d2y.data, (int)d2y.step );
if( dy > 0 )
{
Mat dstripe = dst.rowRange(dsty, dsty + dy);
d2x.rows = d2y.rows = dy; // modify the headers, which should work
d2x += d2y;
d2x.convertTo( dstripe, dtype, scale, delta );
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////
CV_IMPL void
cvSobel( const void* srcarr, void* dstarr, int dx, int dy, int aperture_size )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() &&
((src.depth() == CV_8U && (dst.depth() == CV_16S || dst.depth() == CV_32F)) ||
(src.depth() == CV_32F && dst.depth() == CV_32F)));
cv::Sobel( src, dst, dst.depth(), dx, dy, aperture_size, 1, 0, cv::BORDER_REPLICATE );
if( CV_IS_IMAGE(srcarr) && ((IplImage*)srcarr)->origin && dy % 2 != 0 )
dst *= -1;
}
CV_IMPL void
cvLaplace( const void* srcarr, void* dstarr, int aperture_size )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() &&
((src.depth() == CV_8U && (dst.depth() == CV_16S || dst.depth() == CV_32F)) ||
(src.depth() == CV_32F && dst.depth() == CV_32F)));
cv::Laplacian( src, dst, dst.depth(), aperture_size, 1, 0, cv::BORDER_REPLICATE );
}
/* End of file. */

View File

@@ -0,0 +1,870 @@
/*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"
#define ICV_DIST_SHIFT 16
#define ICV_INIT_DIST0 (INT_MAX >> 2)
static CvStatus
icvInitTopBottom( int* temp, int tempstep, CvSize size, int border )
{
int i, j;
for( i = 0; i < border; i++ )
{
int* ttop = (int*)(temp + i*tempstep);
int* tbottom = (int*)(temp + (size.height + border*2 - i - 1)*tempstep);
for( j = 0; j < size.width + border*2; j++ )
{
ttop[j] = ICV_INIT_DIST0;
tbottom[j] = ICV_INIT_DIST0;
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvDistanceTransform_3x3_C1R( const uchar* src, int srcstep, int* temp,
int step, float* dist, int dststep, CvSize size, const float* metrics )
{
const int BORDER = 1;
int i, j;
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
const float scale = 1.f/(1 << ICV_DIST_SHIFT);
srcstep /= sizeof(src[0]);
step /= sizeof(temp[0]);
dststep /= sizeof(dist[0]);
icvInitTopBottom( temp, step, size, BORDER );
// forward pass
for( i = 0; i < size.height; i++ )
{
const uchar* s = src + i*srcstep;
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
for( j = 0; j < BORDER; j++ )
tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
for( j = 0; j < size.width; j++ )
{
if( !s[j] )
tmp[j] = 0;
else
{
int t0 = tmp[j-step-1] + DIAG_DIST;
int t = tmp[j-step] + HV_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-step+1] + DIAG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-1] + HV_DIST;
if( t0 > t ) t0 = t;
tmp[j] = t0;
}
}
}
// backward pass
for( i = size.height - 1; i >= 0; i-- )
{
float* d = (float*)(dist + i*dststep);
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
for( j = size.width - 1; j >= 0; j-- )
{
int t0 = tmp[j];
if( t0 > HV_DIST )
{
int t = tmp[j+step+1] + DIAG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step] + HV_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step-1] + DIAG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+1] + HV_DIST;
if( t0 > t ) t0 = t;
tmp[j] = t0;
}
d[j] = (float)(t0 * scale);
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvDistanceTransform_5x5_C1R( const uchar* src, int srcstep, int* temp,
int step, float* dist, int dststep, CvSize size, const float* metrics )
{
const int BORDER = 2;
int i, j;
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT );
const float scale = 1.f/(1 << ICV_DIST_SHIFT);
srcstep /= sizeof(src[0]);
step /= sizeof(temp[0]);
dststep /= sizeof(dist[0]);
icvInitTopBottom( temp, step, size, BORDER );
// forward pass
for( i = 0; i < size.height; i++ )
{
const uchar* s = src + i*srcstep;
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
for( j = 0; j < BORDER; j++ )
tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
for( j = 0; j < size.width; j++ )
{
if( !s[j] )
tmp[j] = 0;
else
{
int t0 = tmp[j-step*2-1] + LONG_DIST;
int t = tmp[j-step*2+1] + LONG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-step-2] + LONG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-step-1] + DIAG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-step] + HV_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-step+1] + DIAG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-step+2] + LONG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j-1] + HV_DIST;
if( t0 > t ) t0 = t;
tmp[j] = t0;
}
}
}
// backward pass
for( i = size.height - 1; i >= 0; i-- )
{
float* d = (float*)(dist + i*dststep);
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
for( j = size.width - 1; j >= 0; j-- )
{
int t0 = tmp[j];
if( t0 > HV_DIST )
{
int t = tmp[j+step*2+1] + LONG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step*2-1] + LONG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step+2] + LONG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step+1] + DIAG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step] + HV_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step-1] + DIAG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+step-2] + LONG_DIST;
if( t0 > t ) t0 = t;
t = tmp[j+1] + HV_DIST;
if( t0 > t ) t0 = t;
tmp[j] = t0;
}
d[j] = (float)(t0 * scale);
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvDistanceTransformEx_5x5_C1R( const uchar* src, int srcstep, int* temp,
int step, float* dist, int dststep, int* labels, int lstep,
CvSize size, const float* metrics )
{
const int BORDER = 2;
int i, j;
const int HV_DIST = CV_FLT_TO_FIX( metrics[0], ICV_DIST_SHIFT );
const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], ICV_DIST_SHIFT );
const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], ICV_DIST_SHIFT );
const float scale = 1.f/(1 << ICV_DIST_SHIFT);
srcstep /= sizeof(src[0]);
step /= sizeof(temp[0]);
dststep /= sizeof(dist[0]);
lstep /= sizeof(labels[0]);
icvInitTopBottom( temp, step, size, BORDER );
// forward pass
for( i = 0; i < size.height; i++ )
{
const uchar* s = src + i*srcstep;
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
int* lls = (int*)(labels + i*lstep);
for( j = 0; j < BORDER; j++ )
tmp[-j-1] = tmp[size.width + j] = ICV_INIT_DIST0;
for( j = 0; j < size.width; j++ )
{
if( !s[j] )
{
tmp[j] = 0;
//assert( lls[j] != 0 );
}
else
{
int t0 = ICV_INIT_DIST0, t;
int l0 = 0;
t = tmp[j-step*2-1] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-lstep*2-1];
}
t = tmp[j-step*2+1] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-lstep*2+1];
}
t = tmp[j-step-2] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-lstep-2];
}
t = tmp[j-step-1] + DIAG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-lstep-1];
}
t = tmp[j-step] + HV_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-lstep];
}
t = tmp[j-step+1] + DIAG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-lstep+1];
}
t = tmp[j-step+2] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-lstep+2];
}
t = tmp[j-1] + HV_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j-1];
}
tmp[j] = t0;
lls[j] = l0;
}
}
}
// backward pass
for( i = size.height - 1; i >= 0; i-- )
{
float* d = (float*)(dist + i*dststep);
int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER;
int* lls = (int*)(labels + i*lstep);
for( j = size.width - 1; j >= 0; j-- )
{
int t0 = tmp[j];
int l0 = lls[j];
if( t0 > HV_DIST )
{
int t = tmp[j+step*2+1] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+lstep*2+1];
}
t = tmp[j+step*2-1] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+lstep*2-1];
}
t = tmp[j+step+2] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+lstep+2];
}
t = tmp[j+step+1] + DIAG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+lstep+1];
}
t = tmp[j+step] + HV_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+lstep];
}
t = tmp[j+step-1] + DIAG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+lstep-1];
}
t = tmp[j+step-2] + LONG_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+lstep-2];
}
t = tmp[j+1] + HV_DIST;
if( t0 > t )
{
t0 = t;
l0 = lls[j+1];
}
tmp[j] = t0;
lls[j] = l0;
}
d[j] = (float)(t0 * scale);
}
}
return CV_OK;
}
static CvStatus
icvGetDistanceTransformMask( int maskType, float *metrics )
{
if( !metrics )
return CV_NULLPTR_ERR;
switch (maskType)
{
case 30:
metrics[0] = 1.0f;
metrics[1] = 1.0f;
break;
case 31:
metrics[0] = 1.0f;
metrics[1] = 2.0f;
break;
case 32:
metrics[0] = 0.955f;
metrics[1] = 1.3693f;
break;
case 50:
metrics[0] = 1.0f;
metrics[1] = 1.0f;
metrics[2] = 2.0f;
break;
case 51:
metrics[0] = 1.0f;
metrics[1] = 2.0f;
metrics[2] = 3.0f;
break;
case 52:
metrics[0] = 1.0f;
metrics[1] = 1.4f;
metrics[2] = 2.1969f;
break;
default:
return CV_BADRANGE_ERR;
}
return CV_OK;
}
namespace cv
{
struct DTColumnInvoker
{
DTColumnInvoker( const CvMat* _src, CvMat* _dst, const int* _sat_tab, const float* _sqr_tab)
{
src = _src;
dst = _dst;
sat_tab = _sat_tab + src->rows*2 + 1;
sqr_tab = _sqr_tab;
}
void operator()( const BlockedRange& range ) const
{
int i, i1 = range.begin(), i2 = range.end();
int m = src->rows;
size_t sstep = src->step, dstep = dst->step/sizeof(float);
AutoBuffer<int> _d(m);
int* d = _d;
for( i = i1; i < i2; i++ )
{
const uchar* sptr = src->data.ptr + i + (m-1)*sstep;
float* dptr = dst->data.fl + i;
int j, dist = m-1;
for( j = m-1; j >= 0; j--, sptr -= sstep )
{
dist = (dist + 1) & (sptr[0] == 0 ? 0 : -1);
d[j] = dist;
}
dist = m-1;
for( j = 0; j < m; j++, dptr += dstep )
{
dist = dist + 1 - sat_tab[dist - d[j]];
d[j] = dist;
dptr[0] = sqr_tab[dist];
}
}
}
const CvMat* src;
CvMat* dst;
const int* sat_tab;
const float* sqr_tab;
};
struct DTRowInvoker
{
DTRowInvoker( CvMat* _dst, const float* _sqr_tab, const float* _inv_tab )
{
dst = _dst;
sqr_tab = _sqr_tab;
inv_tab = _inv_tab;
}
void operator()( const BlockedRange& range ) const
{
const float inf = 1e6f;
int i, i1 = range.begin(), i2 = range.end();
int n = dst->cols;
AutoBuffer<uchar> _buf((n+2)*2*sizeof(float) + (n+2)*sizeof(int));
float* f = (float*)(uchar*)_buf;
float* z = f + n;
int* v = alignPtr((int*)(z + n + 1), sizeof(int));
for( i = i1; i < i2; i++ )
{
float* d = (float*)(dst->data.ptr + i*dst->step);
int p, q, k;
v[0] = 0;
z[0] = -inf;
z[1] = inf;
f[0] = d[0];
for( q = 1, k = 0; q < n; q++ )
{
float fq = d[q];
f[q] = fq;
for(;;k--)
{
p = v[k];
float s = (fq + sqr_tab[q] - d[p] - sqr_tab[p])*inv_tab[q - p];
if( s > z[k] )
{
k++;
v[k] = q;
z[k] = s;
z[k+1] = inf;
break;
}
}
}
for( q = 0, k = 0; q < n; q++ )
{
while( z[k+1] < q )
k++;
p = v[k];
d[q] = std::sqrt(sqr_tab[std::abs(q - p)] + f[p]);
}
}
}
CvMat* dst;
const float* sqr_tab;
const float* inv_tab;
};
}
static void
icvTrueDistTrans( const CvMat* src, CvMat* dst )
{
const float inf = 1e6f;
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedSizes, "" );
if( CV_MAT_TYPE(src->type) != CV_8UC1 ||
CV_MAT_TYPE(dst->type) != CV_32FC1 )
CV_Error( CV_StsUnsupportedFormat,
"The input image must have 8uC1 type and the output one must have 32fC1 type" );
int i, m = src->rows, n = src->cols;
cv::AutoBuffer<uchar> _buf(std::max(m*2*sizeof(float) + (m*3+1)*sizeof(int), n*2*sizeof(float)));
// stage 1: compute 1d distance transform of each column
float* sqr_tab = (float*)(uchar*)_buf;
int* sat_tab = cv::alignPtr((int*)(sqr_tab + m*2), sizeof(int));
int shift = m*2;
for( i = 0; i < m; i++ )
sqr_tab[i] = (float)(i*i);
for( i = m; i < m*2; i++ )
sqr_tab[i] = inf;
for( i = 0; i < shift; i++ )
sat_tab[i] = 0;
for( ; i <= m*3; i++ )
sat_tab[i] = i - shift;
cv::parallel_for(cv::BlockedRange(0, n), cv::DTColumnInvoker(src, dst, sat_tab, sqr_tab));
// stage 2: compute modified distance transform for each row
float* inv_tab = sqr_tab + n;
inv_tab[0] = sqr_tab[0] = 0.f;
for( i = 1; i < n; i++ )
{
inv_tab[i] = (float)(0.5/i);
sqr_tab[i] = (float)(i*i);
}
cv::parallel_for(cv::BlockedRange(0, m), cv::DTRowInvoker(dst, sqr_tab, inv_tab));
}
/*********************************** IPP functions *********************************/
typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc)( const uchar* src, int srcstep,
void* dst, int dststep,
CvSize size, const void* metrics );
typedef CvStatus (CV_STDCALL * CvIPPDistTransFunc2)( uchar* src, int srcstep,
CvSize size, const int* metrics );
/***********************************************************************************/
typedef CvStatus (CV_STDCALL * CvDistTransFunc)( const uchar* src, int srcstep,
int* temp, int tempstep,
float* dst, int dststep,
CvSize size, const float* metrics );
/****************************************************************************************\
Non-inplace and Inplace 8u->8u Distance Transform for CityBlock (a.k.a. L1) metric
(C) 2006 by Jay Stavinzky.
\****************************************************************************************/
//BEGIN ATS ADDITION
/* 8-bit grayscale distance transform function */
static void
icvDistanceATS_L1_8u( const CvMat* src, CvMat* dst )
{
int width = src->cols, height = src->rows;
int a;
uchar lut[256];
int x, y;
const uchar *sbase = src->data.ptr;
uchar *dbase = dst->data.ptr;
int srcstep = src->step;
int dststep = dst->step;
CV_Assert( CV_IS_MASK_ARR( src ) && CV_MAT_TYPE( dst->type ) == CV_8UC1 );
CV_Assert( CV_ARE_SIZES_EQ( src, dst ));
////////////////////// forward scan ////////////////////////
for( x = 0; x < 256; x++ )
lut[x] = CV_CAST_8U(x+1);
//init first pixel to max (we're going to be skipping it)
dbase[0] = (uchar)(sbase[0] == 0 ? 0 : 255);
//first row (scan west only, skip first pixel)
for( x = 1; x < width; x++ )
dbase[x] = (uchar)(sbase[x] == 0 ? 0 : lut[dbase[x-1]]);
for( y = 1; y < height; y++ )
{
sbase += srcstep;
dbase += dststep;
//for left edge, scan north only
a = sbase[0] == 0 ? 0 : lut[dbase[-dststep]];
dbase[0] = (uchar)a;
for( x = 1; x < width; x++ )
{
a = sbase[x] == 0 ? 0 : lut[MIN(a, dbase[x - dststep])];
dbase[x] = (uchar)a;
}
}
////////////////////// backward scan ///////////////////////
a = dbase[width-1];
// do last row east pixel scan here (skip bottom right pixel)
for( x = width - 2; x >= 0; x-- )
{
a = lut[a];
dbase[x] = (uchar)(CV_CALC_MIN_8U(a, dbase[x]));
}
// right edge is the only error case
for( y = height - 2; y >= 0; y-- )
{
dbase -= dststep;
// do right edge
a = lut[dbase[width-1+dststep]];
dbase[width-1] = (uchar)(MIN(a, dbase[width-1]));
for( x = width - 2; x >= 0; x-- )
{
int b = dbase[x+dststep];
a = lut[MIN(a, b)];
dbase[x] = (uchar)(MIN(a, dbase[x]));
}
}
}
//END ATS ADDITION
/* Wrapper function for distance transform group */
CV_IMPL void
cvDistTransform( const void* srcarr, void* dstarr,
int distType, int maskSize,
const float *mask,
void* labelsarr )
{
cv::Ptr<CvMat> temp;
cv::Ptr<CvMat> src_copy;
cv::Ptr<CvMemStorage> st;
float _mask[5] = {0};
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvMat lstub, *labels = (CvMat*)labelsarr;
CvSize size;
//CvIPPDistTransFunc ipp_func = 0;
//CvIPPDistTransFunc2 ipp_inp_func = 0;
src = cvGetMat( src, &srcstub );
dst = cvGetMat( dst, &dststub );
if( !CV_IS_MASK_ARR( src ) || (CV_MAT_TYPE( dst->type ) != CV_32FC1 &&
(CV_MAT_TYPE(dst->type) != CV_8UC1 || distType != CV_DIST_L1 || labels)) )
CV_Error( CV_StsUnsupportedFormat,
"source image must be 8uC1 and the distance map must be 32fC1 "
"(or 8uC1 in case of simple L1 distance transform)" );
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedSizes, "the source and the destination images must be of the same size" );
if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE )
CV_Error( CV_StsBadSize, "Mask size should be 3 or 5 or 0 (presize)" );
if( distType == CV_DIST_C || distType == CV_DIST_L1 )
maskSize = !labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5;
else if( distType == CV_DIST_L2 && labels )
maskSize = CV_DIST_MASK_5;
if( maskSize == CV_DIST_MASK_PRECISE )
{
icvTrueDistTrans( src, dst );
return;
}
if( labels )
{
labels = cvGetMat( labels, &lstub );
if( CV_MAT_TYPE( labels->type ) != CV_32SC1 )
CV_Error( CV_StsUnsupportedFormat, "the output array of labels must be 32sC1" );
if( !CV_ARE_SIZES_EQ( labels, dst ))
CV_Error( CV_StsUnmatchedSizes, "the array of labels has a different size" );
if( maskSize == CV_DIST_MASK_3 )
CV_Error( CV_StsNotImplemented,
"3x3 mask can not be used for \"labeled\" distance transform. Use 5x5 mask" );
}
if( distType == CV_DIST_C || distType == CV_DIST_L1 || distType == CV_DIST_L2 )
{
icvGetDistanceTransformMask( (distType == CV_DIST_C ? 0 :
distType == CV_DIST_L1 ? 1 : 2) + maskSize*10, _mask );
}
else if( distType == CV_DIST_USER )
{
if( !mask )
CV_Error( CV_StsNullPtr, "" );
memcpy( _mask, mask, (maskSize/2 + 1)*sizeof(float));
}
/*if( !labels )
{
if( CV_MAT_TYPE(dst->type) == CV_32FC1 )
ipp_func = (CvIPPDistTransFunc)(maskSize == CV_DIST_MASK_3 ?
icvDistanceTransform_3x3_8u32f_C1R_p : icvDistanceTransform_5x5_8u32f_C1R_p);
else if( src->data.ptr != dst->data.ptr )
ipp_func = (CvIPPDistTransFunc)icvDistanceTransform_3x3_8u_C1R_p;
else
ipp_inp_func = icvDistanceTransform_3x3_8u_C1IR_p;
}*/
size = cvGetMatSize(src);
/*if( (ipp_func || ipp_inp_func) && src->cols >= 4 && src->rows >= 2 )
{
int _imask[3];
_imask[0] = cvRound(_mask[0]);
_imask[1] = cvRound(_mask[1]);
_imask[2] = cvRound(_mask[2]);
if( ipp_func )
{
IPPI_CALL( ipp_func( src->data.ptr, src->step,
dst->data.fl, dst->step, size,
CV_MAT_TYPE(dst->type) == CV_8UC1 ?
(void*)_imask : (void*)_mask ));
}
else
{
IPPI_CALL( ipp_inp_func( src->data.ptr, src->step, size, _imask ));
}
}
else*/ if( CV_MAT_TYPE(dst->type) == CV_8UC1 )
{
icvDistanceATS_L1_8u( src, dst );
}
else
{
int border = maskSize == CV_DIST_MASK_3 ? 1 : 2;
temp = cvCreateMat( size.height + border*2, size.width + border*2, CV_32SC1 );
if( !labels )
{
CvDistTransFunc func = maskSize == CV_DIST_MASK_3 ?
icvDistanceTransform_3x3_C1R :
icvDistanceTransform_5x5_C1R;
func( src->data.ptr, src->step, temp->data.i, temp->step,
dst->data.fl, dst->step, size, _mask );
}
else
{
CvSeq *contours = 0;
CvPoint top_left = {0,0}, bottom_right = {size.width-1,size.height-1};
int label;
st = cvCreateMemStorage();
src_copy = cvCreateMat( size.height, size.width, src->type );
cvCmpS( src, 0, src_copy, CV_CMP_EQ );
cvFindContours( src_copy, st, &contours, sizeof(CvContour),
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
cvZero( labels );
for( label = 1; contours != 0; contours = contours->h_next, label++ )
{
CvScalar area_color = cvScalarAll(label);
cvDrawContours( labels, contours, area_color, area_color, -255, -1, 8 );
}
cvCopy( src, src_copy );
cvRectangle( src_copy, top_left, bottom_right, cvScalarAll(255), 1, 8 );
icvDistanceTransformEx_5x5_C1R( src_copy->data.ptr, src_copy->step, temp->data.i, temp->step,
dst->data.fl, dst->step, labels->data.i, labels->step, size, _mask );
}
}
}
void cv::distanceTransform( const Mat& src, Mat& dst, Mat& labels,
int distanceType, int maskSize )
{
dst.create(src.size(), CV_32F);
labels.create(src.size(), CV_32S);
CvMat _src = src, _dst = dst, _labels = labels;
cvDistTransform(&_src, &_dst, distanceType, maskSize, 0, &_labels);
}
void cv::distanceTransform( const Mat& src, Mat& dst,
int distanceType, int maskSize )
{
dst.create(src.size(), CV_32F);
CvMat _src = src, _dst = dst;
cvDistTransform(&_src, &_dst, distanceType, maskSize, 0, 0);
}
/* End of file. */

1137
modules/imgproc/src/emd.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
/*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 <cstdio>
#include <vector>
namespace cv
{
template<typename T> struct greaterThanPtr
{
bool operator()(const T* a, const T* b) const { return *a > *b; }
};
void goodFeaturesToTrack( const Mat& image, vector<Point2f>& corners,
int maxCorners, double qualityLevel, double minDistance,
const Mat& mask, int blockSize,
bool useHarrisDetector, double harrisK )
{
CV_Assert( qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0 );
if( mask.data )
CV_Assert( mask.type() == CV_8UC1 && mask.size() == image.size() );
Mat eig, tmp;
if( useHarrisDetector )
cornerHarris( image, eig, blockSize, 3, harrisK );
else
cornerMinEigenVal( image, eig, blockSize, 3 );
double maxVal = 0;
minMaxLoc( eig, 0, &maxVal, 0, 0, mask );
threshold( eig, eig, maxVal*qualityLevel, 0, THRESH_TOZERO );
dilate( eig, tmp, Mat());
Size imgsize = image.size();
vector<const float*> tmpCorners;
// collect list of pointers to features - put them into temporary image
for( int y = 1; y < imgsize.height - 1; y++ )
{
const float* eig_data = (const float*)eig.ptr(y);
const float* tmp_data = (const float*)tmp.ptr(y);
const uchar* mask_data = mask.data ? mask.ptr(y) : 0;
for( int x = 1; x < imgsize.width - 1; x++ )
{
float val = eig_data[x];
if( val != 0 && val == tmp_data[x] && (!mask_data || mask_data[x]) )
tmpCorners.push_back(eig_data + x);
}
}
sort( tmpCorners, greaterThanPtr<float>() );
corners.clear();
size_t i, j, total = tmpCorners.size(), ncorners = 0;
if(minDistance >= 1)
{
// Partition the image into larger grids
int w = image.cols;
int h = image.rows;
const int cell_size = cvRound(minDistance);
const int grid_width = (w + cell_size - 1) / cell_size;
const int grid_height = (h + cell_size - 1) / cell_size;
std::vector<std::vector<Point2f> > grid(grid_width*grid_height);
minDistance *= minDistance;
for( i = 0; i < total; i++ )
{
int ofs = (int)((const uchar*)tmpCorners[i] - eig.data);
int y = (int)(ofs / eig.step);
int x = (int)((ofs - y*eig.step)/sizeof(float));
bool good = true;
int x_cell = x / cell_size;
int y_cell = y / cell_size;
int x1 = x_cell - 1;
int y1 = y_cell - 1;
int x2 = x_cell + 1;
int y2 = y_cell + 1;
// boundary check
x1 = std::max(0, x1);
y1 = std::max(0, y1);
x2 = std::min(grid_width-1, x2);
y2 = std::min(grid_height-1, y2);
for( int yy = y1; yy <= y2; yy++ )
{
for( int xx = x1; xx <= x2; xx++ )
{
vector <Point2f> &m = grid[yy*grid_width + xx];
if( m.size() )
{
for(j = 0; j < m.size(); j++)
{
float dx = x - m[j].x;
float dy = y - m[j].y;
if( dx*dx + dy*dy < minDistance )
{
good = false;
goto break_out;
}
}
}
}
}
break_out:
if(good)
{
// printf("%d: %d %d -> %d %d, %d, %d -- %d %d %d %d, %d %d, c=%d\n",
// i,x, y, x_cell, y_cell, (int)minDistance, cell_size,x1,y1,x2,y2, grid_width,grid_height,c);
grid[y_cell*grid_width + x_cell].push_back(Point2f((float)x, (float)y));
corners.push_back(Point2f((float)x, (float)y));
++ncorners;
if( maxCorners > 0 && (int)ncorners == maxCorners )
break;
}
}
}
else
{
for( i = 0; i < total; i++ )
{
int ofs = (int)((const uchar*)tmpCorners[i] - eig.data);
int y = (int)(ofs / eig.step);
int x = (int)((ofs - y*eig.step)/sizeof(float));
corners.push_back(Point2f((float)x, (float)y));
++ncorners;
if( maxCorners > 0 && (int)ncorners == maxCorners )
break;
}
}
/*
for( i = 0; i < total; i++ )
{
int ofs = (int)((const uchar*)tmpCorners[i] - eig.data);
int y = (int)(ofs / eig.step);
int x = (int)((ofs - y*eig.step)/sizeof(float));
if( minDistance > 0 )
{
for( j = 0; j < ncorners; j++ )
{
float dx = x - corners[j].x;
float dy = y - corners[j].y;
if( dx*dx + dy*dy < minDistance )
break;
}
if( j < ncorners )
continue;
}
corners.push_back(Point2f((float)x, (float)y));
++ncorners;
if( maxCorners > 0 && (int)ncorners == maxCorners )
break;
}
*/
}
}
CV_IMPL void
cvGoodFeaturesToTrack( const void* _image, void*, void*,
CvPoint2D32f* _corners, int *_corner_count,
double quality_level, double min_distance,
const void* _maskImage, int block_size,
int use_harris, double harris_k )
{
cv::Mat image = cv::cvarrToMat(_image), mask;
cv::vector<cv::Point2f> corners;
if( _maskImage )
mask = cv::cvarrToMat(_maskImage);
CV_Assert( _corners && _corner_count );
cv::goodFeaturesToTrack( image, corners, *_corner_count, quality_level,
min_distance, mask, block_size, use_harris != 0, harris_k );
size_t i, ncorners = corners.size();
for( i = 0; i < ncorners; i++ )
_corners[i] = corners[i];
*_corner_count = (int)ncorners;
}
/* End of file. */

View File

@@ -0,0 +1,64 @@
//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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,384 @@
/*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_GCGRAPH_H_
#define _CV_GCGRAPH_H_
using namespace std;
template <class TWeight> class GCGraph
{
public:
GCGraph();
GCGraph( unsigned int vtxCount, unsigned int edgeCount );
~GCGraph();
void create( unsigned int vtxCount, unsigned int edgeCount );
int addVtx();
void addEdges( int i, int j, TWeight w, TWeight revw );
void addTermWeights( int i, TWeight sourceW, TWeight sinkW );
TWeight maxFlow();
bool inSourceSegment( int i );
private:
class Vtx
{
public:
Vtx *next; // initialized and used in maxFlow() only
int parent;
int first;
int ts;
int dist;
TWeight weight;
uchar t;
};
class Edge
{
public:
int dst;
int next;
TWeight weight;
};
vector<Vtx> vtcs;
vector<Edge> edges;
TWeight flow;
};
template <class TWeight>
GCGraph<TWeight>::GCGraph()
{
flow = 0;
}
template <class TWeight>
GCGraph<TWeight>::GCGraph( unsigned int vtxCount, unsigned int edgeCount )
{
create( vtxCount, edgeCount );
}
template <class TWeight>
GCGraph<TWeight>::~GCGraph()
{
}
template <class TWeight>
void GCGraph<TWeight>::create( unsigned int vtxCount, unsigned int edgeCount )
{
vtcs.reserve( vtxCount );
edges.reserve( edgeCount );
flow = 0;
}
template <class TWeight>
int GCGraph<TWeight>::addVtx()
{
Vtx v;
memset( &v, 0, sizeof(Vtx));
vtcs.push_back(v);
return (int)vtcs.size() - 1;
}
template <class TWeight>
void GCGraph<TWeight>::addEdges( int i, int j, TWeight w, TWeight revw )
{
CV_Assert( i>=0 && i<(int)vtcs.size() );
CV_Assert( j>=0 && j<(int)vtcs.size() );
CV_Assert( w>=0 && revw>=0 );
CV_Assert( i != j );
Edge fromI, toI;
fromI.dst = j;
fromI.next = vtcs[i].first;
fromI.weight = w;
vtcs[i].first = (int)edges.size();
edges.push_back( fromI );
toI.dst = i;
toI.next = vtcs[j].first;
toI.weight = revw;
vtcs[j].first = (int)edges.size();
edges.push_back( toI );
}
template <class TWeight>
void GCGraph<TWeight>::addTermWeights( int i, TWeight sourceW, TWeight sinkW )
{
CV_Assert( i>=0 && i<(int)vtcs.size() );
TWeight dw = vtcs[i].weight;
if( dw > 0 )
sourceW += dw;
else
sinkW -= dw;
flow += (sourceW < sinkW) ? sourceW : sinkW;
vtcs[i].weight = sourceW - sinkW;
}
template <class TWeight>
TWeight GCGraph<TWeight>::maxFlow()
{
const int TERMINAL = -1, ORPHAN = -2;
Vtx stub, *nilNode = &stub, *first = nilNode, *last = nilNode;
int curr_ts = 0;
stub.next = nilNode;
Vtx *vtxPtr = &vtcs[0];
Edge *edgePtr = &edges[0];
vector<Vtx*> orphans;
// initialize the active queue and the graph vertices
for( int i = 0; i < (int)vtcs.size(); i++ )
{
Vtx* v = vtxPtr + i;
v->ts = 0;
if( v->weight != 0 )
{
last = last->next = v;
v->dist = 1;
v->parent = TERMINAL;
v->t = v->weight < 0;
}
else
v->parent = 0;
}
first = first->next;
last->next = nilNode;
nilNode->next = 0;
// run the search-path -> augment-graph -> restore-trees loop
for(;;)
{
Vtx* v, *u;
int e0 = -1, ei = 0, ej = 0;
TWeight minWeight, weight;
uchar vt;
// grow S & T search trees, find an edge connecting them
while( first != nilNode )
{
v = first;
if( v->parent )
{
vt = v->t;
for( ei = v->first; ei != 0; ei = edgePtr[ei].next )
{
if( edgePtr[ei^vt].weight == 0 )
continue;
u = vtxPtr+edgePtr[ei].dst;
if( !u->parent )
{
u->t = vt;
u->parent = ei ^ 1;
u->ts = v->ts;
u->dist = v->dist + 1;
if( !u->next )
{
u->next = nilNode;
last = last->next = u;
}
continue;
}
if( u->t != vt )
{
e0 = ei ^ vt;
break;
}
if( u->dist > v->dist+1 && u->ts <= v->ts )
{
// reassign the parent
u->parent = ei ^ 1;
u->ts = v->ts;
u->dist = v->dist + 1;
}
}
if( e0 > 0 )
break;
}
// exclude the vertex from the active list
first = first->next;
v->next = 0;
}
if( e0 <= 0 )
break;
// find the minimum edge weight along the path
minWeight = edgePtr[e0].weight;
assert( minWeight > 0 );
// k = 1: source tree, k = 0: destination tree
for( int k = 1; k >= 0; k-- )
{
for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst )
{
if( (ei = v->parent) < 0 )
break;
weight = edgePtr[ei^k].weight;
minWeight = MIN(minWeight, weight);
assert( minWeight > 0 );
}
weight = fabs(v->weight);
minWeight = MIN(minWeight, weight);
assert( minWeight > 0 );
}
// modify weights of the edges along the path and collect orphans
edgePtr[e0].weight -= minWeight;
edgePtr[e0^1].weight += minWeight;
flow += minWeight;
// k = 1: source tree, k = 0: destination tree
for( int k = 1; k >= 0; k-- )
{
for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst )
{
if( (ei = v->parent) < 0 )
break;
edgePtr[ei^(k^1)].weight += minWeight;
if( (edgePtr[ei^k].weight -= minWeight) == 0 )
{
orphans.push_back(v);
v->parent = ORPHAN;
}
}
v->weight = v->weight + minWeight*(1-k*2);
if( v->weight == 0 )
{
orphans.push_back(v);
v->parent = ORPHAN;
}
}
// restore the search trees by finding new parents for the orphans
curr_ts++;
while( !orphans.empty() )
{
Vtx* v = orphans.back();
orphans.pop_back();
int d, minDist = INT_MAX;
e0 = 0;
vt = v->t;
for( ei = v->first; ei != 0; ei = edgePtr[ei].next )
{
if( edgePtr[ei^(vt^1)].weight == 0 )
continue;
u = vtxPtr+edgePtr[ei].dst;
if( u->t != vt || u->parent == 0 )
continue;
// compute the distance to the tree root
for( d = 0;; )
{
if( u->ts == curr_ts )
{
d += u->dist;
break;
}
ej = u->parent;
d++;
if( ej < 0 )
{
if( ej == ORPHAN )
d = INT_MAX-1;
else
{
u->ts = curr_ts;
u->dist = 1;
}
break;
}
u = vtxPtr+edgePtr[ej].dst;
}
// update the distance
if( ++d < INT_MAX )
{
if( d < minDist )
{
minDist = d;
e0 = ei;
}
for( u = vtxPtr+edgePtr[ei].dst; u->ts != curr_ts; u = vtxPtr+edgePtr[u->parent].dst )
{
u->ts = curr_ts;
u->dist = --d;
}
}
}
if( (v->parent = e0) > 0 )
{
v->ts = curr_ts;
v->dist = minDist;
continue;
}
/* no parent is found */
v->ts = 0;
for( ei = v->first; ei != 0; ei = edgePtr[ei].next )
{
u = vtxPtr+edgePtr[ei].dst;
ej = u->parent;
if( u->t != vt || !ej )
continue;
if( edgePtr[ei^(vt^1)].weight && !u->next )
{
u->next = nilNode;
last = last->next = u;
}
if( ej > 0 && vtxPtr+edgePtr[ej].dst == v )
{
orphans.push_back(u);
u->parent = ORPHAN;
}
}
}
}
return flow;
}
template <class TWeight>
bool GCGraph<TWeight>::inSourceSegment( int i )
{
CV_Assert( i>=0 && i<(int)vtcs.size() );
return vtcs[i].t == 0;
};
#endif

View File

@@ -0,0 +1,343 @@
/*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"
CV_IMPL CvRect
cvMaxRect( const CvRect* rect1, const CvRect* rect2 )
{
if( rect1 && rect2 )
{
CvRect max_rect;
int a, b;
max_rect.x = a = rect1->x;
b = rect2->x;
if( max_rect.x > b )
max_rect.x = b;
max_rect.width = a += rect1->width;
b += rect2->width;
if( max_rect.width < b )
max_rect.width = b;
max_rect.width -= max_rect.x;
max_rect.y = a = rect1->y;
b = rect2->y;
if( max_rect.y > b )
max_rect.y = b;
max_rect.height = a += rect1->height;
b += rect2->height;
if( max_rect.height < b )
max_rect.height = b;
max_rect.height -= max_rect.y;
return max_rect;
}
else if( rect1 )
return *rect1;
else if( rect2 )
return *rect2;
else
return cvRect(0,0,0,0);
}
CV_IMPL void
cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] )
{
double angle = box.angle*CV_PI/180.;
float a = (float)cos(angle)*0.5f;
float b = (float)sin(angle)*0.5f;
if( !pt )
CV_Error( CV_StsNullPtr, "NULL vertex array pointer" );
pt[0].x = box.center.x - a*box.size.height - b*box.size.width;
pt[0].y = box.center.y + b*box.size.height - a*box.size.width;
pt[1].x = box.center.x + a*box.size.height - b*box.size.width;
pt[1].y = box.center.y - b*box.size.height - a*box.size.width;
pt[2].x = 2*box.center.x - pt[0].x;
pt[2].y = 2*box.center.y - pt[0].y;
pt[3].x = 2*box.center.x - pt[1].x;
pt[3].y = 2*box.center.y - pt[1].y;
}
int
icvIntersectLines( double x1, double dx1, double y1, double dy1,
double x2, double dx2, double y2, double dy2, double *t2 )
{
double d = dx1 * dy2 - dx2 * dy1;
int result = -1;
if( d != 0 )
{
*t2 = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / d;
result = 0;
}
return result;
}
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 )
{
double det = a0[0] * b1[0] - a1[0] * b0[0];
if( det != 0 )
{
det = 1. / det;
point->x = (float) ((b0[0] * c1[0] - b1[0] * c0[0]) * det);
point->y = (float) ((a1[0] * c0[0] - a0[0] * c1[0]) * det);
}
else
{
point->x = point->y = FLT_MAX;
}
}
CV_IMPL double
cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist )
{
double result = 0;
CvSeqBlock block;
CvContour header;
CvSeq* contour = (CvSeq*)_contour;
CvSeqReader reader;
int i, total, counter = 0;
int is_float;
double min_dist_num = FLT_MAX, min_dist_denom = 1;
CvPoint ip = {0,0};
if( !CV_IS_SEQ(contour) )
{
contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE + CV_SEQ_FLAG_CLOSED,
_contour, &header, &block );
}
else if( CV_IS_SEQ_POINT_SET(contour) )
{
if( contour->header_size == sizeof(CvContour) && !measure_dist )
{
CvRect r = ((CvContour*)contour)->rect;
if( pt.x < r.x || pt.y < r.y ||
pt.x >= r.x + r.width || pt.y >= r.y + r.height )
return -100;
}
}
else if( CV_IS_SEQ_CHAIN(contour) )
{
CV_Error( CV_StsBadArg,
"Chains are not supported. Convert them to polygonal representation using cvApproxChains()" );
}
else
CV_Error( CV_StsBadArg, "Input contour is neither a valid sequence nor a matrix" );
total = contour->total;
is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
cvStartReadSeq( contour, &reader, -1 );
if( !is_float && !measure_dist && (ip.x = cvRound(pt.x)) == pt.x && (ip.y = cvRound(pt.y)) == pt.y )
{
// the fastest "pure integer" branch
CvPoint v0, v;
CV_READ_SEQ_ELEM( v, reader );
for( i = 0; i < total; i++ )
{
int dist;
v0 = v;
CV_READ_SEQ_ELEM( v, reader );
if( (v0.y <= ip.y && v.y <= ip.y) ||
(v0.y > ip.y && v.y > ip.y) ||
(v0.x < ip.x && v.x < ip.x) )
{
if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y &&
((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) )
return 0;
continue;
}
dist = (ip.y - v0.y)*(v.x - v0.x) - (ip.x - v0.x)*(v.y - v0.y);
if( dist == 0 )
return 0;
if( v.y < v0.y )
dist = -dist;
counter += dist > 0;
}
result = counter % 2 == 0 ? -100 : 100;
}
else
{
CvPoint2D32f v0, v;
CvPoint iv;
if( is_float )
{
CV_READ_SEQ_ELEM( v, reader );
}
else
{
CV_READ_SEQ_ELEM( iv, reader );
v = cvPointTo32f( iv );
}
if( !measure_dist )
{
for( i = 0; i < total; i++ )
{
double dist;
v0 = v;
if( is_float )
{
CV_READ_SEQ_ELEM( v, reader );
}
else
{
CV_READ_SEQ_ELEM( iv, reader );
v = cvPointTo32f( iv );
}
if( (v0.y <= pt.y && v.y <= pt.y) ||
(v0.y > pt.y && v.y > pt.y) ||
(v0.x < pt.x && v.x < pt.x) )
{
if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y &&
((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) )
return 0;
continue;
}
dist = (double)(pt.y - v0.y)*(v.x - v0.x) - (double)(pt.x - v0.x)*(v.y - v0.y);
if( dist == 0 )
return 0;
if( v.y < v0.y )
dist = -dist;
counter += dist > 0;
}
result = counter % 2 == 0 ? -100 : 100;
}
else
{
for( i = 0; i < total; i++ )
{
double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1;
v0 = v;
if( is_float )
{
CV_READ_SEQ_ELEM( v, reader );
}
else
{
CV_READ_SEQ_ELEM( iv, reader );
v = cvPointTo32f( iv );
}
dx = v.x - v0.x; dy = v.y - v0.y;
dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
dx2 = pt.x - v.x; dy2 = pt.y - v.y;
if( dx1*dx + dy1*dy <= 0 )
dist_num = dx1*dx1 + dy1*dy1;
else if( dx2*dx + dy2*dy >= 0 )
dist_num = dx2*dx2 + dy2*dy2;
else
{
dist_num = (dy1*dx - dx1*dy);
dist_num *= dist_num;
dist_denom = dx*dx + dy*dy;
}
if( dist_num*min_dist_denom < min_dist_num*dist_denom )
{
min_dist_num = dist_num;
min_dist_denom = dist_denom;
if( min_dist_num == 0 )
break;
}
if( (v0.y <= pt.y && v.y <= pt.y) ||
(v0.y > pt.y && v.y > pt.y) ||
(v0.x < pt.x && v.x < pt.x) )
continue;
dist_num = dy1*dx - dx1*dy;
if( dy < 0 )
dist_num = -dist_num;
counter += dist_num > 0;
}
result = sqrt(min_dist_num/min_dist_denom);
if( counter % 2 == 0 )
result = -result;
}
}
return result;
}
/* End of file. */

View File

@@ -0,0 +1,559 @@
/*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 "gcgraph.hpp"
#include <limits>
using namespace cv;
/*
This is implementation of image segmentation algorithm GrabCut described in
"GrabCut — Interactive Foreground Extraction using Iterated Graph Cuts".
Carsten Rother, Vladimir Kolmogorov, Andrew Blake.
*/
/*
GMM - Gaussian Mixture Model
*/
class GMM
{
public:
static const int componentsCount = 5;
GMM( Mat& _model );
float operator()( Vec3f color ) const;
float operator()( int ci, Vec3f color ) const;
int whichComponent( Vec3f color ) const;
void initLearning();
void addSample( int ci, Vec3f color );
void endLearning();
private:
void calcInverseCovAndDeterm( int ci );
Mat model;
float* coefs;
float* mean;
float* cov;
float inverseCovs[componentsCount][3][3];
float covDeterms[componentsCount];
float sums[componentsCount][3];
float prods[componentsCount][3][3];
int sampleCounts[componentsCount];
int totalSampleCount;
};
GMM::GMM( Mat& _model )
{
const int modelSize = 3/*mean*/ + 9/*covariance*/ + 1/*component weight*/;
if( _model.empty() )
{
_model.create( 1, modelSize*componentsCount, CV_32FC1 );
_model.setTo(Scalar(0));
}
else if( (_model.type() != CV_32FC1) || (_model.rows != 1) || (_model.cols != modelSize*componentsCount) )
CV_Error( CV_StsBadArg, "_model must have CV_32FC1 type, rows == 1 and cols == 13*componentsCount" );
model = _model;
coefs = model.ptr<float>(0);
mean = coefs + componentsCount;
cov = mean + 3*componentsCount;
for( int ci = 0; ci < componentsCount; ci++ )
if( coefs[ci] > 0 )
calcInverseCovAndDeterm( ci );
}
float GMM::operator()( Vec3f color ) const
{
float res = 0;
for( int ci = 0; ci < componentsCount; ci++ )
res += coefs[ci] * (*this)(ci, color );
return res;
}
float GMM::operator()( int ci, Vec3f color ) const
{
float res = 0;
if( coefs[ci] > 0 )
{
if( covDeterms[ci] > std::numeric_limits<float>::epsilon() )
{
Vec3f diff = color;
float* m = mean + 3*ci;
diff[0] -= m[0]; diff[1] -= m[1]; diff[2] -= m[2];
float mult = diff[0]*(diff[0]*inverseCovs[ci][0][0] + diff[1]*inverseCovs[ci][1][0] + diff[2]*inverseCovs[ci][2][0])
+ diff[1]*(diff[0]*inverseCovs[ci][0][1] + diff[1]*inverseCovs[ci][1][1] + diff[2]*inverseCovs[ci][2][1])
+ diff[2]*(diff[0]*inverseCovs[ci][0][2] + diff[1]*inverseCovs[ci][1][2] + diff[2]*inverseCovs[ci][2][2]);
res = 1.0f/sqrt(covDeterms[ci]) * exp(-0.5f*mult);
}
}
return res;
}
int GMM::whichComponent( Vec3f color ) const
{
int k = 0;
float max = 0;
for( int ci = 0; ci < componentsCount; ci++ )
{
float p = (*this)( ci, color );
if( p > max )
{
k = ci;
max = p;
}
}
return k;
}
void GMM::initLearning()
{
for( int ci = 0; ci < componentsCount; ci++)
{
sums[ci][0] = sums[ci][1] = sums[ci][2] = 0;
prods[ci][0][0] = prods[ci][0][1] = prods[ci][0][2] = 0;
prods[ci][1][0] = prods[ci][1][1] = prods[ci][1][2] = 0;
prods[ci][2][0] = prods[ci][2][1] = prods[ci][2][2] = 0;
sampleCounts[ci] = 0;
}
totalSampleCount = 0;
}
void GMM::addSample( int ci, Vec3f color )
{
sums[ci][0] += color[0]; sums[ci][1] += color[1]; sums[ci][2] += color[2];
prods[ci][0][0] += color[0]*color[0]; prods[ci][0][1] += color[0]*color[1]; prods[ci][0][2] += color[0]*color[2];
prods[ci][1][0] += color[1]*color[0]; prods[ci][1][1] += color[1]*color[1]; prods[ci][1][2] += color[1]*color[2];
prods[ci][2][0] += color[2]*color[0]; prods[ci][2][1] += color[2]*color[1]; prods[ci][2][2] += color[2]*color[2];
sampleCounts[ci]++;
totalSampleCount++;
}
void GMM::endLearning()
{
for( int ci = 0; ci < componentsCount; ci++ )
{
int n = sampleCounts[ci];
if( n == 0 )
coefs[ci] = 0;
else
{
coefs[ci] = (float)n/totalSampleCount;
float* m = mean + 3*ci;
m[0] = sums[ci][0]/n; m[1] = sums[ci][1]/n; m[2] = sums[ci][2]/n;
float* c = cov + 9*ci;
c[0] = prods[ci][0][0]/n - m[0]*m[0]; c[1] = prods[ci][0][1]/n - m[0]*m[1]; c[2] = prods[ci][0][2]/n - m[0]*m[2];
c[3] = prods[ci][1][0]/n - m[1]*m[0]; c[4] = prods[ci][1][1]/n - m[1]*m[1]; c[5] = prods[ci][1][2]/n - m[1]*m[2];
c[6] = prods[ci][2][0]/n - m[2]*m[0]; c[7] = prods[ci][2][1]/n - m[2]*m[1]; c[8] = prods[ci][2][2]/n - m[2]*m[2];
calcInverseCovAndDeterm(ci);
}
}
}
void GMM::calcInverseCovAndDeterm( int ci )
{
if( coefs[ci] > 0 )
{
float *c = cov + 9*ci;
float dtrm =
covDeterms[ci] = c[0]*(c[4]*c[8]-c[5]*c[7]) - c[1]*(c[3]*c[8]-c[5]*c[6]) + c[2]*(c[3]*c[7]-c[4]*c[6]);
if( dtrm > std::numeric_limits<float>::epsilon() )
{
inverseCovs[ci][0][0] = (c[4]*c[8] - c[5]*c[7]) / dtrm;
inverseCovs[ci][1][0] = -(c[3]*c[8] - c[5]*c[6]) / dtrm;
inverseCovs[ci][2][0] = (c[3]*c[7] - c[4]*c[6]) / dtrm;
inverseCovs[ci][0][1] = -(c[1]*c[8] - c[2]*c[7]) / dtrm;
inverseCovs[ci][1][1] = (c[0]*c[8] - c[2]*c[6]) / dtrm;
inverseCovs[ci][2][1] = -(c[0]*c[7] - c[1]*c[6]) / dtrm;
inverseCovs[ci][0][2] = (c[1]*c[5] - c[2]*c[4]) / dtrm;
inverseCovs[ci][1][2] = -(c[0]*c[5] - c[2]*c[3]) / dtrm;
inverseCovs[ci][2][2] = (c[0]*c[4] - c[1]*c[3]) / dtrm;
}
}
}
/*
Calculate beta - parameter of GrabCut algorithm.
beta = 1/(2*avg(sqr(||color[i] - color[j]||)))
*/
float calcBeta( const Mat& img )
{
float beta = 0;
for( int y = 0; y < img.rows; y++ )
{
for( int x = 0; x < img.cols; x++ )
{
Vec3f color = img.at<Vec3b>(y,x);
if( x>0 ) // left
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y,x-1);
beta += diff.dot(diff);
}
if( y>0 && x>0 ) // upleft
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y-1,x-1);
beta += diff.dot(diff);
}
if( y>0 ) // up
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y-1,x);
beta += diff.dot(diff);
}
if( y>0 && x<img.cols-1) // upright
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y-1,x+1);
beta += diff.dot(diff);
}
}
}
beta = 1.f / (2 * beta/(4*img.cols*img.rows - 3*img.cols - 3*img.rows + 2) );
return beta;
}
/*
Calculate weights of noterminal vertices of graph.
beta and gamma - parameters of GrabCut algorithm.
*/
void calcNWeights( const Mat& img, Mat& leftW, Mat& upleftW, Mat& upW, Mat& uprightW, float beta, float gamma )
{
const float gammaDivSqrt2 = gamma / std::sqrt(2.0f);
leftW.create( img.rows, img.cols, CV_32FC1 );
upleftW.create( img.rows, img.cols, CV_32FC1 );
upW.create( img.rows, img.cols, CV_32FC1 );
uprightW.create( img.rows, img.cols, CV_32FC1 );
for( int y = 0; y < img.rows; y++ )
{
for( int x = 0; x < img.cols; x++ )
{
Vec3f color = img.at<Vec3b>(y,x);
if( x-1>=0 ) // left
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y,x-1);
leftW.at<float>(y,x) = gamma * exp(-beta*diff.dot(diff));
}
else
leftW.at<float>(y,x) = 0;
if( x-1>=0 && y-1>=0 ) // upleft
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y-1,x-1);
upleftW.at<float>(y,x) = gammaDivSqrt2 * exp(-beta*diff.dot(diff));
}
else
upleftW.at<float>(y,x) = 0;
if( y-1>=0 ) // up
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y-1,x);
upW.at<float>(y,x) = gamma * exp(-beta*diff.dot(diff));
}
else
upW.at<float>(y,x) = 0;
if( x+1<img.cols-1 && y-1>=0 ) // upright
{
Vec3f diff = color - (Vec3f)img.at<Vec3b>(y-1,x+1);
uprightW.at<float>(y,x) = gammaDivSqrt2 * exp(-beta*diff.dot(diff));
}
else
uprightW.at<float>(y,x) = 0;
}
}
}
/*
Check size, type and element values of mask matrix.
*/
void checkMask( const Mat& img, const Mat& mask )
{
if( mask.empty() )
CV_Error( CV_StsBadArg, "mask is empty" );
if( mask.type() != CV_8UC1 )
CV_Error( CV_StsBadArg, "mask must have CV_8UC1 type" );
if( mask.cols != img.cols || mask.rows != img.rows )
CV_Error( CV_StsBadArg, "mask must have as many rows and cols as img" );
for( int y = 0; y < mask.rows; y++ )
{
for( int x = 0; x < mask.cols; x++ )
{
uchar val = mask.at<uchar>(y,x);
if( val!=GC_BGD && val!=GC_FGD && val!=GC_PR_BGD && val!=GC_PR_FGD )
CV_Error( CV_StsBadArg, "mask element value must be equel"
"GC_BGD or GC_FGD or GC_PR_BGD or GC_PR_FGD" );
}
}
}
/*
Initialize mask using rectangular.
*/
void initMaskWithRect( Mat& mask, Size imgSize, Rect rect )
{
mask.create( imgSize, CV_8UC1 );
mask.setTo( GC_BGD );
rect.x = max(0, rect.x);
rect.y = max(0, rect.y);
rect.width = min(rect.width, imgSize.width-rect.x);
rect.height = min(rect.height, imgSize.height-rect.y);
(mask(rect)).setTo( Scalar(GC_PR_FGD) );
}
/*
Initialize GMM background and foreground models using kmeans algorithm.
*/
void initGMMs( const Mat& img, const Mat& mask, GMM& bgdGMM, GMM& fgdGMM )
{
const int kMeansItCount = 10;
const int kMeansType = KMEANS_PP_CENTERS;
Mat bgdLabels, fgdLabels;
vector<Vec3f> bgdSamples, fgdSamples;
Point p;
for( p.y = 0; p.y < img.rows; p.y++ )
{
for( p.x = 0; p.x < img.cols; p.x++ )
{
if( mask.at<uchar>(p) == GC_BGD || mask.at<uchar>(p) == GC_PR_BGD )
bgdSamples.push_back( (Vec3f)img.at<Vec3b>(p) );
else // GC_FGD | GC_PR_FGD
fgdSamples.push_back( (Vec3f)img.at<Vec3b>(p) );
}
}
CV_Assert( !bgdSamples.empty() && !fgdSamples.empty() );
Mat _bgdSamples( (int)bgdSamples.size(), 3, CV_32FC1, &bgdSamples[0][0] );
kmeans( _bgdSamples, GMM::componentsCount, bgdLabels,
TermCriteria( CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType, 0 );
Mat _fgdSamples( (int)fgdSamples.size(), 3, CV_32FC1, &fgdSamples[0][0] );
kmeans( _fgdSamples, GMM::componentsCount, fgdLabels,
TermCriteria( CV_TERMCRIT_ITER, kMeansItCount, 0.0), 0, kMeansType, 0 );
bgdGMM.initLearning();
for( int i = 0; i < (int)bgdSamples.size(); i++ )
bgdGMM.addSample( bgdLabels.at<int>(i,0), bgdSamples[i] );
bgdGMM.endLearning();
fgdGMM.initLearning();
for( int i = 0; i < (int)fgdSamples.size(); i++ )
fgdGMM.addSample( fgdLabels.at<int>(i,0), fgdSamples[i] );
fgdGMM.endLearning();
}
/*
Assign GMMs components for each pixel.
*/
void assignGMMsComponents( const Mat& img, const Mat& mask, const GMM& bgdGMM, const GMM& fgdGMM, Mat& compIdxs )
{
Point p;
for( p.y = 0; p.y < img.rows; p.y++ )
{
for( p.x = 0; p.x < img.cols; p.x++ )
{
Vec3f color = img.at<Vec3b>(p);
compIdxs.at<int>(p) = mask.at<uchar>(p) == GC_BGD || mask.at<uchar>(p) == GC_PR_BGD ?
bgdGMM.whichComponent(color) : fgdGMM.whichComponent(color);
}
}
}
/*
Learn GMMs parameters.
*/
void learnGMMs( const Mat& img, const Mat& mask, const Mat& compIdxs, GMM& bgdGMM, GMM& fgdGMM )
{
bgdGMM.initLearning();
fgdGMM.initLearning();
Point p;
for( int ci = 0; ci < GMM::componentsCount; ci++ )
{
for( p.y = 0; p.y < img.rows; p.y++ )
{
for( p.x = 0; p.x < img.cols; p.x++ )
{
if( compIdxs.at<int>(p) == ci )
{
if( mask.at<uchar>(p) == GC_BGD || mask.at<uchar>(p) == GC_PR_BGD )
bgdGMM.addSample( ci, img.at<Vec3b>(p) );
else
fgdGMM.addSample( ci, img.at<Vec3b>(p) );
}
}
}
}
bgdGMM.endLearning();
fgdGMM.endLearning();
}
/*
Construct GCGraph
*/
void constructGCGraph( const Mat& img, const Mat& mask, const GMM& bgdGMM, const GMM& fgdGMM, float lambda,
const Mat& leftW, const Mat& upleftW, const Mat& upW, const Mat& uprightW,
GCGraph<float>& graph )
{
int vtxCount = img.cols*img.rows,
edgeCount = 2*(4*img.cols*img.rows - 3*(img.cols + img.rows) + 2);
graph.create(vtxCount, edgeCount);
Point p;
for( p.y = 0; p.y < img.rows; p.y++ )
{
for( p.x = 0; p.x < img.cols; p.x++)
{
// add node
int vtxIdx = graph.addVtx();
Vec3b color = img.at<Vec3b>(p);
// set t-weights
float fromSource, toSink;
if( mask.at<uchar>(p) == GC_PR_BGD || mask.at<uchar>(p) == GC_PR_FGD )
{
fromSource = -log( bgdGMM(color) );
toSink = -log( fgdGMM(color) );
}
else if( mask.at<uchar>(p) == GC_BGD )
{
fromSource = 0;
toSink = lambda;
}
else // GC_FGD
{
fromSource = lambda;
toSink = 0;
}
graph.addTermWeights( vtxIdx, fromSource, toSink );
// set n-weights
if( p.x>0 )
{
float w = leftW.at<float>(p);
graph.addEdges( vtxIdx, vtxIdx-1, w, w );
}
if( p.x>0 && p.y>0 )
{
float w = upleftW.at<float>(p);
graph.addEdges( vtxIdx, vtxIdx-img.cols-1, w, w );
}
if( p.y>0 )
{
float w = upW.at<float>(p);
graph.addEdges( vtxIdx, vtxIdx-img.cols, w, w );
}
if( p.x<img.cols-1 && p.y>0 )
{
float w = uprightW.at<float>(p);
graph.addEdges( vtxIdx, vtxIdx-img.cols+1, w, w );
}
}
}
}
/*
Estimate segmentation using MaxFlow algorithm
*/
void estimateSegmentation( GCGraph<float>& graph, Mat& mask )
{
graph.maxFlow();
Point p;
for( p.y = 0; p.y < mask.rows; p.y++ )
{
for( p.x = 0; p.x < mask.cols; p.x++ )
{
if( mask.at<uchar>(p) == GC_PR_BGD || mask.at<uchar>(p) == GC_PR_FGD )
{
if( graph.inSourceSegment( p.y*mask.cols+p.x /*vertex index*/ ) )
mask.at<uchar>(p) = GC_PR_FGD;
else
mask.at<uchar>(p) = GC_PR_BGD;
}
}
}
}
void cv::grabCut( const Mat& img, Mat& mask, Rect rect,
Mat& bgdModel, Mat& fgdModel,
int iterCount, int mode )
{
if( img.empty() )
CV_Error( CV_StsBadArg, "image is empty" );
if( img.type() != CV_8UC3 )
CV_Error( CV_StsBadArg, "image mush have CV_8UC3 type" );
GMM bgdGMM( bgdModel ), fgdGMM( fgdModel );
Mat compIdxs( img.size(), CV_32SC1 );
if( mode == GC_INIT_WITH_RECT || mode == GC_INIT_WITH_MASK )
{
if( mode == GC_INIT_WITH_RECT )
initMaskWithRect( mask, img.size(), rect );
else // flag == GC_INIT_WITH_MASK
checkMask( img, mask );
initGMMs( img, mask, bgdGMM, fgdGMM );
}
if( iterCount <= 0)
return;
if( mode == GC_EVAL )
checkMask( img, mask );
const float gamma = 50;
const float lambda = 9*gamma;
const float beta = calcBeta( img );
Mat leftW, upleftW, upW, uprightW;
calcNWeights( img, leftW, upleftW, upW, uprightW, beta, gamma );
for( int i = 0; i < iterCount; i++ )
{
GCGraph<float> graph;
assignGMMsComponents( img, mask, bgdGMM, fgdGMM, compIdxs );
learnGMMs( img, mask, compIdxs, bgdGMM, fgdGMM );
constructGCGraph(img, mask, bgdGMM, fgdGMM, lambda, leftW, upleftW, upW, uprightW, graph );
estimateSegmentation( graph, mask );
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,816 @@
/*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 icvers.
//
// 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*/
/* ////////////////////////////////////////////////////////////////////
//
// Geometrical transforms on images and matrices: rotation, zoom etc.
//
// */
#include "precomp.hpp"
#undef CV_MAT_ELEM_PTR_FAST
#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \
((mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col))
inline float
min4( float a, float b, float c, float d )
{
a = MIN(a,b);
c = MIN(c,d);
return MIN(a,c);
}
#define CV_MAT_3COLOR_ELEM(img,type,y,x,c) CV_MAT_ELEM(img,type,y,(x)*3+(c))
#define KNOWN 0 //known outside narrow band
#define BAND 1 //narrow band (known)
#define INSIDE 2 //unknown
#define CHANGE 3 //servise
typedef struct CvHeapElem
{
float T;
int i,j;
struct CvHeapElem* prev;
struct CvHeapElem* next;
}
CvHeapElem;
class CvPriorityQueueFloat
{
protected:
CvHeapElem *mem,*empty,*head,*tail;
int num,in;
public:
bool Init( const CvMat* f )
{
int i,j;
for( i = num = 0; i < f->rows; i++ )
{
for( j = 0; j < f->cols; j++ )
num += CV_MAT_ELEM(*f,uchar,i,j)!=0;
}
if (num<=0) return false;
mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem));
if (mem==NULL) return false;
head = mem;
head->i = head->j = -1;
head->prev = NULL;
head->next = mem+1;
head->T = -FLT_MAX;
empty = mem+1;
for (i=1; i<=num; i++) {
mem[i].prev = mem+i-1;
mem[i].next = mem+i+1;
mem[i].i = mem[i].i = -1;
mem[i].T = FLT_MAX;
}
tail = mem+i;
tail->i = tail->j = -1;
tail->prev = mem+i-1;
tail->next = NULL;
tail->T = FLT_MAX;
return true;
}
bool Add(const CvMat* f) {
int i,j;
for (i=0; i<f->rows; i++) {
for (j=0; j<f->cols; j++) {
if (CV_MAT_ELEM(*f,uchar,i,j)!=0) {
if (!Push(i,j,0)) return false;
}
}
}
return true;
}
bool Push(int i, int j, float T) {
CvHeapElem *tmp=empty,*add=empty;
if (empty==tail) return false;
while (tmp->prev->T>T) tmp = tmp->prev;
if (tmp!=empty) {
add->prev->next = add->next;
add->next->prev = add->prev;
empty = add->next;
add->prev = tmp->prev;
add->next = tmp;
add->prev->next = add;
add->next->prev = add;
} else {
empty = empty->next;
}
add->i = i;
add->j = j;
add->T = T;
in++;
// printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in);
return true;
}
bool Pop(int *i, int *j) {
CvHeapElem *tmp=head->next;
if (empty==tmp) return false;
*i = tmp->i;
*j = tmp->j;
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
tmp->prev = empty->prev;
tmp->next = empty;
tmp->prev->next = tmp;
tmp->next->prev = tmp;
empty = tmp;
in--;
// printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
return true;
}
bool Pop(int *i, int *j, float *T) {
CvHeapElem *tmp=head->next;
if (empty==tmp) return false;
*i = tmp->i;
*j = tmp->j;
*T = tmp->T;
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
tmp->prev = empty->prev;
tmp->next = empty;
tmp->prev->next = tmp;
tmp->next->prev = tmp;
empty = tmp;
in--;
// printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
return true;
}
CvPriorityQueueFloat(void) {
num=in=0;
mem=empty=head=tail=NULL;
}
~CvPriorityQueueFloat(void)
{
cvFree( &mem );
}
};
inline float VectorScalMult(CvPoint2D32f v1,CvPoint2D32f v2) {
return v1.x*v2.x+v1.y*v2.y;
}
inline float VectorLength(CvPoint2D32f v1) {
return v1.x*v1.x+v1.y*v1.y;
}
///////////////////////////////////////////////////////////////////////////////////////////
//HEAP::iterator Heap_Iterator;
//HEAP Heap;
float FastMarching_solve(int i1,int j1,int i2,int j2, const CvMat* f, const CvMat* t)
{
double sol, a11, a22, m12;
a11=CV_MAT_ELEM(*t,float,i1,j1);
a22=CV_MAT_ELEM(*t,float,i2,j2);
m12=MIN(a11,a22);
if( CV_MAT_ELEM(*f,uchar,i1,j1) != INSIDE )
if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE )
if( fabs(a11-a22) >= 1.0 )
sol = 1+m12;
else
sol = (a11+a22+sqrt((double)(2-(a11-a22)*(a11-a22))))*0.5;
else
sol = 1+a11;
else if( CV_MAT_ELEM(*f,uchar,i2,j2) != INSIDE )
sol = 1+a22;
else
sol = 1+m12;
return (float)sol;
}
/////////////////////////////////////////////////////////////////////////////////////
static void
icvCalcFMM(const CvMat *f, CvMat *t, CvPriorityQueueFloat *Heap, bool negate) {
int i, j, ii = 0, jj = 0, q;
float dist;
while (Heap->Pop(&ii,&jj)) {
unsigned known=(negate)?CHANGE:KNOWN;
CV_MAT_ELEM(*f,uchar,ii,jj) = (uchar)known;
for (q=0; q<4; q++) {
i=0; j=0;
if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;}
else {i=ii; j=jj+1;}
if ((i<=0)||(j<=0)||(i>f->rows)||(j>f->cols)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist;
CV_MAT_ELEM(*f,uchar,i,j) = BAND;
Heap->Push(i,j,dist);
}
}
}
if (negate) {
for (i=0; i<f->rows; i++) {
for(j=0; j<f->cols; j++) {
if (CV_MAT_ELEM(*f,uchar,i,j) == CHANGE) {
CV_MAT_ELEM(*f,uchar,i,j) = KNOWN;
CV_MAT_ELEM(*t,float,i,j) = -CV_MAT_ELEM(*t,float,i,j);
}
}
}
}
}
static void
icvTeleaInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap ) {
int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
float dist;
if (CV_MAT_CN(out->type)==3) {
while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;}
if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist;
for (color=0; color<=2; color++) {
CvPoint2D32f gradI,gradT,r;
float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat;
if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f;
} else {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1)));
} else {
gradT.x=0;
}
}
if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f;
} else {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j)));
} else {
gradT.y=0;
}
}
for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
r.y = (float)(i-k);
r.x = (float)(j-l);
dst = (float)(1./(VectorLength(r)*sqrt((double)VectorLength(r))));
lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j))));
dir=VectorScalMult(r,gradT);
if (fabs(dir)<=0.01) dir=0.000001f;
w = (float)fabs(dst*lev*dir);
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f;
} else {
gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.x=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,km,lp,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)));
} else {
gradI.x=0;
}
}
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f;
} else {
gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.y=(float)((CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)));
} else {
gradI.y=0;
}
}
Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color));
Jx -= (float)w * (float)(gradI.x*r.x);
Jy -= (float)w * (float)(gradI.y*r.y);
s += w;
}
}
}
}
sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
{
int isat = cvRound(sat);
CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = CV_CAST_8U(isat);
}
}
CV_MAT_ELEM(*f,uchar,i,j) = BAND;
Heap->Push(i,j,dist);
}
}
}
} else if (CV_MAT_CN(out->type)==1) {
while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;}
if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist;
for (color=0; color<=0; color++) {
CvPoint2D32f gradI,gradT,r;
float Ia=0,Jx=0,Jy=0,s=1.0e-20f,w,dst,lev,dir,sat;
if (CV_MAT_ELEM(*f,uchar,i,j+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j-1)))*0.5f;
} else {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j+1)-CV_MAT_ELEM(*t,float,i,j)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,i,j-1)!=INSIDE) {
gradT.x=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i,j-1)));
} else {
gradT.x=0;
}
}
if (CV_MAT_ELEM(*f,uchar,i+1,j)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i-1,j)))*0.5f;
} else {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i+1,j)-CV_MAT_ELEM(*t,float,i,j)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,i-1,j)!=INSIDE) {
gradT.y=(float)((CV_MAT_ELEM(*t,float,i,j)-CV_MAT_ELEM(*t,float,i-1,j)));
} else {
gradT.y=0;
}
}
for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
r.y = (float)(i-k);
r.x = (float)(j-l);
dst = (float)(1./(VectorLength(r)*sqrt(VectorLength(r))));
lev = (float)(1./(1+fabs(CV_MAT_ELEM(*t,float,k,l)-CV_MAT_ELEM(*t,float,i,j))));
dir=VectorScalMult(r,gradT);
if (fabs(dir)<=0.01) dir=0.000001f;
w = (float)fabs(dst*lev*dir);
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
} else {
gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.x=(float)((CV_MAT_ELEM(*out,uchar,km,lp)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
} else {
gradI.x=0;
}
}
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
} else {
gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,km,lm)));
}
} else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.y=(float)((CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
} else {
gradI.y=0;
}
}
Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
Jx -= (float)w * (float)(gradI.x*r.x);
Jy -= (float)w * (float)(gradI.y*r.y);
s += w;
}
}
}
}
sat = (float)((Ia/s+(Jx+Jy)/(sqrt(Jx*Jx+Jy*Jy)+1.0e-20f)+0.5f));
{
int isat = cvRound(sat);
CV_MAT_ELEM(*out,uchar,i-1,j-1) = CV_CAST_8U(isat);
}
}
CV_MAT_ELEM(*f,uchar,i,j) = BAND;
Heap->Push(i,j,dist);
}
}
}
}
}
static void
icvNSInpaintFMM(const CvMat *f, CvMat *t, CvMat *out, int range, CvPriorityQueueFloat *Heap) {
int i = 0, j = 0, ii = 0, jj = 0, k, l, q, color = 0;
float dist;
if (CV_MAT_CN(out->type)==3) {
while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;}
if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist;
for (color=0; color<=2; color++) {
CvPoint2D32f gradI,r;
float Ia=0,s=1.0e-20f,w,dst,dir;
for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==f->rows-2);
for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==f->cols-2);
if (k>0&&l>0&&k<f->rows-1&&l<f->cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
r.y=(float)(k-i);
r.x=(float)(l-j);
dst = 1/(VectorLength(r)*VectorLength(r)+1);
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color))+
abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)));
} else {
gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp+1,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)))*2.0f;
}
} else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.x=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,kp,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km-1,lm,color)))*2.0f;
} else {
gradI.x=0;
}
}
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color))+
abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)));
} else {
gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lp+1,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)))*2.0f;
}
} else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.y=(float)(abs(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color)-CV_MAT_3COLOR_ELEM(*out,uchar,km,lm-1,color)))*2.0f;
} else {
gradI.y=0;
}
}
gradI.x=-gradI.x;
dir=VectorScalMult(r,gradI);
if (fabs(dir)<=0.01) {
dir=0.000001f;
} else {
dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
}
w = dst*dir;
Ia += (float)w * (float)(CV_MAT_3COLOR_ELEM(*out,uchar,km,lm,color));
s += w;
}
}
}
}
{
int out_val = cvRound((double)Ia/s);
CV_MAT_3COLOR_ELEM(*out,uchar,i-1,j-1,color) = CV_CAST_8U(out_val);
}
}
CV_MAT_ELEM(*f,uchar,i,j) = BAND;
Heap->Push(i,j,dist);
}
}
}
} else if (CV_MAT_CN(out->type)==1) {
while (Heap->Pop(&ii,&jj)) {
CV_MAT_ELEM(*f,uchar,ii,jj) = KNOWN;
for(q=0; q<4; q++) {
if (q==0) {i=ii-1; j=jj;}
else if(q==1) {i=ii; j=jj-1;}
else if(q==2) {i=ii+1; j=jj;}
else if(q==3) {i=ii; j=jj+1;}
if ((i<=1)||(j<=1)||(i>t->rows-1)||(j>t->cols-1)) continue;
if (CV_MAT_ELEM(*f,uchar,i,j)==INSIDE) {
dist = min4(FastMarching_solve(i-1,j,i,j-1,f,t),
FastMarching_solve(i+1,j,i,j-1,f,t),
FastMarching_solve(i-1,j,i,j+1,f,t),
FastMarching_solve(i+1,j,i,j+1,f,t));
CV_MAT_ELEM(*t,float,i,j) = dist;
{
CvPoint2D32f gradI,r;
float Ia=0,s=1.0e-20f,w,dst,dir;
for (k=i-range; k<=i+range; k++) {
int km=k-1+(k==1),kp=k-1-(k==t->rows-2);
for (l=j-range; l<=j+range; l++) {
int lm=l-1+(l==1),lp=l-1-(l==t->cols-2);
if (k>0&&l>0&&k<t->rows-1&&l<t->cols-1) {
if ((CV_MAT_ELEM(*f,uchar,k,l)!=INSIDE)&&
((l-j)*(l-j)+(k-i)*(k-i)<=range*range)) {
r.y=(float)(i-k);
r.x=(float)(j-l);
dst = 1/(VectorLength(r)*VectorLength(r)+1);
if (CV_MAT_ELEM(*f,uchar,k+1,l)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm))+
abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)));
} else {
gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp+1,lm)-CV_MAT_ELEM(*out,uchar,kp,lm)))*2.0f;
}
} else {
if (CV_MAT_ELEM(*f,uchar,k-1,l)!=INSIDE) {
gradI.x=(float)(abs(CV_MAT_ELEM(*out,uchar,kp,lm)-CV_MAT_ELEM(*out,uchar,km-1,lm)))*2.0f;
} else {
gradI.x=0;
}
}
if (CV_MAT_ELEM(*f,uchar,k,l+1)!=INSIDE) {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm))+
abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)));
} else {
gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lp+1)-CV_MAT_ELEM(*out,uchar,km,lm)))*2.0f;
}
} else {
if (CV_MAT_ELEM(*f,uchar,k,l-1)!=INSIDE) {
gradI.y=(float)(abs(CV_MAT_ELEM(*out,uchar,km,lm)-CV_MAT_ELEM(*out,uchar,km,lm-1)))*2.0f;
} else {
gradI.y=0;
}
}
gradI.x=-gradI.x;
dir=VectorScalMult(r,gradI);
if (fabs(dir)<=0.01) {
dir=0.000001f;
} else {
dir = (float)fabs(VectorScalMult(r,gradI)/sqrt(VectorLength(r)*VectorLength(gradI)));
}
w = dst*dir;
Ia += (float)w * (float)(CV_MAT_ELEM(*out,uchar,km,lm));
s += w;
}
}
}
}
{
int out_val = cvRound((double)Ia/s);
CV_MAT_ELEM(*out,uchar,i-1,j-1) = CV_CAST_8U(out_val);
}
}
CV_MAT_ELEM(*f,uchar,i,j) = BAND;
Heap->Push(i,j,dist);
}
}
}
}
}
#define SET_BORDER1_C1(image,type,value) {\
int i,j;\
for(j=0; j<image->cols; j++) {\
CV_MAT_ELEM(*image,type,0,j) = value;\
}\
for (i=1; i<image->rows-1; i++) {\
CV_MAT_ELEM(*image,type,i,0) = CV_MAT_ELEM(*image,type,i,image->cols-1) = value;\
}\
for(j=0; j<image->cols; j++) {\
CV_MAT_ELEM(*image,type,erows-1,j) = value;\
}\
}
#define COPY_MASK_BORDER1_C1(src,dst,type) {\
int i,j;\
for (i=0; i<src->rows; i++) {\
for(j=0; j<src->cols; j++) {\
if (CV_MAT_ELEM(*src,type,i,j)!=0)\
CV_MAT_ELEM(*dst,type,i+1,j+1) = INSIDE;\
}\
}\
}
CV_IMPL void
cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_img,
double inpaintRange, int flags )
{
cv::Ptr<CvMat> mask, band, f, t, out;
cv::Ptr<CvPriorityQueueFloat> Heap, Out;
cv::Ptr<IplConvKernel> el_cross, el_range;
CvMat input_hdr, mask_hdr, output_hdr;
CvMat* input_img, *inpaint_mask, *output_img;
int range=cvRound(inpaintRange);
int erows, ecols;
input_img = cvGetMat( _input_img, &input_hdr );
inpaint_mask = cvGetMat( _inpaint_mask, &mask_hdr );
output_img = cvGetMat( _output_img, &output_hdr );
if( !CV_ARE_SIZES_EQ(input_img,output_img) || !CV_ARE_SIZES_EQ(input_img,inpaint_mask))
CV_Error( CV_StsUnmatchedSizes, "All the input and output images must have the same size" );
if( (CV_MAT_TYPE(input_img->type) != CV_8UC1 &&
CV_MAT_TYPE(input_img->type) != CV_8UC3) ||
!CV_ARE_TYPES_EQ(input_img,output_img) )
CV_Error( CV_StsUnsupportedFormat,
"Only 8-bit 1-channel and 3-channel input/output images are supported" );
if( CV_MAT_TYPE(inpaint_mask->type) != CV_8UC1 )
CV_Error( CV_StsUnsupportedFormat, "The mask must be 8-bit 1-channel image" );
range = MAX(range,1);
range = MIN(range,100);
ecols = input_img->cols + 2;
erows = input_img->rows + 2;
f = cvCreateMat(erows, ecols, CV_8UC1);
t = cvCreateMat(erows, ecols, CV_32FC1);
band = cvCreateMat(erows, ecols, CV_8UC1);
mask = cvCreateMat(erows, ecols, CV_8UC1);
el_cross = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_CROSS,NULL);
cvCopy( input_img, output_img );
cvSet(mask,cvScalar(KNOWN,0,0,0));
COPY_MASK_BORDER1_C1(inpaint_mask,mask,uchar);
SET_BORDER1_C1(mask,uchar,0);
cvSet(f,cvScalar(KNOWN,0,0,0));
cvSet(t,cvScalar(1.0e6f,0,0,0));
cvDilate(mask,band,el_cross,1); // image with narrow band
Heap=new CvPriorityQueueFloat;
if (!Heap->Init(band))
return;
cvSub(band,mask,band,NULL);
SET_BORDER1_C1(band,uchar,0);
if (!Heap->Add(band))
return;
cvSet(f,cvScalar(BAND,0,0,0),band);
cvSet(f,cvScalar(INSIDE,0,0,0),mask);
cvSet(t,cvScalar(0,0,0,0),band);
if( flags == CV_INPAINT_TELEA )
{
out = cvCreateMat(erows, ecols, CV_8UC1);
el_range = cvCreateStructuringElementEx(2*range+1,2*range+1,
range,range,CV_SHAPE_RECT,NULL);
cvDilate(mask,out,el_range,1);
cvSub(out,mask,out,NULL);
Out=new CvPriorityQueueFloat;
if (!Out->Init(out))
return;
if (!Out->Add(band))
return;
cvSub(out,band,out,NULL);
SET_BORDER1_C1(out,uchar,0);
icvCalcFMM(out,t,Out,true);
icvTeleaInpaintFMM(mask,t,output_img,range,Heap);
}
else if (flags == CV_INPAINT_NS) {
icvNSInpaintFMM(mask,t,output_img,range,Heap);
} else {
CV_Error( CV_StsBadArg, "The flags argument must be one of CV_INPAINT_TELEA or CV_INPAINT_NS" );
}
}
void cv::inpaint( const Mat& src, const Mat& mask, Mat& dst,
double inpaintRange, int flags )
{
dst.create( src.size(), src.type() );
CvMat _src = src, _mask = mask, _dst = dst;
cvInpaint( &_src, &_mask, &_dst, inpaintRange, flags );
}

View File

@@ -0,0 +1,241 @@
/*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

View File

@@ -0,0 +1,721 @@
/*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"
static const double eps = 1e-6;
static CvStatus
icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *line )
{
double x = 0, y = 0, x2 = 0, y2 = 0, xy = 0, w = 0;
double dx2, dy2, dxy;
int i;
int count = _count;
float t;
/* Calculating the average of x and y... */
if( weights == 0 )
{
for( i = 0; i < count; i += 1 )
{
x += points[i].x;
y += points[i].y;
x2 += points[i].x * points[i].x;
y2 += points[i].y * points[i].y;
xy += points[i].x * points[i].y;
}
w = (float) count;
}
else
{
for( i = 0; i < count; i += 1 )
{
x += weights[i] * points[i].x;
y += weights[i] * points[i].y;
x2 += weights[i] * points[i].x * points[i].x;
y2 += weights[i] * points[i].y * points[i].y;
xy += weights[i] * points[i].x * points[i].y;
w += weights[i];
}
}
x /= w;
y /= w;
x2 /= w;
y2 /= w;
xy /= w;
dx2 = x2 - x * x;
dy2 = y2 - y * y;
dxy = xy - x * y;
t = (float) atan2( 2 * dxy, dx2 - dy2 ) / 2;
line[0] = (float) cos( t );
line[1] = (float) sin( t );
line[2] = (float) x;
line[3] = (float) y;
return CV_NO_ERR;
}
static CvStatus
icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line )
{
int i;
float w0 = 0;
float x0 = 0, y0 = 0, z0 = 0;
float x2 = 0, y2 = 0, z2 = 0, xy = 0, yz = 0, xz = 0;
float dx2, dy2, dz2, dxy, dxz, dyz;
float *v;
float n;
float det[9], evc[9], evl[3];
memset( evl, 0, 3*sizeof(evl[0]));
memset( evc, 0, 9*sizeof(evl[0]));
if( weights )
{
for( i = 0; i < count; i++ )
{
float x = points[i].x;
float y = points[i].y;
float z = points[i].z;
float w = weights[i];
x2 += x * x * w;
xy += x * y * w;
xz += x * z * w;
y2 += y * y * w;
yz += y * z * w;
z2 += z * z * w;
x0 += x * w;
y0 += y * w;
z0 += z * w;
w0 += w;
}
}
else
{
for( i = 0; i < count; i++ )
{
float x = points[i].x;
float y = points[i].y;
float z = points[i].z;
x2 += x * x;
xy += x * y;
xz += x * z;
y2 += y * y;
yz += y * z;
z2 += z * z;
x0 += x;
y0 += y;
z0 += z;
}
w0 = (float) count;
}
x2 /= w0;
xy /= w0;
xz /= w0;
y2 /= w0;
yz /= w0;
z2 /= w0;
x0 /= w0;
y0 /= w0;
z0 /= w0;
dx2 = x2 - x0 * x0;
dxy = xy - x0 * y0;
dxz = xz - x0 * z0;
dy2 = y2 - y0 * y0;
dyz = yz - y0 * z0;
dz2 = z2 - z0 * z0;
det[0] = dz2 + dy2;
det[1] = -dxy;
det[2] = -dxz;
det[3] = det[1];
det[4] = dx2 + dz2;
det[5] = -dyz;
det[6] = det[2];
det[7] = det[5];
det[8] = dy2 + dx2;
/* Searching for a eigenvector of det corresponding to the minimal eigenvalue */
#if 1
{
CvMat _det = cvMat( 3, 3, CV_32F, det );
CvMat _evc = cvMat( 3, 3, CV_32F, evc );
CvMat _evl = cvMat( 3, 1, CV_32F, evl );
cvEigenVV( &_det, &_evc, &_evl, 0 );
i = evl[0] < evl[1] ? (evl[0] < evl[2] ? 0 : 2) : (evl[1] < evl[2] ? 1 : 2);
}
#else
{
CvMat _det = cvMat( 3, 3, CV_32F, det );
CvMat _evc = cvMat( 3, 3, CV_32F, evc );
CvMat _evl = cvMat( 1, 3, CV_32F, evl );
cvSVD( &_det, &_evl, &_evc, 0, CV_SVD_MODIFY_A+CV_SVD_U_T );
}
i = 2;
#endif
v = &evc[i * 3];
n = (float) sqrt( (double)v[0] * v[0] + (double)v[1] * v[1] + (double)v[2] * v[2] );
n = (float)MAX(n, eps);
line[0] = v[0] / n;
line[1] = v[1] / n;
line[2] = v[2] / n;
line[3] = x0;
line[4] = y0;
line[5] = z0;
return CV_NO_ERR;
}
static double
icvCalcDist2D( CvPoint2D32f * points, int count, float *_line, float *dist )
{
int j;
float px = _line[2], py = _line[3];
float nx = _line[1], ny = -_line[0];
double sum_dist = 0.;
for( j = 0; j < count; j++ )
{
float x, y;
x = points[j].x - px;
y = points[j].y - py;
dist[j] = (float) fabs( nx * x + ny * y );
sum_dist += dist[j];
}
return sum_dist;
}
static double
icvCalcDist3D( CvPoint3D32f * points, int count, float *_line, float *dist )
{
int j;
float px = _line[3], py = _line[4], pz = _line[5];
float vx = _line[0], vy = _line[1], vz = _line[2];
double sum_dist = 0.;
for( j = 0; j < count; j++ )
{
float x, y, z;
double p1, p2, p3;
x = points[j].x - px;
y = points[j].y - py;
z = points[j].z - pz;
p1 = vy * z - vz * y;
p2 = vz * x - vx * z;
p3 = vx * y - vy * x;
dist[j] = (float) sqrt( p1*p1 + p2*p2 + p3*p3 );
sum_dist += dist[j];
}
return sum_dist;
}
static void
icvWeightL1( float *d, int count, float *w )
{
int i;
for( i = 0; i < count; i++ )
{
double t = fabs( (double) d[i] );
w[i] = (float)(1. / MAX(t, eps));
}
}
static void
icvWeightL12( float *d, int count, float *w )
{
int i;
for( i = 0; i < count; i++ )
{
w[i] = 1.0f / (float) sqrt( 1 + (double) (d[i] * d[i] * 0.5) );
}
}
static void
icvWeightHuber( float *d, int count, float *w, float _c )
{
int i;
const float c = _c <= 0 ? 1.345f : _c;
for( i = 0; i < count; i++ )
{
if( d[i] < c )
w[i] = 1.0f;
else
w[i] = c/d[i];
}
}
static void
icvWeightFair( float *d, int count, float *w, float _c )
{
int i;
const float c = _c == 0 ? 1 / 1.3998f : 1 / _c;
for( i = 0; i < count; i++ )
{
w[i] = 1 / (1 + d[i] * c);
}
}
static void
icvWeightWelsch( float *d, int count, float *w, float _c )
{
int i;
const float c = _c == 0 ? 1 / 2.9846f : 1 / _c;
for( i = 0; i < count; i++ )
{
w[i] = (float) exp( -d[i] * d[i] * c * c );
}
}
/* Takes an array of 2D points, type of distance (including user-defined
distance specified by callbacks, fills the array of four floats with line
parameters A, B, C, D, where (A, B) is the normalized direction vector,
(C, D) is the point that belongs to the line. */
static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
float _param, float reps, float aeps, float *line )
{
double EPS = count*FLT_EPSILON;
void (*calc_weights) (float *, int, float *) = 0;
void (*calc_weights_param) (float *, int, float *, float) = 0;
float *w; /* weights */
float *r; /* square distances */
int i, j, k;
float _line[6], _lineprev[6];
float rdelta = reps != 0 ? reps : 1.0f;
float adelta = aeps != 0 ? aeps : 0.01f;
double min_err = DBL_MAX, err = 0;
CvRNG rng = cvRNG(-1);
memset( line, 0, 4*sizeof(line[0]) );
switch (dist)
{
case CV_DIST_L2:
return icvFitLine2D_wods( points, count, 0, line );
case CV_DIST_L1:
calc_weights = icvWeightL1;
break;
case CV_DIST_L12:
calc_weights = icvWeightL12;
break;
case CV_DIST_FAIR:
calc_weights_param = icvWeightFair;
break;
case CV_DIST_WELSCH:
calc_weights_param = icvWeightWelsch;
break;
case CV_DIST_HUBER:
calc_weights_param = icvWeightHuber;
break;
/*case CV_DIST_USER:
calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
break;*/
default:
return CV_BADFACTOR_ERR;
}
w = (float *) cvAlloc( count * sizeof( float ));
r = (float *) cvAlloc( count * sizeof( float ));
for( k = 0; k < 20; k++ )
{
int first = 1;
for( i = 0; i < count; i++ )
w[i] = 0.f;
for( i = 0; i < MIN(count,10); )
{
j = cvRandInt(&rng) % count;
if( w[j] < FLT_EPSILON )
{
w[j] = 1.f;
i++;
}
}
icvFitLine2D_wods( points, count, w, _line );
for( i = 0; i < 30; i++ )
{
double sum_w = 0;
if( first )
{
first = 0;
}
else
{
double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1];
t = MAX(t,-1.);
t = MIN(t,1.);
if( fabs(acos(t)) < adelta )
{
float x, y, d;
x = (float) fabs( _line[2] - _lineprev[2] );
y = (float) fabs( _line[3] - _lineprev[3] );
d = x > y ? x : y;
if( d < rdelta )
break;
}
}
/* calculate distances */
err = icvCalcDist2D( points, count, _line, r );
if( err < EPS )
break;
/* calculate weights */
if( calc_weights )
calc_weights( r, count, w );
else
calc_weights_param( r, count, w, _param );
for( j = 0; j < count; j++ )
sum_w += w[j];
if( fabs(sum_w) > FLT_EPSILON )
{
sum_w = 1./sum_w;
for( j = 0; j < count; j++ )
w[j] = (float)(w[j]*sum_w);
}
else
{
for( j = 0; j < count; j++ )
w[j] = 1.f;
}
/* save the line parameters */
memcpy( _lineprev, _line, 4 * sizeof( float ));
/* Run again... */
icvFitLine2D_wods( points, count, w, _line );
}
if( err < min_err )
{
min_err = err;
memcpy( line, _line, 4 * sizeof(line[0]));
if( err < EPS )
break;
}
}
cvFree( &w );
cvFree( &r );
return CV_OK;
}
/* Takes an array of 3D points, type of distance (including user-defined
distance specified by callbacks, fills the array of four floats with line
parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector,
(D, E, F) is the point that belongs to the line. */
static CvStatus
icvFitLine3D( CvPoint3D32f * points, int count, int dist,
float _param, float reps, float aeps, float *line )
{
double EPS = count*FLT_EPSILON;
void (*calc_weights) (float *, int, float *) = 0;
void (*calc_weights_param) (float *, int, float *, float) = 0;
float *w; /* weights */
float *r; /* square distances */
int i, j, k;
float _line[6], _lineprev[6];
float rdelta = reps != 0 ? reps : 1.0f;
float adelta = aeps != 0 ? aeps : 0.01f;
double min_err = DBL_MAX, err = 0;
CvRNG rng = cvRNG(-1);
memset( line, 0, 6*sizeof(line[0]) );
switch (dist)
{
case CV_DIST_L2:
return icvFitLine3D_wods( points, count, 0, line );
case CV_DIST_L1:
calc_weights = icvWeightL1;
break;
case CV_DIST_L12:
calc_weights = icvWeightL12;
break;
case CV_DIST_FAIR:
calc_weights_param = icvWeightFair;
break;
case CV_DIST_WELSCH:
calc_weights_param = icvWeightWelsch;
break;
case CV_DIST_HUBER:
calc_weights_param = icvWeightHuber;
break;
/*case CV_DIST_USER:
_PFP.p = param;
calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
break;*/
default:
return CV_BADFACTOR_ERR;
}
w = (float *) cvAlloc( count * sizeof( float ));
r = (float *) cvAlloc( count * sizeof( float ));
for( k = 0; k < 20; k++ )
{
int first = 1;
for( i = 0; i < count; i++ )
w[i] = 0.f;
for( i = 0; i < MIN(count,10); )
{
j = cvRandInt(&rng) % count;
if( w[j] < FLT_EPSILON )
{
w[j] = 1.f;
i++;
}
}
icvFitLine3D_wods( points, count, w, _line );
for( i = 0; i < 30; i++ )
{
double sum_w = 0;
if( first )
{
first = 0;
}
else
{
double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1] + _line[2] * _lineprev[2];
t = MAX(t,-1.);
t = MIN(t,1.);
if( fabs(acos(t)) < adelta )
{
float x, y, z, ax, ay, az, dx, dy, dz, d;
x = _line[3] - _lineprev[3];
y = _line[4] - _lineprev[4];
z = _line[5] - _lineprev[5];
ax = _line[0] - _lineprev[0];
ay = _line[1] - _lineprev[1];
az = _line[2] - _lineprev[2];
dx = (float) fabs( y * az - z * ay );
dy = (float) fabs( z * ax - x * az );
dz = (float) fabs( x * ay - y * ax );
d = dx > dy ? (dx > dz ? dx : dz) : (dy > dz ? dy : dz);
if( d < rdelta )
break;
}
}
/* calculate distances */
if( icvCalcDist3D( points, count, _line, r ) < FLT_EPSILON*count )
break;
/* calculate weights */
if( calc_weights )
calc_weights( r, count, w );
else
calc_weights_param( r, count, w, _param );
for( j = 0; j < count; j++ )
sum_w += w[j];
if( fabs(sum_w) > FLT_EPSILON )
{
sum_w = 1./sum_w;
for( j = 0; j < count; j++ )
w[j] = (float)(w[j]*sum_w);
}
else
{
for( j = 0; j < count; j++ )
w[j] = 1.f;
}
/* save the line parameters */
memcpy( _lineprev, _line, 6 * sizeof( float ));
/* Run again... */
icvFitLine3D_wods( points, count, w, _line );
}
if( err < min_err )
{
min_err = err;
memcpy( line, _line, 6 * sizeof(line[0]));
if( err < EPS )
break;
}
}
// Return...
cvFree( &w );
cvFree( &r );
return CV_OK;
}
CV_IMPL void
cvFitLine( const CvArr* array, int dist, double param,
double reps, double aeps, float *line )
{
cv::AutoBuffer<schar> buffer;
schar* points = 0;
union { CvContour contour; CvSeq seq; } header;
CvSeqBlock block;
CvSeq* ptseq = (CvSeq*)array;
int type;
if( !line )
CV_Error( CV_StsNullPtr, "NULL pointer to line parameters" );
if( CV_IS_SEQ(ptseq) )
{
type = CV_SEQ_ELTYPE(ptseq);
if( ptseq->total == 0 )
CV_Error( CV_StsBadSize, "The sequence has no points" );
if( (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
CV_ELEM_SIZE(type) != ptseq->elem_size )
CV_Error( CV_StsUnsupportedFormat,
"Input sequence must consist of 2d points or 3d points" );
}
else
{
CvMat* mat = (CvMat*)array;
type = CV_MAT_TYPE(mat->type);
if( !CV_IS_MAT(mat))
CV_Error( CV_StsBadArg, "Input array is not a sequence nor matrix" );
if( !CV_IS_MAT_CONT(mat->type) ||
(type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
(mat->width != 1 && mat->height != 1))
CV_Error( CV_StsBadArg,
"Input array must be 1d continuous array of 2d or 3d points" );
ptseq = cvMakeSeqHeaderForArray(
CV_SEQ_KIND_GENERIC|type, sizeof(CvContour), CV_ELEM_SIZE(type), mat->data.ptr,
mat->width + mat->height - 1, &header.seq, &block );
}
if( reps < 0 || aeps < 0 )
CV_Error( CV_StsOutOfRange, "Both reps and aeps must be non-negative" );
if( CV_MAT_DEPTH(type) == CV_32F && ptseq->first->next == ptseq->first )
{
/* no need to copy data in this case */
points = ptseq->first->data;
}
else
{
buffer.allocate(ptseq->total*CV_ELEM_SIZE(type));
points = buffer;
cvCvtSeqToArray( ptseq, points, CV_WHOLE_SEQ );
if( CV_MAT_DEPTH(type) != CV_32F )
{
int i, total = ptseq->total*CV_MAT_CN(type);
assert( CV_MAT_DEPTH(type) == CV_32S );
for( i = 0; i < total; i++ )
((float*)points)[i] = (float)((int*)points)[i];
}
}
if( dist == CV_DIST_USER )
CV_Error( CV_StsBadArg, "User-defined distance is not allowed" );
if( CV_MAT_CN(type) == 2 )
{
IPPI_CALL( icvFitLine2D( (CvPoint2D32f*)points, ptseq->total,
dist, (float)param, (float)reps, (float)aeps, line ));
}
else
{
IPPI_CALL( icvFitLine3D( (CvPoint3D32f*)points, ptseq->total,
dist, (float)param, (float)reps, (float)aeps, line ));
}
}
/* End of file. */

454
modules/imgproc/src/lsh.cpp Normal file
View File

@@ -0,0 +1,454 @@
/*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 = 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 = 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 = 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) {
int* tmp = (int*)cvStackAlloc(sizeof(int) * emax);
typedef std::pair<int, accum_type> dr_type; // * swap int and accum_type here, for naming consistency
dr_type* dr = (dr_type*)cvStackAlloc(sizeof(dr_type) * 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, dr + k1, comp_dist);
} else if (pd < dr[0].second) {
std::pop_heap(dr, dr + k0, comp_dist);
dr[k0 - 1] = std::make_pair(i, pd);
std::push_heap(dr, 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;
}
}

View File

@@ -0,0 +1,198 @@
/*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"
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvMatchContours
// Purpose:
// Calculates matching of the two contours
// Context:
// Parameters:
// contour_1 - pointer to the first input contour object.
// contour_2 - pointer to the second input contour object.
// method - method for the matching calculation
// (now CV_IPPI_CONTOURS_MATCH_I1, CV_CONTOURS_MATCH_I2 or
// CV_CONTOURS_MATCH_I3 only )
// rezult - output calculated measure
//
//F*/
CV_IMPL double
cvMatchShapes( const void* contour1, const void* contour2,
int method, double /*parameter*/ )
{
CvMoments moments;
CvHuMoments huMoments;
double ma[7], mb[7];
int i, sma, smb;
double eps = 1.e-5;
double mmm;
double result = 0;
if( !contour1 || !contour2 )
CV_Error( CV_StsNullPtr, "" );
// calculate moments of the first shape
cvMoments( contour1, &moments );
cvGetHuMoments( &moments, &huMoments );
ma[0] = huMoments.hu1;
ma[1] = huMoments.hu2;
ma[2] = huMoments.hu3;
ma[3] = huMoments.hu4;
ma[4] = huMoments.hu5;
ma[5] = huMoments.hu6;
ma[6] = huMoments.hu7;
// calculate moments of the second shape
cvMoments( contour2, &moments );
cvGetHuMoments( &moments, &huMoments );
mb[0] = huMoments.hu1;
mb[1] = huMoments.hu2;
mb[2] = huMoments.hu3;
mb[3] = huMoments.hu4;
mb[4] = huMoments.hu5;
mb[5] = huMoments.hu6;
mb[6] = huMoments.hu7;
switch (method)
{
case 1:
{
for( i = 0; i < 7; i++ )
{
double ama = fabs( ma[i] );
double amb = fabs( mb[i] );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{
ama = 1. / (sma * log10( ama ));
amb = 1. / (smb * log10( amb ));
result += fabs( -ama + amb );
}
}
break;
}
case 2:
{
for( i = 0; i < 7; i++ )
{
double ama = fabs( ma[i] );
double amb = fabs( mb[i] );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{
ama = sma * log10( ama );
amb = smb * log10( amb );
result += fabs( -ama + amb );
}
}
break;
}
case 3:
{
for( i = 0; i < 7; i++ )
{
double ama = fabs( ma[i] );
double amb = fabs( mb[i] );
if( ma[i] > 0 )
sma = 1;
else if( ma[i] < 0 )
sma = -1;
else
sma = 0;
if( mb[i] > 0 )
smb = 1;
else if( mb[i] < 0 )
smb = -1;
else
smb = 0;
if( ama > eps && amb > eps )
{
ama = sma * log10( ama );
amb = smb * log10( amb );
mmm = fabs( (ama - amb) / ama );
if( result < mmm )
result = mmm;
}
}
break;
}
default:
CV_Error( CV_StsBadArg, "Unknown comparison method" );
}
return result;
}
/* End of file. */

View File

@@ -0,0 +1,642 @@
/*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"
// The function calculates center of gravity and the central second order moments
static void icvCompleteMomentState( CvMoments* moments )
{
double cx = 0, cy = 0;
double mu20, mu11, mu02;
assert( moments != 0 );
moments->inv_sqrt_m00 = 0;
if( fabs(moments->m00) > DBL_EPSILON )
{
double inv_m00 = 1. / moments->m00;
cx = moments->m10 * inv_m00;
cy = moments->m01 * inv_m00;
moments->inv_sqrt_m00 = std::sqrt( fabs(inv_m00) );
}
// mu20 = m20 - m10*cx
mu20 = moments->m20 - moments->m10 * cx;
// mu11 = m11 - m10*cy
mu11 = moments->m11 - moments->m10 * cy;
// mu02 = m02 - m01*cy
mu02 = moments->m02 - moments->m01 * cy;
moments->mu20 = mu20;
moments->mu11 = mu11;
moments->mu02 = mu02;
// mu30 = m30 - cx*(3*mu20 + cx*m10)
moments->mu30 = moments->m30 - cx * (3 * mu20 + cx * moments->m10);
mu11 += mu11;
// mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20
moments->mu21 = moments->m21 - cx * (mu11 + cx * moments->m01) - cy * mu20;
// mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02
moments->mu12 = moments->m12 - cy * (mu11 + cy * moments->m10) - cx * mu02;
// mu03 = m03 - cy*(3*mu02 + cy*m01)
moments->mu03 = moments->m03 - cy * (3 * mu02 + cy * moments->m01);
}
static void icvContourMoments( CvSeq* contour, CvMoments* moments )
{
int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
if( contour->total )
{
CvSeqReader reader;
double a00, a10, a01, a20, a11, a02, a30, a21, a12, a03;
double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1;
int lpt = contour->total;
a00 = a10 = a01 = a20 = a11 = a02 = a30 = a21 = a12 = a03 = 0;
cvStartReadSeq( contour, &reader, 0 );
if( !is_float )
{
xi_1 = ((CvPoint*)(reader.ptr))->x;
yi_1 = ((CvPoint*)(reader.ptr))->y;
}
else
{
xi_1 = ((CvPoint2D32f*)(reader.ptr))->x;
yi_1 = ((CvPoint2D32f*)(reader.ptr))->y;
}
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
xi_12 = xi_1 * xi_1;
yi_12 = yi_1 * yi_1;
while( lpt-- > 0 )
{
if( !is_float )
{
xi = ((CvPoint*)(reader.ptr))->x;
yi = ((CvPoint*)(reader.ptr))->y;
}
else
{
xi = ((CvPoint2D32f*)(reader.ptr))->x;
yi = ((CvPoint2D32f*)(reader.ptr))->y;
}
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
xi2 = xi * xi;
yi2 = yi * yi;
dxy = xi_1 * yi - xi * yi_1;
xii_1 = xi_1 + xi;
yii_1 = yi_1 + yi;
a00 += dxy;
a10 += dxy * xii_1;
a01 += dxy * yii_1;
a20 += dxy * (xi_1 * xii_1 + xi2);
a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi));
a02 += dxy * (yi_1 * yii_1 + yi2);
a30 += dxy * xii_1 * (xi_12 + xi2);
a03 += dxy * yii_1 * (yi_12 + yi2);
a21 +=
dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 +
xi2 * (yi_1 + 3 * yi));
a12 +=
dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 +
yi2 * (xi_1 + 3 * xi));
xi_1 = xi;
yi_1 = yi;
xi_12 = xi2;
yi_12 = yi2;
}
double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60;
if( fabs(a00) > FLT_EPSILON )
{
if( a00 > 0 )
{
db1_2 = 0.5;
db1_6 = 0.16666666666666666666666666666667;
db1_12 = 0.083333333333333333333333333333333;
db1_24 = 0.041666666666666666666666666666667;
db1_20 = 0.05;
db1_60 = 0.016666666666666666666666666666667;
}
else
{
db1_2 = -0.5;
db1_6 = -0.16666666666666666666666666666667;
db1_12 = -0.083333333333333333333333333333333;
db1_24 = -0.041666666666666666666666666666667;
db1_20 = -0.05;
db1_60 = -0.016666666666666666666666666666667;
}
// spatial moments
moments->m00 = a00 * db1_2;
moments->m10 = a10 * db1_6;
moments->m01 = a01 * db1_6;
moments->m20 = a20 * db1_12;
moments->m11 = a11 * db1_24;
moments->m02 = a02 * db1_12;
moments->m30 = a30 * db1_20;
moments->m21 = a21 * db1_60;
moments->m12 = a12 * db1_60;
moments->m03 = a03 * db1_20;
icvCompleteMomentState( moments );
}
}
}
/****************************************************************************************\
* Spatial Raster Moments *
\****************************************************************************************/
template<typename T, typename WT, typename MT>
static void momentsInTile( const cv::Mat& img, double* moments )
{
cv::Size size = img.size();
int x, y;
MT mom[10] = {0,0,0,0,0,0,0,0,0,0};
for( y = 0; y < size.height; y++ )
{
const T* ptr = img.ptr<T>(y);
WT x0 = 0, x1 = 0, x2 = 0;
MT x3 = 0;
for( x = 0; x < size.width; x++ )
{
WT p = ptr[x];
WT xp = x * p, xxp;
x0 += p;
x1 += xp;
xxp = xp * x;
x2 += xxp;
x3 += xxp * x;
}
WT py = y * x0, sy = y*y;
mom[9] += ((MT)py) * sy; // m03
mom[8] += ((MT)x1) * sy; // m12
mom[7] += ((MT)x2) * y; // m21
mom[6] += x3; // m30
mom[5] += x0 * sy; // m02
mom[4] += x1 * y; // m11
mom[3] += x2; // m20
mom[2] += py; // m01
mom[1] += x1; // m10
mom[0] += x0; // m00
}
for( x = 0; x < 10; x++ )
moments[x] = (double)mom[x];
}
#if CV_SSE2
template<> void momentsInTile<uchar, int, int>( const cv::Mat& img, double* moments )
{
typedef uchar T;
typedef int WT;
typedef int MT;
cv::Size size = img.size();
int x, y;
MT mom[10] = {0,0,0,0,0,0,0,0,0,0};
bool useSIMD = cv::checkHardwareSupport(CV_CPU_SSE2);
for( y = 0; y < size.height; y++ )
{
const T* ptr = img.ptr<T>(y);
int x0 = 0, x1 = 0, x2 = 0, x3 = 0, x = 0;
if( useSIMD )
{
__m128i qx_init = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
__m128i dx = _mm_set1_epi16(8);
__m128i z = _mm_setzero_si128(), qx0 = z, qx1 = z, qx2 = z, qx3 = z, qx = qx_init;
for( ; x <= size.width - 8; x += 8 )
{
__m128i p = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(ptr + x)), z);
qx0 = _mm_add_epi32(qx0, _mm_sad_epu8(p, z));
__m128i px = _mm_mullo_epi16(p, qx);
__m128i sx = _mm_mullo_epi16(qx, qx);
qx1 = _mm_add_epi32(qx1, _mm_madd_epi16(p, qx));
qx2 = _mm_add_epi32(qx2, _mm_madd_epi16(p, sx));
qx3 = _mm_add_epi32(qx3, _mm_madd_epi16(px, sx));
qx = _mm_add_epi16(qx, dx);
}
int CV_DECL_ALIGNED(16) buf[4];
_mm_store_si128((__m128i*)buf, qx0);
x0 = buf[0] + buf[1] + buf[2] + buf[3];
_mm_store_si128((__m128i*)buf, qx1);
x1 = buf[0] + buf[1] + buf[2] + buf[3];
_mm_store_si128((__m128i*)buf, qx2);
x2 = buf[0] + buf[1] + buf[2] + buf[3];
_mm_store_si128((__m128i*)buf, qx3);
x3 = buf[0] + buf[1] + buf[2] + buf[3];
}
for( ; x < size.width; x++ )
{
WT p = ptr[x];
WT xp = x * p, xxp;
x0 += p;
x1 += xp;
xxp = xp * x;
x2 += xxp;
x3 += xxp * x;
}
WT py = y * x0, sy = y*y;
mom[9] += ((MT)py) * sy; // m03
mom[8] += ((MT)x1) * sy; // m12
mom[7] += ((MT)x2) * y; // m21
mom[6] += x3; // m30
mom[5] += x0 * sy; // m02
mom[4] += x1 * y; // m11
mom[3] += x2; // m20
mom[2] += py; // m01
mom[1] += x1; // m10
mom[0] += x0; // m00
}
for( x = 0; x < 10; x++ )
moments[x] = (double)mom[x];
}
#endif
typedef void (*CvMomentsInTileFunc)(const cv::Mat& img, double* moments);
CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary )
{
const int TILE_SIZE = 32;
int type, depth, cn, coi = 0;
CvMat stub, *mat = (CvMat*)array;
CvMomentsInTileFunc func = 0;
CvContour contourHeader;
CvSeq* contour = 0;
CvSeqBlock block;
double buf[TILE_SIZE*TILE_SIZE];
uchar nzbuf[TILE_SIZE*TILE_SIZE];
if( CV_IS_SEQ( array ))
{
contour = (CvSeq*)array;
if( !CV_IS_SEQ_POINT_SET( contour ))
CV_Error( CV_StsBadArg, "The passed sequence is not a valid contour" );
}
if( !moments )
CV_Error( CV_StsNullPtr, "" );
memset( moments, 0, sizeof(*moments));
if( !contour )
{
mat = cvGetMat( mat, &stub, &coi );
type = CV_MAT_TYPE( mat->type );
if( type == CV_32SC2 || type == CV_32FC2 )
{
contour = cvPointSeqFromMat(
CV_SEQ_KIND_CURVE | CV_SEQ_FLAG_CLOSED,
mat, &contourHeader, &block );
}
}
if( contour )
{
icvContourMoments( contour, moments );
return;
}
type = CV_MAT_TYPE( mat->type );
depth = CV_MAT_DEPTH( type );
cn = CV_MAT_CN( type );
cv::Size size = cvGetMatSize( mat );
if( cn > 1 && coi == 0 )
CV_Error( CV_StsBadArg, "Invalid image type" );
if( size.width <= 0 || size.height <= 0 )
return;
if( binary || depth == CV_8U )
func = momentsInTile<uchar, int, int>;
else if( depth == CV_16U )
func = momentsInTile<ushort, int, int64>;
else if( depth == CV_16S )
func = momentsInTile<short, int, int64>;
else if( depth == CV_32F )
func = momentsInTile<float, double, double>;
else if( depth == CV_64F )
func = momentsInTile<double, double, double>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
cv::Mat src0(mat);
for( int y = 0; y < size.height; y += TILE_SIZE )
{
cv::Size tileSize;
tileSize.height = std::min(TILE_SIZE, size.height - y);
for( int x = 0; x < size.width; x += TILE_SIZE )
{
tileSize.width = std::min(TILE_SIZE, size.width - x);
cv::Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height));
if( coi > 0 )
{
cv::Mat tmp(tileSize, depth, buf);
int pairs[] = {coi-1, 0};
cv::mixChannels(&src, 1, &tmp, 1, pairs, 1);
src = tmp;
}
if( binary )
{
cv::Mat tmp(tileSize, CV_8U, nzbuf);
cv::compare( src, 0, tmp, CV_CMP_NE );
src = tmp;
}
double mom[10];
func( src, mom );
if(binary)
{
double s = 1./255;
for( int k = 0; k < 10; k++ )
mom[k] *= s;
}
double xm = x * mom[0], ym = y * mom[0];
// accumulate moments computed in each tile
// + m00 ( = m00' )
moments->m00 += mom[0];
// + m10 ( = m10' + x*m00' )
moments->m10 += mom[1] + xm;
// + m01 ( = m01' + y*m00' )
moments->m01 += mom[2] + ym;
// + m20 ( = m20' + 2*x*m10' + x*x*m00' )
moments->m20 += mom[3] + x * (mom[1] * 2 + xm);
// + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' )
moments->m11 += mom[4] + x * (mom[2] + ym) + y * mom[1];
// + m02 ( = m02' + 2*y*m01' + y*y*m00' )
moments->m02 += mom[5] + y * (mom[2] * 2 + ym);
// + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' )
moments->m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm));
// + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20')
moments->m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3];
// + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02')
moments->m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5];
// + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' )
moments->m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym));
}
}
icvCompleteMomentState( moments );
}
CV_IMPL void cvGetHuMoments( CvMoments * mState, CvHuMoments * HuState )
{
if( !mState || !HuState )
CV_Error( CV_StsNullPtr, "" );
double m00s = mState->inv_sqrt_m00, m00 = m00s * m00s, s2 = m00 * m00, s3 = s2 * m00s;
double nu20 = mState->mu20 * s2,
nu11 = mState->mu11 * s2,
nu02 = mState->mu02 * s2,
nu30 = mState->mu30 * s3,
nu21 = mState->mu21 * s3, nu12 = mState->mu12 * s3, nu03 = mState->mu03 * s3;
double t0 = nu30 + nu12;
double t1 = nu21 + nu03;
double q0 = t0 * t0, q1 = t1 * t1;
double n4 = 4 * nu11;
double s = nu20 + nu02;
double d = nu20 - nu02;
HuState->hu1 = s;
HuState->hu2 = d * d + n4 * nu11;
HuState->hu4 = q0 + q1;
HuState->hu6 = d * (q0 - q1) + n4 * t0 * t1;
t0 *= q0 - 3 * q1;
t1 *= 3 * q0 - q1;
q0 = nu30 - 3 * nu12;
q1 = 3 * nu21 - nu03;
HuState->hu3 = q0 * q0 + q1 * q1;
HuState->hu5 = q0 * t0 + q1 * t1;
HuState->hu7 = q1 * t0 - q0 * t1;
}
CV_IMPL double cvGetSpatialMoment( CvMoments * moments, int x_order, int y_order )
{
int order = x_order + y_order;
if( !moments )
CV_Error( CV_StsNullPtr, "" );
if( (x_order | y_order) < 0 || order > 3 )
CV_Error( CV_StsOutOfRange, "" );
return (&(moments->m00))[order + (order >> 1) + (order > 2) * 2 + y_order];
}
CV_IMPL double cvGetCentralMoment( CvMoments * moments, int x_order, int y_order )
{
int order = x_order + y_order;
if( !moments )
CV_Error( CV_StsNullPtr, "" );
if( (x_order | y_order) < 0 || order > 3 )
CV_Error( CV_StsOutOfRange, "" );
return order >= 2 ? (&(moments->m00))[4 + order * 3 + y_order] :
order == 0 ? moments->m00 : 0;
}
CV_IMPL double cvGetNormalizedCentralMoment( CvMoments * moments, int x_order, int y_order )
{
int order = x_order + y_order;
double mu = cvGetCentralMoment( moments, x_order, y_order );
double m00s = moments->inv_sqrt_m00;
while( --order >= 0 )
mu *= m00s;
return mu * m00s * m00s;
}
namespace cv
{
Moments::Moments()
{
m00 = m10 = m01 = m20 = m11 = m02 = m30 = m21 = m12 = m03 =
mu20 = mu11 = mu02 = mu30 = mu21 = mu12 = mu03 =
nu20 = nu11 = nu02 = nu30 = nu21 = nu12 = nu03 = 0.;
}
Moments::Moments( double _m00, double _m10, double _m01, double _m20, double _m11,
double _m02, double _m30, double _m21, double _m12, double _m03 )
{
m00 = _m00; m10 = _m10; m01 = _m01;
m20 = _m20; m11 = _m11; m02 = _m02;
m30 = _m30; m21 = _m21; m12 = _m12; m03 = _m03;
double cx = 0, cy = 0, inv_m00 = 0;
if( std::abs(m00) > DBL_EPSILON )
{
inv_m00 = 1./m00;
cx = m10*inv_m00; cy = m01*inv_m00;
}
mu20 = m20 - m10*cx;
mu11 = m11 - m10*cy;
mu02 = m02 - m01*cy;
mu30 = m30 - cx*(3*mu20 + cx*m10);
mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20;
mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02;
mu03 = m03 - cy*(3*mu02 + cy*m01);
double inv_sqrt_m00 = std::sqrt(std::abs(inv_m00));
double s2 = inv_m00*inv_m00, s3 = s2*inv_sqrt_m00;
nu20 = mu20*s2; nu11 = mu11*s2; nu02 = mu02*s2;
nu30 = mu30*s3; nu21 = mu21*s3; nu12 = mu12*s3; nu03 = mu03*s3;
}
Moments::Moments( const CvMoments& m )
{
*this = Moments(m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03);
}
Moments::operator CvMoments() const
{
CvMoments m;
m.m00 = m00; m.m10 = m10; m.m01 = m01;
m.m20 = m20; m.m11 = m11; m.m02 = m02;
m.m30 = m30; m.m21 = m21; m.m12 = m12; m.m03 = m03;
m.mu20 = mu20; m.mu11 = mu11; m.mu02 = mu02;
m.mu30 = mu30; m.mu21 = mu21; m.mu12 = mu12; m.mu03 = mu03;
double am00 = std::abs(m00);
m.inv_sqrt_m00 = am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0;
return m;
}
}
cv::Moments cv::moments( const Mat& array, bool binaryImage )
{
CvMoments om;
CvMat _array = array;
cvMoments(&_array, &om, binaryImage);
return om;
}
void cv::HuMoments( const Moments& m, double hu[7] )
{
double t0 = m.nu30 + m.nu12;
double t1 = m.nu21 + m.nu03;
double q0 = t0 * t0, q1 = t1 * t1;
double n4 = 4 * m.nu11;
double s = m.nu20 + m.nu02;
double d = m.nu20 - m.nu02;
hu[0] = s;
hu[1] = d * d + n4 * m.nu11;
hu[3] = q0 + q1;
hu[5] = d * (q0 - q1) + n4 * t0 * t1;
t0 *= q0 - 3 * q1;
t1 *= 3 * q0 - q1;
q0 = m.nu30 - 3 * m.nu12;
q1 = 3 * m.nu21 - m.nu03;
hu[2] = q0 * q0 + q1 * q1;
hu[4] = q0 * t0 + q1 * t1;
hu[6] = q1 * t0 - q0 * t1;
}
/* End of file. */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
/*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"
/* End of file. */

View File

@@ -0,0 +1,155 @@
/*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.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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 _OPENCV_PRECOMP_HPP_
#define _OPENCV_PRECOMP_HPP_
#if defined _MSC_VER && _MSC_VER >= 1200
// disable warnings related to inline functions
#pragma warning( disable: 4251 4711 4710 4514 )
#endif
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/core/internal.hpp"
#include <math.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <float.h>
/* helper tables */
extern const uchar icvSaturate8u_cv[];
#define CV_FAST_CAST_8U(t) (assert(-256 <= (t) || (t) <= 512), icvSaturate8u_cv[(t)+256])
#define CV_CALC_MIN_8U(a,b) (a) -= CV_FAST_CAST_8U((a) - (b))
#define CV_CALC_MAX_8U(a,b) (a) += CV_FAST_CAST_8U((b) - (a))
// -256.f ... 511.f
extern const float icv8x32fTab_cv[];
#define CV_8TO32F(x) icv8x32fTab_cv[(x)+256]
// (-128.f)^2 ... (255.f)^2
extern const float icv8x32fSqrTab[];
#define CV_8TO32F_SQR(x) icv8x32fSqrTab[(x)+128]
namespace cv
{
static inline Point normalizeAnchor( Point anchor, Size ksize )
{
if( anchor.x == -1 )
anchor.x = ksize.width/2;
if( anchor.y == -1 )
anchor.y = ksize.height/2;
CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) );
return anchor;
}
void preprocess2DKernel( const Mat& kernel, vector<Point>& coords, vector<uchar>& coeffs );
void crossCorr( const Mat& src, const Mat& templ, Mat& dst,
Point anchor=Point(0,0), double delta=0,
int borderType=BORDER_REFLECT_101 );
}
typedef struct CvPyramid
{
uchar **ptr;
CvSize *sz;
double *rate;
int *step;
uchar *state;
int level;
}
CvPyramid;
#define CV_COPY( dst, src, len, idx ) \
for( (idx) = 0; (idx) < (len); (idx)++) (dst)[idx] = (src)[idx]
#define CV_SET( dst, val, len, idx ) \
for( (idx) = 0; (idx) < (len); (idx)++) (dst)[idx] = (val)
/* performs convolution of 2d floating-point array with 3x1, 1x3 or separable 3x3 mask */
void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
CvSize src_size, const float* kx, const float* ky, float* buffer );
#undef CV_CALC_MIN
#define CV_CALC_MIN(a, b) if((a) > (b)) (a) = (b)
#undef CV_CALC_MAX
#define CV_CALC_MAX(a, b) if((a) < (b)) (a) = (b)
void
icvCrossCorr( const CvArr* _img, const CvArr* _templ,
CvArr* _corr, CvPoint anchor=cvPoint(0,0),
double delta=0, int borderType=IPL_BORDER_REPLICATE);
CvStatus CV_STDCALL
icvCopyReplicateBorder_8u( const uchar* src, int srcstep, CvSize srcroi,
uchar* dst, int dststep, CvSize dstroi,
int left, int right, int cn, const uchar* value = 0 );
CvStatus CV_STDCALL icvGetRectSubPix_8u_C1R
( const uchar* src, int src_step, CvSize src_size,
uchar* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R
( const uchar* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
CvStatus CV_STDCALL icvGetRectSubPix_32f_C1R
( const float* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, CvPoint2D32f center );
CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u_C1R
( const uchar* src, int src_step, CvSize src_size,
uchar* dst, int dst_step, CvSize win_size, const float *matrix );
CvStatus CV_STDCALL icvGetQuadrangleSubPix_8u32f_C1R
( const uchar* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, const float *matrix );
CvStatus CV_STDCALL icvGetQuadrangleSubPix_32f_C1R
( const float* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, const float *matrix );
#include "_geom.h"
#endif /*__OPENCV_CV_INTERNAL_H_*/

View File

@@ -0,0 +1,562 @@
/*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.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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"
namespace cv
{
//#undef CV_SSE2
template<typename T, int shift> struct FixPtCast
{
typedef int type1;
typedef T rtype;
rtype operator ()(type1 arg) const { return (T)((arg + (1 << (shift-1))) >> shift); }
};
template<typename T, int shift> struct FltCast
{
typedef T type1;
typedef T rtype;
rtype operator ()(type1 arg) const { return arg*(T)(1./(1 << shift)); }
};
template<typename T1, typename T2> struct NoVec
{
int operator()(T1**, T2*, int, int) const { return 0; }
};
#if CV_SSE2
struct PyrDownVec_32s8u
{
int operator()(int** src, uchar* dst, int, int width) const
{
if( !checkHardwareSupport(CV_CPU_SSE2) )
return 0;
int x = 0;
const int *row0 = src[0], *row1 = src[1], *row2 = src[2], *row3 = src[3], *row4 = src[4];
__m128i delta = _mm_set1_epi16(128);
for( ; x <= width - 16; x += 16 )
{
__m128i r0, r1, r2, r3, r4, t0, t1;
r0 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row0 + x)),
_mm_load_si128((const __m128i*)(row0 + x + 4)));
r1 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row1 + x)),
_mm_load_si128((const __m128i*)(row1 + x + 4)));
r2 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row2 + x)),
_mm_load_si128((const __m128i*)(row2 + x + 4)));
r3 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row3 + x)),
_mm_load_si128((const __m128i*)(row3 + x + 4)));
r4 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row4 + x)),
_mm_load_si128((const __m128i*)(row4 + x + 4)));
r0 = _mm_add_epi16(r0, r4);
r1 = _mm_add_epi16(_mm_add_epi16(r1, r3), r2);
r0 = _mm_add_epi16(r0, _mm_add_epi16(r2, r2));
t0 = _mm_add_epi16(r0, _mm_slli_epi16(r1, 2));
r0 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row0 + x + 8)),
_mm_load_si128((const __m128i*)(row0 + x + 12)));
r1 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row1 + x + 8)),
_mm_load_si128((const __m128i*)(row1 + x + 12)));
r2 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row2 + x + 8)),
_mm_load_si128((const __m128i*)(row2 + x + 12)));
r3 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row3 + x + 8)),
_mm_load_si128((const __m128i*)(row3 + x + 12)));
r4 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row4 + x + 8)),
_mm_load_si128((const __m128i*)(row4 + x + 12)));
r0 = _mm_add_epi16(r0, r4);
r1 = _mm_add_epi16(_mm_add_epi16(r1, r3), r2);
r0 = _mm_add_epi16(r0, _mm_add_epi16(r2, r2));
t1 = _mm_add_epi16(r0, _mm_slli_epi16(r1, 2));
t0 = _mm_srli_epi16(_mm_add_epi16(t0, delta), 8);
t1 = _mm_srli_epi16(_mm_add_epi16(t1, delta), 8);
_mm_storeu_si128((__m128i*)(dst + x), _mm_packus_epi16(t0, t1));
}
for( ; x <= width - 4; x += 4 )
{
__m128i r0, r1, r2, r3, r4, z = _mm_setzero_si128();
r0 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row0 + x)), z);
r1 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row1 + x)), z);
r2 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row2 + x)), z);
r3 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row3 + x)), z);
r4 = _mm_packs_epi32(_mm_load_si128((const __m128i*)(row4 + x)), z);
r0 = _mm_add_epi16(r0, r4);
r1 = _mm_add_epi16(_mm_add_epi16(r1, r3), r2);
r0 = _mm_add_epi16(r0, _mm_add_epi16(r2, r2));
r0 = _mm_add_epi16(r0, _mm_slli_epi16(r1, 2));
r0 = _mm_srli_epi16(_mm_add_epi16(r0, delta), 8);
*(int*)(dst + x) = _mm_cvtsi128_si32(_mm_packus_epi16(r0, r0));
}
return x;
}
};
struct PyrDownVec_32f
{
int operator()(float** src, float* dst, int, int width) const
{
if( !checkHardwareSupport(CV_CPU_SSE) )
return 0;
int x = 0;
const float *row0 = src[0], *row1 = src[1], *row2 = src[2], *row3 = src[3], *row4 = src[4];
__m128 _4 = _mm_set1_ps(4.f), _scale = _mm_set1_ps(1.f/256);
for( ; x <= width - 8; x += 8 )
{
__m128 r0, r1, r2, r3, r4, t0, t1;
r0 = _mm_load_ps(row0 + x);
r1 = _mm_load_ps(row1 + x);
r2 = _mm_load_ps(row2 + x);
r3 = _mm_load_ps(row3 + x);
r4 = _mm_load_ps(row4 + x);
r0 = _mm_add_ps(r0, r4);
r1 = _mm_add_ps(_mm_add_ps(r1, r3), r2);
r0 = _mm_add_ps(r0, _mm_add_ps(r2, r2));
t0 = _mm_add_ps(r0, _mm_mul_ps(r1, _4));
r0 = _mm_load_ps(row0 + x + 4);
r1 = _mm_load_ps(row1 + x + 4);
r2 = _mm_load_ps(row2 + x + 4);
r3 = _mm_load_ps(row3 + x + 4);
r4 = _mm_load_ps(row4 + x + 4);
r0 = _mm_add_ps(r0, r4);
r1 = _mm_add_ps(_mm_add_ps(r1, r3), r2);
r0 = _mm_add_ps(r0, _mm_add_ps(r2, r2));
t1 = _mm_add_ps(r0, _mm_mul_ps(r1, _4));
t0 = _mm_mul_ps(t0, _scale);
t1 = _mm_mul_ps(t1, _scale);
_mm_storeu_ps(dst + x, t0);
_mm_storeu_ps(dst + x + 4, t1);
}
return x;
}
};
#else
typedef NoVec<int, uchar> PyrDownVec_32s8u;
typedef NoVec<float, float> PyrDownVec_32f;
#endif
template<class CastOp, class VecOp> void
pyrDown_( const Mat& _src, Mat& _dst )
{
const int PD_SZ = 5;
typedef typename CastOp::type1 WT;
typedef typename CastOp::rtype T;
Size ssize = _src.size(), dsize = _dst.size();
int cn = _src.channels();
int bufstep = (int)alignSize(dsize.width*cn, 16);
AutoBuffer<WT> _buf(bufstep*PD_SZ + 16);
WT* buf = alignPtr((WT*)_buf, 16);
int tabL[CV_CN_MAX*(PD_SZ+2)], tabR[CV_CN_MAX*(PD_SZ+2)];
AutoBuffer<int> _tabM(dsize.width*cn);
int* tabM = _tabM;
WT* rows[PD_SZ];
CastOp castOp;
VecOp vecOp;
CV_Assert( std::abs(dsize.width*2 - ssize.width) <= 2 &&
std::abs(dsize.height*2 - ssize.height) <= 2 );
int k, x, sy0 = -PD_SZ/2, sy = sy0, width0 = std::min((ssize.width-PD_SZ/2-1)/2 + 1, dsize.width);
for( x = 0; x <= PD_SZ+1; x++ )
{
int sx0 = borderInterpolate(x - PD_SZ/2, ssize.width, BORDER_REFLECT_101)*cn;
int sx1 = borderInterpolate(x + width0*2 - PD_SZ/2, ssize.width, BORDER_REFLECT_101)*cn;
for( k = 0; k < cn; k++ )
{
tabL[x*cn + k] = sx0 + k;
tabR[x*cn + k] = sx1 + k;
}
}
ssize.width *= cn;
dsize.width *= cn;
width0 *= cn;
for( x = 0; x < dsize.width; x++ )
tabM[x] = (x/cn)*2*cn + x % cn;
for( int y = 0; y < dsize.height; y++ )
{
T* dst = (T*)(_dst.data + _dst.step*y);
WT *row0, *row1, *row2, *row3, *row4;
// fill the ring buffer (horizontal convolution and decimation)
for( ; sy <= y*2 + 2; sy++ )
{
WT* row = buf + ((sy - sy0) % PD_SZ)*bufstep;
int _sy = borderInterpolate(sy, ssize.height, BORDER_REFLECT_101);
const T* src = (const T*)(_src.data + _src.step*_sy);
int limit = cn;
const int* tab = tabL;
for( x = 0;;)
{
for( ; x < limit; x++ )
{
row[x] = src[tab[x+cn*2]]*6 + (src[tab[x+cn]] + src[tab[x+cn*3]])*4 +
src[tab[x]] + src[tab[x+cn*4]];
}
if( x == dsize.width )
break;
if( cn == 1 )
{
for( ; x < width0; x++ )
row[x] = src[x*2]*6 + (src[x*2 - 1] + src[x*2 + 1])*4 +
src[x*2 - 2] + src[x*2 + 2];
}
else if( cn == 3 )
{
for( ; x < width0; x += 3 )
{
const T* s = src + x*2;
WT t0 = s[0]*6 + (s[-3] + s[3])*4 + s[-6] + s[6];
WT t1 = s[1]*6 + (s[-2] + s[4])*4 + s[-5] + s[7];
WT t2 = s[2]*6 + (s[-1] + s[5])*4 + s[-4] + s[8];
row[x] = t0; row[x+1] = t1; row[x+2] = t2;
}
}
else if( cn == 4 )
{
for( ; x < width0; x += 4 )
{
const T* s = src + x*2;
WT t0 = s[0]*6 + (s[-4] + s[4])*4 + s[-8] + s[8];
WT t1 = s[1]*6 + (s[-3] + s[5])*4 + s[-7] + s[9];
row[x] = t0; row[x+1] = t1;
t0 = s[2]*6 + (s[-2] + s[6])*4 + s[-6] + s[10];
t1 = s[3]*6 + (s[-1] + s[7])*4 + s[-5] + s[11];
row[x+2] = t0; row[x+3] = t1;
}
}
else
{
for( ; x < width0; x++ )
{
int sx = tabM[x];
row[x] = src[sx]*6 + (src[sx - cn] + src[sx + cn])*4 +
src[sx - cn*2] + src[sx + cn*2];
}
}
limit = dsize.width;
tab = tabR - x;
}
}
// do vertical convolution and decimation and write the result to the destination image
for( k = 0; k < PD_SZ; k++ )
rows[k] = buf + ((y*2 - PD_SZ/2 + k - sy0) % PD_SZ)*bufstep;
row0 = rows[0]; row1 = rows[1]; row2 = rows[2]; row3 = rows[3]; row4 = rows[4];
x = vecOp(rows, dst, (int)_dst.step, dsize.width);
for( ; x < dsize.width; x++ )
dst[x] = castOp(row2[x]*6 + (row1[x] + row3[x])*4 + row0[x] + row4[x]);
}
}
template<class CastOp, class VecOp> void
pyrUp_( const Mat& _src, Mat& _dst )
{
const int PU_SZ = 3;
typedef typename CastOp::type1 WT;
typedef typename CastOp::rtype T;
Size ssize = _src.size(), dsize = _dst.size();
int cn = _src.channels();
int bufstep = (int)alignSize((dsize.width+1)*cn, 16);
AutoBuffer<WT> _buf(bufstep*PU_SZ + 16);
WT* buf = alignPtr((WT*)_buf, 16);
AutoBuffer<int> _dtab(ssize.width*cn);
int* dtab = _dtab;
WT* rows[PU_SZ];
CastOp castOp;
VecOp vecOp;
CV_Assert( std::abs(dsize.width - ssize.width*2) == dsize.width % 2 &&
std::abs(dsize.height - ssize.height*2) == dsize.height % 2);
int k, x, sy0 = -PU_SZ/2, sy = sy0, width0 = ssize.width - 1;
ssize.width *= cn;
dsize.width *= cn;
width0 *= cn;
for( x = 0; x < ssize.width; x++ )
dtab[x] = (x/cn)*2*cn + x % cn;
for( int y = 0; y < ssize.height; y++ )
{
T* dst0 = (T*)(_dst.data + _dst.step*y*2);
T* dst1 = (T*)(_dst.data + _dst.step*(y*2+1));
WT *row0, *row1, *row2;
if( y*2+1 >= dsize.height )
dst1 = dst0;
// fill the ring buffer (horizontal convolution and decimation)
for( ; sy <= y + 1; sy++ )
{
WT* row = buf + ((sy - sy0) % PU_SZ)*bufstep;
int _sy = borderInterpolate(sy, ssize.height, BORDER_REFLECT_101);
const T* src = (const T*)(_src.data + _src.step*_sy);
if( ssize.width == cn )
{
for( x = 0; x < cn; x++ )
row[x] = row[x + cn] = src[x]*8;
continue;
}
for( x = 0; x < cn; x++ )
{
int dx = dtab[x];
WT t0 = src[x]*6 + src[x + cn]*2;
WT t1 = (src[x] + src[x + cn])*4;
row[dx] = t0; row[dx + cn] = t1;
dx = dtab[ssize.width - cn + x];
int sx = ssize.width - cn + x;
t0 = src[sx - cn] + src[sx]*7;
t1 = src[sx]*8;
row[dx] = t0; row[dx + cn] = t1;
}
for( x = cn; x < ssize.width - cn; x++ )
{
int dx = dtab[x];
WT t0 = src[x-cn] + src[x]*6 + src[x+cn];
WT t1 = (src[x] + src[x+cn])*4;
row[dx] = t0;
row[dx+cn] = t1;
}
}
// do vertical convolution and decimation and write the result to the destination image
for( k = 0; k < PU_SZ; k++ )
rows[k] = buf + ((y - PU_SZ/2 + k - sy0) % PU_SZ)*bufstep;
row0 = rows[0]; row1 = rows[1]; row2 = rows[2];
x = vecOp(rows, dst0, (int)_dst.step, dsize.width);
for( ; x < dsize.width; x++ )
{
T t1 = castOp((row1[x] + row2[x])*4);
T t0 = castOp(row0[x] + row1[x]*6 + row2[x]);
dst1[x] = t1; dst0[x] = t0;
}
}
}
typedef void (*PyrFunc)(const Mat&, Mat&);
void pyrDown( const Mat& _src, Mat& _dst, const Size& _dsz )
{
Size dsz = _dsz == Size() ? Size((_src.cols + 1)/2, (_src.rows + 1)/2) : _dsz;
_dst.create( dsz, _src.type() );
int depth = _src.depth();
PyrFunc func = 0;
if( depth == CV_8U )
func = pyrDown_<FixPtCast<uchar, 8>, PyrDownVec_32s8u>;
else if( depth == CV_16U )
func = pyrDown_<FixPtCast<ushort, 8>, NoVec<int, ushort> >;
else if( depth == CV_32F )
func = pyrDown_<FltCast<float, 8>, PyrDownVec_32f>;
else if( depth == CV_64F )
func = pyrDown_<FltCast<double, 8>, NoVec<double, double> >;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( _src, _dst );
}
void pyrUp( const Mat& _src, Mat& _dst, const Size& _dsz )
{
Size dsz = _dsz == Size() ? Size(_src.cols*2, _src.rows*2) : _dsz;
_dst.create( dsz, _src.type() );
int depth = _src.depth();
PyrFunc func = 0;
if( depth == CV_8U )
func = pyrUp_<FixPtCast<uchar, 6>, NoVec<int, uchar> >;
else if( depth == CV_16U )
func = pyrUp_<FixPtCast<ushort, 6>, NoVec<int, ushort> >;
else if( depth == CV_32F )
func = pyrUp_<FltCast<float, 6>, NoVec<float, float> >;
else if( depth == CV_64F )
func = pyrUp_<FltCast<double, 6>, NoVec<double, double> >;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( _src, _dst );
}
void buildPyramid( const Mat& _src, vector<Mat>& _dst, int maxlevel )
{
_dst.resize( maxlevel + 1 );
_dst[0] = _src;
for( int i = 1; i <= maxlevel; i++ )
pyrDown( _dst[i-1], _dst[i] );
}
}
CV_IMPL void cvPyrDown( const void* srcarr, void* dstarr, int _filter )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( _filter == CV_GAUSSIAN_5x5 && src.type() == dst.type());
cv::pyrDown( src, dst, dst.size() );
}
CV_IMPL void cvPyrUp( const void* srcarr, void* dstarr, int _filter )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( _filter == CV_GAUSSIAN_5x5 && src.type() == dst.type());
cv::pyrUp( src, dst, dst.size() );
}
CV_IMPL void
cvReleasePyramid( CvMat*** _pyramid, int extra_layers )
{
if( !_pyramid )
CV_Error( CV_StsNullPtr, "" );
if( *_pyramid )
for( int i = 0; i <= extra_layers; i++ )
cvReleaseMat( &(*_pyramid)[i] );
cvFree( _pyramid );
}
CV_IMPL CvMat**
cvCreatePyramid( const CvArr* srcarr, int extra_layers, double rate,
const CvSize* layer_sizes, CvArr* bufarr,
int calc, int filter )
{
const float eps = 0.1f;
uchar* ptr = 0;
CvMat stub, *src = cvGetMat( srcarr, &stub );
if( extra_layers < 0 )
CV_Error( CV_StsOutOfRange, "The number of extra layers must be non negative" );
int i, layer_step, elem_size = CV_ELEM_SIZE(src->type);
CvSize layer_size, size = cvGetMatSize(src);
if( bufarr )
{
CvMat bstub, *buf;
int bufsize = 0;
buf = cvGetMat( bufarr, &bstub );
bufsize = buf->rows*buf->cols*CV_ELEM_SIZE(buf->type);
layer_size = size;
for( i = 1; i <= extra_layers; i++ )
{
if( !layer_sizes )
{
layer_size.width = cvRound(layer_size.width*rate+eps);
layer_size.height = cvRound(layer_size.height*rate+eps);
}
else
layer_size = layer_sizes[i-1];
layer_step = layer_size.width*elem_size;
bufsize -= layer_step*layer_size.height;
}
if( bufsize < 0 )
CV_Error( CV_StsOutOfRange, "The buffer is too small to fit the pyramid" );
ptr = buf->data.ptr;
}
CvMat** pyramid = (CvMat**)cvAlloc( (extra_layers+1)*sizeof(pyramid[0]) );
memset( pyramid, 0, (extra_layers+1)*sizeof(pyramid[0]) );
pyramid[0] = cvCreateMatHeader( size.height, size.width, src->type );
cvSetData( pyramid[0], src->data.ptr, src->step );
layer_size = size;
for( i = 1; i <= extra_layers; i++ )
{
if( !layer_sizes )
{
layer_size.width = cvRound(layer_size.width*rate + eps);
layer_size.height = cvRound(layer_size.height*rate + eps);
}
else
layer_size = layer_sizes[i];
if( bufarr )
{
pyramid[i] = cvCreateMatHeader( layer_size.height, layer_size.width, src->type );
layer_step = layer_size.width*elem_size;
cvSetData( pyramid[i], ptr, layer_step );
ptr += layer_step*layer_size.height;
}
else
pyramid[i] = cvCreateMat( layer_size.height, layer_size.width, src->type );
if( calc )
cvPyrDown( pyramid[i-1], pyramid[i], filter );
//cvResize( pyramid[i-1], pyramid[i], CV_INTER_LINEAR );
}
return pyramid;
}
/* End of file. */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,465 @@
/*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"
typedef struct
{
int bottom;
int left;
float height;
float width;
float base_a;
float base_b;
}
icvMinAreaState;
#define CV_CALIPERS_MAXHEIGHT 0
#define CV_CALIPERS_MINAREARECT 1
#define CV_CALIPERS_MAXDIST 2
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: icvRotatingCalipers
// Purpose:
// Rotating calipers algorithm with some applications
//
// Context:
// Parameters:
// points - convex hull vertices ( any orientation )
// n - number of vertices
// mode - concrete application of algorithm
// can be CV_CALIPERS_MAXDIST or
// CV_CALIPERS_MINAREARECT
// left, bottom, right, top - indexes of extremal points
// out - output info.
// In case CV_CALIPERS_MAXDIST it points to float value -
// maximal height of polygon.
// In case CV_CALIPERS_MINAREARECT
// ((CvPoint2D32f*)out)[0] - corner
// ((CvPoint2D32f*)out)[1] - vector1
// ((CvPoint2D32f*)out)[0] - corner2
//
// ^
// |
// vector2 |
// |
// |____________\
// corner /
// vector1
//
// Returns:
// Notes:
//F*/
/* we will use usual cartesian coordinates */
static void
icvRotatingCalipers( CvPoint2D32f* points, int n, int mode, float* out )
{
float minarea = FLT_MAX;
float max_dist = 0;
char buffer[32];
int i, k;
CvPoint2D32f* vect = (CvPoint2D32f*)cvAlloc( n * sizeof(vect[0]) );
float* inv_vect_length = (float*)cvAlloc( n * sizeof(inv_vect_length[0]) );
int left = 0, bottom = 0, right = 0, top = 0;
int seq[4] = { -1, -1, -1, -1 };
/* rotating calipers sides will always have coordinates
(a,b) (-b,a) (-a,-b) (b, -a)
*/
/* this is a first base bector (a,b) initialized by (1,0) */
float orientation = 0;
float base_a;
float base_b = 0;
float left_x, right_x, top_y, bottom_y;
CvPoint2D32f pt0 = points[0];
left_x = right_x = pt0.x;
top_y = bottom_y = pt0.y;
for( i = 0; i < n; i++ )
{
double dx, dy;
if( pt0.x < left_x )
left_x = pt0.x, left = i;
if( pt0.x > right_x )
right_x = pt0.x, right = i;
if( pt0.y > top_y )
top_y = pt0.y, top = i;
if( pt0.y < bottom_y )
bottom_y = pt0.y, bottom = i;
CvPoint2D32f pt = points[(i+1) & (i+1 < n ? -1 : 0)];
dx = pt.x - pt0.x;
dy = pt.y - pt0.y;
vect[i].x = (float)dx;
vect[i].y = (float)dy;
inv_vect_length[i] = (float)(1./sqrt(dx*dx + dy*dy));
pt0 = pt;
}
//cvbInvSqrt( inv_vect_length, inv_vect_length, n );
/* find convex hull orientation */
{
double ax = vect[n-1].x;
double ay = vect[n-1].y;
for( i = 0; i < n; i++ )
{
double bx = vect[i].x;
double by = vect[i].y;
double convexity = ax * by - ay * bx;
if( convexity != 0 )
{
orientation = (convexity > 0) ? 1.f : (-1.f);
break;
}
ax = bx;
ay = by;
}
assert( orientation != 0 );
}
base_a = orientation;
/*****************************************************************************************/
/* init calipers position */
seq[0] = bottom;
seq[1] = right;
seq[2] = top;
seq[3] = left;
/*****************************************************************************************/
/* Main loop - evaluate angles and rotate calipers */
/* all of edges will be checked while rotating calipers by 90 degrees */
for( k = 0; k < n; k++ )
{
/* sinus of minimal angle */
/*float sinus;*/
/* compute cosine of angle between calipers side and polygon edge */
/* dp - dot product */
float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y;
float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y;
float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y;
float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y;
float cosalpha = dp0 * inv_vect_length[seq[0]];
float maxcos = cosalpha;
/* number of calipers edges, that has minimal angle with edge */
int main_element = 0;
/* choose minimal angle */
cosalpha = dp1 * inv_vect_length[seq[1]];
maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos;
cosalpha = dp2 * inv_vect_length[seq[2]];
maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos;
cosalpha = dp3 * inv_vect_length[seq[3]];
maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos;
/*rotate calipers*/
{
//get next base
int pindex = seq[main_element];
float lead_x = vect[pindex].x*inv_vect_length[pindex];
float lead_y = vect[pindex].y*inv_vect_length[pindex];
switch( main_element )
{
case 0:
base_a = lead_x;
base_b = lead_y;
break;
case 1:
base_a = lead_y;
base_b = -lead_x;
break;
case 2:
base_a = -lead_x;
base_b = -lead_y;
break;
case 3:
base_a = -lead_y;
base_b = lead_x;
break;
default: assert(0);
}
}
/* change base point of main edge */
seq[main_element] += 1;
seq[main_element] = (seq[main_element] == n) ? 0 : seq[main_element];
switch (mode)
{
case CV_CALIPERS_MAXHEIGHT:
{
/* now main element lies on edge alligned to calipers side */
/* find opposite element i.e. transform */
/* 0->2, 1->3, 2->0, 3->1 */
int opposite_el = main_element ^ 2;
float dx = points[seq[opposite_el]].x - points[seq[main_element]].x;
float dy = points[seq[opposite_el]].y - points[seq[main_element]].y;
float dist;
if( main_element & 1 )
dist = (float)fabs(dx * base_a + dy * base_b);
else
dist = (float)fabs(dx * (-base_b) + dy * base_a);
if( dist > max_dist )
max_dist = dist;
break;
}
case CV_CALIPERS_MINAREARECT:
/* find area of rectangle */
{
float height;
float area;
/* find vector left-right */
float dx = points[seq[1]].x - points[seq[3]].x;
float dy = points[seq[1]].y - points[seq[3]].y;
/* dotproduct */
float width = dx * base_a + dy * base_b;
/* find vector left-right */
dx = points[seq[2]].x - points[seq[0]].x;
dy = points[seq[2]].y - points[seq[0]].y;
/* dotproduct */
height = -dx * base_b + dy * base_a;
area = width * height;
if( area <= minarea )
{
float *buf = (float *) buffer;
minarea = area;
/* leftist point */
((int *) buf)[0] = seq[3];
buf[1] = base_a;
buf[2] = width;
buf[3] = base_b;
buf[4] = height;
/* bottom point */
((int *) buf)[5] = seq[0];
buf[6] = area;
}
break;
}
} /*switch */
} /* for */
switch (mode)
{
case CV_CALIPERS_MINAREARECT:
{
float *buf = (float *) buffer;
float A1 = buf[1];
float B1 = buf[3];
float A2 = -buf[3];
float B2 = buf[1];
float C1 = A1 * points[((int *) buf)[0]].x + points[((int *) buf)[0]].y * B1;
float C2 = A2 * points[((int *) buf)[5]].x + points[((int *) buf)[5]].y * B2;
float idet = 1.f / (A1 * B2 - A2 * B1);
float px = (C1 * B2 - C2 * B1) * idet;
float py = (A1 * C2 - A2 * C1) * idet;
out[0] = px;
out[1] = py;
out[2] = A1 * buf[2];
out[3] = B1 * buf[2];
out[4] = A2 * buf[4];
out[5] = B2 * buf[4];
}
break;
case CV_CALIPERS_MAXHEIGHT:
{
out[0] = max_dist;
}
break;
}
cvFree( &vect );
cvFree( &inv_vect_length );
}
CV_IMPL CvBox2D
cvMinAreaRect2( const CvArr* array, CvMemStorage* storage )
{
cv::Ptr<CvMemStorage> temp_storage;
CvBox2D box;
cv::AutoBuffer<CvPoint2D32f> _points;
CvPoint2D32f* points;
memset(&box, 0, sizeof(box));
int i, n;
CvSeqReader reader;
CvContour contour_header;
CvSeqBlock block;
CvSeq* ptseq = (CvSeq*)array;
CvPoint2D32f out[3];
if( CV_IS_SEQ(ptseq) )
{
if( !CV_IS_SEQ_POINT_SET(ptseq) &&
(CV_SEQ_KIND(ptseq) != CV_SEQ_KIND_CURVE || !CV_IS_SEQ_CONVEX(ptseq) ||
CV_SEQ_ELTYPE(ptseq) != CV_SEQ_ELTYPE_PPOINT ))
CV_Error( CV_StsUnsupportedFormat,
"Input sequence must consist of 2d points or pointers to 2d points" );
if( !storage )
storage = ptseq->storage;
}
else
{
ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block );
}
if( storage )
{
temp_storage = cvCreateChildMemStorage( storage );
}
else
{
temp_storage = cvCreateMemStorage(1 << 10);
}
if( !CV_IS_SEQ_CONVEX( ptseq ))
{
ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 );
}
else if( !CV_IS_SEQ_POINT_SET( ptseq ))
{
CvSeqWriter writer;
if( !CV_IS_SEQ(ptseq->v_prev) || !CV_IS_SEQ_POINT_SET(ptseq->v_prev))
CV_Error( CV_StsBadArg,
"Convex hull must have valid pointer to point sequence stored in v_prev" );
cvStartReadSeq( ptseq, &reader );
cvStartWriteSeq( CV_SEQ_KIND_CURVE|CV_SEQ_FLAG_CONVEX|CV_SEQ_ELTYPE(ptseq->v_prev),
sizeof(CvContour), CV_ELEM_SIZE(ptseq->v_prev->flags),
temp_storage, &writer );
for( i = 0; i < ptseq->total; i++ )
{
CvPoint pt = **(CvPoint**)(reader.ptr);
CV_WRITE_SEQ_ELEM( pt, writer );
}
ptseq = cvEndWriteSeq( &writer );
}
n = ptseq->total;
_points.allocate(n);
points = _points;
cvStartReadSeq( ptseq, &reader );
if( CV_SEQ_ELTYPE( ptseq ) == CV_32SC2 )
{
for( i = 0; i < n; i++ )
{
CvPoint pt;
CV_READ_SEQ_ELEM( pt, reader );
points[i].x = (float)pt.x;
points[i].y = (float)pt.y;
}
}
else
{
for( i = 0; i < n; i++ )
{
CV_READ_SEQ_ELEM( points[i], reader );
}
}
if( n > 2 )
{
icvRotatingCalipers( points, n, CV_CALIPERS_MINAREARECT, (float*)out );
box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f;
box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f;
box.size.height = (float)sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y);
box.size.width = (float)sqrt((double)out[2].x*out[2].x + (double)out[2].y*out[2].y);
box.angle = (float)atan2( -(double)out[1].y, (double)out[1].x );
}
else if( n == 2 )
{
box.center.x = (points[0].x + points[1].x)*0.5f;
box.center.y = (points[0].y + points[1].y)*0.5f;
double dx = points[1].x - points[0].x;
double dy = points[1].y - points[0].y;
box.size.height = (float)sqrt(dx*dx + dy*dy);
box.size.width = 0;
box.angle = (float)atan2( -dy, dx );
}
else
{
if( n == 1 )
box.center = points[0];
}
box.angle = (float)(box.angle*180/CV_PI);
return box;
}

View File

@@ -0,0 +1,880 @@
/*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"
/**************************************************************************************\
* line samplers *
\**************************************************************************************/
CV_IMPL int
cvSampleLine( const void* img, CvPoint pt1, CvPoint pt2,
void* _buffer, int connectivity )
{
int count = -1;
int i, coi = 0, pix_size;
CvMat stub, *mat = cvGetMat( img, &stub, &coi );
CvLineIterator iterator;
uchar* buffer = (uchar*)_buffer;
if( coi != 0 )
CV_Error( CV_BadCOI, "" );
if( !buffer )
CV_Error( CV_StsNullPtr, "" );
count = cvInitLineIterator( mat, pt1, pt2, &iterator, connectivity );
pix_size = CV_ELEM_SIZE(mat->type);
for( i = 0; i < count; i++ )
{
for( int j = 0; j < pix_size; j++ )
buffer[j] = iterator.ptr[j];
buffer += pix_size;
CV_NEXT_LINE_POINT( iterator );
}
return count;
}
static const void*
icvAdjustRect( const void* srcptr, int src_step, int pix_size,
CvSize src_size, CvSize win_size,
CvPoint ip, CvRect* pRect )
{
CvRect rect;
const char* src = (const char*)srcptr;
if( ip.x >= 0 )
{
src += ip.x*pix_size;
rect.x = 0;
}
else
{
rect.x = -ip.x;
if( rect.x > win_size.width )
rect.x = win_size.width;
}
if( ip.x + win_size.width < src_size.width )
rect.width = win_size.width;
else
{
rect.width = src_size.width - ip.x - 1;
if( rect.width < 0 )
{
src += rect.width*pix_size;
rect.width = 0;
}
assert( rect.width <= win_size.width );
}
if( ip.y >= 0 )
{
src += ip.y * src_step;
rect.y = 0;
}
else
rect.y = -ip.y;
if( ip.y + win_size.height < src_size.height )
rect.height = win_size.height;
else
{
rect.height = src_size.height - ip.y - 1;
if( rect.height < 0 )
{
src += rect.height*src_step;
rect.height = 0;
}
}
*pRect = rect;
return src - rect.x*pix_size;
}
#define ICV_DEF_GET_RECT_SUB_PIX_FUNC( flavor, srctype, dsttype, worktype, \
cast_macro, scale_macro, cast_macro2 )\
CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C1R \
( const srctype* src, int src_step, CvSize src_size, \
dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \
{ \
CvPoint ip; \
worktype a11, a12, a21, a22, b1, b2; \
float a, b; \
int i, j; \
\
center.x -= (win_size.width-1)*0.5f; \
center.y -= (win_size.height-1)*0.5f; \
\
ip.x = cvFloor( center.x ); \
ip.y = cvFloor( center.y ); \
\
a = center.x - ip.x; \
b = center.y - ip.y; \
a11 = scale_macro((1.f-a)*(1.f-b)); \
a12 = scale_macro(a*(1.f-b)); \
a21 = scale_macro((1.f-a)*b); \
a22 = scale_macro(a*b); \
b1 = scale_macro(1.f - b); \
b2 = scale_macro(b); \
\
src_step /= sizeof(src[0]); \
dst_step /= sizeof(dst[0]); \
\
if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \
0 <= ip.y && ip.y + win_size.height < src_size.height ) \
{ \
/* extracted rectangle is totally inside the image */ \
src += ip.y * src_step + ip.x; \
\
for( i = 0; i < win_size.height; i++, src += src_step, \
dst += dst_step ) \
{ \
for( j = 0; j <= win_size.width - 2; j += 2 ) \
{ \
worktype s0 = cast_macro(src[j])*a11 + \
cast_macro(src[j+1])*a12 + \
cast_macro(src[j+src_step])*a21 + \
cast_macro(src[j+src_step+1])*a22; \
worktype s1 = cast_macro(src[j+1])*a11 + \
cast_macro(src[j+2])*a12 + \
cast_macro(src[j+src_step+1])*a21 + \
cast_macro(src[j+src_step+2])*a22; \
\
dst[j] = (dsttype)cast_macro2(s0); \
dst[j+1] = (dsttype)cast_macro2(s1); \
} \
\
for( ; j < win_size.width; j++ ) \
{ \
worktype s0 = cast_macro(src[j])*a11 + \
cast_macro(src[j+1])*a12 + \
cast_macro(src[j+src_step])*a21 + \
cast_macro(src[j+src_step+1])*a22; \
\
dst[j] = (dsttype)cast_macro2(s0); \
} \
} \
} \
else \
{ \
CvRect r; \
\
src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \
sizeof(*src), src_size, win_size,ip, &r); \
\
for( i = 0; i < win_size.height; i++, dst += dst_step ) \
{ \
const srctype *src2 = src + src_step; \
\
if( i < r.y || i >= r.height ) \
src2 -= src_step; \
\
for( j = 0; j < r.x; j++ ) \
{ \
worktype s0 = cast_macro(src[r.x])*b1 + \
cast_macro(src2[r.x])*b2; \
\
dst[j] = (dsttype)cast_macro2(s0); \
} \
\
for( ; j < r.width; j++ ) \
{ \
worktype s0 = cast_macro(src[j])*a11 + \
cast_macro(src[j+1])*a12 + \
cast_macro(src2[j])*a21 + \
cast_macro(src2[j+1])*a22; \
\
dst[j] = (dsttype)cast_macro2(s0); \
} \
\
for( ; j < win_size.width; j++ ) \
{ \
worktype s0 = cast_macro(src[r.width])*b1 + \
cast_macro(src2[r.width])*b2; \
\
dst[j] = (dsttype)cast_macro2(s0); \
} \
\
if( i < r.height ) \
src = src2; \
} \
} \
\
return CV_OK; \
}
#define ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, worktype, \
cast_macro, scale_macro, mul_macro )\
static CvStatus CV_STDCALL icvGetRectSubPix_##flavor##_C3R \
( const srctype* src, int src_step, CvSize src_size, \
dsttype* dst, int dst_step, CvSize win_size, CvPoint2D32f center ) \
{ \
CvPoint ip; \
worktype a, b; \
int i, j; \
\
center.x -= (win_size.width-1)*0.5f; \
center.y -= (win_size.height-1)*0.5f; \
\
ip.x = cvFloor( center.x ); \
ip.y = cvFloor( center.y ); \
\
a = scale_macro( center.x - ip.x ); \
b = scale_macro( center.y - ip.y ); \
\
src_step /= sizeof( src[0] ); \
dst_step /= sizeof( dst[0] ); \
\
if( 0 <= ip.x && ip.x + win_size.width < src_size.width && \
0 <= ip.y && ip.y + win_size.height < src_size.height ) \
{ \
/* extracted rectangle is totally inside the image */ \
src += ip.y * src_step + ip.x*3; \
\
for( i = 0; i < win_size.height; i++, src += src_step, \
dst += dst_step ) \
{ \
for( j = 0; j < win_size.width; j++ ) \
{ \
worktype s0 = cast_macro(src[j*3]); \
worktype s1 = cast_macro(src[j*3 + src_step]); \
s0 += mul_macro( a, (cast_macro(src[j*3+3]) - s0)); \
s1 += mul_macro( a, (cast_macro(src[j*3+3+src_step]) - s1));\
dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[j*3+1]); \
s1 = cast_macro(src[j*3+1 + src_step]); \
s0 += mul_macro( a, (cast_macro(src[j*3+4]) - s0)); \
s1 += mul_macro( a, (cast_macro(src[j*3+4+src_step]) - s1));\
dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[j*3+2]); \
s1 = cast_macro(src[j*3+2 + src_step]); \
s0 += mul_macro( a, (cast_macro(src[j*3+5]) - s0)); \
s1 += mul_macro( a, (cast_macro(src[j*3+5+src_step]) - s1));\
dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
} \
} \
} \
else \
{ \
CvRect r; \
\
src = (const srctype*)icvAdjustRect( src, src_step*sizeof(*src), \
sizeof(*src)*3, src_size, win_size, ip, &r ); \
\
for( i = 0; i < win_size.height; i++, dst += dst_step ) \
{ \
const srctype *src2 = src + src_step; \
\
if( i < r.y || i >= r.height ) \
src2 -= src_step; \
\
for( j = 0; j < r.x; j++ ) \
{ \
worktype s0 = cast_macro(src[r.x*3]); \
worktype s1 = cast_macro(src2[r.x*3]); \
dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[r.x*3+1]); \
s1 = cast_macro(src2[r.x*3+1]); \
dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[r.x*3+2]); \
s1 = cast_macro(src2[r.x*3+2]); \
dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
} \
\
for( ; j < r.width; j++ ) \
{ \
worktype s0 = cast_macro(src[j*3]); \
worktype s1 = cast_macro(src2[j*3]); \
s0 += mul_macro( a, (cast_macro(src[j*3 + 3]) - s0)); \
s1 += mul_macro( a, (cast_macro(src2[j*3 + 3]) - s1)); \
dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[j*3+1]); \
s1 = cast_macro(src2[j*3+1]); \
s0 += mul_macro( a, (cast_macro(src[j*3 + 4]) - s0)); \
s1 += mul_macro( a, (cast_macro(src2[j*3 + 4]) - s1)); \
dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[j*3+2]); \
s1 = cast_macro(src2[j*3+2]); \
s0 += mul_macro( a, (cast_macro(src[j*3 + 5]) - s0)); \
s1 += mul_macro( a, (cast_macro(src2[j*3 + 5]) - s1)); \
dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
} \
\
for( ; j < win_size.width; j++ ) \
{ \
worktype s0 = cast_macro(src[r.width*3]); \
worktype s1 = cast_macro(src2[r.width*3]); \
dst[j*3] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[r.width*3+1]); \
s1 = cast_macro(src2[r.width*3+1]); \
dst[j*3+1] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
\
s0 = cast_macro(src[r.width*3+2]); \
s1 = cast_macro(src2[r.width*3+2]); \
dst[j*3+2] = (dsttype)(s0 + mul_macro( b, (s1 - s0))); \
} \
\
if( i < r.height ) \
src = src2; \
} \
} \
\
return CV_OK; \
}
CvStatus CV_STDCALL icvGetRectSubPix_8u32f_C1R
( const uchar* src, int src_step, CvSize src_size,
float* dst, int dst_step, CvSize win_size, CvPoint2D32f center )
{
CvPoint ip;
float a12, a22, b1, b2;
float a, b;
double s = 0;
int i, j;
center.x -= (win_size.width-1)*0.5f;
center.y -= (win_size.height-1)*0.5f;
ip.x = cvFloor( center.x );
ip.y = cvFloor( center.y );
if( win_size.width <= 0 || win_size.height <= 0 )
return CV_BADRANGE_ERR;
a = center.x - ip.x;
b = center.y - ip.y;
a = MAX(a,0.0001f);
a12 = a*(1.f-b);
a22 = a*b;
b1 = 1.f - b;
b2 = b;
s = (1. - a)/a;
src_step /= sizeof(src[0]);
dst_step /= sizeof(dst[0]);
if( 0 <= ip.x && ip.x + win_size.width < src_size.width &&
0 <= ip.y && ip.y + win_size.height < src_size.height )
{
// extracted rectangle is totally inside the image
src += ip.y * src_step + ip.x;
#if 0
if( icvCopySubpix_8u32f_C1R_p &&
icvCopySubpix_8u32f_C1R_p( src, src_step, dst,
dst_step*sizeof(dst[0]), win_size, a, b ) >= 0 )
return CV_OK;
#endif
for( ; win_size.height--; src += src_step, dst += dst_step )
{
float prev = (1 - a)*(b1*CV_8TO32F(src[0]) + b2*CV_8TO32F(src[src_step]));
for( j = 0; j < win_size.width; j++ )
{
float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src[j+1+src_step]);
dst[j] = prev + t;
prev = (float)(t*s);
}
}
}
else
{
CvRect r;
src = (const uchar*)icvAdjustRect( src, src_step*sizeof(*src),
sizeof(*src), src_size, win_size,ip, &r);
for( i = 0; i < win_size.height; i++, dst += dst_step )
{
const uchar *src2 = src + src_step;
if( i < r.y || i >= r.height )
src2 -= src_step;
for( j = 0; j < r.x; j++ )
{
float s0 = CV_8TO32F(src[r.x])*b1 +
CV_8TO32F(src2[r.x])*b2;
dst[j] = (float)(s0);
}
if( j < r.width )
{
float prev = (1 - a)*(b1*CV_8TO32F(src[j]) + b2*CV_8TO32F(src2[j]));
for( ; j < r.width; j++ )
{
float t = a12*CV_8TO32F(src[j+1]) + a22*CV_8TO32F(src2[j+1]);
dst[j] = prev + t;
prev = (float)(t*s);
}
}
for( ; j < win_size.width; j++ )
{
float s0 = CV_8TO32F(src[r.width])*b1 +
CV_8TO32F(src2[r.width])*b2;
dst[j] = (float)(s0);
}
if( i < r.height )
src = src2;
}
}
return CV_OK;
}
#define ICV_SHIFT 16
#define ICV_SCALE(x) cvRound((x)*(1 << ICV_SHIFT))
#define ICV_MUL_SCALE(x,y) (((x)*(y) + (1 << (ICV_SHIFT-1))) >> ICV_SHIFT)
#define ICV_DESCALE(x) (((x)+(1 << (ICV_SHIFT-1))) >> ICV_SHIFT)
/*icvCopySubpix_8u_C1R_t icvCopySubpix_8u_C1R_p = 0;
icvCopySubpix_8u32f_C1R_t icvCopySubpix_8u32f_C1R_p = 0;
icvCopySubpix_32f_C1R_t icvCopySubpix_32f_C1R_p = 0;*/
ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_DESCALE )
//ICV_DEF_GET_RECT_SUB_PIX_FUNC( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_NOP )
ICV_DEF_GET_RECT_SUB_PIX_FUNC( 32f, float, float, float, CV_NOP, CV_NOP, CV_NOP )
ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u, uchar, uchar, int, CV_NOP, ICV_SCALE, ICV_MUL_SCALE )
ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 8u32f, uchar, float, float, CV_8TO32F, CV_NOP, CV_MUL )
ICV_DEF_GET_RECT_SUB_PIX_FUNC_C3( 32f, float, float, float, CV_NOP, CV_NOP, CV_MUL )
#define ICV_DEF_INIT_SUBPIX_TAB( FUNCNAME, FLAG ) \
static void icvInit##FUNCNAME##FLAG##Table( CvFuncTable* tab ) \
{ \
tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_##FLAG; \
tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_##FLAG; \
\
tab->fn_2d[1] = (void*)icv##FUNCNAME##_8u32f_##FLAG; \
}
ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C1R )
ICV_DEF_INIT_SUBPIX_TAB( GetRectSubPix, C3R )
typedef CvStatus (CV_STDCALL *CvGetRectSubPixFunc)( const void* src, int src_step,
CvSize src_size, void* dst,
int dst_step, CvSize win_size,
CvPoint2D32f center );
CV_IMPL void
cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center )
{
static CvFuncTable gr_tab[2];
static int inittab = 0;
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvSize src_size, dst_size;
CvGetRectSubPixFunc func;
int cn, src_step, dst_step;
if( !inittab )
{
icvInitGetRectSubPixC1RTable( gr_tab + 0 );
icvInitGetRectSubPixC3RTable( gr_tab + 1 );
inittab = 1;
}
if( !CV_IS_MAT(src))
src = cvGetMat( src, &srcstub );
if( !CV_IS_MAT(dst))
dst = cvGetMat( dst, &dststub );
cn = CV_MAT_CN( src->type );
if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst ))
CV_Error( CV_StsUnsupportedFormat, "" );
src_size = cvGetMatSize( src );
dst_size = cvGetMatSize( dst );
src_step = src->step ? src->step : CV_STUB_STEP;
dst_step = dst->step ? dst->step : CV_STUB_STEP;
//if( dst_size.width > src_size.width || dst_size.height > src_size.height )
// CV_ERROR( CV_StsBadSize, "destination ROI must be smaller than source ROI" );
if( CV_ARE_DEPTHS_EQ( src, dst ))
{
func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]);
}
else
{
if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F )
CV_Error( CV_StsUnsupportedFormat, "" );
func = (CvGetRectSubPixFunc)(gr_tab[cn != 1].fn_2d[1]);
}
if( !func )
CV_Error( CV_StsUnsupportedFormat, "" );
IPPI_CALL( func( src->data.ptr, src_step, src_size,
dst->data.ptr, dst_step, dst_size, center ));
}
#define ICV_32F8U(x) ((uchar)cvRound(x))
#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( flavor, srctype, dsttype, \
worktype, cast_macro, cvt ) \
CvStatus CV_STDCALL \
icvGetQuadrangleSubPix_##flavor##_C1R \
( const srctype * src, int src_step, CvSize src_size, \
dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \
{ \
int x, y; \
double dx = (win_size.width - 1)*0.5; \
double dy = (win_size.height - 1)*0.5; \
double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \
double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \
\
src_step /= sizeof(srctype); \
dst_step /= sizeof(dsttype); \
\
for( y = 0; y < win_size.height; y++, dst += dst_step ) \
{ \
double xs = A12*y + A13; \
double ys = A22*y + A23; \
double xe = A11*(win_size.width-1) + A12*y + A13; \
double ye = A21*(win_size.width-1) + A22*y + A23; \
\
if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \
(unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \
(unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \
(unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \
{ \
for( x = 0; x < win_size.width; x++ ) \
{ \
int ixs = cvFloor( xs ); \
int iys = cvFloor( ys ); \
const srctype *ptr = src + src_step*iys + ixs; \
double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \
worktype p0 = cvt(ptr[0])*a1 + cvt(ptr[1])*a; \
worktype p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+1])*a;\
xs += A11; \
ys += A21; \
\
dst[x] = cast_macro(p0 + b * (p1 - p0)); \
} \
} \
else \
{ \
for( x = 0; x < win_size.width; x++ ) \
{ \
int ixs = cvFloor( xs ), iys = cvFloor( ys ); \
double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \
const srctype *ptr0, *ptr1; \
worktype p0, p1; \
xs += A11; ys += A21; \
\
if( (unsigned)iys < (unsigned)(src_size.height-1) ) \
ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \
else \
ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \
\
if( (unsigned)ixs < (unsigned)(src_size.width-1) ) \
{ \
p0 = cvt(ptr0[ixs])*a1 + cvt(ptr0[ixs+1])*a; \
p1 = cvt(ptr1[ixs])*a1 + cvt(ptr1[ixs+1])*a; \
} \
else \
{ \
ixs = ixs < 0 ? 0 : src_size.width - 1; \
p0 = cvt(ptr0[ixs]); p1 = cvt(ptr1[ixs]); \
} \
dst[x] = cast_macro(p0 + b * (p1 - p0)); \
} \
} \
} \
\
return CV_OK; \
}
#define ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( flavor, srctype, dsttype, \
worktype, cast_macro, cvt ) \
static CvStatus CV_STDCALL \
icvGetQuadrangleSubPix_##flavor##_C3R \
( const srctype * src, int src_step, CvSize src_size, \
dsttype *dst, int dst_step, CvSize win_size, const float *matrix ) \
{ \
int x, y; \
double dx = (win_size.width - 1)*0.5; \
double dy = (win_size.height - 1)*0.5; \
double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2]-A11*dx-A12*dy; \
double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5]-A21*dx-A22*dy; \
\
src_step /= sizeof(srctype); \
dst_step /= sizeof(dsttype); \
\
for( y = 0; y < win_size.height; y++, dst += dst_step ) \
{ \
double xs = A12*y + A13; \
double ys = A22*y + A23; \
double xe = A11*(win_size.width-1) + A12*y + A13; \
double ye = A21*(win_size.width-1) + A22*y + A23; \
\
if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) && \
(unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) && \
(unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) && \
(unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3)) \
{ \
for( x = 0; x < win_size.width; x++ ) \
{ \
int ixs = cvFloor( xs ); \
int iys = cvFloor( ys ); \
const srctype *ptr = src + src_step*iys + ixs*3; \
double a = xs - ixs, b = ys - iys, a1 = 1.f - a; \
worktype p0, p1; \
xs += A11; \
ys += A21; \
\
p0 = cvt(ptr[0])*a1 + cvt(ptr[3])*a; \
p1 = cvt(ptr[src_step])*a1 + cvt(ptr[src_step+3])*a; \
dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \
\
p0 = cvt(ptr[1])*a1 + cvt(ptr[4])*a; \
p1 = cvt(ptr[src_step+1])*a1 + cvt(ptr[src_step+4])*a; \
dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \
\
p0 = cvt(ptr[2])*a1 + cvt(ptr[5])*a; \
p1 = cvt(ptr[src_step+2])*a1 + cvt(ptr[src_step+5])*a; \
dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \
} \
} \
else \
{ \
for( x = 0; x < win_size.width; x++ ) \
{ \
int ixs = cvFloor(xs), iys = cvFloor(ys); \
double a = xs - ixs, b = ys - iys; \
const srctype *ptr0, *ptr1; \
xs += A11; ys += A21; \
\
if( (unsigned)iys < (unsigned)(src_size.height-1) ) \
ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step; \
else \
ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step; \
\
if( (unsigned)ixs < (unsigned)(src_size.width - 1) ) \
{ \
double a1 = 1.f - a; \
worktype p0, p1; \
ptr0 += ixs*3; ptr1 += ixs*3; \
p0 = cvt(ptr0[0])*a1 + cvt(ptr0[3])*a; \
p1 = cvt(ptr1[0])*a1 + cvt(ptr1[3])*a; \
dst[x*3] = cast_macro(p0 + b * (p1 - p0)); \
\
p0 = cvt(ptr0[1])*a1 + cvt(ptr0[4])*a; \
p1 = cvt(ptr1[1])*a1 + cvt(ptr1[4])*a; \
dst[x*3+1] = cast_macro(p0 + b * (p1 - p0)); \
\
p0 = cvt(ptr0[2])*a1 + cvt(ptr0[5])*a; \
p1 = cvt(ptr1[2])*a1 + cvt(ptr1[5])*a; \
dst[x*3+2] = cast_macro(p0 + b * (p1 - p0)); \
} \
else \
{ \
double b1 = 1.f - b; \
ixs = ixs < 0 ? 0 : src_size.width - 1; \
ptr0 += ixs*3; ptr1 += ixs*3; \
\
dst[x*3] = cast_macro(cvt(ptr0[0])*b1 + cvt(ptr1[0])*b);\
dst[x*3+1]=cast_macro(cvt(ptr0[1])*b1 + cvt(ptr1[1])*b);\
dst[x*3+2]=cast_macro(cvt(ptr0[2])*b1 + cvt(ptr1[2])*b);\
} \
} \
} \
} \
\
return CV_OK; \
}
/*#define srctype uchar
#define dsttype uchar
#define worktype float
#define cvt CV_8TO32F
#define cast_macro ICV_32F8U
#undef srctype
#undef dsttype
#undef worktype
#undef cvt
#undef cast_macro*/
ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F )
ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 32f, float, float, double, CV_CAST_32F, CV_NOP )
ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F )
ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u, uchar, uchar, double, ICV_32F8U, CV_8TO32F )
ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 32f, float, float, double, CV_CAST_32F, CV_NOP )
ICV_DEF_GET_QUADRANGLE_SUB_PIX_FUNC_C3( 8u32f, uchar, float, double, CV_CAST_32F, CV_8TO32F )
ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C1R )
ICV_DEF_INIT_SUBPIX_TAB( GetQuadrangleSubPix, C3R )
typedef CvStatus (CV_STDCALL *CvGetQuadrangleSubPixFunc)(
const void* src, int src_step,
CvSize src_size, void* dst,
int dst_step, CvSize win_size,
const float* matrix );
CV_IMPL void
cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat )
{
static CvFuncTable gq_tab[2];
static int inittab = 0;
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvSize src_size, dst_size;
CvGetQuadrangleSubPixFunc func;
float m[6];
int k, cn;
if( !inittab )
{
icvInitGetQuadrangleSubPixC1RTable( gq_tab + 0 );
icvInitGetQuadrangleSubPixC3RTable( gq_tab + 1 );
inittab = 1;
}
if( !CV_IS_MAT(src))
src = cvGetMat( src, &srcstub );
if( !CV_IS_MAT(dst))
dst = cvGetMat( dst, &dststub );
if( !CV_IS_MAT(mat))
CV_Error( CV_StsBadArg, "map matrix is not valid" );
cn = CV_MAT_CN( src->type );
if( (cn != 1 && cn != 3) || !CV_ARE_CNS_EQ( src, dst ))
CV_Error( CV_StsUnsupportedFormat, "" );
src_size = cvGetMatSize( src );
dst_size = cvGetMatSize( dst );
/*if( dst_size.width > src_size.width || dst_size.height > src_size.height )
CV_ERROR( CV_StsBadSize, "destination ROI must not be larger than source ROI" );*/
if( mat->rows != 2 || mat->cols != 3 )
CV_Error( CV_StsBadArg,
"Transformation matrix must be 2x3" );
if( CV_MAT_TYPE( mat->type ) == CV_32FC1 )
{
for( k = 0; k < 3; k++ )
{
m[k] = mat->data.fl[k];
m[3 + k] = ((float*)(mat->data.ptr + mat->step))[k];
}
}
else if( CV_MAT_TYPE( mat->type ) == CV_64FC1 )
{
for( k = 0; k < 3; k++ )
{
m[k] = (float)mat->data.db[k];
m[3 + k] = (float)((double*)(mat->data.ptr + mat->step))[k];
}
}
else
CV_Error( CV_StsUnsupportedFormat,
"The transformation matrix should have 32fC1 or 64fC1 type" );
if( CV_ARE_DEPTHS_EQ( src, dst ))
{
func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[CV_MAT_DEPTH(src->type)]);
}
else
{
if( CV_MAT_DEPTH( src->type ) != CV_8U || CV_MAT_DEPTH( dst->type ) != CV_32F )
CV_Error( CV_StsUnsupportedFormat, "" );
func = (CvGetQuadrangleSubPixFunc)(gq_tab[cn != 1].fn_2d[1]);
}
if( !func )
CV_Error( CV_StsUnsupportedFormat, "" );
IPPI_CALL( func( src->data.ptr, src->step, src_size,
dst->data.ptr, dst->step, dst_size, m ));
}
void cv::getRectSubPix( const Mat& image, Size patchSize, Point2f center,
Mat& patch, int patchType )
{
patch.create(patchSize, patchType < 0 ? image.type() :
CV_MAKETYPE(CV_MAT_DEPTH(patchType),image.channels()));
CvMat _image = image, _patch = patch;
cvGetRectSubPix(&_image, &_patch, center);
}
/* End of file. */

View File

@@ -0,0 +1,531 @@
/*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"
/****************************************************************************************\
* Watershed *
\****************************************************************************************/
typedef struct CvWSNode
{
struct CvWSNode* next;
int mask_ofs;
int img_ofs;
}
CvWSNode;
typedef struct CvWSQueue
{
CvWSNode* first;
CvWSNode* last;
}
CvWSQueue;
static CvWSNode*
icvAllocWSNodes( CvMemStorage* storage )
{
CvWSNode* n = 0;
int i, count = (storage->block_size - sizeof(CvMemBlock))/sizeof(*n) - 1;
n = (CvWSNode*)cvMemStorageAlloc( storage, count*sizeof(*n) );
for( i = 0; i < count-1; i++ )
n[i].next = n + i + 1;
n[count-1].next = 0;
return n;
}
CV_IMPL void
cvWatershed( const CvArr* srcarr, CvArr* dstarr )
{
const int IN_QUEUE = -2;
const int WSHED = -1;
const int NQ = 256;
cv::Ptr<CvMemStorage> storage;
CvMat sstub, *src;
CvMat dstub, *dst;
CvSize size;
CvWSNode* free_node = 0, *node;
CvWSQueue q[NQ];
int active_queue;
int i, j;
int db, dg, dr;
int* mask;
uchar* img;
int mstep, istep;
int subs_tab[513];
// MAX(a,b) = b + MAX(a-b,0)
#define ws_max(a,b) ((b) + subs_tab[(a)-(b)+NQ])
// MIN(a,b) = a - MAX(a-b,0)
#define ws_min(a,b) ((a) - subs_tab[(a)-(b)+NQ])
#define ws_push(idx,mofs,iofs) \
{ \
if( !free_node ) \
free_node = icvAllocWSNodes( storage );\
node = free_node; \
free_node = free_node->next;\
node->next = 0; \
node->mask_ofs = mofs; \
node->img_ofs = iofs; \
if( q[idx].last ) \
q[idx].last->next=node; \
else \
q[idx].first = node; \
q[idx].last = node; \
}
#define ws_pop(idx,mofs,iofs) \
{ \
node = q[idx].first; \
q[idx].first = node->next; \
if( !node->next ) \
q[idx].last = 0; \
node->next = free_node; \
free_node = node; \
mofs = node->mask_ofs; \
iofs = node->img_ofs; \
}
#define c_diff(ptr1,ptr2,diff) \
{ \
db = abs((ptr1)[0] - (ptr2)[0]);\
dg = abs((ptr1)[1] - (ptr2)[1]);\
dr = abs((ptr1)[2] - (ptr2)[2]);\
diff = ws_max(db,dg); \
diff = ws_max(diff,dr); \
assert( 0 <= diff && diff <= 255 ); \
}
src = cvGetMat( srcarr, &sstub );
dst = cvGetMat( dstarr, &dstub );
if( CV_MAT_TYPE(src->type) != CV_8UC3 )
CV_Error( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel input images are supported" );
if( CV_MAT_TYPE(dst->type) != CV_32SC1 )
CV_Error( CV_StsUnsupportedFormat,
"Only 32-bit, 1-channel output images are supported" );
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedSizes, "The input and output images must have the same size" );
size = cvGetMatSize(src);
storage = cvCreateMemStorage();
istep = src->step;
img = src->data.ptr;
mstep = dst->step / sizeof(mask[0]);
mask = dst->data.i;
memset( q, 0, NQ*sizeof(q[0]) );
for( i = 0; i < 256; i++ )
subs_tab[i] = 0;
for( i = 256; i <= 512; i++ )
subs_tab[i] = i - 256;
// draw a pixel-wide border of dummy "watershed" (i.e. boundary) pixels
for( j = 0; j < size.width; j++ )
mask[j] = mask[j + mstep*(size.height-1)] = WSHED;
// initial phase: put all the neighbor pixels of each marker to the ordered queue -
// determine the initial boundaries of the basins
for( i = 1; i < size.height-1; i++ )
{
img += istep; mask += mstep;
mask[0] = mask[size.width-1] = WSHED;
for( j = 1; j < size.width-1; j++ )
{
int* m = mask + j;
if( m[0] < 0 ) m[0] = 0;
if( m[0] == 0 && (m[-1] > 0 || m[1] > 0 || m[-mstep] > 0 || m[mstep] > 0) )
{
uchar* ptr = img + j*3;
int idx = 256, t;
if( m[-1] > 0 )
c_diff( ptr, ptr - 3, idx );
if( m[1] > 0 )
{
c_diff( ptr, ptr + 3, t );
idx = ws_min( idx, t );
}
if( m[-mstep] > 0 )
{
c_diff( ptr, ptr - istep, t );
idx = ws_min( idx, t );
}
if( m[mstep] > 0 )
{
c_diff( ptr, ptr + istep, t );
idx = ws_min( idx, t );
}
assert( 0 <= idx && idx <= 255 );
ws_push( idx, i*mstep + j, i*istep + j*3 );
m[0] = IN_QUEUE;
}
}
}
// find the first non-empty queue
for( i = 0; i < NQ; i++ )
if( q[i].first )
break;
// if there is no markers, exit immediately
if( i == NQ )
return;
active_queue = i;
img = src->data.ptr;
mask = dst->data.i;
// recursively fill the basins
for(;;)
{
int mofs, iofs;
int lab = 0, t;
int* m;
uchar* ptr;
if( q[active_queue].first == 0 )
{
for( i = active_queue+1; i < NQ; i++ )
if( q[i].first )
break;
if( i == NQ )
break;
active_queue = i;
}
ws_pop( active_queue, mofs, iofs );
m = mask + mofs;
ptr = img + iofs;
t = m[-1];
if( t > 0 ) lab = t;
t = m[1];
if( t > 0 )
{
if( lab == 0 ) lab = t;
else if( t != lab ) lab = WSHED;
}
t = m[-mstep];
if( t > 0 )
{
if( lab == 0 ) lab = t;
else if( t != lab ) lab = WSHED;
}
t = m[mstep];
if( t > 0 )
{
if( lab == 0 ) lab = t;
else if( t != lab ) lab = WSHED;
}
assert( lab != 0 );
m[0] = lab;
if( lab == WSHED )
continue;
if( m[-1] == 0 )
{
c_diff( ptr, ptr - 3, t );
ws_push( t, mofs - 1, iofs - 3 );
active_queue = ws_min( active_queue, t );
m[-1] = IN_QUEUE;
}
if( m[1] == 0 )
{
c_diff( ptr, ptr + 3, t );
ws_push( t, mofs + 1, iofs + 3 );
active_queue = ws_min( active_queue, t );
m[1] = IN_QUEUE;
}
if( m[-mstep] == 0 )
{
c_diff( ptr, ptr - istep, t );
ws_push( t, mofs - mstep, iofs - istep );
active_queue = ws_min( active_queue, t );
m[-mstep] = IN_QUEUE;
}
if( m[mstep] == 0 )
{
c_diff( ptr, ptr + istep, t );
ws_push( t, mofs + mstep, iofs + istep );
active_queue = ws_min( active_queue, t );
m[mstep] = IN_QUEUE;
}
}
}
void cv::watershed( const Mat& src, Mat& markers )
{
CvMat _src = src, _markers = markers;
cvWatershed( &_src, &_markers );
}
/****************************************************************************************\
* Meanshift *
\****************************************************************************************/
CV_IMPL void
cvPyrMeanShiftFiltering( const CvArr* srcarr, CvArr* dstarr,
double sp0, double sr, int max_level,
CvTermCriteria termcrit )
{
const int cn = 3;
const int MAX_LEVELS = 8;
cv::Ptr<CvMat> src_pyramid[MAX_LEVELS+1];
cv::Ptr<CvMat> dst_pyramid[MAX_LEVELS+1];
cv::Ptr<CvMat> mask0;
int i, j, level;
//uchar* submask = 0;
#define cdiff(ofs0) (tab[c0-dptr[ofs0]+255] + \
tab[c1-dptr[(ofs0)+1]+255] + tab[c2-dptr[(ofs0)+2]+255] >= isr22)
memset( src_pyramid, 0, sizeof(src_pyramid) );
memset( dst_pyramid, 0, sizeof(dst_pyramid) );
double sr2 = sr * sr;
int isr2 = cvRound(sr2), isr22 = MAX(isr2,16);
int tab[768];
CvMat sstub0, *src0;
CvMat dstub0, *dst0;
src0 = cvGetMat( srcarr, &sstub0 );
dst0 = cvGetMat( dstarr, &dstub0 );
if( CV_MAT_TYPE(src0->type) != CV_8UC3 )
CV_Error( CV_StsUnsupportedFormat, "Only 8-bit, 3-channel images are supported" );
if( !CV_ARE_TYPES_EQ( src0, dst0 ))
CV_Error( CV_StsUnmatchedFormats, "The input and output images must have the same type" );
if( !CV_ARE_SIZES_EQ( src0, dst0 ))
CV_Error( CV_StsUnmatchedSizes, "The input and output images must have the same size" );
if( (unsigned)max_level > (unsigned)MAX_LEVELS )
CV_Error( CV_StsOutOfRange, "The number of pyramid levels is too large or negative" );
if( !(termcrit.type & CV_TERMCRIT_ITER) )
termcrit.max_iter = 5;
termcrit.max_iter = MAX(termcrit.max_iter,1);
termcrit.max_iter = MIN(termcrit.max_iter,100);
if( !(termcrit.type & CV_TERMCRIT_EPS) )
termcrit.epsilon = 1.f;
termcrit.epsilon = MAX(termcrit.epsilon, 0.f);
for( i = 0; i < 768; i++ )
tab[i] = (i - 255)*(i - 255);
// 1. construct pyramid
src_pyramid[0] = src0;
dst_pyramid[0] = dst0;
for( level = 1; level <= max_level; level++ )
{
src_pyramid[level] = cvCreateMat( (src_pyramid[level-1]->rows+1)/2,
(src_pyramid[level-1]->cols+1)/2, src_pyramid[level-1]->type );
dst_pyramid[level] = cvCreateMat( src_pyramid[level]->rows,
src_pyramid[level]->cols, src_pyramid[level]->type );
cvPyrDown( src_pyramid[level-1], src_pyramid[level] );
//CV_CALL( cvResize( src_pyramid[level-1], src_pyramid[level], CV_INTER_AREA ));
}
mask0 = cvCreateMat( src0->rows, src0->cols, CV_8UC1 );
//CV_CALL( submask = (uchar*)cvAlloc( (sp+2)*(sp+2) ));
// 2. apply meanshift, starting from the pyramid top (i.e. the smallest layer)
for( level = max_level; level >= 0; level-- )
{
CvMat* src = src_pyramid[level];
CvSize size = cvGetMatSize(src);
uchar* sptr = src->data.ptr;
int sstep = src->step;
uchar* mask = 0;
int mstep = 0;
uchar* dptr;
int dstep;
float sp = (float)(sp0 / (1 << level));
sp = MAX( sp, 1 );
if( level < max_level )
{
CvSize size1 = cvGetMatSize(dst_pyramid[level+1]);
CvMat m = cvMat( size.height, size.width, CV_8UC1, mask0->data.ptr );
dstep = dst_pyramid[level+1]->step;
dptr = dst_pyramid[level+1]->data.ptr + dstep + cn;
mstep = m.step;
mask = m.data.ptr + mstep;
//cvResize( dst_pyramid[level+1], dst_pyramid[level], CV_INTER_CUBIC );
cvPyrUp( dst_pyramid[level+1], dst_pyramid[level] );
cvZero( &m );
for( i = 1; i < size1.height-1; i++, dptr += dstep - (size1.width-2)*3, mask += mstep*2 )
{
for( j = 1; j < size1.width-1; j++, dptr += cn )
{
int c0 = dptr[0], c1 = dptr[1], c2 = dptr[2];
mask[j*2 - 1] = cdiff(-3) || cdiff(3) || cdiff(-dstep-3) || cdiff(-dstep) ||
cdiff(-dstep+3) || cdiff(dstep-3) || cdiff(dstep) || cdiff(dstep+3);
}
}
cvDilate( &m, &m, 0, 1 );
mask = m.data.ptr;
}
dptr = dst_pyramid[level]->data.ptr;
dstep = dst_pyramid[level]->step;
for( i = 0; i < size.height; i++, sptr += sstep - size.width*3,
dptr += dstep - size.width*3,
mask += mstep )
{
for( j = 0; j < size.width; j++, sptr += 3, dptr += 3 )
{
int x0 = j, y0 = i, x1, y1, iter;
int c0, c1, c2;
if( mask && !mask[j] )
continue;
c0 = sptr[0], c1 = sptr[1], c2 = sptr[2];
// iterate meanshift procedure
for( iter = 0; iter < termcrit.max_iter; iter++ )
{
uchar* ptr;
int x, y, count = 0;
int minx, miny, maxx, maxy;
int s0 = 0, s1 = 0, s2 = 0, sx = 0, sy = 0;
double icount;
int stop_flag;
//mean shift: process pixels in window (p-sigmaSp)x(p+sigmaSp)
minx = cvRound(x0 - sp); minx = MAX(minx, 0);
miny = cvRound(y0 - sp); miny = MAX(miny, 0);
maxx = cvRound(x0 + sp); maxx = MIN(maxx, size.width-1);
maxy = cvRound(y0 + sp); maxy = MIN(maxy, size.height-1);
ptr = sptr + (miny - i)*sstep + (minx - j)*3;
for( y = miny; y <= maxy; y++, ptr += sstep - (maxx-minx+1)*3 )
{
int row_count = 0;
x = minx;
for( ; x + 3 <= maxx; x += 4, ptr += 12 )
{
int t0 = ptr[0], t1 = ptr[1], t2 = ptr[2];
if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
{
s0 += t0; s1 += t1; s2 += t2;
sx += x; row_count++;
}
t0 = ptr[3], t1 = ptr[4], t2 = ptr[5];
if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
{
s0 += t0; s1 += t1; s2 += t2;
sx += x+1; row_count++;
}
t0 = ptr[6], t1 = ptr[7], t2 = ptr[8];
if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
{
s0 += t0; s1 += t1; s2 += t2;
sx += x+2; row_count++;
}
t0 = ptr[9], t1 = ptr[10], t2 = ptr[11];
if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
{
s0 += t0; s1 += t1; s2 += t2;
sx += x+3; row_count++;
}
}
for( ; x <= maxx; x++, ptr += 3 )
{
int t0 = ptr[0], t1 = ptr[1], t2 = ptr[2];
if( tab[t0-c0+255] + tab[t1-c1+255] + tab[t2-c2+255] <= isr2 )
{
s0 += t0; s1 += t1; s2 += t2;
sx += x; row_count++;
}
}
count += row_count;
sy += y*row_count;
}
if( count == 0 )
break;
icount = 1./count;
x1 = cvRound(sx*icount);
y1 = cvRound(sy*icount);
s0 = cvRound(s0*icount);
s1 = cvRound(s1*icount);
s2 = cvRound(s2*icount);
stop_flag = (x0 == x1 && y0 == y1) || abs(x1-x0) + abs(y1-y0) +
tab[s0 - c0 + 255] + tab[s1 - c1 + 255] +
tab[s2 - c2 + 255] <= termcrit.epsilon;
x0 = x1; y0 = y1;
c0 = s0; c1 = s1; c2 = s2;
if( stop_flag )
break;
}
dptr[0] = (uchar)c0;
dptr[1] = (uchar)c1;
dptr[2] = (uchar)c2;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,484 @@
/* 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
bool* cache; // visited or not
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
};
// 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->cache = (bool*)cvAlloc( sizeof(bool)*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( CvSpillTreeNode** heap,
int i,
const int k )
{
if ( heap[i] == NULL )
return;
int l, r, largest = i;
CvSpillTreeNode* inp;
do {
i = largest;
r = (i+1)<<1;
l = r-1;
if (( l < k )&&( heap[l] == NULL ))
largest = l;
else if (( r < k )&&( heap[r] == NULL ))
largest = r;
else {
if (( l < k )&&( heap[l]->mp > heap[i]->mp ))
largest = l;
if (( r < k )&&( heap[r]->mp > heap[largest]->mp ))
largest = r;
}
if ( largest != i )
CV_SWAP( heap[largest], heap[i], inp );
} while ( largest != i );
}
static void
icvSpillTreeDFSearch( CvSpillTree* tr,
CvSpillTreeNode* node,
CvSpillTreeNode** heap,
int* es,
const CvMat* desc,
const int k,
const int emax )
{
if ((emax > 0)&&( *es >= emax ))
return;
double dist, p=0;
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 ( !tr->cache[it->i] )
{
it->mp = cvNorm( it->center, desc );
tr->cache[it->i] = true;
if (( heap[0] == NULL)||( it->mp < heap[0]->mp ))
{
heap[0] = it;
icvSpillTreeNodeHeapify( heap, 0, k );
(*es)++;
}
}
it = it->rc;
}
return;
}
dist = cvNorm( node->center, desc );
// impossible case, skip
if (( heap[0] != NULL )&&( dist-node->r > heap[0]->mp ))
return;
p = cvDotProduct( node->u, desc );
// guided dfs
if ( p < node->mp )
{
icvSpillTreeDFSearch( tr, node->lc, heap, es, desc, k, emax );
icvSpillTreeDFSearch( tr, node->rc, heap, es, desc, k, emax );
} else {
icvSpillTreeDFSearch( tr, node->rc, heap, es, desc, k, emax );
icvSpillTreeDFSearch( tr, node->lc, heap, es, desc, k, emax );
}
}
static void
icvFindSpillTreeFeatures( CvSpillTree* tr,
const CvMat* desc,
CvMat* results,
CvMat* dist,
const int k,
const int emax )
{
assert( desc->type == tr->type );
CvSpillTreeNode** heap = (CvSpillTreeNode**)cvAlloc( k*sizeof(heap[0]) );
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++ )
heap[i] = NULL;
memset( tr->cache, 0, sizeof(bool)*tr->total );
int es = 0;
icvSpillTreeDFSearch( tr, tr->root, heap, &es, &_desc, k, emax );
CvSpillTreeNode* 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] != NULL )
{
*rs = heap[i]->i;
*dt = heap[i]->mp;
} else
*rs = -1;
}
cvFree( &heap );
}
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) );
cvFree( &((*tr)->cache) );
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);
}

View File

@@ -0,0 +1,714 @@
/*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"
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);
Cv32suf cw_area;
cw_area.f = (float)cvTriangleArea( pt, dst->pt, org->pt );
return (cw_area.i > 0)*2 - (cw_area.i*2 != 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 )
{
double val = (a.x * a.x + a.y * a.y) * cvTriangleArea( b, c, pt );
val -= (b.x * b.x + b.y * b.y) * cvTriangleArea( a, c, pt );
val += (c.x * c.x + c.y * c.y) * cvTriangleArea( a, b, pt );
val -= (pt.x * pt.x + pt.y * pt.y) * cvTriangleArea( a, b, c );
return val > FLT_EPSILON ? 1 : val < -FLT_EPSILON ? -1 : 0;
}
CV_IMPL CvSubdiv2DPoint *
cvSubdivDelaunay2DInsert( CvSubdiv2D * subdiv, CvPoint2D32f pt )
{
CvSubdiv2DPoint *point = 0;
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:
point = curr_point;
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 )
{
Cv32suf cw_area;
cw_area.f = (org.x - pt.x)*diff.y - (org.y - pt.y)*diff.x;
return (cw_area.i > 0)*2 - (cw_area.i*2 != 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;
}
/* End of file. */

View File

@@ -0,0 +1,289 @@
/*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.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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"
namespace cv
{
template<typename QT> inline QT sqr(uchar a) { return a*a; }
template<typename QT> inline QT sqr(float a) { return a*a; }
template<typename QT> inline QT sqr(double a) { return a*a; }
template<> inline double sqr(uchar a) { return CV_8TO32F_SQR(a); }
template<typename T, typename ST, typename QT>
void integral_( const Mat& _src, Mat& _sum, Mat& _sqsum, Mat& _tilted )
{
int cn = _src.channels();
Size size = _src.size();
int x, y, k;
const T* src = (const T*)_src.data;
ST* sum = (ST*)_sum.data;
ST* tilted = (ST*)_tilted.data;
QT* sqsum = (QT*)_sqsum.data;
int srcstep = (int)(_src.step/sizeof(T));
int sumstep = (int)(_sum.step/sizeof(ST));
int tiltedstep = (int)(_tilted.step/sizeof(ST));
int sqsumstep = (int)(_sqsum.step/sizeof(QT));
size.width *= cn;
memset( sum, 0, (size.width+cn)*sizeof(sum[0]));
sum += sumstep + cn;
if( sqsum )
{
memset( sqsum, 0, (size.width+cn)*sizeof(sqsum[0]));
sqsum += sqsumstep + cn;
}
if( tilted )
{
memset( tilted, 0, (size.width+cn)*sizeof(tilted[0]));
tilted += tiltedstep + cn;
}
if( sqsum == 0 && tilted == 0 )
{
for( y = 0; y < size.height; y++, src += srcstep - cn, sum += sumstep - cn )
{
for( k = 0; k < cn; k++, src++, sum++ )
{
ST s = sum[-cn] = 0;
for( x = 0; x < size.width; x += cn )
{
s += src[x];
sum[x] = sum[x - sumstep] + s;
}
}
}
}
else if( tilted == 0 )
{
for( y = 0; y < size.height; y++, src += srcstep - cn,
sum += sumstep - cn, sqsum += sqsumstep - cn )
{
for( k = 0; k < cn; k++, src++, sum++, sqsum++ )
{
ST s = sum[-cn] = 0;
QT sq = sqsum[-cn] = 0;
for( x = 0; x < size.width; x += cn )
{
T it = src[x];
s += it;
sq += sqr<QT>(it);
ST t = sum[x - sumstep] + s;
QT tq = sqsum[x - sqsumstep] + sq;
sum[x] = t;
sqsum[x] = tq;
}
}
}
}
else
{
AutoBuffer<ST> _buf(size.width+cn);
ST* buf = _buf;
ST s;
QT sq;
for( k = 0; k < cn; k++, src++, sum++, tilted++, sqsum++, buf++ )
{
sum[-cn] = tilted[-cn] = 0;
sqsum[-cn] = 0;
for( x = 0, s = 0, sq = 0; x < size.width; x += cn )
{
T it = src[x];
buf[x] = tilted[x] = it;
s += it;
sq += sqr<QT>(it);
sum[x] = s;
sqsum[x] = sq;
}
if( size.width == cn )
buf[cn] = 0;
}
for( y = 1; y < size.height; y++ )
{
src += srcstep - cn;
sum += sumstep - cn;
sqsum += sqsumstep - cn;
tilted += tiltedstep - cn;
buf += -cn;
for( k = 0; k < cn; k++, src++, sum++, sqsum++, tilted++, buf++ )
{
T it = src[0];
ST t0 = s = it;
QT tq0 = sq = sqr<QT>(it);
sum[-cn] = 0;
sqsum[-cn] = 0;
tilted[-cn] = tilted[-tiltedstep];
sum[0] = sum[-sumstep] + t0;
sqsum[0] = sqsum[-sqsumstep] + tq0;
tilted[0] = tilted[-tiltedstep] + t0 + buf[cn];
for( x = cn; x < size.width - cn; x += cn )
{
ST t1 = buf[x];
buf[x - cn] = t1 + t0;
t0 = it = src[x];
tq0 = sqr<QT>(it);
s += t0;
sq += tq0;
sum[x] = sum[x - sumstep] + s;
sqsum[x] = sqsum[x - sqsumstep] + sq;
t1 += buf[x + cn] + t0 + tilted[x - tiltedstep - cn];
tilted[x] = t1;
}
if( size.width > cn )
{
ST t1 = buf[x];
buf[x - cn] = t1 + t0;
t0 = it = src[x];
tq0 = sqr<QT>(it);
s += t0;
sq += tq0;
sum[x] = sum[x - sumstep] + s;
sqsum[x] = sqsum[x - sqsumstep] + sq;
tilted[x] = t0 + t1 + tilted[x - tiltedstep - cn];
buf[x] = t0;
}
}
}
}
}
typedef void (*IntegralFunc)(const Mat& _src, Mat& _sum, Mat& _sqsum, Mat& _tilted );
static void
integral( const Mat& src, Mat& sum, Mat* _sqsum, Mat* _tilted, int sdepth )
{
int depth = src.depth(), cn = src.channels();
Size isize(src.cols + 1, src.rows+1);
Mat sqsum, tilted;
if( sdepth <= 0 )
sdepth = depth == CV_8U ? CV_32S : CV_64F;
sdepth = CV_MAT_DEPTH(sdepth);
sum.create( isize, CV_MAKETYPE(sdepth, cn) );
if( _tilted )
_tilted->create( isize, CV_MAKETYPE(sdepth, cn) );
else
_tilted = &tilted;
if( !_sqsum )
_sqsum = &sqsum;
if( _sqsum != &sqsum || _tilted->data )
_sqsum->create( isize, CV_MAKETYPE(CV_64F, cn) );
IntegralFunc func = 0;
if( depth == CV_8U && sdepth == CV_32S )
func = integral_<uchar, int, double>;
else if( depth == CV_8U && sdepth == CV_32F )
func = integral_<uchar, float, double>;
else if( depth == CV_8U && sdepth == CV_64F )
func = integral_<uchar, double, double>;
else if( depth == CV_32F && sdepth == CV_64F )
func = integral_<float, double, double>;
else if( depth == CV_64F && sdepth == CV_64F )
func = integral_<double, double, double>;
else
CV_Error( CV_StsUnsupportedFormat, "" );
func( src, sum, *_sqsum, *_tilted );
}
void integral( const Mat& src, Mat& sum, int sdepth )
{
integral( src, sum, 0, 0, sdepth );
}
void integral( const Mat& src, Mat& sum, Mat& sqsum, int sdepth )
{
integral( src, sum, &sqsum, 0, sdepth );
}
void integral( const Mat& src, Mat& sum, Mat& sqsum, Mat& tilted, int sdepth )
{
integral( src, sum, &sqsum, &tilted, sdepth );
}
}
CV_IMPL void
cvIntegral( const CvArr* image, CvArr* sumImage,
CvArr* sumSqImage, CvArr* tiltedSumImage )
{
cv::Mat src = cv::cvarrToMat(image), sum = cv::cvarrToMat(sumImage), sum0 = sum;
cv::Mat sqsum0, sqsum, tilted0, tilted;
cv::Mat *psqsum = 0, *ptilted = 0;
if( sumSqImage )
{
sqsum0 = sqsum = cv::cvarrToMat(sumSqImage);
psqsum = &sqsum;
}
if( tiltedSumImage )
{
tilted0 = tilted = cv::cvarrToMat(tiltedSumImage);
ptilted = &tilted;
}
cv::integral( src, sum, psqsum, ptilted, sum.depth() );
CV_Assert( sum.data == sum0.data && sqsum.data == sqsum0.data && tilted.data == tilted0.data );
}
/* End of file. */

View File

@@ -0,0 +1,214 @@
/* ////////////////////////////////////////////////////////////////////
//
// CvMat helper tables
//
// */
#include "precomp.hpp"
const float icv8x32fTab_cv[] =
{
-256.f, -255.f, -254.f, -253.f, -252.f, -251.f, -250.f, -249.f,
-248.f, -247.f, -246.f, -245.f, -244.f, -243.f, -242.f, -241.f,
-240.f, -239.f, -238.f, -237.f, -236.f, -235.f, -234.f, -233.f,
-232.f, -231.f, -230.f, -229.f, -228.f, -227.f, -226.f, -225.f,
-224.f, -223.f, -222.f, -221.f, -220.f, -219.f, -218.f, -217.f,
-216.f, -215.f, -214.f, -213.f, -212.f, -211.f, -210.f, -209.f,
-208.f, -207.f, -206.f, -205.f, -204.f, -203.f, -202.f, -201.f,
-200.f, -199.f, -198.f, -197.f, -196.f, -195.f, -194.f, -193.f,
-192.f, -191.f, -190.f, -189.f, -188.f, -187.f, -186.f, -185.f,
-184.f, -183.f, -182.f, -181.f, -180.f, -179.f, -178.f, -177.f,
-176.f, -175.f, -174.f, -173.f, -172.f, -171.f, -170.f, -169.f,
-168.f, -167.f, -166.f, -165.f, -164.f, -163.f, -162.f, -161.f,
-160.f, -159.f, -158.f, -157.f, -156.f, -155.f, -154.f, -153.f,
-152.f, -151.f, -150.f, -149.f, -148.f, -147.f, -146.f, -145.f,
-144.f, -143.f, -142.f, -141.f, -140.f, -139.f, -138.f, -137.f,
-136.f, -135.f, -134.f, -133.f, -132.f, -131.f, -130.f, -129.f,
-128.f, -127.f, -126.f, -125.f, -124.f, -123.f, -122.f, -121.f,
-120.f, -119.f, -118.f, -117.f, -116.f, -115.f, -114.f, -113.f,
-112.f, -111.f, -110.f, -109.f, -108.f, -107.f, -106.f, -105.f,
-104.f, -103.f, -102.f, -101.f, -100.f, -99.f, -98.f, -97.f,
-96.f, -95.f, -94.f, -93.f, -92.f, -91.f, -90.f, -89.f,
-88.f, -87.f, -86.f, -85.f, -84.f, -83.f, -82.f, -81.f,
-80.f, -79.f, -78.f, -77.f, -76.f, -75.f, -74.f, -73.f,
-72.f, -71.f, -70.f, -69.f, -68.f, -67.f, -66.f, -65.f,
-64.f, -63.f, -62.f, -61.f, -60.f, -59.f, -58.f, -57.f,
-56.f, -55.f, -54.f, -53.f, -52.f, -51.f, -50.f, -49.f,
-48.f, -47.f, -46.f, -45.f, -44.f, -43.f, -42.f, -41.f,
-40.f, -39.f, -38.f, -37.f, -36.f, -35.f, -34.f, -33.f,
-32.f, -31.f, -30.f, -29.f, -28.f, -27.f, -26.f, -25.f,
-24.f, -23.f, -22.f, -21.f, -20.f, -19.f, -18.f, -17.f,
-16.f, -15.f, -14.f, -13.f, -12.f, -11.f, -10.f, -9.f,
-8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f,
0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f,
8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f,
16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f,
24.f, 25.f, 26.f, 27.f, 28.f, 29.f, 30.f, 31.f,
32.f, 33.f, 34.f, 35.f, 36.f, 37.f, 38.f, 39.f,
40.f, 41.f, 42.f, 43.f, 44.f, 45.f, 46.f, 47.f,
48.f, 49.f, 50.f, 51.f, 52.f, 53.f, 54.f, 55.f,
56.f, 57.f, 58.f, 59.f, 60.f, 61.f, 62.f, 63.f,
64.f, 65.f, 66.f, 67.f, 68.f, 69.f, 70.f, 71.f,
72.f, 73.f, 74.f, 75.f, 76.f, 77.f, 78.f, 79.f,
80.f, 81.f, 82.f, 83.f, 84.f, 85.f, 86.f, 87.f,
88.f, 89.f, 90.f, 91.f, 92.f, 93.f, 94.f, 95.f,
96.f, 97.f, 98.f, 99.f, 100.f, 101.f, 102.f, 103.f,
104.f, 105.f, 106.f, 107.f, 108.f, 109.f, 110.f, 111.f,
112.f, 113.f, 114.f, 115.f, 116.f, 117.f, 118.f, 119.f,
120.f, 121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f,
128.f, 129.f, 130.f, 131.f, 132.f, 133.f, 134.f, 135.f,
136.f, 137.f, 138.f, 139.f, 140.f, 141.f, 142.f, 143.f,
144.f, 145.f, 146.f, 147.f, 148.f, 149.f, 150.f, 151.f,
152.f, 153.f, 154.f, 155.f, 156.f, 157.f, 158.f, 159.f,
160.f, 161.f, 162.f, 163.f, 164.f, 165.f, 166.f, 167.f,
168.f, 169.f, 170.f, 171.f, 172.f, 173.f, 174.f, 175.f,
176.f, 177.f, 178.f, 179.f, 180.f, 181.f, 182.f, 183.f,
184.f, 185.f, 186.f, 187.f, 188.f, 189.f, 190.f, 191.f,
192.f, 193.f, 194.f, 195.f, 196.f, 197.f, 198.f, 199.f,
200.f, 201.f, 202.f, 203.f, 204.f, 205.f, 206.f, 207.f,
208.f, 209.f, 210.f, 211.f, 212.f, 213.f, 214.f, 215.f,
216.f, 217.f, 218.f, 219.f, 220.f, 221.f, 222.f, 223.f,
224.f, 225.f, 226.f, 227.f, 228.f, 229.f, 230.f, 231.f,
232.f, 233.f, 234.f, 235.f, 236.f, 237.f, 238.f, 239.f,
240.f, 241.f, 242.f, 243.f, 244.f, 245.f, 246.f, 247.f,
248.f, 249.f, 250.f, 251.f, 252.f, 253.f, 254.f, 255.f,
256.f, 257.f, 258.f, 259.f, 260.f, 261.f, 262.f, 263.f,
264.f, 265.f, 266.f, 267.f, 268.f, 269.f, 270.f, 271.f,
272.f, 273.f, 274.f, 275.f, 276.f, 277.f, 278.f, 279.f,
280.f, 281.f, 282.f, 283.f, 284.f, 285.f, 286.f, 287.f,
288.f, 289.f, 290.f, 291.f, 292.f, 293.f, 294.f, 295.f,
296.f, 297.f, 298.f, 299.f, 300.f, 301.f, 302.f, 303.f,
304.f, 305.f, 306.f, 307.f, 308.f, 309.f, 310.f, 311.f,
312.f, 313.f, 314.f, 315.f, 316.f, 317.f, 318.f, 319.f,
320.f, 321.f, 322.f, 323.f, 324.f, 325.f, 326.f, 327.f,
328.f, 329.f, 330.f, 331.f, 332.f, 333.f, 334.f, 335.f,
336.f, 337.f, 338.f, 339.f, 340.f, 341.f, 342.f, 343.f,
344.f, 345.f, 346.f, 347.f, 348.f, 349.f, 350.f, 351.f,
352.f, 353.f, 354.f, 355.f, 356.f, 357.f, 358.f, 359.f,
360.f, 361.f, 362.f, 363.f, 364.f, 365.f, 366.f, 367.f,
368.f, 369.f, 370.f, 371.f, 372.f, 373.f, 374.f, 375.f,
376.f, 377.f, 378.f, 379.f, 380.f, 381.f, 382.f, 383.f,
384.f, 385.f, 386.f, 387.f, 388.f, 389.f, 390.f, 391.f,
392.f, 393.f, 394.f, 395.f, 396.f, 397.f, 398.f, 399.f,
400.f, 401.f, 402.f, 403.f, 404.f, 405.f, 406.f, 407.f,
408.f, 409.f, 410.f, 411.f, 412.f, 413.f, 414.f, 415.f,
416.f, 417.f, 418.f, 419.f, 420.f, 421.f, 422.f, 423.f,
424.f, 425.f, 426.f, 427.f, 428.f, 429.f, 430.f, 431.f,
432.f, 433.f, 434.f, 435.f, 436.f, 437.f, 438.f, 439.f,
440.f, 441.f, 442.f, 443.f, 444.f, 445.f, 446.f, 447.f,
448.f, 449.f, 450.f, 451.f, 452.f, 453.f, 454.f, 455.f,
456.f, 457.f, 458.f, 459.f, 460.f, 461.f, 462.f, 463.f,
464.f, 465.f, 466.f, 467.f, 468.f, 469.f, 470.f, 471.f,
472.f, 473.f, 474.f, 475.f, 476.f, 477.f, 478.f, 479.f,
480.f, 481.f, 482.f, 483.f, 484.f, 485.f, 486.f, 487.f,
488.f, 489.f, 490.f, 491.f, 492.f, 493.f, 494.f, 495.f,
496.f, 497.f, 498.f, 499.f, 500.f, 501.f, 502.f, 503.f,
504.f, 505.f, 506.f, 507.f, 508.f, 509.f, 510.f, 511.f,
};
const float icv8x32fSqrTab[] =
{
16384.f, 16129.f, 15876.f, 15625.f, 15376.f, 15129.f, 14884.f, 14641.f,
14400.f, 14161.f, 13924.f, 13689.f, 13456.f, 13225.f, 12996.f, 12769.f,
12544.f, 12321.f, 12100.f, 11881.f, 11664.f, 11449.f, 11236.f, 11025.f,
10816.f, 10609.f, 10404.f, 10201.f, 10000.f, 9801.f, 9604.f, 9409.f,
9216.f, 9025.f, 8836.f, 8649.f, 8464.f, 8281.f, 8100.f, 7921.f,
7744.f, 7569.f, 7396.f, 7225.f, 7056.f, 6889.f, 6724.f, 6561.f,
6400.f, 6241.f, 6084.f, 5929.f, 5776.f, 5625.f, 5476.f, 5329.f,
5184.f, 5041.f, 4900.f, 4761.f, 4624.f, 4489.f, 4356.f, 4225.f,
4096.f, 3969.f, 3844.f, 3721.f, 3600.f, 3481.f, 3364.f, 3249.f,
3136.f, 3025.f, 2916.f, 2809.f, 2704.f, 2601.f, 2500.f, 2401.f,
2304.f, 2209.f, 2116.f, 2025.f, 1936.f, 1849.f, 1764.f, 1681.f,
1600.f, 1521.f, 1444.f, 1369.f, 1296.f, 1225.f, 1156.f, 1089.f,
1024.f, 961.f, 900.f, 841.f, 784.f, 729.f, 676.f, 625.f,
576.f, 529.f, 484.f, 441.f, 400.f, 361.f, 324.f, 289.f,
256.f, 225.f, 196.f, 169.f, 144.f, 121.f, 100.f, 81.f,
64.f, 49.f, 36.f, 25.f, 16.f, 9.f, 4.f, 1.f,
0.f, 1.f, 4.f, 9.f, 16.f, 25.f, 36.f, 49.f,
64.f, 81.f, 100.f, 121.f, 144.f, 169.f, 196.f, 225.f,
256.f, 289.f, 324.f, 361.f, 400.f, 441.f, 484.f, 529.f,
576.f, 625.f, 676.f, 729.f, 784.f, 841.f, 900.f, 961.f,
1024.f, 1089.f, 1156.f, 1225.f, 1296.f, 1369.f, 1444.f, 1521.f,
1600.f, 1681.f, 1764.f, 1849.f, 1936.f, 2025.f, 2116.f, 2209.f,
2304.f, 2401.f, 2500.f, 2601.f, 2704.f, 2809.f, 2916.f, 3025.f,
3136.f, 3249.f, 3364.f, 3481.f, 3600.f, 3721.f, 3844.f, 3969.f,
4096.f, 4225.f, 4356.f, 4489.f, 4624.f, 4761.f, 4900.f, 5041.f,
5184.f, 5329.f, 5476.f, 5625.f, 5776.f, 5929.f, 6084.f, 6241.f,
6400.f, 6561.f, 6724.f, 6889.f, 7056.f, 7225.f, 7396.f, 7569.f,
7744.f, 7921.f, 8100.f, 8281.f, 8464.f, 8649.f, 8836.f, 9025.f,
9216.f, 9409.f, 9604.f, 9801.f, 10000.f, 10201.f, 10404.f, 10609.f,
10816.f, 11025.f, 11236.f, 11449.f, 11664.f, 11881.f, 12100.f, 12321.f,
12544.f, 12769.f, 12996.f, 13225.f, 13456.f, 13689.f, 13924.f, 14161.f,
14400.f, 14641.f, 14884.f, 15129.f, 15376.f, 15625.f, 15876.f, 16129.f,
16384.f, 16641.f, 16900.f, 17161.f, 17424.f, 17689.f, 17956.f, 18225.f,
18496.f, 18769.f, 19044.f, 19321.f, 19600.f, 19881.f, 20164.f, 20449.f,
20736.f, 21025.f, 21316.f, 21609.f, 21904.f, 22201.f, 22500.f, 22801.f,
23104.f, 23409.f, 23716.f, 24025.f, 24336.f, 24649.f, 24964.f, 25281.f,
25600.f, 25921.f, 26244.f, 26569.f, 26896.f, 27225.f, 27556.f, 27889.f,
28224.f, 28561.f, 28900.f, 29241.f, 29584.f, 29929.f, 30276.f, 30625.f,
30976.f, 31329.f, 31684.f, 32041.f, 32400.f, 32761.f, 33124.f, 33489.f,
33856.f, 34225.f, 34596.f, 34969.f, 35344.f, 35721.f, 36100.f, 36481.f,
36864.f, 37249.f, 37636.f, 38025.f, 38416.f, 38809.f, 39204.f, 39601.f,
40000.f, 40401.f, 40804.f, 41209.f, 41616.f, 42025.f, 42436.f, 42849.f,
43264.f, 43681.f, 44100.f, 44521.f, 44944.f, 45369.f, 45796.f, 46225.f,
46656.f, 47089.f, 47524.f, 47961.f, 48400.f, 48841.f, 49284.f, 49729.f,
50176.f, 50625.f, 51076.f, 51529.f, 51984.f, 52441.f, 52900.f, 53361.f,
53824.f, 54289.f, 54756.f, 55225.f, 55696.f, 56169.f, 56644.f, 57121.f,
57600.f, 58081.f, 58564.f, 59049.f, 59536.f, 60025.f, 60516.f, 61009.f,
61504.f, 62001.f, 62500.f, 63001.f, 63504.f, 64009.f, 64516.f, 65025.f
};
const uchar icvSaturate8u_cv[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255
};
/* End of file. */

View File

@@ -0,0 +1,488 @@
/*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"
void
icvCrossCorr( const CvArr* _img, const CvArr* _templ, CvArr* _corr,
CvPoint anchor, double delta, int borderType )
{
const int CV_MAX_THREADS = 1;
const double block_scale = 4.5;
const int min_block_size = 256;
cv::Ptr<CvMat> dft_img[CV_MAX_THREADS];
cv::Ptr<CvMat> dft_templ;
std::vector<uchar> buf[CV_MAX_THREADS];
int k, num_threads = 0;
CvMat istub, *img = (CvMat*)_img;
CvMat tstub, *templ = (CvMat*)_templ;
CvMat cstub, *corr = (CvMat*)_corr;
CvSize dftsize, blocksize;
int depth, templ_depth, corr_depth, max_depth = CV_32F,
cn, templ_cn, corr_cn, buf_size = 0,
tile_count_x, tile_count_y, tile_count;
img = cvGetMat( img, &istub );
templ = cvGetMat( templ, &tstub );
corr = cvGetMat( corr, &cstub );
if( CV_MAT_DEPTH( img->type ) != CV_8U &&
CV_MAT_DEPTH( img->type ) != CV_16U &&
CV_MAT_DEPTH( img->type ) != CV_32F &&
CV_MAT_DEPTH( img->type ) != CV_64F )
CV_Error( CV_StsUnsupportedFormat,
"The function supports only 8u, 16u and 32f data types" );
if( !CV_ARE_DEPTHS_EQ( img, templ ) && CV_MAT_DEPTH( templ->type ) != CV_32F )
CV_Error( CV_StsUnsupportedFormat,
"Template (kernel) must be of the same depth as the input image, or be 32f" );
if( !CV_ARE_DEPTHS_EQ( img, corr ) && CV_MAT_DEPTH( corr->type ) != CV_32F &&
CV_MAT_DEPTH( corr->type ) != CV_64F )
CV_Error( CV_StsUnsupportedFormat,
"The output image must have the same depth as the input image, or be 32f/64f" );
if( (!CV_ARE_CNS_EQ( img, corr ) || CV_MAT_CN(templ->type) > 1) &&
(CV_MAT_CN( corr->type ) > 1 || !CV_ARE_CNS_EQ( img, templ)) )
CV_Error( CV_StsUnsupportedFormat,
"The output must have the same number of channels as the input (when the template has 1 channel), "
"or the output must have 1 channel when the input and the template have the same number of channels" );
depth = CV_MAT_DEPTH(img->type);
cn = CV_MAT_CN(img->type);
templ_depth = CV_MAT_DEPTH(templ->type);
templ_cn = CV_MAT_CN(templ->type);
corr_depth = CV_MAT_DEPTH(corr->type);
corr_cn = CV_MAT_CN(corr->type);
CV_Assert( corr_cn == 1 || delta == 0 );
max_depth = MAX( max_depth, templ_depth );
max_depth = MAX( max_depth, depth );
max_depth = MAX( max_depth, corr_depth );
if( depth > CV_8U )
max_depth = CV_64F;
/*if( img->cols < templ->cols || img->rows < templ->rows )
CV_Error( CV_StsUnmatchedSizes,
"Such a combination of image and template/filter size is not supported" );*/
if( corr->rows > img->rows + templ->rows - 1 ||
corr->cols > img->cols + templ->cols - 1 )
CV_Error( CV_StsUnmatchedSizes,
"output image should not be greater than (W + w - 1)x(H + h - 1)" );
blocksize.width = cvRound(templ->cols*block_scale);
blocksize.width = MAX( blocksize.width, min_block_size - templ->cols + 1 );
blocksize.width = MIN( blocksize.width, corr->cols );
blocksize.height = cvRound(templ->rows*block_scale);
blocksize.height = MAX( blocksize.height, min_block_size - templ->rows + 1 );
blocksize.height = MIN( blocksize.height, corr->rows );
dftsize.width = cvGetOptimalDFTSize(blocksize.width + templ->cols - 1);
if( dftsize.width == 1 )
dftsize.width = 2;
dftsize.height = cvGetOptimalDFTSize(blocksize.height + templ->rows - 1);
if( dftsize.width <= 0 || dftsize.height <= 0 )
CV_Error( CV_StsOutOfRange, "the input arrays are too big" );
// recompute block size
blocksize.width = dftsize.width - templ->cols + 1;
blocksize.width = MIN( blocksize.width, corr->cols );
blocksize.height = dftsize.height - templ->rows + 1;
blocksize.height = MIN( blocksize.height, corr->rows );
dft_templ = cvCreateMat( dftsize.height*templ_cn, dftsize.width, max_depth );
#ifdef USE_OPENMP
num_threads = cvGetNumThreads();
#else
num_threads = 1;
#endif
for( k = 0; k < num_threads; k++ )
dft_img[k] = cvCreateMat( dftsize.height, dftsize.width, max_depth );
if( templ_cn > 1 && templ_depth != max_depth )
buf_size = templ->cols*templ->rows*CV_ELEM_SIZE(templ_depth);
if( cn > 1 && depth != max_depth )
buf_size = MAX( buf_size, (blocksize.width + templ->cols - 1)*
(blocksize.height + templ->rows - 1)*CV_ELEM_SIZE(depth));
if( (corr_cn > 1 || cn > 1) && corr_depth != max_depth )
buf_size = MAX( buf_size, blocksize.width*blocksize.height*CV_ELEM_SIZE(corr_depth));
if( buf_size > 0 )
{
for( k = 0; k < num_threads; k++ )
buf[k].resize(buf_size);
}
// compute DFT of each template plane
for( k = 0; k < templ_cn; k++ )
{
CvMat dstub, *src, *dst, temp;
CvMat* planes[] = { 0, 0, 0, 0 };
int yofs = k*dftsize.height;
src = templ;
dst = cvGetSubRect( dft_templ, &dstub, cvRect(0,yofs,templ->cols,templ->rows));
if( templ_cn > 1 )
{
planes[k] = templ_depth == max_depth ? dst :
cvInitMatHeader( &temp, templ->rows, templ->cols, templ_depth, &buf[0][0] );
cvSplit( templ, planes[0], planes[1], planes[2], planes[3] );
src = planes[k];
planes[k] = 0;
}
if( dst != src )
cvConvert( src, dst );
if( dft_templ->cols > templ->cols )
{
cvGetSubRect( dft_templ, dst, cvRect(templ->cols, yofs,
dft_templ->cols - templ->cols, templ->rows) );
cvZero( dst );
}
cvGetSubRect( dft_templ, dst, cvRect(0,yofs,dftsize.width,dftsize.height) );
cvDFT( dst, dst, CV_DXT_FORWARD + CV_DXT_SCALE, templ->rows );
}
tile_count_x = (corr->cols + blocksize.width - 1)/blocksize.width;
tile_count_y = (corr->rows + blocksize.height - 1)/blocksize.height;
tile_count = tile_count_x*tile_count_y;
#if defined _OPENMP && defined USE_OPENMP
#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
#endif
// calculate correlation by blocks
for( k = 0; k < tile_count; k++ )
{
#ifdef USE_OPENMP
int thread_idx = cvGetThreadNum();
#else
int thread_idx = 0;
#endif
int x = (k%tile_count_x)*blocksize.width;
int y = (k/tile_count_x)*blocksize.height;
int i, yofs;
CvMat sstub, dstub, *src, *dst, temp;
CvMat* planes[] = { 0, 0, 0, 0 };
CvMat* _dft_img = dft_img[thread_idx];
uchar* _buf = buf_size > 0 ? &buf[thread_idx][0] : 0;
CvSize csz = { blocksize.width, blocksize.height }, isz;
int x0 = x - anchor.x, y0 = y - anchor.y;
int x1 = MAX( 0, x0 ), y1 = MAX( 0, y0 ), x2, y2;
csz.width = MIN( csz.width, corr->cols - x );
csz.height = MIN( csz.height, corr->rows - y );
isz.width = csz.width + templ->cols - 1;
isz.height = csz.height + templ->rows - 1;
x2 = MIN( img->cols, x0 + isz.width );
y2 = MIN( img->rows, y0 + isz.height );
for( i = 0; i < cn; i++ )
{
CvMat dstub1, *dst1;
yofs = i*dftsize.height;
src = cvGetSubRect( img, &sstub, cvRect(x1,y1,x2-x1,y2-y1) );
dst = cvGetSubRect( _dft_img, &dstub,
cvRect(0,0,isz.width,isz.height) );
dst1 = dst;
if( x2 - x1 < isz.width || y2 - y1 < isz.height )
dst1 = cvGetSubRect( _dft_img, &dstub1,
cvRect( x1 - x0, y1 - y0, x2 - x1, y2 - y1 ));
if( cn > 1 )
{
planes[i] = dst1;
if( depth != max_depth )
planes[i] = cvInitMatHeader( &temp, y2 - y1, x2 - x1, depth, _buf );
cvSplit( src, planes[0], planes[1], planes[2], planes[3] );
src = planes[i];
planes[i] = 0;
}
if( dst1 != src )
cvConvert( src, dst1 );
if( dst != dst1 )
cvCopyMakeBorder( dst1, dst, cvPoint(x1 - x0, y1 - y0), borderType );
if( dftsize.width > isz.width )
{
cvGetSubRect( _dft_img, dst, cvRect(isz.width, 0,
dftsize.width - isz.width,dftsize.height) );
cvZero( dst );
}
cvDFT( _dft_img, _dft_img, CV_DXT_FORWARD, isz.height );
cvGetSubRect( dft_templ, dst,
cvRect(0,(templ_cn>1?yofs:0),dftsize.width,dftsize.height) );
cvMulSpectrums( _dft_img, dst, _dft_img, CV_DXT_MUL_CONJ );
cvDFT( _dft_img, _dft_img, CV_DXT_INVERSE, csz.height );
src = cvGetSubRect( _dft_img, &sstub, cvRect(0,0,csz.width,csz.height) );
dst = cvGetSubRect( corr, &dstub, cvRect(x,y,csz.width,csz.height) );
if( corr_cn > 1 )
{
planes[i] = src;
if( corr_depth != max_depth )
{
planes[i] = cvInitMatHeader( &temp, csz.height, csz.width,
corr_depth, _buf );
cvConvertScale( src, planes[i], 1, delta );
}
cvMerge( planes[0], planes[1], planes[2], planes[3], dst );
planes[i] = 0;
}
else
{
if( i == 0 )
cvConvertScale( src, dst, 1, delta );
else
{
if( max_depth > corr_depth )
{
cvInitMatHeader( &temp, csz.height, csz.width,
corr_depth, _buf );
cvConvert( src, &temp );
src = &temp;
}
cvAcc( src, dst );
}
}
}
}
}
void
cv::crossCorr( const Mat& img, const Mat& templ, Mat& corr,
Point anchor, double delta, int borderType )
{
CvMat _img = img, _templ = templ, _corr = corr;
icvCrossCorr( &_img, &_templ, &_corr, anchor, delta, borderType );
}
/*****************************************************************************************/
CV_IMPL void
cvMatchTemplate( const CvArr* _img, const CvArr* _templ, CvArr* _result, int method )
{
cv::Ptr<CvMat> sum, sqsum;
int coi1 = 0, coi2 = 0;
int depth, cn;
int i, j, k;
CvMat stub, *img = (CvMat*)_img;
CvMat tstub, *templ = (CvMat*)_templ;
CvMat rstub, *result = (CvMat*)_result;
CvScalar templ_mean = cvScalarAll(0);
double templ_norm = 0, templ_sum2 = 0;
int idx = 0, idx2 = 0;
double *p0, *p1, *p2, *p3;
double *q0, *q1, *q2, *q3;
double inv_area;
int sum_step, sqsum_step;
int num_type = method == CV_TM_CCORR || method == CV_TM_CCORR_NORMED ? 0 :
method == CV_TM_CCOEFF || method == CV_TM_CCOEFF_NORMED ? 1 : 2;
int is_normed = method == CV_TM_CCORR_NORMED ||
method == CV_TM_SQDIFF_NORMED ||
method == CV_TM_CCOEFF_NORMED;
img = cvGetMat( img, &stub, &coi1 );
templ = cvGetMat( templ, &tstub, &coi2 );
result = cvGetMat( result, &rstub );
if( CV_MAT_DEPTH( img->type ) != CV_8U &&
CV_MAT_DEPTH( img->type ) != CV_32F )
CV_Error( CV_StsUnsupportedFormat,
"The function supports only 8u and 32f data types" );
if( !CV_ARE_TYPES_EQ( img, templ ))
CV_Error( CV_StsUnmatchedSizes, "image and template should have the same type" );
if( CV_MAT_TYPE( result->type ) != CV_32FC1 )
CV_Error( CV_StsUnsupportedFormat, "output image should have 32f type" );
if( img->rows < templ->rows || img->cols < templ->cols )
{
CvMat* t;
CV_SWAP( img, templ, t );
}
if( result->rows != img->rows - templ->rows + 1 ||
result->cols != img->cols - templ->cols + 1 )
CV_Error( CV_StsUnmatchedSizes, "output image should be (W - w + 1)x(H - h + 1)" );
if( method < CV_TM_SQDIFF || method > CV_TM_CCOEFF_NORMED )
CV_Error( CV_StsBadArg, "unknown comparison method" );
depth = CV_MAT_DEPTH(img->type);
cn = CV_MAT_CN(img->type);
icvCrossCorr( img, templ, result );
if( method == CV_TM_CCORR )
return;
inv_area = 1./((double)templ->rows * templ->cols);
sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_MAKETYPE( CV_64F, cn ));
if( method == CV_TM_CCOEFF )
{
cvIntegral( img, sum, 0, 0 );
templ_mean = cvAvg( templ );
q0 = q1 = q2 = q3 = 0;
}
else
{
CvScalar _templ_sdv = cvScalarAll(0);
sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_MAKETYPE( CV_64F, cn ));
cvIntegral( img, sum, sqsum, 0 );
cvAvgSdv( templ, &templ_mean, &_templ_sdv );
templ_norm = CV_SQR(_templ_sdv.val[0]) + CV_SQR(_templ_sdv.val[1]) +
CV_SQR(_templ_sdv.val[2]) + CV_SQR(_templ_sdv.val[3]);
if( templ_norm < DBL_EPSILON && method == CV_TM_CCOEFF_NORMED )
{
cvSet( result, cvScalarAll(1.) );
return;
}
templ_sum2 = templ_norm +
CV_SQR(templ_mean.val[0]) + CV_SQR(templ_mean.val[1]) +
CV_SQR(templ_mean.val[2]) + CV_SQR(templ_mean.val[3]);
if( num_type != 1 )
{
templ_mean = cvScalarAll(0);
templ_norm = templ_sum2;
}
templ_sum2 /= inv_area;
templ_norm = sqrt(templ_norm);
templ_norm /= sqrt(inv_area); // care of accuracy here
q0 = (double*)sqsum->data.ptr;
q1 = q0 + templ->cols*cn;
q2 = (double*)(sqsum->data.ptr + templ->rows*sqsum->step);
q3 = q2 + templ->cols*cn;
}
p0 = (double*)sum->data.ptr;
p1 = p0 + templ->cols*cn;
p2 = (double*)(sum->data.ptr + templ->rows*sum->step);
p3 = p2 + templ->cols*cn;
sum_step = sum ? sum->step / sizeof(double) : 0;
sqsum_step = sqsum ? sqsum->step / sizeof(double) : 0;
for( i = 0; i < result->rows; i++ )
{
float* rrow = (float*)(result->data.ptr + i*result->step);
idx = i * sum_step;
idx2 = i * sqsum_step;
for( j = 0; j < result->cols; j++, idx += cn, idx2 += cn )
{
double num = rrow[j], t;
double wnd_mean2 = 0, wnd_sum2 = 0;
if( num_type == 1 )
{
for( k = 0; k < cn; k++ )
{
t = p0[idx+k] - p1[idx+k] - p2[idx+k] + p3[idx+k];
wnd_mean2 += CV_SQR(t);
num -= t*templ_mean.val[k];
}
wnd_mean2 *= inv_area;
}
if( is_normed || num_type == 2 )
{
for( k = 0; k < cn; k++ )
{
t = q0[idx2+k] - q1[idx2+k] - q2[idx2+k] + q3[idx2+k];
wnd_sum2 += t;
}
if( num_type == 2 )
num = wnd_sum2 - 2*num + templ_sum2;
}
if( is_normed )
{
t = sqrt(MAX(wnd_sum2 - wnd_mean2,0))*templ_norm;
if( fabs(num) < t )
num /= t;
else if( fabs(num) < t*1.125 )
num = num > 0 ? 1 : -1;
else
num = method != CV_TM_SQDIFF_NORMED ? 0 : 1;
}
rrow[j] = (float)num;
}
}
}
void cv::matchTemplate( const Mat& image, const Mat& templ, Mat& result, int method )
{
result.create( std::abs(image.rows - templ.rows) + 1,
std::abs(image.cols - templ.cols) + 1, CV_32F );
CvMat _image = image, _templ = templ, _result = result;
cvMatchTemplate( &_image, &_templ, &_result, method );
}
/* End of file. */

View File

@@ -0,0 +1,611 @@
/*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.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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"
namespace cv
{
static void
thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
{
int i, j, j_scalar = 0;
uchar tab[256];
Size roi = _src.size();
roi.width *= _src.channels();
if( _src.isContinuous() && _dst.isContinuous() )
{
roi.width *= roi.height;
roi.height = 1;
}
switch( type )
{
case THRESH_BINARY:
for( i = 0; i <= thresh; i++ )
tab[i] = 0;
for( ; i < 256; i++ )
tab[i] = maxval;
break;
case THRESH_BINARY_INV:
for( i = 0; i <= thresh; i++ )
tab[i] = maxval;
for( ; i < 256; i++ )
tab[i] = 0;
break;
case THRESH_TRUNC:
for( i = 0; i <= thresh; i++ )
tab[i] = (uchar)i;
for( ; i < 256; i++ )
tab[i] = thresh;
break;
case THRESH_TOZERO:
for( i = 0; i <= thresh; i++ )
tab[i] = 0;
for( ; i < 256; i++ )
tab[i] = (uchar)i;
break;
case THRESH_TOZERO_INV:
for( i = 0; i <= thresh; i++ )
tab[i] = (uchar)i;
for( ; i < 256; i++ )
tab[i] = 0;
break;
default:
CV_Error( CV_StsBadArg, "Unknown threshold type" );
}
#if CV_SSE2
if( checkHardwareSupport(CV_CPU_SSE2) )
{
__m128i _x80 = _mm_set1_epi8('\x80');
__m128i thresh_u = _mm_set1_epi8(thresh);
__m128i thresh_s = _mm_set1_epi8(thresh ^ 0x80);
__m128i maxval_ = _mm_set1_epi8(maxval);
j_scalar = roi.width & -8;
for( i = 0; i < roi.height; i++ )
{
const uchar* src = (const uchar*)(_src.data + _src.step*i);
uchar* dst = (uchar*)(_dst.data + _dst.step*i);
switch( type )
{
case THRESH_BINARY:
for( j = 0; j <= roi.width - 32; j += 32 )
{
__m128i v0, v1;
v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s );
v0 = _mm_and_si128( v0, maxval_ );
v1 = _mm_and_si128( v1, maxval_ );
_mm_storeu_si128( (__m128i*)(dst + j), v0 );
_mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
}
for( ; j <= roi.width - 8; j += 8 )
{
__m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
v0 = _mm_and_si128( v0, maxval_ );
_mm_storel_epi64( (__m128i*)(dst + j), v0 );
}
break;
case THRESH_BINARY_INV:
for( j = 0; j <= roi.width - 32; j += 32 )
{
__m128i v0, v1;
v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s );
v0 = _mm_andnot_si128( v0, maxval_ );
v1 = _mm_andnot_si128( v1, maxval_ );
_mm_storeu_si128( (__m128i*)(dst + j), v0 );
_mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
}
for( ; j <= roi.width - 8; j += 8 )
{
__m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
v0 = _mm_andnot_si128( v0, maxval_ );
_mm_storel_epi64( (__m128i*)(dst + j), v0 );
}
break;
case THRESH_TRUNC:
for( j = 0; j <= roi.width - 32; j += 32 )
{
__m128i v0, v1;
v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u ));
v1 = _mm_subs_epu8( v1, _mm_subs_epu8( v1, thresh_u ));
_mm_storeu_si128( (__m128i*)(dst + j), v0 );
_mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
}
for( ; j <= roi.width - 8; j += 8 )
{
__m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u ));
_mm_storel_epi64( (__m128i*)(dst + j), v0 );
}
break;
case THRESH_TOZERO:
for( j = 0; j <= roi.width - 32; j += 32 )
{
__m128i v0, v1;
v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ));
v1 = _mm_and_si128( v1, _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s ));
_mm_storeu_si128( (__m128i*)(dst + j), v0 );
_mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
}
for( ; j <= roi.width - 8; j += 8 )
{
__m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ));
_mm_storel_epi64( (__m128i*)(dst + j), v0 );
}
break;
case THRESH_TOZERO_INV:
for( j = 0; j <= roi.width - 32; j += 32 )
{
__m128i v0, v1;
v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 );
v1 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s ), v1 );
_mm_storeu_si128( (__m128i*)(dst + j), v0 );
_mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
}
for( ; j <= roi.width - 8; j += 8 )
{
__m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 );
_mm_storel_epi64( (__m128i*)(dst + j), v0 );
}
break;
}
}
}
#endif
if( j_scalar < roi.width )
{
for( i = 0; i < roi.height; i++ )
{
const uchar* src = (const uchar*)(_src.data + _src.step*i);
uchar* dst = (uchar*)(_dst.data + _dst.step*i);
for( j = j_scalar; j <= roi.width - 4; j += 4 )
{
uchar t0 = tab[src[j]];
uchar t1 = tab[src[j+1]];
dst[j] = t0;
dst[j+1] = t1;
t0 = tab[src[j+2]];
t1 = tab[src[j+3]];
dst[j+2] = t0;
dst[j+3] = t1;
}
for( ; j < roi.width; j++ )
dst[j] = tab[src[j]];
}
}
}
static void
thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
{
int i, j;
Size roi = _src.size();
roi.width *= _src.channels();
const float* src = (const float*)_src.data;
float* dst = (float*)_dst.data;
size_t src_step = _src.step/sizeof(src[0]);
size_t dst_step = _dst.step/sizeof(dst[0]);
#if CV_SSE2
volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE);
#endif
if( _src.isContinuous() && _dst.isContinuous() )
{
roi.width *= roi.height;
roi.height = 1;
}
switch( type )
{
case THRESH_BINARY:
for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
{
j = 0;
#if CV_SSE2
if( useSIMD )
{
__m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval);
for( ; j <= roi.width - 8; j += 8 )
{
__m128 v0, v1;
v0 = _mm_loadu_ps( src + j );
v1 = _mm_loadu_ps( src + j + 4 );
v0 = _mm_cmpgt_ps( v0, thresh4 );
v1 = _mm_cmpgt_ps( v1, thresh4 );
v0 = _mm_and_ps( v0, maxval4 );
v1 = _mm_and_ps( v1, maxval4 );
_mm_storeu_ps( dst + j, v0 );
_mm_storeu_ps( dst + j + 4, v1 );
}
}
#endif
for( ; j < roi.width; j++ )
dst[j] = src[j] > thresh ? maxval : 0;
}
break;
case THRESH_BINARY_INV:
for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
{
j = 0;
#if CV_SSE2
if( useSIMD )
{
__m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval);
for( ; j <= roi.width - 8; j += 8 )
{
__m128 v0, v1;
v0 = _mm_loadu_ps( src + j );
v1 = _mm_loadu_ps( src + j + 4 );
v0 = _mm_cmple_ps( v0, thresh4 );
v1 = _mm_cmple_ps( v1, thresh4 );
v0 = _mm_and_ps( v0, maxval4 );
v1 = _mm_and_ps( v1, maxval4 );
_mm_storeu_ps( dst + j, v0 );
_mm_storeu_ps( dst + j + 4, v1 );
}
}
#endif
for( ; j < roi.width; j++ )
dst[j] = src[j] <= thresh ? maxval : 0;
}
break;
case THRESH_TRUNC:
for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
{
j = 0;
#if CV_SSE2
if( useSIMD )
{
__m128 thresh4 = _mm_set1_ps(thresh);
for( ; j <= roi.width - 8; j += 8 )
{
__m128 v0, v1;
v0 = _mm_loadu_ps( src + j );
v1 = _mm_loadu_ps( src + j + 4 );
v0 = _mm_min_ps( v0, thresh4 );
v1 = _mm_min_ps( v1, thresh4 );
_mm_storeu_ps( dst + j, v0 );
_mm_storeu_ps( dst + j + 4, v1 );
}
}
#endif
for( ; j < roi.width; j++ )
dst[j] = std::min(src[j], thresh);
}
break;
case THRESH_TOZERO:
for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
{
j = 0;
#if CV_SSE2
if( useSIMD )
{
__m128 thresh4 = _mm_set1_ps(thresh);
for( ; j <= roi.width - 8; j += 8 )
{
__m128 v0, v1;
v0 = _mm_loadu_ps( src + j );
v1 = _mm_loadu_ps( src + j + 4 );
v0 = _mm_and_ps(v0, _mm_cmpgt_ps(v0, thresh4));
v1 = _mm_and_ps(v1, _mm_cmpgt_ps(v1, thresh4));
_mm_storeu_ps( dst + j, v0 );
_mm_storeu_ps( dst + j + 4, v1 );
}
}
#endif
for( ; j < roi.width; j++ )
{
float v = src[j];
dst[j] = v > thresh ? v : 0;
}
}
break;
case THRESH_TOZERO_INV:
for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
{
j = 0;
#if CV_SSE2
if( useSIMD )
{
__m128 thresh4 = _mm_set1_ps(thresh);
for( ; j <= roi.width - 8; j += 8 )
{
__m128 v0, v1;
v0 = _mm_loadu_ps( src + j );
v1 = _mm_loadu_ps( src + j + 4 );
v0 = _mm_and_ps(v0, _mm_cmple_ps(v0, thresh4));
v1 = _mm_and_ps(v1, _mm_cmple_ps(v1, thresh4));
_mm_storeu_ps( dst + j, v0 );
_mm_storeu_ps( dst + j + 4, v1 );
}
}
#endif
for( ; j < roi.width; j++ )
{
float v = src[j];
dst[j] = v <= thresh ? v : 0;
}
}
break;
default:
return CV_Error( CV_StsBadArg, "" );
}
}
static double
getThreshVal_Otsu_8u( const Mat& _src )
{
Size size = _src.size();
if( _src.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
const int N = 256;
int i, j, h[N] = {0};
for( i = 0; i < size.height; i++ )
{
const uchar* src = _src.data + _src.step*i;
for( j = 0; j <= size.width - 4; j += 4 )
{
int v0 = src[j], v1 = src[j+1];
h[v0]++; h[v1]++;
v0 = src[j+2]; v1 = src[j+3];
h[v0]++; h[v1]++;
}
for( ; j < size.width; j++ )
h[src[j]]++;
}
double mu = 0, scale = 1./(size.width*size.height);
for( i = 0; i < N; i++ )
mu += i*h[i];
mu *= scale;
double mu1 = 0, q1 = 0;
double max_sigma = 0, max_val = 0;
for( i = 0; i < N; i++ )
{
double p_i, q2, mu2, sigma;
p_i = h[i]*scale;
mu1 *= q1;
q1 += p_i;
q2 = 1. - q1;
if( std::min(q1,q2) < FLT_EPSILON || std::max(q1,q2) > 1. - FLT_EPSILON )
continue;
mu1 = (mu1 + i*p_i)/q1;
mu2 = (mu - q1*mu1)/q2;
sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
if( sigma > max_sigma )
{
max_sigma = sigma;
max_val = i;
}
}
return max_val;
}
double threshold( const Mat& _src, Mat& _dst, double thresh, double maxval, int type )
{
bool use_otsu = (type & THRESH_OTSU) != 0;
type &= THRESH_MASK;
if( use_otsu )
{
CV_Assert( _src.type() == CV_8UC1 );
thresh = getThreshVal_Otsu_8u(_src);
}
_dst.create( _src.size(), _src.type() );
if( _src.depth() == CV_8U )
{
int ithresh = cvFloor(thresh);
thresh = ithresh;
int imaxval = cvRound(maxval);
if( type == THRESH_TRUNC )
imaxval = ithresh;
imaxval = saturate_cast<uchar>(imaxval);
if( ithresh < 0 || ithresh >= 255 )
{
if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < 0) ||
(type == THRESH_TOZERO && ithresh >= 255) )
{
int v = type == THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) :
type == THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) :
type == THRESH_TRUNC ? imaxval : 0;
_dst = Scalar::all(v);
}
else
_src.copyTo(_dst);
}
else
thresh_8u( _src, _dst, (uchar)ithresh, (uchar)imaxval, type );
}
else if( _src.depth() == CV_32F )
thresh_32f( _src, _dst, (float)thresh, (float)maxval, type );
else
CV_Error( CV_StsUnsupportedFormat, "" );
return thresh;
}
void adaptiveThreshold( const Mat& _src, Mat& _dst, double maxValue,
int method, int type, int blockSize, double delta )
{
CV_Assert( _src.type() == CV_8UC1 );
CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
Size size = _src.size();
_dst.create( size, _src.type() );
if( maxValue < 0 )
{
_dst = Scalar(0);
return;
}
Mat _mean;
if( _src.data != _dst.data )
_mean = _dst;
if( method == ADAPTIVE_THRESH_MEAN_C )
boxFilter( _src, _mean, _src.type(), Size(blockSize, blockSize),
Point(-1,-1), true, BORDER_REPLICATE );
else if( method == ADAPTIVE_THRESH_GAUSSIAN_C )
GaussianBlur( _src, _mean, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE );
else
CV_Error( CV_StsBadFlag, "Unknown/unsupported adaptive threshold method" );
int i, j;
uchar imaxval = saturate_cast<uchar>(maxValue);
int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
uchar tab[768];
if( type == CV_THRESH_BINARY )
for( i = 0; i < 768; i++ )
tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
else if( type == CV_THRESH_BINARY_INV )
for( i = 0; i < 768; i++ )
tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
else
CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type" );
if( _src.isContinuous() && _mean.isContinuous() && _dst.isContinuous() )
{
size.width *= size.height;
size.height = 1;
}
for( i = 0; i < size.height; i++ )
{
const uchar* src = _src.data + _src.step*i;
const uchar* mean = _mean.data + _mean.step*i;
uchar* dst = _dst.data + _dst.step*i;
for( j = 0; j < size.width; j++ )
dst[j] = tab[src[j] - mean[j] + 255];
}
}
}
CV_IMPL double
cvThreshold( const void* srcarr, void* dstarr, double thresh, double maxval, int type )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), dst0 = dst;
CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() &&
(src.depth() == dst.depth() || dst.depth() == CV_8U));
thresh = cv::threshold( src, dst, thresh, maxval, type );
if( dst0.data != dst.data )
dst.convertTo( dst0, dst0.depth() );
return thresh;
}
CV_IMPL void
cvAdaptiveThreshold( const void *srcIm, void *dstIm, double maxValue,
int method, int type, int blockSize, double delta )
{
cv::Mat src = cv::cvarrToMat(srcIm), dst = cv::cvarrToMat(dstIm);
CV_Assert( src.size() == dst.size() && src.type() == dst.type() );
cv::adaptiveThreshold( src, dst, maxValue, method, type, blockSize, delta );
}
/* End of file. */

View File

@@ -0,0 +1,482 @@
/*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"
CV_IMPL CvSeq* cvPointSeqFromMat( int seq_kind, const CvArr* arr,
CvContour* contour_header, CvSeqBlock* block )
{
CV_Assert( arr != 0 && contour_header != 0 && block != 0 );
int eltype;
CvMat* mat = (CvMat*)arr;
if( !CV_IS_MAT( mat ))
CV_Error( CV_StsBadArg, "Input array is not a valid matrix" );
eltype = CV_MAT_TYPE( mat->type );
if( eltype != CV_32SC2 && eltype != CV_32FC2 )
CV_Error( CV_StsUnsupportedFormat,
"The matrix can not be converted to point sequence because of "
"inappropriate element type" );
if( (mat->width != 1 && mat->height != 1) || !CV_IS_MAT_CONT(mat->type))
CV_Error( CV_StsBadArg,
"The matrix converted to point sequence must be "
"1-dimensional and continuous" );
cvMakeSeqHeaderForArray(
(seq_kind & (CV_SEQ_KIND_MASK|CV_SEQ_FLAG_CLOSED)) | eltype,
sizeof(CvContour), CV_ELEM_SIZE(eltype), mat->data.ptr,
mat->width*mat->height, (CvSeq*)contour_header, block );
return (CvSeq*)contour_header;
}
typedef CvStatus (CV_STDCALL * CvCopyNonConstBorderFunc)(
const void*, int, CvSize, void*, int, CvSize, int, int );
typedef CvStatus (CV_STDCALL * CvCopyNonConstBorderFuncI)(
const void*, int, CvSize, CvSize, int, int );
CvStatus CV_STDCALL
icvCopyReplicateBorder_8u( const uchar* src, int srcstep, CvSize srcroi,
uchar* dst, int dststep, CvSize dstroi,
int top, int left, int cn, const uchar* )
{
const int isz = (int)sizeof(int);
int i, j;
if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 )
{
const int* isrc = (const int*)src;
int* idst = (int*)dst;
cn /= isz;
srcstep /= isz;
dststep /= isz;
srcroi.width *= cn;
dstroi.width *= cn;
left *= cn;
for( i = 0; i < dstroi.height; i++, idst += dststep )
{
if( idst + left != isrc )
memcpy( idst + left, isrc, srcroi.width*sizeof(idst[0]) );
for( j = left - 1; j >= 0; j-- )
idst[j] = idst[j + cn];
for( j = left+srcroi.width; j < dstroi.width; j++ )
idst[j] = idst[j - cn];
if( i >= top && i < top + srcroi.height - 1 )
isrc += srcstep;
}
}
else
{
srcroi.width *= cn;
dstroi.width *= cn;
left *= cn;
for( i = 0; i < dstroi.height; i++, dst += dststep )
{
if( dst + left != src )
memcpy( dst + left, src, srcroi.width );
for( j = left - 1; j >= 0; j-- )
dst[j] = dst[j + cn];
for( j = left+srcroi.width; j < dstroi.width; j++ )
dst[j] = dst[j - cn];
if( i >= top && i < top + srcroi.height - 1 )
src += srcstep;
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvCopyReflect101Border_8u( const uchar* src, int srcstep, CvSize srcroi,
uchar* dst, int dststep, CvSize dstroi,
int top, int left, int cn )
{
const int isz = (int)sizeof(int);
int i, j, k, t, dj, tab_size, int_mode = 0;
const int* isrc = (const int*)src;
int* idst = (int*)dst, *tab;
if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 )
{
cn /= isz;
srcstep /= isz;
dststep /= isz;
int_mode = 1;
}
srcroi.width *= cn;
dstroi.width *= cn;
left *= cn;
tab_size = dstroi.width - srcroi.width;
tab = (int*)cvStackAlloc( tab_size*sizeof(tab[0]) );
if( srcroi.width == 1 )
{
for( k = 0; k < cn; k++ )
for( i = 0; i < tab_size; i += cn )
tab[i + k] = k + left;
}
else
{
j = dj = cn;
for( i = left - cn; i >= 0; i -= cn )
{
for( k = 0; k < cn; k++ )
tab[i + k] = j + k + left;
if( (unsigned)(j += dj) >= (unsigned)srcroi.width )
j -= 2*dj, dj = -dj;
}
j = srcroi.width - cn*2;
dj = -cn;
for( i = left; i < tab_size; i += cn )
{
for( k = 0; k < cn; k++ )
tab[i + k] = j + k + left;
if( (unsigned)(j += dj) >= (unsigned)srcroi.width )
j -= 2*dj, dj = -dj;
}
}
if( int_mode )
{
idst += top*dststep;
for( i = 0; i < srcroi.height; i++, isrc += srcstep, idst += dststep )
{
if( idst + left != isrc )
memcpy( idst + left, isrc, srcroi.width*sizeof(idst[0]) );
for( j = 0; j < left; j++ )
{
k = tab[j];
idst[j] = idst[k];
}
for( ; j < tab_size; j++ )
{
k = tab[j];
idst[j + srcroi.width] = idst[k];
}
}
isrc -= srcroi.height*srcstep;
idst -= (top + srcroi.height)*dststep;
}
else
{
dst += top*dststep;
for( i = 0; i < srcroi.height; i++, src += srcstep, dst += dststep )
{
if( dst + left != src )
memcpy( dst + left, src, srcroi.width );
for( j = 0; j < left; j++ )
{
k = tab[j];
dst[j] = dst[k];
}
for( ; j < tab_size; j++ )
{
k = tab[j];
dst[j + srcroi.width] = dst[k];
}
}
src -= srcroi.height*srcstep;
dst -= (top + srcroi.height)*dststep;
}
for( t = 0; t < 2; t++ )
{
int i1, i2, di;
if( t == 0 )
i1 = top-1, i2 = 0, di = -1, j = 1, dj = 1;
else
i1 = top+srcroi.height, i2=dstroi.height, di = 1, j = srcroi.height-2, dj = -1;
for( i = i1; (di > 0 && i < i2) || (di < 0 && i > i2); i += di )
{
if( int_mode )
{
const int* s = idst + i*dststep;
int* d = idst + (j+top)*dststep;
for( k = 0; k < dstroi.width; k++ )
d[k] = s[k];
}
else
{
const uchar* s = dst + i*dststep;
uchar* d = dst + (j+top)*dststep;
for( k = 0; k < dstroi.width; k++ )
d[k] = s[k];
}
if( (unsigned)(j += dj) >= (unsigned)srcroi.height )
j -= 2*dj, dj = -dj;
}
}
return CV_OK;
}
static CvStatus CV_STDCALL
icvCopyConstBorder_8u( const uchar* src, int srcstep, CvSize srcroi,
uchar* dst, int dststep, CvSize dstroi,
int top, int left, int cn, const uchar* value )
{
const int isz = (int)sizeof(int);
int i, j, k;
if( (cn | srcstep | dststep | (size_t)src | (size_t)dst | (size_t)value) % isz == 0 )
{
const int* isrc = (const int*)src;
int* idst = (int*)dst;
const int* ivalue = (const int*)value;
int v0 = ivalue[0];
cn /= isz;
srcstep /= isz;
dststep /= isz;
srcroi.width *= cn;
dstroi.width *= cn;
left *= cn;
for( j = 1; j < cn; j++ )
if( ivalue[j] != ivalue[0] )
break;
if( j == cn )
cn = 1;
if( dstroi.width <= 0 )
return CV_OK;
for( i = 0; i < dstroi.height; i++, idst += dststep )
{
if( i < top || i >= top + srcroi.height )
{
if( cn == 1 )
{
for( j = 0; j < dstroi.width; j++ )
idst[j] = v0;
}
else
{
for( j = 0; j < cn; j++ )
idst[j] = ivalue[j];
for( ; j < dstroi.width; j++ )
idst[j] = idst[j - cn];
}
continue;
}
if( cn == 1 )
{
for( j = 0; j < left; j++ )
idst[j] = v0;
for( j = srcroi.width + left; j < dstroi.width; j++ )
idst[j] = v0;
}
else
{
for( k = 0; k < cn; k++ )
{
for( j = 0; j < left; j += cn )
idst[j+k] = ivalue[k];
for( j = srcroi.width + left; j < dstroi.width; j += cn )
idst[j+k] = ivalue[k];
}
}
if( idst + left != isrc )
for( j = 0; j < srcroi.width; j++ )
idst[j + left] = isrc[j];
isrc += srcstep;
}
}
else
{
uchar v0 = value[0];
srcroi.width *= cn;
dstroi.width *= cn;
left *= cn;
for( j = 1; j < cn; j++ )
if( value[j] != value[0] )
break;
if( j == cn )
cn = 1;
if( dstroi.width <= 0 )
return CV_OK;
for( i = 0; i < dstroi.height; i++, dst += dststep )
{
if( i < top || i >= top + srcroi.height )
{
if( cn == 1 )
{
for( j = 0; j < dstroi.width; j++ )
dst[j] = v0;
}
else
{
for( j = 0; j < cn; j++ )
dst[j] = value[j];
for( ; j < dstroi.width; j++ )
dst[j] = dst[j - cn];
}
continue;
}
if( cn == 1 )
{
for( j = 0; j < left; j++ )
dst[j] = v0;
for( j = srcroi.width + left; j < dstroi.width; j++ )
dst[j] = v0;
}
else
{
for( k = 0; k < cn; k++ )
{
for( j = 0; j < left; j += cn )
dst[j+k] = value[k];
for( j = srcroi.width + left; j < dstroi.width; j += cn )
dst[j+k] = value[k];
}
}
if( dst + left != src )
for( j = 0; j < srcroi.width; j++ )
dst[j + left] = src[j];
src += srcstep;
}
}
return CV_OK;
}
CV_IMPL void
cvCopyMakeBorder( const CvArr* srcarr, CvArr* dstarr, CvPoint offset,
int bordertype, CvScalar value )
{
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvSize srcsize, dstsize;
int srcstep, dststep;
int pix_size, type;
if( !CV_IS_MAT(src) )
src = cvGetMat( src, &srcstub );
if( !CV_IS_MAT(dst) )
dst = cvGetMat( dst, &dststub );
if( offset.x < 0 || offset.y < 0 )
CV_Error( CV_StsOutOfRange, "Offset (left/top border width) is negative" );
if( src->rows + offset.y > dst->rows || src->cols + offset.x > dst->cols )
CV_Error( CV_StsBadSize, "Source array is too big or destination array is too small" );
if( !CV_ARE_TYPES_EQ( src, dst ))
CV_Error( CV_StsUnmatchedFormats, "" );
type = CV_MAT_TYPE(src->type);
pix_size = CV_ELEM_SIZE(type);
srcsize = cvGetMatSize(src);
dstsize = cvGetMatSize(dst);
srcstep = src->step;
dststep = dst->step;
if( srcstep == 0 )
srcstep = CV_STUB_STEP;
if( dststep == 0 )
dststep = CV_STUB_STEP;
if( bordertype == IPL_BORDER_REPLICATE )
{
icvCopyReplicateBorder_8u( src->data.ptr, srcstep, srcsize,
dst->data.ptr, dststep, dstsize,
offset.y, offset.x, pix_size );
}
else if( bordertype == IPL_BORDER_REFLECT_101 )
{
icvCopyReflect101Border_8u( src->data.ptr, srcstep, srcsize,
dst->data.ptr, dststep, dstsize,
offset.y, offset.x, pix_size );
}
else if( bordertype == IPL_BORDER_CONSTANT )
{
double buf[4];
cvScalarToRawData( &value, buf, src->type, 0 );
icvCopyConstBorder_8u( src->data.ptr, srcstep, srcsize,
dst->data.ptr, dststep, dstsize,
offset.y, offset.x, pix_size, (uchar*)buf );
}
else
CV_Error( CV_StsBadFlag, "Unknown/unsupported border type" );
}
namespace cv
{
void copyMakeBorder( const Mat& src, Mat& dst, int top, int bottom,
int left, int right, int borderType, const Scalar& value )
{
dst.create( src.rows + top + bottom, src.cols + left + right, src.type() );
CvMat _src = src, _dst = dst;
cvCopyMakeBorder( &_src, &_dst, Point(left, top), borderType, value );
}
}
/* End of file. */