a LOT of obsolete stuff has been moved to the legacy module.

This commit is contained in:
Vadim Pisarevsky 2012-03-30 12:19:25 +00:00
parent 7e5726e251
commit beb7fc3c92
42 changed files with 3711 additions and 1960 deletions

View File

@ -361,37 +361,6 @@ CVAPI(void) cvValidateDisparity( CvArr* disparity, const CvArr* cost,
int minDisparity, int numberOfDisparities,
int disp12MaxDiff CV_DEFAULT(1) );
/* Kolmogorov-Zabin stereo-correspondence algorithm (a.k.a. KZ1) */
#define CV_STEREO_GC_OCCLUDED SHRT_MAX
typedef struct CvStereoGCState
{
int Ithreshold;
int interactionRadius;
float K, lambda, lambda1, lambda2;
int occlusionCost;
int minDisparity;
int numberOfDisparities;
int maxIters;
CvMat* left;
CvMat* right;
CvMat* dispLeft;
CvMat* dispRight;
CvMat* ptrLeft;
CvMat* ptrRight;
CvMat* vtxBuf;
CvMat* edgeBuf;
} CvStereoGCState;
CVAPI(CvStereoGCState*) cvCreateStereoGCState( int numberOfDisparities, int maxIters );
CVAPI(void) cvReleaseStereoGCState( CvStereoGCState** state );
CVAPI(void) cvFindStereoCorrespondenceGC( const CvArr* left, const CvArr* right,
CvArr* disparityLeft, CvArr* disparityRight,
CvStereoGCState* state,
int useDisparityGuess CV_DEFAULT(0) );
/* Reprojects the computed disparity image to the 3D space using the specified 4x4 matrix */
CVAPI(void) cvReprojectImageTo3D( const CvArr* disparityImage,
CvArr* _3dImage, const CvMat* Q,

View File

@ -706,73 +706,6 @@ protected:
}
};
//----------------------------------- StereoGC test -----------------------------------------------------
class CV_StereoGCTest : public CV_StereoMatchingTest
{
public:
CV_StereoGCTest()
{
name = "stereogc";
fill(rmsEps.begin(), rmsEps.end(), 3.f);
fracEps[0] = 0.05f; // all
fracEps[1] = 0.05f; // noOccl
fracEps[2] = 0.25f; // occl
fracEps[3] = 0.05f; // textured
fracEps[4] = 0.10f; // textureless
fracEps[5] = 0.10f; // borderedDepthDiscont
}
protected:
struct RunParams
{
int ndisp;
int iterCount;
};
vector<RunParams> caseRunParams;
virtual int readRunParams( FileStorage& fs )
{
int code = CV_StereoMatchingTest::readRunParams(fs);
FileNode fn = fs.getFirstTopLevelNode();
assert(fn.isSeq());
for( int i = 0; i < (int)fn.size(); i+=4 )
{
string caseName = fn[i], datasetName = fn[i+1];
RunParams params;
string ndisp = fn[i+2]; params.ndisp = atoi(ndisp.c_str());
string iterCount = fn[i+3]; params.iterCount = atoi(iterCount.c_str());
caseNames.push_back( caseName );
caseDatasets.push_back( datasetName );
caseRunParams.push_back( params );
}
return code;
}
virtual int runStereoMatchingAlgorithm( const Mat& _leftImg, const Mat& _rightImg,
Mat& leftDisp, Mat& rightDisp, int caseIdx )
{
RunParams params = caseRunParams[caseIdx];
assert( _leftImg.type() == CV_8UC3 && _rightImg.type() == CV_8UC3 );
Mat leftImg, rightImg, tmp;
cvtColor( _leftImg, leftImg, CV_BGR2GRAY );
cvtColor( _rightImg, rightImg, CV_BGR2GRAY );
leftDisp.create( leftImg.size(), CV_16SC1 );
rightDisp.create( rightImg.size(), CV_16SC1 );
CvMat _limg = leftImg, _rimg = rightImg, _ldisp = leftDisp, _rdisp = rightDisp;
CvStereoGCState *state = cvCreateStereoGCState( params.ndisp, params.iterCount );
cvFindStereoCorrespondenceGC( &_limg, &_rimg, &_ldisp, &_rdisp, state );
cvReleaseStereoGCState( &state );
leftDisp = - leftDisp;
return 0;
}
};
//----------------------------------- StereoSGBM test -----------------------------------------------------
class CV_StereoSGBMTest : public CV_StereoMatchingTest
@ -829,5 +762,4 @@ protected:
TEST(Calib3d_StereoBM, regression) { CV_StereoBMTest test; test.safe_run(); }
TEST(Calib3d_StereoGC, regression) { CV_StereoGCTest test; test.safe_run(); }
TEST(Calib3d_StereoSGBM, regression) { CV_StereoSGBMTest test; test.safe_run(); }

View File

@ -442,6 +442,7 @@ void cv::Mesh3D::clearOctree(){ octree = Octree(); }
float cv::Mesh3D::estimateResolution(float tryRatio)
{
#if 0
const int neighbors = 3;
const int minReasonable = 10;
@ -475,8 +476,13 @@ float cv::Mesh3D::estimateResolution(float tryRatio)
sort(dist, less<double>());
return resolution = (float)dist[ dist.size() / 2 ];
#else
CV_Error(CV_StsNotImplemented, "");
return 1.f;
#endif
}
void cv::Mesh3D::computeNormals(float normalRadius, int minNeighbors)
{
buildOctree();

View File

@ -155,109 +155,6 @@ void NearestNeighborTest::run( int /*start_from*/ ) {
ts->set_failed_test_info( code );
}
//--------------------------------------------------------------------------------
class CV_LSHTest : public NearestNeighborTest
{
public:
CV_LSHTest() {}
protected:
virtual void createModel( const Mat& data );
virtual int findNeighbors( Mat& points, Mat& neighbors );
virtual void releaseModel();
struct CvLSH* lsh;
CvMat desc;
};
void CV_LSHTest::createModel( const Mat& data )
{
desc = data;
lsh = cvCreateMemoryLSH( data.cols, data.rows, 70, 20, CV_32FC1 );
cvLSHAdd( lsh, &desc );
}
int CV_LSHTest::findNeighbors( Mat& points, Mat& neighbors )
{
const int emax = 20;
Mat dist( points.rows, neighbors.cols, CV_64FC1);
CvMat _dist = dist, _points = points, _neighbors = neighbors;
cvLSHQuery( lsh, &_points, &_neighbors, &_dist, neighbors.cols, emax );
return cvtest::TS::OK;
}
void CV_LSHTest::releaseModel()
{
cvReleaseLSH( &lsh );
}
//--------------------------------------------------------------------------------
class CV_FeatureTreeTest_C : public NearestNeighborTest
{
public:
CV_FeatureTreeTest_C() {}
protected:
virtual int findNeighbors( Mat& points, Mat& neighbors );
virtual void releaseModel();
CvFeatureTree* tr;
CvMat desc;
};
int CV_FeatureTreeTest_C::findNeighbors( Mat& points, Mat& neighbors )
{
const int emax = 20;
Mat dist( points.rows, neighbors.cols, CV_64FC1);
CvMat _dist = dist, _points = points, _neighbors = neighbors;
cvFindFeatures( tr, &_points, &_neighbors, &_dist, neighbors.cols, emax );
return cvtest::TS::OK;
}
void CV_FeatureTreeTest_C::releaseModel()
{
cvReleaseFeatureTree( tr );
}
//--------------------------------------
class CV_SpillTreeTest_C : public CV_FeatureTreeTest_C
{
public:
CV_SpillTreeTest_C() {}
protected:
virtual void createModel( const Mat& data );
};
void CV_SpillTreeTest_C::createModel( const Mat& data )
{
desc = data;
tr = cvCreateSpillTree( &desc );
}
//--------------------------------------
class CV_KDTreeTest_C : public CV_FeatureTreeTest_C
{
public:
CV_KDTreeTest_C() {}
protected:
virtual void createModel( const Mat& data );
virtual int checkFindBoxed();
};
void CV_KDTreeTest_C::createModel( const Mat& data )
{
desc = data;
tr = cvCreateKDTree( &desc );
}
int CV_KDTreeTest_C::checkFindBoxed()
{
Mat min(1, dims, CV_32FC1 ), max(1, dims, CV_32FC1 ), indices( 1, 1, CV_32SC1 );
float l = minValue, r = maxValue;
min.setTo(Scalar(l)), max.setTo(Scalar(r));
CvMat _min = min, _max = max, _indices = indices;
// TODO check indices
if( cvFindFeaturesBoxed( tr, &_min, &_max, &_indices ) != featuresCount )
return cvtest::TS::FAIL_BAD_ACCURACY;
return cvtest::TS::OK;
}
//--------------------------------------------------------------------------------
class CV_KDTreeTest_CPP : public NearestNeighborTest
{
@ -506,9 +403,6 @@ void CV_FlannSavedIndexTest::createModel(const cv::Mat &data)
remove( filename.c_str() );
}
TEST(Features2d_LSH, regression) { CV_LSHTest test; test.safe_run(); }
TEST(Features2d_SpillTree, regression) { CV_SpillTreeTest_C test; test.safe_run(); }
TEST(Features2d_KDTree_C, regression) { CV_KDTreeTest_C test; test.safe_run(); }
TEST(Features2d_KDTree_CPP, regression) { CV_KDTreeTest_CPP test; test.safe_run(); }
TEST(Features2d_FLANN_Linear, regression) { CV_FlannLinearIndexTest test; test.safe_run(); }
TEST(Features2d_FLANN_KMeans, regression) { CV_FlannKMeansIndexTest test; test.safe_run(); }

View File

@ -1142,27 +1142,6 @@ protected:
}
// 2009-01-12, Xavier Delacour <xavier.delacour@gmail.com>
struct lsh_hash {
int h1, h2;
};
struct CvLSHOperations
{
virtual ~CvLSHOperations() {}
virtual int vector_add(const void* data) = 0;
virtual void vector_remove(int i) = 0;
virtual const void* vector_lookup(int i) = 0;
virtual void vector_reserve(int n) = 0;
virtual unsigned int vector_count() = 0;
virtual void hash_insert(lsh_hash h, int l, int i) = 0;
virtual void hash_remove(lsh_hash h, int l, int i) = 0;
virtual int hash_lookup(lsh_hash h, int l, int* ret_i, int ret_i_max) = 0;
};
#endif /* __cplusplus */
#endif

View File

@ -121,15 +121,6 @@ CVAPI(CvMat**) cvCreatePyramid( const CvArr* img, int extra_layers, double rate,
CVAPI(void) cvReleasePyramid( CvMat*** pyramid, int extra_layers );
/* Splits color or grayscale image into multiple connected components
of nearly the same color/brightness using modification of Burt algorithm.
comp with contain a pointer to sequence (CvSeq)
of connected components (CvConnectedComp) */
CVAPI(void) cvPyrSegmentation( IplImage* src, IplImage* dst,
CvMemStorage* storage, CvSeq** comp,
int level, double threshold1,
double threshold2 );
/* Filters image using meanshift algorithm */
CVAPI(void) cvPyrMeanShiftFiltering( const CvArr* src, CvArr* dst,
double sp, double sr, int max_level CV_DEFAULT(1),
@ -351,99 +342,6 @@ CVAPI(void) cvStartReadChainPoints( CvChain* chain, CvChainPtReader* reader );
/* Retrieves the next chain point */
CVAPI(CvPoint) cvReadChainPoint( CvChainPtReader* reader );
/****************************************************************************************\
* Planar subdivisions *
\****************************************************************************************/
/* Initializes Delaunay triangulation */
CVAPI(void) cvInitSubdivDelaunay2D( CvSubdiv2D* subdiv, CvRect rect );
/* Creates new subdivision */
CVAPI(CvSubdiv2D*) cvCreateSubdiv2D( int subdiv_type, int header_size,
int vtx_size, int quadedge_size,
CvMemStorage* storage );
/************************* high-level subdivision functions ***************************/
/* Simplified Delaunay diagram creation */
CV_INLINE CvSubdiv2D* cvCreateSubdivDelaunay2D( CvRect rect, CvMemStorage* storage )
{
CvSubdiv2D* subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*subdiv),
sizeof(CvSubdiv2DPoint), sizeof(CvQuadEdge2D), storage );
cvInitSubdivDelaunay2D( subdiv, rect );
return subdiv;
}
/* Inserts new point to the Delaunay triangulation */
CVAPI(CvSubdiv2DPoint*) cvSubdivDelaunay2DInsert( CvSubdiv2D* subdiv, CvPoint2D32f pt);
/* Locates a point within the Delaunay triangulation (finds the edge
the point is left to or belongs to, or the triangulation point the given
point coinsides with */
CVAPI(CvSubdiv2DPointLocation) cvSubdiv2DLocate(
CvSubdiv2D* subdiv, CvPoint2D32f pt,
CvSubdiv2DEdge* edge,
CvSubdiv2DPoint** vertex CV_DEFAULT(NULL) );
/* Calculates Voronoi tesselation (i.e. coordinates of Voronoi points) */
CVAPI(void) cvCalcSubdivVoronoi2D( CvSubdiv2D* subdiv );
/* Removes all Voronoi points from the tesselation */
CVAPI(void) cvClearSubdivVoronoi2D( CvSubdiv2D* subdiv );
/* Finds the nearest to the given point vertex in subdivision. */
CVAPI(CvSubdiv2DPoint*) cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt );
/************ Basic quad-edge navigation and operations ************/
CV_INLINE CvSubdiv2DEdge cvSubdiv2DNextEdge( CvSubdiv2DEdge edge )
{
return CV_SUBDIV2D_NEXT_EDGE(edge);
}
CV_INLINE CvSubdiv2DEdge cvSubdiv2DRotateEdge( CvSubdiv2DEdge edge, int rotate )
{
return (edge & ~3) + ((edge + rotate) & 3);
}
CV_INLINE CvSubdiv2DEdge cvSubdiv2DSymEdge( CvSubdiv2DEdge edge )
{
return edge ^ 2;
}
CV_INLINE CvSubdiv2DEdge cvSubdiv2DGetEdge( CvSubdiv2DEdge edge, CvNextEdgeType type )
{
CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
edge = e->next[(edge + (int)type) & 3];
return (edge & ~3) + ((edge + ((int)type >> 4)) & 3);
}
CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeOrg( CvSubdiv2DEdge edge )
{
CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
return (CvSubdiv2DPoint*)e->pt[edge & 3];
}
CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeDst( CvSubdiv2DEdge edge )
{
CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
return (CvSubdiv2DPoint*)e->pt[(edge + 2) & 3];
}
CV_INLINE double cvTriangleArea( CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c )
{
return ((double)b.x - a.x) * ((double)c.y - a.y) - ((double)b.y - a.y) * ((double)c.x - a.x);
}
/****************************************************************************************\
* Contour Processing and Shape Analysis *
@ -718,61 +616,6 @@ CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage,
CVAPI(void) cvFitLine( const CvArr* points, int dist_type, double param,
double reps, double aeps, float* line );
/* Constructs kd-tree from set of feature descriptors */
CVAPI(struct CvFeatureTree*) cvCreateKDTree(CvMat* desc);
/* Constructs spill-tree from set of feature descriptors */
CVAPI(struct CvFeatureTree*) cvCreateSpillTree( const CvMat* raw_data,
const int naive CV_DEFAULT(50),
const double rho CV_DEFAULT(.7),
const double tau CV_DEFAULT(.1) );
/* Release feature tree */
CVAPI(void) cvReleaseFeatureTree(struct CvFeatureTree* tr);
/* Searches feature tree for k nearest neighbors of given reference points,
searching (in case of kd-tree/bbf) at most emax leaves. */
CVAPI(void) cvFindFeatures(struct CvFeatureTree* tr, const CvMat* query_points,
CvMat* indices, CvMat* dist, int k, int emax CV_DEFAULT(20));
/* Search feature tree for all points that are inlier to given rect region.
Only implemented for kd trees */
CVAPI(int) cvFindFeaturesBoxed(struct CvFeatureTree* tr,
CvMat* bounds_min, CvMat* bounds_max,
CvMat* out_indices);
/* Construct a Locality Sensitive Hash (LSH) table, for indexing d-dimensional vectors of
given type. Vectors will be hashed L times with k-dimensional p-stable (p=2) functions. */
CVAPI(struct CvLSH*) cvCreateLSH(struct CvLSHOperations* ops, int d,
int L CV_DEFAULT(10), int k CV_DEFAULT(10),
int type CV_DEFAULT(CV_64FC1), double r CV_DEFAULT(4),
int64 seed CV_DEFAULT(-1));
/* Construct in-memory LSH table, with n bins. */
CVAPI(struct CvLSH*) cvCreateMemoryLSH(int d, int n, int L CV_DEFAULT(10), int k CV_DEFAULT(10),
int type CV_DEFAULT(CV_64FC1), double r CV_DEFAULT(4),
int64 seed CV_DEFAULT(-1));
/* Free the given LSH structure. */
CVAPI(void) cvReleaseLSH(struct CvLSH** lsh);
/* Return the number of vectors in the LSH. */
CVAPI(unsigned int) LSHSize(struct CvLSH* lsh);
/* Add vectors to the LSH structure, optionally returning indices. */
CVAPI(void) cvLSHAdd(struct CvLSH* lsh, const CvMat* data, CvMat* indices CV_DEFAULT(0));
/* Remove vectors from LSH, as addressed by given indices. */
CVAPI(void) cvLSHRemove(struct CvLSH* lsh, const CvMat* indices);
/* Query the LSH n times for at most k nearest points; data is n x d,
indices and dist are n x k. At most emax stored points will be accessed. */
CVAPI(void) cvLSHQuery(struct CvLSH* lsh, const CvMat* query_points,
CvMat* indices, CvMat* dist, int k, int emax);
#ifdef __cplusplus
}
#endif

View File

@ -1,47 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef _CV_IMG_PROC_H_
#define _CV_IMG_PROC_H_
#endif /*_CV_INTERNAL_H_*/

View File

@ -108,22 +108,6 @@ icvIntersectLines( double x1, double dx1, double y1, double dy1,
}
void
icvCreateCenterNormalLine( CvSubdiv2DEdge edge, double *_a, double *_b, double *_c )
{
CvPoint2D32f org = cvSubdiv2DEdgeOrg( edge )->pt;
CvPoint2D32f dst = cvSubdiv2DEdgeDst( edge )->pt;
double a = dst.x - org.x;
double b = dst.y - org.y;
double c = -(a * (dst.x + org.x) + b * (dst.y + org.y));
*_a = a + a;
*_b = b + b;
*_c = c;
}
void
icvIntersectLines3( double *a0, double *b0, double *c0,
double *a1, double *b1, double *c1, CvPoint2D32f * point )

View File

@ -40,675 +40,6 @@
//M*/
#include "precomp.hpp"
CV_IMPL CvSubdiv2D *
cvCreateSubdiv2D( int subdiv_type, int header_size,
int vtx_size, int quadedge_size, CvMemStorage * storage )
{
if( !storage )
CV_Error( CV_StsNullPtr, "" );
if( header_size < (int)sizeof( CvSubdiv2D ) ||
quadedge_size < (int)sizeof( CvQuadEdge2D ) ||
vtx_size < (int)sizeof( CvSubdiv2DPoint ))
CV_Error( CV_StsBadSize, "" );
return (CvSubdiv2D *)cvCreateGraph( subdiv_type, header_size,
vtx_size, quadedge_size, storage );
}
/****************************************************************************************\
* Quad Edge algebra *
\****************************************************************************************/
static CvSubdiv2DEdge
cvSubdiv2DMakeEdge( CvSubdiv2D * subdiv )
{
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
CvQuadEdge2D* edge = (CvQuadEdge2D*)cvSetNew( (CvSet*)subdiv->edges );
memset( edge->pt, 0, sizeof( edge->pt ));
CvSubdiv2DEdge edgehandle = (CvSubdiv2DEdge) edge;
edge->next[0] = edgehandle;
edge->next[1] = edgehandle + 3;
edge->next[2] = edgehandle + 2;
edge->next[3] = edgehandle + 1;
subdiv->quad_edges++;
return edgehandle;
}
static CvSubdiv2DPoint *
cvSubdiv2DAddPoint( CvSubdiv2D * subdiv, CvPoint2D32f pt, int is_virtual )
{
CvSubdiv2DPoint* subdiv_point = (CvSubdiv2DPoint*)cvSetNew( (CvSet*)subdiv );
if( subdiv_point )
{
memset( subdiv_point, 0, subdiv->elem_size );
subdiv_point->pt = pt;
subdiv_point->first = 0;
subdiv_point->flags |= is_virtual ? CV_SUBDIV2D_VIRTUAL_POINT_FLAG : 0;
subdiv_point->id = -1;
}
return subdiv_point;
}
static void
cvSubdiv2DSplice( CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
{
CvSubdiv2DEdge *a_next = &CV_SUBDIV2D_NEXT_EDGE( edgeA );
CvSubdiv2DEdge *b_next = &CV_SUBDIV2D_NEXT_EDGE( edgeB );
CvSubdiv2DEdge a_rot = cvSubdiv2DRotateEdge( *a_next, 1 );
CvSubdiv2DEdge b_rot = cvSubdiv2DRotateEdge( *b_next, 1 );
CvSubdiv2DEdge *a_rot_next = &CV_SUBDIV2D_NEXT_EDGE( a_rot );
CvSubdiv2DEdge *b_rot_next = &CV_SUBDIV2D_NEXT_EDGE( b_rot );
CvSubdiv2DEdge t;
CV_SWAP( *a_next, *b_next, t );
CV_SWAP( *a_rot_next, *b_rot_next, t );
}
static void
cvSubdiv2DSetEdgePoints( CvSubdiv2DEdge edge,
CvSubdiv2DPoint * org_pt, CvSubdiv2DPoint * dst_pt )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
if( !quadedge )
CV_Error( CV_StsNullPtr, "" );
quadedge->pt[edge & 3] = org_pt;
quadedge->pt[(edge + 2) & 3] = dst_pt;
}
static void
cvSubdiv2DDeleteEdge( CvSubdiv2D * subdiv, CvSubdiv2DEdge edge )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
if( !subdiv || !quadedge )
CV_Error( CV_StsNullPtr, "" );
cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG ));
CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG ));
cvSetRemoveByPtr( (CvSet*)(subdiv->edges), quadedge );
subdiv->quad_edges--;
}
static CvSubdiv2DEdge
cvSubdiv2DConnectEdges( CvSubdiv2D * subdiv, CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
{
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
CvSubdiv2DEdge new_edge = cvSubdiv2DMakeEdge( subdiv );
cvSubdiv2DSplice( new_edge, cvSubdiv2DGetEdge( edgeA, CV_NEXT_AROUND_LEFT ));
cvSubdiv2DSplice( cvSubdiv2DSymEdge( new_edge ), edgeB );
CvSubdiv2DPoint* dstA = cvSubdiv2DEdgeDst( edgeA );
CvSubdiv2DPoint* orgB = cvSubdiv2DEdgeOrg( edgeB );
cvSubdiv2DSetEdgePoints( new_edge, dstA, orgB );
return new_edge;
}
static void
cvSubdiv2DSwapEdges( CvSubdiv2DEdge edge )
{
CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
CvSubdiv2DEdge a = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG );
CvSubdiv2DEdge b = cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG );
CvSubdiv2DPoint *dstB, *dstA;
cvSubdiv2DSplice( edge, a );
cvSubdiv2DSplice( sym_edge, b );
dstA = cvSubdiv2DEdgeDst( a );
dstB = cvSubdiv2DEdgeDst( b );
cvSubdiv2DSetEdgePoints( edge, dstA, dstB );
cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( a, CV_NEXT_AROUND_LEFT ));
cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( b, CV_NEXT_AROUND_LEFT ));
}
static int
icvIsRightOf( CvPoint2D32f& pt, CvSubdiv2DEdge edge )
{
CvSubdiv2DPoint *org = cvSubdiv2DEdgeOrg(edge), *dst = cvSubdiv2DEdgeDst(edge);
double cw_area = cvTriangleArea( pt, dst->pt, org->pt );
return (cw_area > 0) - (cw_area < 0);
}
CV_IMPL CvSubdiv2DPointLocation
cvSubdiv2DLocate( CvSubdiv2D * subdiv, CvPoint2D32f pt,
CvSubdiv2DEdge * _edge, CvSubdiv2DPoint ** _point )
{
CvSubdiv2DPoint *point = 0;
int right_of_curr = 0;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
if( !CV_IS_SUBDIV2D(subdiv) )
CV_Error( CV_StsBadFlag, "" );
int i, max_edges = subdiv->quad_edges * 4;
CvSubdiv2DEdge edge = subdiv->recent_edge;
if( max_edges == 0 )
CV_Error( CV_StsBadSize, "" );
CV_Assert(edge != 0);
if( pt.x < subdiv->topleft.x || pt.y < subdiv->topleft.y ||
pt.x >= subdiv->bottomright.x || pt.y >= subdiv->bottomright.y )
CV_Error( CV_StsOutOfRange, "" );
CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
right_of_curr = icvIsRightOf( pt, edge );
if( right_of_curr > 0 )
{
edge = cvSubdiv2DSymEdge( edge );
right_of_curr = -right_of_curr;
}
for( i = 0; i < max_edges; i++ )
{
CvSubdiv2DEdge onext_edge = cvSubdiv2DNextEdge( edge );
CvSubdiv2DEdge dprev_edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_DST );
int right_of_onext = icvIsRightOf( pt, onext_edge );
int right_of_dprev = icvIsRightOf( pt, dprev_edge );
if( right_of_dprev > 0 )
{
if( right_of_onext > 0 || (right_of_onext == 0 && right_of_curr == 0) )
{
location = CV_PTLOC_INSIDE;
goto exit;
}
else
{
right_of_curr = right_of_onext;
edge = onext_edge;
}
}
else
{
if( right_of_onext > 0 )
{
if( right_of_dprev == 0 && right_of_curr == 0 )
{
location = CV_PTLOC_INSIDE;
goto exit;
}
else
{
right_of_curr = right_of_dprev;
edge = dprev_edge;
}
}
else if( right_of_curr == 0 &&
icvIsRightOf( cvSubdiv2DEdgeDst( onext_edge )->pt, edge ) >= 0 )
{
edge = cvSubdiv2DSymEdge( edge );
}
else
{
right_of_curr = right_of_onext;
edge = onext_edge;
}
}
}
exit:
subdiv->recent_edge = edge;
if( location == CV_PTLOC_INSIDE )
{
double t1, t2, t3;
CvPoint2D32f org_pt = cvSubdiv2DEdgeOrg( edge )->pt;
CvPoint2D32f dst_pt = cvSubdiv2DEdgeDst( edge )->pt;
t1 = fabs( pt.x - org_pt.x );
t1 += fabs( pt.y - org_pt.y );
t2 = fabs( pt.x - dst_pt.x );
t2 += fabs( pt.y - dst_pt.y );
t3 = fabs( org_pt.x - dst_pt.x );
t3 += fabs( org_pt.y - dst_pt.y );
if( t1 < FLT_EPSILON )
{
location = CV_PTLOC_VERTEX;
point = cvSubdiv2DEdgeOrg( edge );
edge = 0;
}
else if( t2 < FLT_EPSILON )
{
location = CV_PTLOC_VERTEX;
point = cvSubdiv2DEdgeDst( edge );
edge = 0;
}
else if( (t1 < t3 || t2 < t3) &&
fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
{
location = CV_PTLOC_ON_EDGE;
point = 0;
}
}
if( location == CV_PTLOC_ERROR )
{
edge = 0;
point = 0;
}
if( _edge )
*_edge = edge;
if( _point )
*_point = point;
return location;
}
CV_INLINE int
icvIsPtInCircle3( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c )
{
const double eps = FLT_EPSILON*0.125;
double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt );
val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt );
val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt );
val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c );
return val > eps ? 1 : val < -eps ? -1 : 0;
}
CV_IMPL CvSubdiv2DPoint *
cvSubdivDelaunay2DInsert( CvSubdiv2D * subdiv, CvPoint2D32f pt )
{
CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
CvSubdiv2DPoint *curr_point = 0, *first_point = 0;
CvSubdiv2DEdge curr_edge = 0, deleted_edge = 0, base_edge = 0;
int i, max_edges;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
if( !CV_IS_SUBDIV2D(subdiv) )
CV_Error( CV_StsBadFlag, "" );
location = cvSubdiv2DLocate( subdiv, pt, &curr_edge, &curr_point );
switch (location)
{
case CV_PTLOC_ERROR:
CV_Error( CV_StsBadSize, "" );
case CV_PTLOC_OUTSIDE_RECT:
CV_Error( CV_StsOutOfRange, "" );
case CV_PTLOC_VERTEX:
break;
case CV_PTLOC_ON_EDGE:
deleted_edge = curr_edge;
subdiv->recent_edge = curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
cvSubdiv2DDeleteEdge( subdiv, deleted_edge );
/* no break */
case CV_PTLOC_INSIDE:
assert( curr_edge != 0 );
subdiv->is_geometry_valid = 0;
curr_point = cvSubdiv2DAddPoint( subdiv, pt, 0 );
base_edge = cvSubdiv2DMakeEdge( subdiv );
first_point = cvSubdiv2DEdgeOrg( curr_edge );
cvSubdiv2DSetEdgePoints( base_edge, first_point, curr_point );
cvSubdiv2DSplice( base_edge, curr_edge );
do
{
base_edge = cvSubdiv2DConnectEdges( subdiv, curr_edge,
cvSubdiv2DSymEdge( base_edge ));
curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
}
while( cvSubdiv2DEdgeDst( curr_edge ) != first_point );
curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
max_edges = subdiv->quad_edges * 4;
for( i = 0; i < max_edges; i++ )
{
CvSubdiv2DPoint *temp_dst = 0, *curr_org = 0, *curr_dst = 0;
CvSubdiv2DEdge temp_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
temp_dst = cvSubdiv2DEdgeDst( temp_edge );
curr_org = cvSubdiv2DEdgeOrg( curr_edge );
curr_dst = cvSubdiv2DEdgeDst( curr_edge );
if( icvIsRightOf( temp_dst->pt, curr_edge ) > 0 &&
icvIsPtInCircle3( curr_org->pt, temp_dst->pt,
curr_dst->pt, curr_point->pt ) < 0 )
{
cvSubdiv2DSwapEdges( curr_edge );
curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
}
else if( curr_org == first_point )
{
break;
}
else
{
curr_edge = cvSubdiv2DGetEdge( cvSubdiv2DNextEdge( curr_edge ),
CV_PREV_AROUND_LEFT );
}
}
break;
default:
CV_Error_(CV_StsError, ("cvSubdiv2DLocate returned invalid location = %d", location) );
}
return curr_point;
}
CV_IMPL void
cvInitSubdivDelaunay2D( CvSubdiv2D * subdiv, CvRect rect )
{
float big_coord = 3.f * MAX( rect.width, rect.height );
CvPoint2D32f ppA, ppB, ppC;
CvSubdiv2DPoint *pA, *pB, *pC;
CvSubdiv2DEdge edge_AB, edge_BC, edge_CA;
float rx = (float) rect.x;
float ry = (float) rect.y;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
cvClearSet( (CvSet *) (subdiv->edges) );
cvClearSet( (CvSet *) subdiv );
subdiv->quad_edges = 0;
subdiv->recent_edge = 0;
subdiv->is_geometry_valid = 0;
subdiv->topleft = cvPoint2D32f( rx, ry );
subdiv->bottomright = cvPoint2D32f( rx + rect.width, ry + rect.height );
ppA = cvPoint2D32f( rx + big_coord, ry );
ppB = cvPoint2D32f( rx, ry + big_coord );
ppC = cvPoint2D32f( rx - big_coord, ry - big_coord );
pA = cvSubdiv2DAddPoint( subdiv, ppA, 0 );
pB = cvSubdiv2DAddPoint( subdiv, ppB, 0 );
pC = cvSubdiv2DAddPoint( subdiv, ppC, 0 );
edge_AB = cvSubdiv2DMakeEdge( subdiv );
edge_BC = cvSubdiv2DMakeEdge( subdiv );
edge_CA = cvSubdiv2DMakeEdge( subdiv );
cvSubdiv2DSetEdgePoints( edge_AB, pA, pB );
cvSubdiv2DSetEdgePoints( edge_BC, pB, pC );
cvSubdiv2DSetEdgePoints( edge_CA, pC, pA );
cvSubdiv2DSplice( edge_AB, cvSubdiv2DSymEdge( edge_CA ));
cvSubdiv2DSplice( edge_BC, cvSubdiv2DSymEdge( edge_AB ));
cvSubdiv2DSplice( edge_CA, cvSubdiv2DSymEdge( edge_BC ));
subdiv->recent_edge = edge_AB;
}
CV_IMPL void
cvClearSubdivVoronoi2D( CvSubdiv2D * subdiv )
{
int elem_size;
int i, total;
CvSeqReader reader;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
/* clear pointers to voronoi points */
total = subdiv->edges->total;
elem_size = subdiv->edges->elem_size;
cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
for( i = 0; i < total; i++ )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) reader.ptr;
quadedge->pt[1] = quadedge->pt[3] = 0;
CV_NEXT_SEQ_ELEM( elem_size, reader );
}
/* remove voronoi points */
total = subdiv->total;
elem_size = subdiv->elem_size;
cvStartReadSeq( (CvSeq *) subdiv, &reader, 0 );
for( i = 0; i < total; i++ )
{
CvSubdiv2DPoint *pt = (CvSubdiv2DPoint *) reader.ptr;
/* check for virtual point. it is also check that the point exists */
if( pt->flags & CV_SUBDIV2D_VIRTUAL_POINT_FLAG )
{
cvSetRemoveByPtr( (CvSet*)subdiv, pt );
}
CV_NEXT_SEQ_ELEM( elem_size, reader );
}
subdiv->is_geometry_valid = 0;
}
CV_IMPL void
cvCalcSubdivVoronoi2D( CvSubdiv2D * subdiv )
{
CvSeqReader reader;
int i, total, elem_size;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
/* check if it is already calculated */
if( subdiv->is_geometry_valid )
return;
total = subdiv->edges->total;
elem_size = subdiv->edges->elem_size;
cvClearSubdivVoronoi2D( subdiv );
cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
if( total <= 3 )
return;
/* skip first three edges (bounding triangle) */
for( i = 0; i < 3; i++ )
CV_NEXT_SEQ_ELEM( elem_size, reader );
/* loop through all quad-edges */
for( ; i < total; i++ )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (reader.ptr);
if( CV_IS_SET_ELEM( quadedge ))
{
CvSubdiv2DEdge edge0 = (CvSubdiv2DEdge) quadedge, edge1, edge2;
double a0, b0, c0, a1, b1, c1;
CvPoint2D32f virt_point;
CvSubdiv2DPoint *voronoi_point;
if( !quadedge->pt[3] )
{
edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_LEFT );
edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_LEFT );
icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
fabs( virt_point.y ) < FLT_MAX * 0.5 )
{
voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
quadedge->pt[3] =
((CvQuadEdge2D *) (edge1 & ~3))->pt[3 - (edge1 & 2)] =
((CvQuadEdge2D *) (edge2 & ~3))->pt[3 - (edge2 & 2)] = voronoi_point;
}
}
if( !quadedge->pt[1] )
{
edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_RIGHT );
edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_RIGHT );
icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
fabs( virt_point.y ) < FLT_MAX * 0.5 )
{
voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
quadedge->pt[1] =
((CvQuadEdge2D *) (edge1 & ~3))->pt[1 + (edge1 & 2)] =
((CvQuadEdge2D *) (edge2 & ~3))->pt[1 + (edge2 & 2)] = voronoi_point;
}
}
}
CV_NEXT_SEQ_ELEM( elem_size, reader );
}
subdiv->is_geometry_valid = 1;
}
static int
icvIsRightOf2( const CvPoint2D32f& pt, const CvPoint2D32f& org, const CvPoint2D32f& diff )
{
double cw_area = ((double)org.x - pt.x)*diff.y - ((double)org.y - pt.y)*diff.x;
return (cw_area > 0) - (cw_area < 0);
}
CV_IMPL CvSubdiv2DPoint*
cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt )
{
CvSubdiv2DPoint* point = 0;
CvPoint2D32f start;
CvPoint2D32f diff;
CvSubdiv2DPointLocation loc;
CvSubdiv2DEdge edge;
int i;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
if( !CV_IS_SUBDIV2D( subdiv ))
CV_Error( CV_StsNullPtr, "" );
if( subdiv->edges->active_count <= 3 )
return 0;
if( !subdiv->is_geometry_valid )
cvCalcSubdivVoronoi2D( subdiv );
loc = cvSubdiv2DLocate( subdiv, pt, &edge, &point );
switch( loc )
{
case CV_PTLOC_ON_EDGE:
case CV_PTLOC_INSIDE:
break;
default:
return point;
}
point = 0;
start = cvSubdiv2DEdgeOrg( edge )->pt;
diff.x = pt.x - start.x;
diff.y = pt.y - start.y;
edge = cvSubdiv2DRotateEdge( edge, 1 );
for( i = 0; i < subdiv->total; i++ )
{
CvPoint2D32f t;
for(;;)
{
assert( cvSubdiv2DEdgeDst( edge ));
t = cvSubdiv2DEdgeDst( edge )->pt;
if( icvIsRightOf2( t, start, diff ) >= 0 )
break;
edge = cvSubdiv2DGetEdge( edge, CV_NEXT_AROUND_LEFT );
}
for(;;)
{
assert( cvSubdiv2DEdgeOrg( edge ));
t = cvSubdiv2DEdgeOrg( edge )->pt;
if( icvIsRightOf2( t, start, diff ) < 0 )
break;
edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_LEFT );
}
{
CvPoint2D32f tempDiff = cvSubdiv2DEdgeDst( edge )->pt;
t = cvSubdiv2DEdgeOrg( edge )->pt;
tempDiff.x -= t.x;
tempDiff.y -= t.y;
if( icvIsRightOf2( pt, t, tempDiff ) >= 0 )
{
point = cvSubdiv2DEdgeOrg( cvSubdiv2DRotateEdge( edge, 3 ));
break;
}
}
edge = cvSubdiv2DSymEdge( edge );
}
return point;
}
namespace cv
{
@ -879,17 +210,21 @@ void Subdiv2D::swapEdges( int edge )
splice(sedge, getEdge(b, NEXT_AROUND_LEFT));
}
static double triangleArea( Point2f a, Point2f b, Point2f c )
{
return ((double)b.x - a.x) * ((double)c.y - a.y) - ((double)b.y - a.y) * ((double)c.x - a.x);
}
int Subdiv2D::isRightOf(Point2f pt, int edge) const
{
Point2f org, dst;
edgeOrg(edge, &org);
edgeDst(edge, &dst);
double cw_area = cvTriangleArea( pt, dst, org );
double cw_area = triangleArea( pt, dst, org );
return (cw_area > 0) - (cw_area < 0);
}
int Subdiv2D::newEdge()
{
if( freeQEdge <= 0 )
@ -1039,7 +374,7 @@ int Subdiv2D::locate(Point2f pt, int& _edge, int& _vertex)
edge = 0;
}
else if( (t1 < t3 || t2 < t3) &&
fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
fabs( triangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
{
location = PTLOC_ON_EDGE;
vertex = 0;
@ -1063,10 +398,10 @@ inline int
isPtInCircle3( Point2f pt, Point2f a, Point2f b, Point2f c)
{
const double eps = FLT_EPSILON*0.125;
double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt );
val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt );
val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt );
val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c );
double val = ((double)a.x * a.x + (double)a.y * a.y) * triangleArea( b, c, pt );
val -= ((double)b.x * b.x + (double)b.y * b.y) * triangleArea( a, c, pt );
val += ((double)c.x * c.x + (double)c.y * c.y) * triangleArea( a, b, pt );
val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * triangleArea( a, b, c );
return val > eps ? 1 : val < -eps ? -1 : 0;
}

View File

@ -6,3 +6,5 @@ legacy. Deprecated stuff
.. toctree::
:maxdepth: 2
motion_analysis

View File

@ -0,0 +1,88 @@
Motion Analysis
===============
.. highlight:: cpp
CalcOpticalFlowBM
-----------------
Calculates the optical flow for two images by using the block matching method.
.. ocv:cfunction:: void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, CvSize blockSize, CvSize shiftSize, CvSize maxRange, int usePrevious, CvArr* velx, CvArr* vely )
.. ocv:pyoldfunction:: cv.CalcOpticalFlowBM(prev, curr, blockSize, shiftSize, maxRange, usePrevious, velx, vely)-> None
:param prev: First image, 8-bit, single-channel
:param curr: Second image, 8-bit, single-channel
:param blockSize: Size of basic blocks that are compared
:param shiftSize: Block coordinate increments
:param maxRange: Size of the scanned neighborhood in pixels around the block
:param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not.
:param velx: Horizontal component of the optical flow of
.. math::
\left \lfloor \frac{\texttt{prev->width} - \texttt{blockSize.width}}{\texttt{shiftSize.width}} \right \rfloor \times \left \lfloor \frac{\texttt{prev->height} - \texttt{blockSize.height}}{\texttt{shiftSize.height}} \right \rfloor
size, 32-bit floating-point, single-channel
:param vely: Vertical component of the optical flow of the same size ``velx`` , 32-bit floating-point, single-channel
The function calculates the optical flow for overlapped blocks ``blockSize.width x blockSize.height`` pixels each, thus the velocity fields are smaller than the original images. For every block in ``prev``
the functions tries to find a similar block in ``curr`` in some neighborhood of the original block or shifted by ``(velx(x0,y0), vely(x0,y0))`` block as has been calculated by previous function call (if ``usePrevious=1``)
CalcOpticalFlowHS
-----------------
Calculates the optical flow for two images using Horn-Schunck algorithm.
.. ocv:cfunction:: void cvCalcOpticalFlowHS(const CvArr* prev, const CvArr* curr, int usePrevious, CvArr* velx, CvArr* vely, double lambda, CvTermCriteria criteria)
.. ocv:pyoldfunction:: cv.CalcOpticalFlowHS(prev, curr, usePrevious, velx, vely, lambda, criteria)-> None
:param prev: First image, 8-bit, single-channel
:param curr: Second image, 8-bit, single-channel
:param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not.
:param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
:param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
:param lambda: Smoothness weight. The larger it is, the smoother optical flow map you get.
:param criteria: Criteria of termination of velocity computing
The function computes the flow for every pixel of the first input image using the Horn and Schunck algorithm [Horn81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`.
CalcOpticalFlowLK
-----------------
Calculates the optical flow for two images using Lucas-Kanade algorithm.
.. ocv:cfunction:: void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, CvSize winSize, CvArr* velx, CvArr* vely )
.. ocv:pyoldfunction:: cv.CalcOpticalFlowLK(prev, curr, winSize, velx, vely)-> None
:param prev: First image, 8-bit, single-channel
:param curr: Second image, 8-bit, single-channel
:param winSize: Size of the averaging window used for grouping pixels
:param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
:param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
The function computes the flow for every pixel of the first input image using the Lucas and Kanade algorithm [Lucas81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`.

View File

@ -2797,8 +2797,529 @@ protected:
}
// 2009-01-12, Xavier Delacour <xavier.delacour@gmail.com>
//#include "cvvidsurv.hpp"
struct lsh_hash {
int h1, h2;
};
struct CvLSHOperations
{
virtual ~CvLSHOperations() {}
virtual int vector_add(const void* data) = 0;
virtual void vector_remove(int i) = 0;
virtual const void* vector_lookup(int i) = 0;
virtual void vector_reserve(int n) = 0;
virtual unsigned int vector_count() = 0;
virtual void hash_insert(lsh_hash h, int l, int i) = 0;
virtual void hash_remove(lsh_hash h, int l, int i) = 0;
virtual int hash_lookup(lsh_hash h, int l, int* ret_i, int ret_i_max) = 0;
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Splits color or grayscale image into multiple connected components
of nearly the same color/brightness using modification of Burt algorithm.
comp with contain a pointer to sequence (CvSeq)
of connected components (CvConnectedComp) */
CVAPI(void) cvPyrSegmentation( IplImage* src, IplImage* dst,
CvMemStorage* storage, CvSeq** comp,
int level, double threshold1,
double threshold2 );
/****************************************************************************************\
* Planar subdivisions *
\****************************************************************************************/
/* Initializes Delaunay triangulation */
CVAPI(void) cvInitSubdivDelaunay2D( CvSubdiv2D* subdiv, CvRect rect );
/* Creates new subdivision */
CVAPI(CvSubdiv2D*) cvCreateSubdiv2D( int subdiv_type, int header_size,
int vtx_size, int quadedge_size,
CvMemStorage* storage );
/************************* high-level subdivision functions ***************************/
/* Simplified Delaunay diagram creation */
CV_INLINE CvSubdiv2D* cvCreateSubdivDelaunay2D( CvRect rect, CvMemStorage* storage )
{
CvSubdiv2D* subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*subdiv),
sizeof(CvSubdiv2DPoint), sizeof(CvQuadEdge2D), storage );
cvInitSubdivDelaunay2D( subdiv, rect );
return subdiv;
}
/* Inserts new point to the Delaunay triangulation */
CVAPI(CvSubdiv2DPoint*) cvSubdivDelaunay2DInsert( CvSubdiv2D* subdiv, CvPoint2D32f pt);
/* Locates a point within the Delaunay triangulation (finds the edge
the point is left to or belongs to, or the triangulation point the given
point coinsides with */
CVAPI(CvSubdiv2DPointLocation) cvSubdiv2DLocate(
CvSubdiv2D* subdiv, CvPoint2D32f pt,
CvSubdiv2DEdge* edge,
CvSubdiv2DPoint** vertex CV_DEFAULT(NULL) );
/* Calculates Voronoi tesselation (i.e. coordinates of Voronoi points) */
CVAPI(void) cvCalcSubdivVoronoi2D( CvSubdiv2D* subdiv );
/* Removes all Voronoi points from the tesselation */
CVAPI(void) cvClearSubdivVoronoi2D( CvSubdiv2D* subdiv );
/* Finds the nearest to the given point vertex in subdivision. */
CVAPI(CvSubdiv2DPoint*) cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt );
/************ Basic quad-edge navigation and operations ************/
CV_INLINE CvSubdiv2DEdge cvSubdiv2DNextEdge( CvSubdiv2DEdge edge )
{
return CV_SUBDIV2D_NEXT_EDGE(edge);
}
CV_INLINE CvSubdiv2DEdge cvSubdiv2DRotateEdge( CvSubdiv2DEdge edge, int rotate )
{
return (edge & ~3) + ((edge + rotate) & 3);
}
CV_INLINE CvSubdiv2DEdge cvSubdiv2DSymEdge( CvSubdiv2DEdge edge )
{
return edge ^ 2;
}
CV_INLINE CvSubdiv2DEdge cvSubdiv2DGetEdge( CvSubdiv2DEdge edge, CvNextEdgeType type )
{
CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
edge = e->next[(edge + (int)type) & 3];
return (edge & ~3) + ((edge + ((int)type >> 4)) & 3);
}
CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeOrg( CvSubdiv2DEdge edge )
{
CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
return (CvSubdiv2DPoint*)e->pt[edge & 3];
}
CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeDst( CvSubdiv2DEdge edge )
{
CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3);
return (CvSubdiv2DPoint*)e->pt[(edge + 2) & 3];
}
CV_INLINE double cvTriangleArea( CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c )
{
return ((double)b.x - a.x) * ((double)c.y - a.y) - ((double)b.y - a.y) * ((double)c.x - a.x);
}
/* Constructs kd-tree from set of feature descriptors */
CVAPI(struct CvFeatureTree*) cvCreateKDTree(CvMat* desc);
/* Constructs spill-tree from set of feature descriptors */
CVAPI(struct CvFeatureTree*) cvCreateSpillTree( const CvMat* raw_data,
const int naive CV_DEFAULT(50),
const double rho CV_DEFAULT(.7),
const double tau CV_DEFAULT(.1) );
/* Release feature tree */
CVAPI(void) cvReleaseFeatureTree(struct CvFeatureTree* tr);
/* Searches feature tree for k nearest neighbors of given reference points,
searching (in case of kd-tree/bbf) at most emax leaves. */
CVAPI(void) cvFindFeatures(struct CvFeatureTree* tr, const CvMat* query_points,
CvMat* indices, CvMat* dist, int k, int emax CV_DEFAULT(20));
/* Search feature tree for all points that are inlier to given rect region.
Only implemented for kd trees */
CVAPI(int) cvFindFeaturesBoxed(struct CvFeatureTree* tr,
CvMat* bounds_min, CvMat* bounds_max,
CvMat* out_indices);
/* Construct a Locality Sensitive Hash (LSH) table, for indexing d-dimensional vectors of
given type. Vectors will be hashed L times with k-dimensional p-stable (p=2) functions. */
CVAPI(struct CvLSH*) cvCreateLSH(struct CvLSHOperations* ops, int d,
int L CV_DEFAULT(10), int k CV_DEFAULT(10),
int type CV_DEFAULT(CV_64FC1), double r CV_DEFAULT(4),
int64 seed CV_DEFAULT(-1));
/* Construct in-memory LSH table, with n bins. */
CVAPI(struct CvLSH*) cvCreateMemoryLSH(int d, int n, int L CV_DEFAULT(10), int k CV_DEFAULT(10),
int type CV_DEFAULT(CV_64FC1), double r CV_DEFAULT(4),
int64 seed CV_DEFAULT(-1));
/* Free the given LSH structure. */
CVAPI(void) cvReleaseLSH(struct CvLSH** lsh);
/* Return the number of vectors in the LSH. */
CVAPI(unsigned int) LSHSize(struct CvLSH* lsh);
/* Add vectors to the LSH structure, optionally returning indices. */
CVAPI(void) cvLSHAdd(struct CvLSH* lsh, const CvMat* data, CvMat* indices CV_DEFAULT(0));
/* Remove vectors from LSH, as addressed by given indices. */
CVAPI(void) cvLSHRemove(struct CvLSH* lsh, const CvMat* indices);
/* Query the LSH n times for at most k nearest points; data is n x d,
indices and dist are n x k. At most emax stored points will be accessed. */
CVAPI(void) cvLSHQuery(struct CvLSH* lsh, const CvMat* query_points,
CvMat* indices, CvMat* dist, int k, int emax);
/* Kolmogorov-Zabin stereo-correspondence algorithm (a.k.a. KZ1) */
#define CV_STEREO_GC_OCCLUDED SHRT_MAX
typedef struct CvStereoGCState
{
int Ithreshold;
int interactionRadius;
float K, lambda, lambda1, lambda2;
int occlusionCost;
int minDisparity;
int numberOfDisparities;
int maxIters;
CvMat* left;
CvMat* right;
CvMat* dispLeft;
CvMat* dispRight;
CvMat* ptrLeft;
CvMat* ptrRight;
CvMat* vtxBuf;
CvMat* edgeBuf;
} CvStereoGCState;
CVAPI(CvStereoGCState*) cvCreateStereoGCState( int numberOfDisparities, int maxIters );
CVAPI(void) cvReleaseStereoGCState( CvStereoGCState** state );
CVAPI(void) cvFindStereoCorrespondenceGC( const CvArr* left, const CvArr* right,
CvArr* disparityLeft, CvArr* disparityRight,
CvStereoGCState* state,
int useDisparityGuess CV_DEFAULT(0) );
/* Calculates optical flow for 2 images using classical Lucas & Kanade algorithm */
CVAPI(void) cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr,
CvSize win_size, CvArr* velx, CvArr* vely );
/* Calculates optical flow for 2 images using block matching algorithm */
CVAPI(void) cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr,
CvSize block_size, CvSize shift_size,
CvSize max_range, int use_previous,
CvArr* velx, CvArr* vely );
/* Calculates Optical flow for 2 images using Horn & Schunck algorithm */
CVAPI(void) cvCalcOpticalFlowHS( const CvArr* prev, const CvArr* curr,
int use_previous, CvArr* velx, CvArr* vely,
double lambda, CvTermCriteria criteria );
/****************************************************************************************\
* Background/foreground segmentation *
\****************************************************************************************/
/* We discriminate between foreground and background pixels
* by building and maintaining a model of the background.
* Any pixel which does not fit this model is then deemed
* to be foreground.
*
* At present we support two core background models,
* one of which has two variations:
*
* o CV_BG_MODEL_FGD: latest and greatest algorithm, described in
*
* Foreground Object Detection from Videos Containing Complex Background.
* Liyuan Li, Weimin Huang, Irene Y.H. Gu, and Qi Tian.
* ACM MM2003 9p
*
* o CV_BG_MODEL_FGD_SIMPLE:
* A code comment describes this as a simplified version of the above,
* but the code is in fact currently identical
*
* o CV_BG_MODEL_MOG: "Mixture of Gaussians", older algorithm, described in
*
* Moving target classification and tracking from real-time video.
* A Lipton, H Fujijoshi, R Patil
* Proceedings IEEE Workshop on Application of Computer Vision pp 8-14 1998
*
* Learning patterns of activity using real-time tracking
* C Stauffer and W Grimson August 2000
* IEEE Transactions on Pattern Analysis and Machine Intelligence 22(8):747-757
*/
#define CV_BG_MODEL_FGD 0
#define CV_BG_MODEL_MOG 1 /* "Mixture of Gaussians". */
#define CV_BG_MODEL_FGD_SIMPLE 2
struct CvBGStatModel;
typedef void (CV_CDECL * CvReleaseBGStatModel)( struct CvBGStatModel** bg_model );
typedef int (CV_CDECL * CvUpdateBGStatModel)( IplImage* curr_frame, struct CvBGStatModel* bg_model,
double learningRate );
#define CV_BG_STAT_MODEL_FIELDS() \
int type; /*type of BG model*/ \
CvReleaseBGStatModel release; \
CvUpdateBGStatModel update; \
IplImage* background; /*8UC3 reference background image*/ \
IplImage* foreground; /*8UC1 foreground image*/ \
IplImage** layers; /*8UC3 reference background image, can be null */ \
int layer_count; /* can be zero */ \
CvMemStorage* storage; /*storage for foreground_regions*/ \
CvSeq* foreground_regions /*foreground object contours*/
typedef struct CvBGStatModel
{
CV_BG_STAT_MODEL_FIELDS();
} CvBGStatModel;
//
// Releases memory used by BGStatModel
CVAPI(void) cvReleaseBGStatModel( CvBGStatModel** bg_model );
// Updates statistical model and returns number of found foreground regions
CVAPI(int) cvUpdateBGStatModel( IplImage* current_frame, CvBGStatModel* bg_model,
double learningRate CV_DEFAULT(-1));
// Performs FG post-processing using segmentation
// (all pixels of a region will be classified as foreground if majority of pixels of the region are FG).
// parameters:
// segments - pointer to result of segmentation (for example MeanShiftSegmentation)
// bg_model - pointer to CvBGStatModel structure
CVAPI(void) cvRefineForegroundMaskBySegm( CvSeq* segments, CvBGStatModel* bg_model );
/* Common use change detection function */
CVAPI(int) cvChangeDetection( IplImage* prev_frame,
IplImage* curr_frame,
IplImage* change_mask );
/*
Interface of ACM MM2003 algorithm
*/
/* Default parameters of foreground detection algorithm: */
#define CV_BGFG_FGD_LC 128
#define CV_BGFG_FGD_N1C 15
#define CV_BGFG_FGD_N2C 25
#define CV_BGFG_FGD_LCC 64
#define CV_BGFG_FGD_N1CC 25
#define CV_BGFG_FGD_N2CC 40
/* Background reference image update parameter: */
#define CV_BGFG_FGD_ALPHA_1 0.1f
/* stat model update parameter
* 0.002f ~ 1K frame(~45sec), 0.005 ~ 18sec (if 25fps and absolutely static BG)
*/
#define CV_BGFG_FGD_ALPHA_2 0.005f
/* start value for alpha parameter (to fast initiate statistic model) */
#define CV_BGFG_FGD_ALPHA_3 0.1f
#define CV_BGFG_FGD_DELTA 2
#define CV_BGFG_FGD_T 0.9f
#define CV_BGFG_FGD_MINAREA 15.f
#define CV_BGFG_FGD_BG_UPDATE_TRESH 0.5f
/* See the above-referenced Li/Huang/Gu/Tian paper
* for a full description of these background-model
* tuning parameters.
*
* Nomenclature: 'c' == "color", a three-component red/green/blue vector.
* We use histograms of these to model the range of
* colors we've seen at a given background pixel.
*
* 'cc' == "color co-occurrence", a six-component vector giving
* RGB color for both this frame and preceding frame.
* We use histograms of these to model the range of
* color CHANGES we've seen at a given background pixel.
*/
typedef struct CvFGDStatModelParams
{
int Lc; /* Quantized levels per 'color' component. Power of two, typically 32, 64 or 128. */
int N1c; /* Number of color vectors used to model normal background color variation at a given pixel. */
int N2c; /* Number of color vectors retained at given pixel. Must be > N1c, typically ~ 5/3 of N1c. */
/* Used to allow the first N1c vectors to adapt over time to changing background. */
int Lcc; /* Quantized levels per 'color co-occurrence' component. Power of two, typically 16, 32 or 64. */
int N1cc; /* Number of color co-occurrence vectors used to model normal background color variation at a given pixel. */
int N2cc; /* Number of color co-occurrence vectors retained at given pixel. Must be > N1cc, typically ~ 5/3 of N1cc. */
/* Used to allow the first N1cc vectors to adapt over time to changing background. */
int is_obj_without_holes;/* If TRUE we ignore holes within foreground blobs. Defaults to TRUE. */
int perform_morphing; /* Number of erode-dilate-erode foreground-blob cleanup iterations. */
/* These erase one-pixel junk blobs and merge almost-touching blobs. Default value is 1. */
float alpha1; /* How quickly we forget old background pixel values seen. Typically set to 0.1 */
float alpha2; /* "Controls speed of feature learning". Depends on T. Typical value circa 0.005. */
float alpha3; /* Alternate to alpha2, used (e.g.) for quicker initial convergence. Typical value 0.1. */
float delta; /* Affects color and color co-occurrence quantization, typically set to 2. */
float T; /* "A percentage value which determines when new features can be recognized as new background." (Typically 0.9).*/
float minArea; /* Discard foreground blobs whose bounding box is smaller than this threshold. */
} CvFGDStatModelParams;
typedef struct CvBGPixelCStatTable
{
float Pv, Pvb;
uchar v[3];
} CvBGPixelCStatTable;
typedef struct CvBGPixelCCStatTable
{
float Pv, Pvb;
uchar v[6];
} CvBGPixelCCStatTable;
typedef struct CvBGPixelStat
{
float Pbc;
float Pbcc;
CvBGPixelCStatTable* ctable;
CvBGPixelCCStatTable* cctable;
uchar is_trained_st_model;
uchar is_trained_dyn_model;
} CvBGPixelStat;
typedef struct CvFGDStatModel
{
CV_BG_STAT_MODEL_FIELDS();
CvBGPixelStat* pixel_stat;
IplImage* Ftd;
IplImage* Fbd;
IplImage* prev_frame;
CvFGDStatModelParams params;
} CvFGDStatModel;
/* Creates FGD model */
CVAPI(CvBGStatModel*) cvCreateFGDStatModel( IplImage* first_frame,
CvFGDStatModelParams* parameters CV_DEFAULT(NULL));
/*
Interface of Gaussian mixture algorithm
"An improved adaptive background mixture model for real-time tracking with shadow detection"
P. KadewTraKuPong and R. Bowden,
Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001."
http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
*/
/* Note: "MOG" == "Mixture Of Gaussians": */
#define CV_BGFG_MOG_MAX_NGAUSSIANS 500
/* default parameters of gaussian background detection algorithm */
#define CV_BGFG_MOG_BACKGROUND_THRESHOLD 0.7 /* threshold sum of weights for background test */
#define CV_BGFG_MOG_STD_THRESHOLD 2.5 /* lambda=2.5 is 99% */
#define CV_BGFG_MOG_WINDOW_SIZE 200 /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */
#define CV_BGFG_MOG_NGAUSSIANS 5 /* = K = number of Gaussians in mixture */
#define CV_BGFG_MOG_WEIGHT_INIT 0.05
#define CV_BGFG_MOG_SIGMA_INIT 30
#define CV_BGFG_MOG_MINAREA 15.f
#define CV_BGFG_MOG_NCOLORS 3
typedef struct CvGaussBGStatModelParams
{
int win_size; /* = 1/alpha */
int n_gauss;
double bg_threshold, std_threshold, minArea;
double weight_init, variance_init;
}CvGaussBGStatModelParams;
typedef struct CvGaussBGValues
{
int match_sum;
double weight;
double variance[CV_BGFG_MOG_NCOLORS];
double mean[CV_BGFG_MOG_NCOLORS];
} CvGaussBGValues;
typedef struct CvGaussBGPoint
{
CvGaussBGValues* g_values;
} CvGaussBGPoint;
typedef struct CvGaussBGModel
{
CV_BG_STAT_MODEL_FIELDS();
CvGaussBGStatModelParams params;
CvGaussBGPoint* g_point;
int countFrames;
} CvGaussBGModel;
/* Creates Gaussian mixture background model */
CVAPI(CvBGStatModel*) cvCreateGaussianBGModel( IplImage* first_frame,
CvGaussBGStatModelParams* parameters CV_DEFAULT(NULL));
typedef struct CvBGCodeBookElem
{
struct CvBGCodeBookElem* next;
int tLastUpdate;
int stale;
uchar boxMin[3];
uchar boxMax[3];
uchar learnMin[3];
uchar learnMax[3];
} CvBGCodeBookElem;
typedef struct CvBGCodeBookModel
{
CvSize size;
int t;
uchar cbBounds[3];
uchar modMin[3];
uchar modMax[3];
CvBGCodeBookElem** cbmap;
CvMemStorage* storage;
CvBGCodeBookElem* freeList;
} CvBGCodeBookModel;
CVAPI(CvBGCodeBookModel*) cvCreateBGCodeBookModel();
CVAPI(void) cvReleaseBGCodeBookModel( CvBGCodeBookModel** model );
CVAPI(void) cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* image,
CvRect roi CV_DEFAULT(cvRect(0,0,0,0)),
const CvArr* mask CV_DEFAULT(0) );
CVAPI(int) cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* image,
CvArr* fgmask, CvRect roi CV_DEFAULT(cvRect(0,0,0,0)) );
CVAPI(void) cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh,
CvRect roi CV_DEFAULT(cvRect(0,0,0,0)),
const CvArr* mask CV_DEFAULT(0) );
CVAPI(CvSeq*) cvSegmentFGMask( CvArr *fgmask, int poly1Hull0 CV_DEFAULT(1),
float perimScale CV_DEFAULT(4.f),
CvMemStorage* storage CV_DEFAULT(0),
CvPoint offset CV_DEFAULT(cvPoint(0,0)));
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,709 @@
#include "precomp.hpp"
CV_IMPL CvSubdiv2D *
cvCreateSubdiv2D( int subdiv_type, int header_size,
int vtx_size, int quadedge_size, CvMemStorage * storage )
{
if( !storage )
CV_Error( CV_StsNullPtr, "" );
if( header_size < (int)sizeof( CvSubdiv2D ) ||
quadedge_size < (int)sizeof( CvQuadEdge2D ) ||
vtx_size < (int)sizeof( CvSubdiv2DPoint ))
CV_Error( CV_StsBadSize, "" );
return (CvSubdiv2D *)cvCreateGraph( subdiv_type, header_size,
vtx_size, quadedge_size, storage );
}
/****************************************************************************************\
* Quad Edge algebra *
\****************************************************************************************/
static CvSubdiv2DEdge
cvSubdiv2DMakeEdge( CvSubdiv2D * subdiv )
{
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
CvQuadEdge2D* edge = (CvQuadEdge2D*)cvSetNew( (CvSet*)subdiv->edges );
memset( edge->pt, 0, sizeof( edge->pt ));
CvSubdiv2DEdge edgehandle = (CvSubdiv2DEdge) edge;
edge->next[0] = edgehandle;
edge->next[1] = edgehandle + 3;
edge->next[2] = edgehandle + 2;
edge->next[3] = edgehandle + 1;
subdiv->quad_edges++;
return edgehandle;
}
static CvSubdiv2DPoint *
cvSubdiv2DAddPoint( CvSubdiv2D * subdiv, CvPoint2D32f pt, int is_virtual )
{
CvSubdiv2DPoint* subdiv_point = (CvSubdiv2DPoint*)cvSetNew( (CvSet*)subdiv );
if( subdiv_point )
{
memset( subdiv_point, 0, subdiv->elem_size );
subdiv_point->pt = pt;
subdiv_point->first = 0;
subdiv_point->flags |= is_virtual ? CV_SUBDIV2D_VIRTUAL_POINT_FLAG : 0;
subdiv_point->id = -1;
}
return subdiv_point;
}
static void
cvSubdiv2DSplice( CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
{
CvSubdiv2DEdge *a_next = &CV_SUBDIV2D_NEXT_EDGE( edgeA );
CvSubdiv2DEdge *b_next = &CV_SUBDIV2D_NEXT_EDGE( edgeB );
CvSubdiv2DEdge a_rot = cvSubdiv2DRotateEdge( *a_next, 1 );
CvSubdiv2DEdge b_rot = cvSubdiv2DRotateEdge( *b_next, 1 );
CvSubdiv2DEdge *a_rot_next = &CV_SUBDIV2D_NEXT_EDGE( a_rot );
CvSubdiv2DEdge *b_rot_next = &CV_SUBDIV2D_NEXT_EDGE( b_rot );
CvSubdiv2DEdge t;
CV_SWAP( *a_next, *b_next, t );
CV_SWAP( *a_rot_next, *b_rot_next, t );
}
static void
cvSubdiv2DSetEdgePoints( CvSubdiv2DEdge edge,
CvSubdiv2DPoint * org_pt, CvSubdiv2DPoint * dst_pt )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
if( !quadedge )
CV_Error( CV_StsNullPtr, "" );
quadedge->pt[edge & 3] = org_pt;
quadedge->pt[(edge + 2) & 3] = dst_pt;
}
static void
cvSubdiv2DDeleteEdge( CvSubdiv2D * subdiv, CvSubdiv2DEdge edge )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3);
if( !subdiv || !quadedge )
CV_Error( CV_StsNullPtr, "" );
cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG ));
CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG ));
cvSetRemoveByPtr( (CvSet*)(subdiv->edges), quadedge );
subdiv->quad_edges--;
}
static CvSubdiv2DEdge
cvSubdiv2DConnectEdges( CvSubdiv2D * subdiv, CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB )
{
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
CvSubdiv2DEdge new_edge = cvSubdiv2DMakeEdge( subdiv );
cvSubdiv2DSplice( new_edge, cvSubdiv2DGetEdge( edgeA, CV_NEXT_AROUND_LEFT ));
cvSubdiv2DSplice( cvSubdiv2DSymEdge( new_edge ), edgeB );
CvSubdiv2DPoint* dstA = cvSubdiv2DEdgeDst( edgeA );
CvSubdiv2DPoint* orgB = cvSubdiv2DEdgeOrg( edgeB );
cvSubdiv2DSetEdgePoints( new_edge, dstA, orgB );
return new_edge;
}
static void
cvSubdiv2DSwapEdges( CvSubdiv2DEdge edge )
{
CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge );
CvSubdiv2DEdge a = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG );
CvSubdiv2DEdge b = cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG );
CvSubdiv2DPoint *dstB, *dstA;
cvSubdiv2DSplice( edge, a );
cvSubdiv2DSplice( sym_edge, b );
dstA = cvSubdiv2DEdgeDst( a );
dstB = cvSubdiv2DEdgeDst( b );
cvSubdiv2DSetEdgePoints( edge, dstA, dstB );
cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( a, CV_NEXT_AROUND_LEFT ));
cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( b, CV_NEXT_AROUND_LEFT ));
}
static int
icvIsRightOf( CvPoint2D32f& pt, CvSubdiv2DEdge edge )
{
CvSubdiv2DPoint *org = cvSubdiv2DEdgeOrg(edge), *dst = cvSubdiv2DEdgeDst(edge);
double cw_area = cvTriangleArea( pt, dst->pt, org->pt );
return (cw_area > 0) - (cw_area < 0);
}
CV_IMPL CvSubdiv2DPointLocation
cvSubdiv2DLocate( CvSubdiv2D * subdiv, CvPoint2D32f pt,
CvSubdiv2DEdge * _edge, CvSubdiv2DPoint ** _point )
{
CvSubdiv2DPoint *point = 0;
int right_of_curr = 0;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
if( !CV_IS_SUBDIV2D(subdiv) )
CV_Error( CV_StsBadFlag, "" );
int i, max_edges = subdiv->quad_edges * 4;
CvSubdiv2DEdge edge = subdiv->recent_edge;
if( max_edges == 0 )
CV_Error( CV_StsBadSize, "" );
CV_Assert(edge != 0);
if( pt.x < subdiv->topleft.x || pt.y < subdiv->topleft.y ||
pt.x >= subdiv->bottomright.x || pt.y >= subdiv->bottomright.y )
CV_Error( CV_StsOutOfRange, "" );
CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
right_of_curr = icvIsRightOf( pt, edge );
if( right_of_curr > 0 )
{
edge = cvSubdiv2DSymEdge( edge );
right_of_curr = -right_of_curr;
}
for( i = 0; i < max_edges; i++ )
{
CvSubdiv2DEdge onext_edge = cvSubdiv2DNextEdge( edge );
CvSubdiv2DEdge dprev_edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_DST );
int right_of_onext = icvIsRightOf( pt, onext_edge );
int right_of_dprev = icvIsRightOf( pt, dprev_edge );
if( right_of_dprev > 0 )
{
if( right_of_onext > 0 || (right_of_onext == 0 && right_of_curr == 0) )
{
location = CV_PTLOC_INSIDE;
goto exit;
}
else
{
right_of_curr = right_of_onext;
edge = onext_edge;
}
}
else
{
if( right_of_onext > 0 )
{
if( right_of_dprev == 0 && right_of_curr == 0 )
{
location = CV_PTLOC_INSIDE;
goto exit;
}
else
{
right_of_curr = right_of_dprev;
edge = dprev_edge;
}
}
else if( right_of_curr == 0 &&
icvIsRightOf( cvSubdiv2DEdgeDst( onext_edge )->pt, edge ) >= 0 )
{
edge = cvSubdiv2DSymEdge( edge );
}
else
{
right_of_curr = right_of_onext;
edge = onext_edge;
}
}
}
exit:
subdiv->recent_edge = edge;
if( location == CV_PTLOC_INSIDE )
{
double t1, t2, t3;
CvPoint2D32f org_pt = cvSubdiv2DEdgeOrg( edge )->pt;
CvPoint2D32f dst_pt = cvSubdiv2DEdgeDst( edge )->pt;
t1 = fabs( pt.x - org_pt.x );
t1 += fabs( pt.y - org_pt.y );
t2 = fabs( pt.x - dst_pt.x );
t2 += fabs( pt.y - dst_pt.y );
t3 = fabs( org_pt.x - dst_pt.x );
t3 += fabs( org_pt.y - dst_pt.y );
if( t1 < FLT_EPSILON )
{
location = CV_PTLOC_VERTEX;
point = cvSubdiv2DEdgeOrg( edge );
edge = 0;
}
else if( t2 < FLT_EPSILON )
{
location = CV_PTLOC_VERTEX;
point = cvSubdiv2DEdgeDst( edge );
edge = 0;
}
else if( (t1 < t3 || t2 < t3) &&
fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON )
{
location = CV_PTLOC_ON_EDGE;
point = 0;
}
}
if( location == CV_PTLOC_ERROR )
{
edge = 0;
point = 0;
}
if( _edge )
*_edge = edge;
if( _point )
*_point = point;
return location;
}
CV_INLINE int
icvIsPtInCircle3( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c )
{
const double eps = FLT_EPSILON*0.125;
double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt );
val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt );
val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt );
val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c );
return val > eps ? 1 : val < -eps ? -1 : 0;
}
CV_IMPL CvSubdiv2DPoint *
cvSubdivDelaunay2DInsert( CvSubdiv2D * subdiv, CvPoint2D32f pt )
{
CvSubdiv2DPointLocation location = CV_PTLOC_ERROR;
CvSubdiv2DPoint *curr_point = 0, *first_point = 0;
CvSubdiv2DEdge curr_edge = 0, deleted_edge = 0, base_edge = 0;
int i, max_edges;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
if( !CV_IS_SUBDIV2D(subdiv) )
CV_Error( CV_StsBadFlag, "" );
location = cvSubdiv2DLocate( subdiv, pt, &curr_edge, &curr_point );
switch (location)
{
case CV_PTLOC_ERROR:
CV_Error( CV_StsBadSize, "" );
case CV_PTLOC_OUTSIDE_RECT:
CV_Error( CV_StsOutOfRange, "" );
case CV_PTLOC_VERTEX:
break;
case CV_PTLOC_ON_EDGE:
deleted_edge = curr_edge;
subdiv->recent_edge = curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
cvSubdiv2DDeleteEdge( subdiv, deleted_edge );
/* no break */
case CV_PTLOC_INSIDE:
assert( curr_edge != 0 );
subdiv->is_geometry_valid = 0;
curr_point = cvSubdiv2DAddPoint( subdiv, pt, 0 );
base_edge = cvSubdiv2DMakeEdge( subdiv );
first_point = cvSubdiv2DEdgeOrg( curr_edge );
cvSubdiv2DSetEdgePoints( base_edge, first_point, curr_point );
cvSubdiv2DSplice( base_edge, curr_edge );
do
{
base_edge = cvSubdiv2DConnectEdges( subdiv, curr_edge,
cvSubdiv2DSymEdge( base_edge ));
curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
}
while( cvSubdiv2DEdgeDst( curr_edge ) != first_point );
curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG );
max_edges = subdiv->quad_edges * 4;
for( i = 0; i < max_edges; i++ )
{
CvSubdiv2DPoint *temp_dst = 0, *curr_org = 0, *curr_dst = 0;
CvSubdiv2DEdge temp_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
temp_dst = cvSubdiv2DEdgeDst( temp_edge );
curr_org = cvSubdiv2DEdgeOrg( curr_edge );
curr_dst = cvSubdiv2DEdgeDst( curr_edge );
if( icvIsRightOf( temp_dst->pt, curr_edge ) > 0 &&
icvIsPtInCircle3( curr_org->pt, temp_dst->pt,
curr_dst->pt, curr_point->pt ) < 0 )
{
cvSubdiv2DSwapEdges( curr_edge );
curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG );
}
else if( curr_org == first_point )
{
break;
}
else
{
curr_edge = cvSubdiv2DGetEdge( cvSubdiv2DNextEdge( curr_edge ),
CV_PREV_AROUND_LEFT );
}
}
break;
default:
CV_Error_(CV_StsError, ("cvSubdiv2DLocate returned invalid location = %d", location) );
}
return curr_point;
}
CV_IMPL void
cvInitSubdivDelaunay2D( CvSubdiv2D * subdiv, CvRect rect )
{
float big_coord = 3.f * MAX( rect.width, rect.height );
CvPoint2D32f ppA, ppB, ppC;
CvSubdiv2DPoint *pA, *pB, *pC;
CvSubdiv2DEdge edge_AB, edge_BC, edge_CA;
float rx = (float) rect.x;
float ry = (float) rect.y;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
cvClearSet( (CvSet *) (subdiv->edges) );
cvClearSet( (CvSet *) subdiv );
subdiv->quad_edges = 0;
subdiv->recent_edge = 0;
subdiv->is_geometry_valid = 0;
subdiv->topleft = cvPoint2D32f( rx, ry );
subdiv->bottomright = cvPoint2D32f( rx + rect.width, ry + rect.height );
ppA = cvPoint2D32f( rx + big_coord, ry );
ppB = cvPoint2D32f( rx, ry + big_coord );
ppC = cvPoint2D32f( rx - big_coord, ry - big_coord );
pA = cvSubdiv2DAddPoint( subdiv, ppA, 0 );
pB = cvSubdiv2DAddPoint( subdiv, ppB, 0 );
pC = cvSubdiv2DAddPoint( subdiv, ppC, 0 );
edge_AB = cvSubdiv2DMakeEdge( subdiv );
edge_BC = cvSubdiv2DMakeEdge( subdiv );
edge_CA = cvSubdiv2DMakeEdge( subdiv );
cvSubdiv2DSetEdgePoints( edge_AB, pA, pB );
cvSubdiv2DSetEdgePoints( edge_BC, pB, pC );
cvSubdiv2DSetEdgePoints( edge_CA, pC, pA );
cvSubdiv2DSplice( edge_AB, cvSubdiv2DSymEdge( edge_CA ));
cvSubdiv2DSplice( edge_BC, cvSubdiv2DSymEdge( edge_AB ));
cvSubdiv2DSplice( edge_CA, cvSubdiv2DSymEdge( edge_BC ));
subdiv->recent_edge = edge_AB;
}
CV_IMPL void
cvClearSubdivVoronoi2D( CvSubdiv2D * subdiv )
{
int elem_size;
int i, total;
CvSeqReader reader;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
/* clear pointers to voronoi points */
total = subdiv->edges->total;
elem_size = subdiv->edges->elem_size;
cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
for( i = 0; i < total; i++ )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) reader.ptr;
quadedge->pt[1] = quadedge->pt[3] = 0;
CV_NEXT_SEQ_ELEM( elem_size, reader );
}
/* remove voronoi points */
total = subdiv->total;
elem_size = subdiv->elem_size;
cvStartReadSeq( (CvSeq *) subdiv, &reader, 0 );
for( i = 0; i < total; i++ )
{
CvSubdiv2DPoint *pt = (CvSubdiv2DPoint *) reader.ptr;
/* check for virtual point. it is also check that the point exists */
if( pt->flags & CV_SUBDIV2D_VIRTUAL_POINT_FLAG )
{
cvSetRemoveByPtr( (CvSet*)subdiv, pt );
}
CV_NEXT_SEQ_ELEM( elem_size, reader );
}
subdiv->is_geometry_valid = 0;
}
static 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;
}
static 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 void
cvCalcSubdivVoronoi2D( CvSubdiv2D * subdiv )
{
CvSeqReader reader;
int i, total, elem_size;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
/* check if it is already calculated */
if( subdiv->is_geometry_valid )
return;
total = subdiv->edges->total;
elem_size = subdiv->edges->elem_size;
cvClearSubdivVoronoi2D( subdiv );
cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 );
if( total <= 3 )
return;
/* skip first three edges (bounding triangle) */
for( i = 0; i < 3; i++ )
CV_NEXT_SEQ_ELEM( elem_size, reader );
/* loop through all quad-edges */
for( ; i < total; i++ )
{
CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (reader.ptr);
if( CV_IS_SET_ELEM( quadedge ))
{
CvSubdiv2DEdge edge0 = (CvSubdiv2DEdge) quadedge, edge1, edge2;
double a0, b0, c0, a1, b1, c1;
CvPoint2D32f virt_point;
CvSubdiv2DPoint *voronoi_point;
if( !quadedge->pt[3] )
{
edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_LEFT );
edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_LEFT );
icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
fabs( virt_point.y ) < FLT_MAX * 0.5 )
{
voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
quadedge->pt[3] =
((CvQuadEdge2D *) (edge1 & ~3))->pt[3 - (edge1 & 2)] =
((CvQuadEdge2D *) (edge2 & ~3))->pt[3 - (edge2 & 2)] = voronoi_point;
}
}
if( !quadedge->pt[1] )
{
edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_RIGHT );
edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_RIGHT );
icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 );
icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 );
icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point );
if( fabs( virt_point.x ) < FLT_MAX * 0.5 &&
fabs( virt_point.y ) < FLT_MAX * 0.5 )
{
voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 );
quadedge->pt[1] =
((CvQuadEdge2D *) (edge1 & ~3))->pt[1 + (edge1 & 2)] =
((CvQuadEdge2D *) (edge2 & ~3))->pt[1 + (edge2 & 2)] = voronoi_point;
}
}
}
CV_NEXT_SEQ_ELEM( elem_size, reader );
}
subdiv->is_geometry_valid = 1;
}
static int
icvIsRightOf2( const CvPoint2D32f& pt, const CvPoint2D32f& org, const CvPoint2D32f& diff )
{
double cw_area = ((double)org.x - pt.x)*diff.y - ((double)org.y - pt.y)*diff.x;
return (cw_area > 0) - (cw_area < 0);
}
CV_IMPL CvSubdiv2DPoint*
cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt )
{
CvSubdiv2DPoint* point = 0;
CvPoint2D32f start;
CvPoint2D32f diff;
CvSubdiv2DPointLocation loc;
CvSubdiv2DEdge edge;
int i;
if( !subdiv )
CV_Error( CV_StsNullPtr, "" );
if( !CV_IS_SUBDIV2D( subdiv ))
CV_Error( CV_StsNullPtr, "" );
if( subdiv->edges->active_count <= 3 )
return 0;
if( !subdiv->is_geometry_valid )
cvCalcSubdivVoronoi2D( subdiv );
loc = cvSubdiv2DLocate( subdiv, pt, &edge, &point );
switch( loc )
{
case CV_PTLOC_ON_EDGE:
case CV_PTLOC_INSIDE:
break;
default:
return point;
}
point = 0;
start = cvSubdiv2DEdgeOrg( edge )->pt;
diff.x = pt.x - start.x;
diff.y = pt.y - start.y;
edge = cvSubdiv2DRotateEdge( edge, 1 );
for( i = 0; i < subdiv->total; i++ )
{
CvPoint2D32f t;
for(;;)
{
assert( cvSubdiv2DEdgeDst( edge ));
t = cvSubdiv2DEdgeDst( edge )->pt;
if( icvIsRightOf2( t, start, diff ) >= 0 )
break;
edge = cvSubdiv2DGetEdge( edge, CV_NEXT_AROUND_LEFT );
}
for(;;)
{
assert( cvSubdiv2DEdgeOrg( edge ));
t = cvSubdiv2DEdgeOrg( edge )->pt;
if( icvIsRightOf2( t, start, diff ) < 0 )
break;
edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_LEFT );
}
{
CvPoint2D32f tempDiff = cvSubdiv2DEdgeDst( edge )->pt;
t = cvSubdiv2DEdgeOrg( edge )->pt;
tempDiff.x -= t.x;
tempDiff.y -= t.y;
if( icvIsRightOf2( pt, t, tempDiff ) >= 0 )
{
point = cvSubdiv2DEdgeOrg( cvSubdiv2DRotateEdge( edge, 3 ));
break;
}
}
edge = cvSubdiv2DSymEdge( edge );
}
return point;
}
CV_IMPL int
icvSubdiv2DCheck( CvSubdiv2D* subdiv )
{

View File

@ -0,0 +1,264 @@
/*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 "test_precomp.hpp"
#include <algorithm>
#include <vector>
#include <iostream>
using namespace cv;
using namespace cv::flann;
//--------------------------------------------------------------------------------
class NearestNeighborTest : public cvtest::BaseTest
{
public:
NearestNeighborTest() {}
protected:
static const int minValue = 0;
static const int maxValue = 1;
static const int dims = 30;
static const int featuresCount = 2000;
static const int K = 1; // * should also test 2nd nn etc.?
virtual void run( int start_from );
virtual void createModel( const Mat& data ) = 0;
virtual int findNeighbors( Mat& points, Mat& neighbors ) = 0;
virtual int checkGetPoins( const Mat& data );
virtual int checkFindBoxed();
virtual int checkFind( const Mat& data );
virtual void releaseModel() = 0;
};
int NearestNeighborTest::checkGetPoins( const Mat& )
{
return cvtest::TS::OK;
}
int NearestNeighborTest::checkFindBoxed()
{
return cvtest::TS::OK;
}
int NearestNeighborTest::checkFind( const Mat& data )
{
int code = cvtest::TS::OK;
int pointsCount = 1000;
float noise = 0.2f;
RNG rng;
Mat points( pointsCount, dims, CV_32FC1 );
Mat results( pointsCount, K, CV_32SC1 );
std::vector<int> fmap( pointsCount );
for( int pi = 0; pi < pointsCount; pi++ )
{
int fi = rng.next() % featuresCount;
fmap[pi] = fi;
for( int d = 0; d < dims; d++ )
points.at<float>(pi, d) = data.at<float>(fi, d) + rng.uniform(0.0f, 1.0f) * noise;
}
code = findNeighbors( points, results );
if( code == cvtest::TS::OK )
{
int correctMatches = 0;
for( int pi = 0; pi < pointsCount; pi++ )
{
if( fmap[pi] == results.at<int>(pi, 0) )
correctMatches++;
}
double correctPerc = correctMatches / (double)pointsCount;
if (correctPerc < .75)
{
ts->printf( cvtest::TS::LOG, "correct_perc = %d\n", correctPerc );
code = cvtest::TS::FAIL_BAD_ACCURACY;
}
}
return code;
}
void NearestNeighborTest::run( int /*start_from*/ ) {
int code = cvtest::TS::OK, tempCode;
Mat desc( featuresCount, dims, CV_32FC1 );
randu( desc, Scalar(minValue), Scalar(maxValue) );
createModel( desc );
tempCode = checkGetPoins( desc );
if( tempCode != cvtest::TS::OK )
{
ts->printf( cvtest::TS::LOG, "bad accuracy of GetPoints \n" );
code = tempCode;
}
tempCode = checkFindBoxed();
if( tempCode != cvtest::TS::OK )
{
ts->printf( cvtest::TS::LOG, "bad accuracy of FindBoxed \n" );
code = tempCode;
}
tempCode = checkFind( desc );
if( tempCode != cvtest::TS::OK )
{
ts->printf( cvtest::TS::LOG, "bad accuracy of Find \n" );
code = tempCode;
}
releaseModel();
ts->set_failed_test_info( code );
}
//--------------------------------------------------------------------------------
class CV_LSHTest : public NearestNeighborTest
{
public:
CV_LSHTest() {}
protected:
virtual void createModel( const Mat& data );
virtual int findNeighbors( Mat& points, Mat& neighbors );
virtual void releaseModel();
struct CvLSH* lsh;
CvMat desc;
};
void CV_LSHTest::createModel( const Mat& data )
{
desc = data;
lsh = cvCreateMemoryLSH( data.cols, data.rows, 70, 20, CV_32FC1 );
cvLSHAdd( lsh, &desc );
}
int CV_LSHTest::findNeighbors( Mat& points, Mat& neighbors )
{
const int emax = 20;
Mat dist( points.rows, neighbors.cols, CV_64FC1);
CvMat _dist = dist, _points = points, _neighbors = neighbors;
cvLSHQuery( lsh, &_points, &_neighbors, &_dist, neighbors.cols, emax );
return cvtest::TS::OK;
}
void CV_LSHTest::releaseModel()
{
cvReleaseLSH( &lsh );
}
//--------------------------------------------------------------------------------
class CV_FeatureTreeTest_C : public NearestNeighborTest
{
public:
CV_FeatureTreeTest_C() {}
protected:
virtual int findNeighbors( Mat& points, Mat& neighbors );
virtual void releaseModel();
CvFeatureTree* tr;
CvMat desc;
};
int CV_FeatureTreeTest_C::findNeighbors( Mat& points, Mat& neighbors )
{
const int emax = 20;
Mat dist( points.rows, neighbors.cols, CV_64FC1);
CvMat _dist = dist, _points = points, _neighbors = neighbors;
cvFindFeatures( tr, &_points, &_neighbors, &_dist, neighbors.cols, emax );
return cvtest::TS::OK;
}
void CV_FeatureTreeTest_C::releaseModel()
{
cvReleaseFeatureTree( tr );
}
//--------------------------------------
class CV_SpillTreeTest_C : public CV_FeatureTreeTest_C
{
public:
CV_SpillTreeTest_C() {}
protected:
virtual void createModel( const Mat& data );
};
void CV_SpillTreeTest_C::createModel( const Mat& data )
{
desc = data;
tr = cvCreateSpillTree( &desc );
}
//--------------------------------------
class CV_KDTreeTest_C : public CV_FeatureTreeTest_C
{
public:
CV_KDTreeTest_C() {}
protected:
virtual void createModel( const Mat& data );
virtual int checkFindBoxed();
};
void CV_KDTreeTest_C::createModel( const Mat& data )
{
desc = data;
tr = cvCreateKDTree( &desc );
}
int CV_KDTreeTest_C::checkFindBoxed()
{
Mat min(1, dims, CV_32FC1 ), max(1, dims, CV_32FC1 ), indices( 1, 1, CV_32SC1 );
float l = minValue, r = maxValue;
min.setTo(Scalar(l)), max.setTo(Scalar(r));
CvMat _min = min, _max = max, _indices = indices;
// TODO check indices
if( cvFindFeaturesBoxed( tr, &_min, &_max, &_indices ) != featuresCount )
return cvtest::TS::FAIL_BAD_ACCURACY;
return cvtest::TS::OK;
}
TEST(Features2d_LSH, regression) { CV_LSHTest test; test.safe_run(); }
TEST(Features2d_SpillTree, regression) { CV_SpillTreeTest_C test; test.safe_run(); }
TEST(Features2d_KDTree_C, regression) { CV_KDTreeTest_C test; test.safe_run(); }

View File

@ -41,6 +41,7 @@
//M*/
#include "test_precomp.hpp"
#include "opencv2/video/tracking.hpp"
#include <string>
#include <iostream>

View File

@ -6,6 +6,7 @@
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/legacy/legacy.hpp"
#include <iostream>
#endif

View File

@ -0,0 +1,722 @@
/*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*/
/*
This is a regression test for stereo matching algorithms. This test gets some quality metrics
discribed in "A Taxonomy and Evaluation of Dense Two-Frame Stereo Correspondence Algorithms".
Daniel Scharstein, Richard Szeliski
*/
#include "test_precomp.hpp"
#include <limits>
#include <cstdio>
using namespace std;
using namespace cv;
const float EVAL_BAD_THRESH = 1.f;
const int EVAL_TEXTURELESS_WIDTH = 3;
const float EVAL_TEXTURELESS_THRESH = 4.f;
const float EVAL_DISP_THRESH = 1.f;
const float EVAL_DISP_GAP = 2.f;
const int EVAL_DISCONT_WIDTH = 9;
const int EVAL_IGNORE_BORDER = 10;
const int ERROR_KINDS_COUNT = 6;
//============================== quality measuring functions =================================================
/*
Calculate textureless regions of image (regions where the squared horizontal intensity gradient averaged over
a square window of size=evalTexturelessWidth is below a threshold=evalTexturelessThresh) and textured regions.
*/
void computeTextureBasedMasks( const Mat& _img, Mat* texturelessMask, Mat* texturedMask,
int texturelessWidth = EVAL_TEXTURELESS_WIDTH, float texturelessThresh = EVAL_TEXTURELESS_THRESH )
{
if( !texturelessMask && !texturedMask )
return;
if( _img.empty() )
CV_Error( CV_StsBadArg, "img is empty" );
Mat img = _img;
if( _img.channels() > 1)
{
Mat tmp; cvtColor( _img, tmp, CV_BGR2GRAY ); img = tmp;
}
Mat dxI; Sobel( img, dxI, CV_32FC1, 1, 0, 3 );
Mat dxI2; pow( dxI / 8.f/*normalize*/, 2, dxI2 );
Mat avgDxI2; boxFilter( dxI2, avgDxI2, CV_32FC1, Size(texturelessWidth,texturelessWidth) );
if( texturelessMask )
*texturelessMask = avgDxI2 < texturelessThresh;
if( texturedMask )
*texturedMask = avgDxI2 >= texturelessThresh;
}
void checkTypeAndSizeOfDisp( const Mat& dispMap, const Size* sz )
{
if( dispMap.empty() )
CV_Error( CV_StsBadArg, "dispMap is empty" );
if( dispMap.type() != CV_32FC1 )
CV_Error( CV_StsBadArg, "dispMap must have CV_32FC1 type" );
if( sz && (dispMap.rows != sz->height || dispMap.cols != sz->width) )
CV_Error( CV_StsBadArg, "dispMap has incorrect size" );
}
void checkTypeAndSizeOfMask( const Mat& mask, Size sz )
{
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.rows != sz.height || mask.cols != sz.width )
CV_Error( CV_StsBadArg, "mask has incorrect size" );
}
void checkDispMapsAndUnknDispMasks( const Mat& leftDispMap, const Mat& rightDispMap,
const Mat& leftUnknDispMask, const Mat& rightUnknDispMask )
{
// check type and size of disparity maps
checkTypeAndSizeOfDisp( leftDispMap, 0 );
if( !rightDispMap.empty() )
{
Size sz = leftDispMap.size();
checkTypeAndSizeOfDisp( rightDispMap, &sz );
}
// check size and type of unknown disparity maps
if( !leftUnknDispMask.empty() )
checkTypeAndSizeOfMask( leftUnknDispMask, leftDispMap.size() );
if( !rightUnknDispMask.empty() )
checkTypeAndSizeOfMask( rightUnknDispMask, rightDispMap.size() );
// check values of disparity maps (known disparity values musy be positive)
double leftMinVal = 0, rightMinVal = 0;
if( leftUnknDispMask.empty() )
minMaxLoc( leftDispMap, &leftMinVal );
else
minMaxLoc( leftDispMap, &leftMinVal, 0, 0, 0, ~leftUnknDispMask );
if( !rightDispMap.empty() )
{
if( rightUnknDispMask.empty() )
minMaxLoc( rightDispMap, &rightMinVal );
else
minMaxLoc( rightDispMap, &rightMinVal, 0, 0, 0, ~rightUnknDispMask );
}
if( leftMinVal < 0 || rightMinVal < 0)
CV_Error( CV_StsBadArg, "known disparity values must be positive" );
}
/*
Calculate occluded regions of reference image (left image) (regions that are occluded in the matching image (right image),
i.e., where the forward-mapped disparity lands at a location with a larger (nearer) disparity) and non occluded regions.
*/
void computeOcclusionBasedMasks( const Mat& leftDisp, const Mat& _rightDisp,
Mat* occludedMask, Mat* nonOccludedMask,
const Mat& leftUnknDispMask = Mat(), const Mat& rightUnknDispMask = Mat(),
float dispThresh = EVAL_DISP_THRESH )
{
if( !occludedMask && !nonOccludedMask )
return;
checkDispMapsAndUnknDispMasks( leftDisp, _rightDisp, leftUnknDispMask, rightUnknDispMask );
Mat rightDisp;
if( _rightDisp.empty() )
{
if( !rightUnknDispMask.empty() )
CV_Error( CV_StsBadArg, "rightUnknDispMask must be empty if _rightDisp is empty" );
rightDisp.create(leftDisp.size(), CV_32FC1);
rightDisp.setTo(Scalar::all(0) );
for( int leftY = 0; leftY < leftDisp.rows; leftY++ )
{
for( int leftX = 0; leftX < leftDisp.cols; leftX++ )
{
if( !leftUnknDispMask.empty() && leftUnknDispMask.at<uchar>(leftY,leftX) )
continue;
float leftDispVal = leftDisp.at<float>(leftY, leftX);
int rightX = leftX - cvRound(leftDispVal), rightY = leftY;
if( rightX >= 0)
rightDisp.at<float>(rightY,rightX) = max(rightDisp.at<float>(rightY,rightX), leftDispVal);
}
}
}
else
_rightDisp.copyTo(rightDisp);
if( occludedMask )
{
occludedMask->create(leftDisp.size(), CV_8UC1);
occludedMask->setTo(Scalar::all(0) );
}
if( nonOccludedMask )
{
nonOccludedMask->create(leftDisp.size(), CV_8UC1);
nonOccludedMask->setTo(Scalar::all(0) );
}
for( int leftY = 0; leftY < leftDisp.rows; leftY++ )
{
for( int leftX = 0; leftX < leftDisp.cols; leftX++ )
{
if( !leftUnknDispMask.empty() && leftUnknDispMask.at<uchar>(leftY,leftX) )
continue;
float leftDispVal = leftDisp.at<float>(leftY, leftX);
int rightX = leftX - cvRound(leftDispVal), rightY = leftY;
if( rightX < 0 && occludedMask )
occludedMask->at<uchar>(leftY, leftX) = 255;
else
{
if( !rightUnknDispMask.empty() && rightUnknDispMask.at<uchar>(rightY,rightX) )
continue;
float rightDispVal = rightDisp.at<float>(rightY, rightX);
if( rightDispVal > leftDispVal + dispThresh )
{
if( occludedMask )
occludedMask->at<uchar>(leftY, leftX) = 255;
}
else
{
if( nonOccludedMask )
nonOccludedMask->at<uchar>(leftY, leftX) = 255;
}
}
}
}
}
/*
Calculate depth discontinuty regions: pixels whose neiboring disparities differ by more than
dispGap, dilated by window of width discontWidth.
*/
void computeDepthDiscontMask( const Mat& disp, Mat& depthDiscontMask, const Mat& unknDispMask = Mat(),
float dispGap = EVAL_DISP_GAP, int discontWidth = EVAL_DISCONT_WIDTH )
{
if( disp.empty() )
CV_Error( CV_StsBadArg, "disp is empty" );
if( disp.type() != CV_32FC1 )
CV_Error( CV_StsBadArg, "disp must have CV_32FC1 type" );
if( !unknDispMask.empty() )
checkTypeAndSizeOfMask( unknDispMask, disp.size() );
Mat curDisp; disp.copyTo( curDisp );
if( !unknDispMask.empty() )
curDisp.setTo( Scalar(numeric_limits<float>::min()), unknDispMask );
Mat maxNeighbDisp; dilate( curDisp, maxNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
if( !unknDispMask.empty() )
curDisp.setTo( Scalar(numeric_limits<float>::max()), unknDispMask );
Mat minNeighbDisp; erode( curDisp, minNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
depthDiscontMask = max( (Mat)(maxNeighbDisp-disp), (Mat)(disp-minNeighbDisp) ) > dispGap;
if( !unknDispMask.empty() )
depthDiscontMask &= ~unknDispMask;
dilate( depthDiscontMask, depthDiscontMask, Mat(discontWidth, discontWidth, CV_8UC1, Scalar(1)) );
}
/*
Get evaluation masks excluding a border.
*/
Mat getBorderedMask( Size maskSize, int border = EVAL_IGNORE_BORDER )
{
CV_Assert( border >= 0 );
Mat mask(maskSize, CV_8UC1, Scalar(0));
int w = maskSize.width - 2*border, h = maskSize.height - 2*border;
if( w < 0 || h < 0 )
mask.setTo(Scalar(0));
else
mask( Rect(Point(border,border),Size(w,h)) ).setTo(Scalar(255));
return mask;
}
/*
Calculate root-mean-squared error between the computed disparity map (computedDisp) and ground truth map (groundTruthDisp).
*/
float dispRMS( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask )
{
checkTypeAndSizeOfDisp( groundTruthDisp, 0 );
Size sz = groundTruthDisp.size();
checkTypeAndSizeOfDisp( computedDisp, &sz );
int pointsCount = sz.height*sz.width;
if( !mask.empty() )
{
checkTypeAndSizeOfMask( mask, sz );
pointsCount = countNonZero(mask);
}
return 1.f/sqrt((float)pointsCount) * (float)norm(computedDisp, groundTruthDisp, NORM_L2, mask);
}
/*
Calculate fraction of bad matching pixels.
*/
float badMatchPxlsFraction( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask,
float _badThresh = EVAL_BAD_THRESH )
{
int badThresh = cvRound(_badThresh);
checkTypeAndSizeOfDisp( groundTruthDisp, 0 );
Size sz = groundTruthDisp.size();
checkTypeAndSizeOfDisp( computedDisp, &sz );
Mat badPxlsMap;
absdiff( computedDisp, groundTruthDisp, badPxlsMap );
badPxlsMap = badPxlsMap > badThresh;
int pointsCount = sz.height*sz.width;
if( !mask.empty() )
{
checkTypeAndSizeOfMask( mask, sz );
badPxlsMap = badPxlsMap & mask;
pointsCount = countNonZero(mask);
}
return 1.f/pointsCount * countNonZero(badPxlsMap);
}
//===================== regression test for stereo matching algorithms ==============================
const string ALGORITHMS_DIR = "stereomatching/algorithms/";
const string DATASETS_DIR = "stereomatching/datasets/";
const string DATASETS_FILE = "datasets.xml";
const string RUN_PARAMS_FILE = "_params.xml";
const string RESULT_FILE = "_res.xml";
const string LEFT_IMG_NAME = "im2.png";
const string RIGHT_IMG_NAME = "im6.png";
const string TRUE_LEFT_DISP_NAME = "disp2.png";
const string TRUE_RIGHT_DISP_NAME = "disp6.png";
string ERROR_PREFIXES[] = { "borderedAll",
"borderedNoOccl",
"borderedOccl",
"borderedTextured",
"borderedTextureless",
"borderedDepthDiscont" }; // size of ERROR_KINDS_COUNT
const string RMS_STR = "RMS";
const string BAD_PXLS_FRACTION_STR = "BadPxlsFraction";
class QualityEvalParams
{
public:
QualityEvalParams() { setDefaults(); }
QualityEvalParams( int _ignoreBorder )
{
setDefaults();
ignoreBorder = _ignoreBorder;
}
void setDefaults()
{
badThresh = EVAL_BAD_THRESH;
texturelessWidth = EVAL_TEXTURELESS_WIDTH;
texturelessThresh = EVAL_TEXTURELESS_THRESH;
dispThresh = EVAL_DISP_THRESH;
dispGap = EVAL_DISP_GAP;
discontWidth = EVAL_DISCONT_WIDTH;
ignoreBorder = EVAL_IGNORE_BORDER;
}
float badThresh;
int texturelessWidth;
float texturelessThresh;
float dispThresh;
float dispGap;
int discontWidth;
int ignoreBorder;
};
class CV_StereoMatchingTest : public cvtest::BaseTest
{
public:
CV_StereoMatchingTest()
{ rmsEps.resize( ERROR_KINDS_COUNT, 0.01f ); fracEps.resize( ERROR_KINDS_COUNT, 1.e-6f ); }
protected:
// assumed that left image is a reference image
virtual int runStereoMatchingAlgorithm( const Mat& leftImg, const Mat& rightImg,
Mat& leftDisp, Mat& rightDisp, int caseIdx ) = 0; // return ignored border width
int readDatasetsParams( FileStorage& fs );
virtual int readRunParams( FileStorage& fs );
void writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs = 0 );
void readErrors( FileNode& fn, const string& errName, vector<float>& errors );
int compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
const vector<float>& eps, const string& errName );
int processStereoMatchingResults( FileStorage& fs, int caseIdx, bool isWrite,
const Mat& leftImg, const Mat& rightImg,
const Mat& trueLeftDisp, const Mat& trueRightDisp,
const Mat& leftDisp, const Mat& rightDisp,
const QualityEvalParams& qualityEvalParams );
void run( int );
vector<float> rmsEps;
vector<float> fracEps;
struct DatasetParams
{
int dispScaleFactor;
int dispUnknVal;
};
map<string, DatasetParams> datasetsParams;
vector<string> caseNames;
vector<string> caseDatasets;
};
void CV_StereoMatchingTest::run(int)
{
string dataPath = ts->get_data_path();
string algorithmName = name;
assert( !algorithmName.empty() );
if( dataPath.empty() )
{
ts->printf( cvtest::TS::LOG, "dataPath is empty" );
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ARG_CHECK );
return;
}
FileStorage datasetsFS( dataPath + DATASETS_DIR + DATASETS_FILE, FileStorage::READ );
int code = readDatasetsParams( datasetsFS );
if( code != cvtest::TS::OK )
{
ts->set_failed_test_info( code );
return;
}
FileStorage runParamsFS( dataPath + ALGORITHMS_DIR + algorithmName + RUN_PARAMS_FILE, FileStorage::READ );
code = readRunParams( runParamsFS );
if( code != cvtest::TS::OK )
{
ts->set_failed_test_info( code );
return;
}
string fullResultFilename = dataPath + ALGORITHMS_DIR + algorithmName + RESULT_FILE;
FileStorage resFS( fullResultFilename, FileStorage::READ );
bool isWrite = true; // write or compare results
if( resFS.isOpened() )
isWrite = false;
else
{
resFS.open( fullResultFilename, FileStorage::WRITE );
if( !resFS.isOpened() )
{
ts->printf( cvtest::TS::LOG, "file %s can not be read or written\n", fullResultFilename.c_str() );
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ARG_CHECK );
return;
}
resFS << "stereo_matching" << "{";
}
int progress = 0, caseCount = (int)caseNames.size();
for( int ci = 0; ci < caseCount; ci++)
{
progress = update_progress( progress, ci, caseCount, 0 );
printf("progress: %d%%\n", progress);
fflush(stdout);
string datasetName = caseDatasets[ci];
string datasetFullDirName = dataPath + DATASETS_DIR + datasetName + "/";
Mat leftImg = imread(datasetFullDirName + LEFT_IMG_NAME);
Mat rightImg = imread(datasetFullDirName + RIGHT_IMG_NAME);
Mat trueLeftDisp = imread(datasetFullDirName + TRUE_LEFT_DISP_NAME, 0);
Mat trueRightDisp = imread(datasetFullDirName + TRUE_RIGHT_DISP_NAME, 0);
if( leftImg.empty() || rightImg.empty() || trueLeftDisp.empty() )
{
ts->printf( cvtest::TS::LOG, "images or left ground-truth disparities of dataset %s can not be read", datasetName.c_str() );
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
continue;
}
int dispScaleFactor = datasetsParams[datasetName].dispScaleFactor;
Mat tmp; trueLeftDisp.convertTo( tmp, CV_32FC1, 1.f/dispScaleFactor ); trueLeftDisp = tmp; tmp.release();
if( !trueRightDisp.empty() )
trueRightDisp.convertTo( tmp, CV_32FC1, 1.f/dispScaleFactor ); trueRightDisp = tmp; tmp.release();
Mat leftDisp, rightDisp;
int ignBorder = max(runStereoMatchingAlgorithm(leftImg, rightImg, leftDisp, rightDisp, ci), EVAL_IGNORE_BORDER);
leftDisp.convertTo( tmp, CV_32FC1 ); leftDisp = tmp; tmp.release();
rightDisp.convertTo( tmp, CV_32FC1 ); rightDisp = tmp; tmp.release();
int tempCode = processStereoMatchingResults( resFS, ci, isWrite,
leftImg, rightImg, trueLeftDisp, trueRightDisp, leftDisp, rightDisp, QualityEvalParams(ignBorder));
code = tempCode==cvtest::TS::OK ? code : tempCode;
}
if( isWrite )
resFS << "}"; // "stereo_matching"
ts->set_failed_test_info( code );
}
void calcErrors( const Mat& leftImg, const Mat& /*rightImg*/,
const Mat& trueLeftDisp, const Mat& trueRightDisp,
const Mat& trueLeftUnknDispMask, const Mat& trueRightUnknDispMask,
const Mat& calcLeftDisp, const Mat& /*calcRightDisp*/,
vector<float>& rms, vector<float>& badPxlsFractions,
const QualityEvalParams& qualityEvalParams )
{
Mat texturelessMask, texturedMask;
computeTextureBasedMasks( leftImg, &texturelessMask, &texturedMask,
qualityEvalParams.texturelessWidth, qualityEvalParams.texturelessThresh );
Mat occludedMask, nonOccludedMask;
computeOcclusionBasedMasks( trueLeftDisp, trueRightDisp, &occludedMask, &nonOccludedMask,
trueLeftUnknDispMask, trueRightUnknDispMask, qualityEvalParams.dispThresh);
Mat depthDiscontMask;
computeDepthDiscontMask( trueLeftDisp, depthDiscontMask, trueLeftUnknDispMask,
qualityEvalParams.dispGap, qualityEvalParams.discontWidth);
Mat borderedKnownMask = getBorderedMask( leftImg.size(), qualityEvalParams.ignoreBorder ) & ~trueLeftUnknDispMask;
nonOccludedMask &= borderedKnownMask;
occludedMask &= borderedKnownMask;
texturedMask &= nonOccludedMask; // & borderedKnownMask
texturelessMask &= nonOccludedMask; // & borderedKnownMask
depthDiscontMask &= nonOccludedMask; // & borderedKnownMask
rms.resize(ERROR_KINDS_COUNT);
rms[0] = dispRMS( calcLeftDisp, trueLeftDisp, borderedKnownMask );
rms[1] = dispRMS( calcLeftDisp, trueLeftDisp, nonOccludedMask );
rms[2] = dispRMS( calcLeftDisp, trueLeftDisp, occludedMask );
rms[3] = dispRMS( calcLeftDisp, trueLeftDisp, texturedMask );
rms[4] = dispRMS( calcLeftDisp, trueLeftDisp, texturelessMask );
rms[5] = dispRMS( calcLeftDisp, trueLeftDisp, depthDiscontMask );
badPxlsFractions.resize(ERROR_KINDS_COUNT);
badPxlsFractions[0] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, borderedKnownMask, qualityEvalParams.badThresh );
badPxlsFractions[1] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, nonOccludedMask, qualityEvalParams.badThresh );
badPxlsFractions[2] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, occludedMask, qualityEvalParams.badThresh );
badPxlsFractions[3] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, texturedMask, qualityEvalParams.badThresh );
badPxlsFractions[4] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, texturelessMask, qualityEvalParams.badThresh );
badPxlsFractions[5] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, depthDiscontMask, qualityEvalParams.badThresh );
}
int CV_StereoMatchingTest::processStereoMatchingResults( FileStorage& fs, int caseIdx, bool isWrite,
const Mat& leftImg, const Mat& rightImg,
const Mat& trueLeftDisp, const Mat& trueRightDisp,
const Mat& leftDisp, const Mat& rightDisp,
const QualityEvalParams& qualityEvalParams )
{
// rightDisp is not used in current test virsion
int code = cvtest::TS::OK;
assert( fs.isOpened() );
assert( trueLeftDisp.type() == CV_32FC1 && trueRightDisp.type() == CV_32FC1 );
assert( leftDisp.type() == CV_32FC1 && rightDisp.type() == CV_32FC1 );
// get masks for unknown ground truth disparity values
Mat leftUnknMask, rightUnknMask;
DatasetParams params = datasetsParams[caseDatasets[caseIdx]];
absdiff( trueLeftDisp, Scalar(params.dispUnknVal), leftUnknMask );
leftUnknMask = leftUnknMask < numeric_limits<float>::epsilon();
assert(leftUnknMask.type() == CV_8UC1);
if( !trueRightDisp.empty() )
{
absdiff( trueRightDisp, Scalar(params.dispUnknVal), rightUnknMask );
rightUnknMask = rightUnknMask < numeric_limits<float>::epsilon();
assert(leftUnknMask.type() == CV_8UC1);
}
// calculate errors
vector<float> rmss, badPxlsFractions;
calcErrors( leftImg, rightImg, trueLeftDisp, trueRightDisp, leftUnknMask, rightUnknMask,
leftDisp, rightDisp, rmss, badPxlsFractions, qualityEvalParams );
if( isWrite )
{
fs << caseNames[caseIdx] << "{";
cvWriteComment( fs.fs, RMS_STR.c_str(), 0 );
writeErrors( RMS_STR, rmss, &fs );
cvWriteComment( fs.fs, BAD_PXLS_FRACTION_STR.c_str(), 0 );
writeErrors( BAD_PXLS_FRACTION_STR, badPxlsFractions, &fs );
fs << "}"; // datasetName
}
else // compare
{
ts->printf( cvtest::TS::LOG, "\nquality of case named %s\n", caseNames[caseIdx].c_str() );
ts->printf( cvtest::TS::LOG, "%s\n", RMS_STR.c_str() );
writeErrors( RMS_STR, rmss );
ts->printf( cvtest::TS::LOG, "%s\n", BAD_PXLS_FRACTION_STR.c_str() );
writeErrors( BAD_PXLS_FRACTION_STR, badPxlsFractions );
FileNode fn = fs.getFirstTopLevelNode()[caseNames[caseIdx]];
vector<float> validRmss, validBadPxlsFractions;
readErrors( fn, RMS_STR, validRmss );
readErrors( fn, BAD_PXLS_FRACTION_STR, validBadPxlsFractions );
int tempCode = compareErrors( rmss, validRmss, rmsEps, RMS_STR );
code = tempCode==cvtest::TS::OK ? code : tempCode;
tempCode = compareErrors( badPxlsFractions, validBadPxlsFractions, fracEps, BAD_PXLS_FRACTION_STR );
code = tempCode==cvtest::TS::OK ? code : tempCode;
}
return code;
}
int CV_StereoMatchingTest::readDatasetsParams( FileStorage& fs )
{
if( !fs.isOpened() )
{
ts->printf( cvtest::TS::LOG, "datasetsParams can not be read " );
return cvtest::TS::FAIL_INVALID_TEST_DATA;
}
datasetsParams.clear();
FileNode fn = fs.getFirstTopLevelNode();
assert(fn.isSeq());
for( int i = 0; i < (int)fn.size(); i+=3 )
{
string name = fn[i];
DatasetParams params;
string sf = fn[i+1]; params.dispScaleFactor = atoi(sf.c_str());
string uv = fn[i+2]; params.dispUnknVal = atoi(uv.c_str());
datasetsParams[name] = params;
}
return cvtest::TS::OK;
}
int CV_StereoMatchingTest::readRunParams( FileStorage& fs )
{
if( !fs.isOpened() )
{
ts->printf( cvtest::TS::LOG, "runParams can not be read " );
return cvtest::TS::FAIL_INVALID_TEST_DATA;
}
caseNames.clear();;
caseDatasets.clear();
return cvtest::TS::OK;
}
void CV_StereoMatchingTest::writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs )
{
assert( (int)errors.size() == ERROR_KINDS_COUNT );
vector<float>::const_iterator it = errors.begin();
if( fs )
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
*fs << ERROR_PREFIXES[i] + errName << *it;
else
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
ts->printf( cvtest::TS::LOG, "%s = %f\n", string(ERROR_PREFIXES[i]+errName).c_str(), *it );
}
void CV_StereoMatchingTest::readErrors( FileNode& fn, const string& errName, vector<float>& errors )
{
errors.resize( ERROR_KINDS_COUNT );
vector<float>::iterator it = errors.begin();
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
fn[ERROR_PREFIXES[i]+errName] >> *it;
}
int CV_StereoMatchingTest::compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
const vector<float>& eps, const string& errName )
{
assert( (int)calcErrors.size() == ERROR_KINDS_COUNT );
assert( (int)validErrors.size() == ERROR_KINDS_COUNT );
assert( (int)eps.size() == ERROR_KINDS_COUNT );
vector<float>::const_iterator calcIt = calcErrors.begin(),
validIt = validErrors.begin(),
epsIt = eps.begin();
bool ok = true;
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++calcIt, ++validIt, ++epsIt )
if( *calcIt - *validIt > *epsIt )
{
ts->printf( cvtest::TS::LOG, "bad accuracy of %s (valid=%f; calc=%f)\n", string(ERROR_PREFIXES[i]+errName).c_str(), *validIt, *calcIt );
ok = false;
}
return ok ? cvtest::TS::OK : cvtest::TS::FAIL_BAD_ACCURACY;
}
//----------------------------------- StereoGC test -----------------------------------------------------
class CV_StereoGCTest : public CV_StereoMatchingTest
{
public:
CV_StereoGCTest()
{
name = "stereogc";
fill(rmsEps.begin(), rmsEps.end(), 3.f);
fracEps[0] = 0.05f; // all
fracEps[1] = 0.05f; // noOccl
fracEps[2] = 0.25f; // occl
fracEps[3] = 0.05f; // textured
fracEps[4] = 0.10f; // textureless
fracEps[5] = 0.10f; // borderedDepthDiscont
}
protected:
struct RunParams
{
int ndisp;
int iterCount;
};
vector<RunParams> caseRunParams;
virtual int readRunParams( FileStorage& fs )
{
int code = CV_StereoMatchingTest::readRunParams(fs);
FileNode fn = fs.getFirstTopLevelNode();
assert(fn.isSeq());
for( int i = 0; i < (int)fn.size(); i+=4 )
{
string caseName = fn[i], datasetName = fn[i+1];
RunParams params;
string ndisp = fn[i+2]; params.ndisp = atoi(ndisp.c_str());
string iterCount = fn[i+3]; params.iterCount = atoi(iterCount.c_str());
caseNames.push_back( caseName );
caseDatasets.push_back( datasetName );
caseRunParams.push_back( params );
}
return code;
}
virtual int runStereoMatchingAlgorithm( const Mat& _leftImg, const Mat& _rightImg,
Mat& leftDisp, Mat& rightDisp, int caseIdx )
{
RunParams params = caseRunParams[caseIdx];
assert( _leftImg.type() == CV_8UC3 && _rightImg.type() == CV_8UC3 );
Mat leftImg, rightImg, tmp;
cvtColor( _leftImg, leftImg, CV_BGR2GRAY );
cvtColor( _rightImg, rightImg, CV_BGR2GRAY );
leftDisp.create( leftImg.size(), CV_16SC1 );
rightDisp.create( rightImg.size(), CV_16SC1 );
CvMat _limg = leftImg, _rimg = rightImg, _ldisp = leftDisp, _rdisp = rightDisp;
CvStereoGCState *state = cvCreateStereoGCState( params.ndisp, params.iterCount );
cvFindStereoCorrespondenceGC( &_limg, &_rimg, &_ldisp, &_rdisp, state );
cvReleaseStereoGCState( &state );
leftDisp = - leftDisp;
return 0;
}
};
TEST(Calib3d_StereoGC, regression) { CV_StereoGCTest test; test.safe_run(); }

View File

@ -1,49 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// 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
{
}

View File

@ -4,7 +4,6 @@ Motion Analysis and Object Tracking
.. highlight:: cpp
calcOpticalFlowPyrLK
------------------------
Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with pyramids.
@ -86,89 +85,6 @@ The function finds an optical flow for each ``prevImg`` pixel using the [Farneba
\texttt{prevImg} (y,x) \sim \texttt{nextImg} ( y + \texttt{flow} (y,x)[1], x + \texttt{flow} (y,x)[0])
CalcOpticalFlowBM
-----------------
Calculates the optical flow for two images by using the block matching method.
.. ocv:cfunction:: void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, CvSize blockSize, CvSize shiftSize, CvSize maxRange, int usePrevious, CvArr* velx, CvArr* vely )
.. ocv:pyoldfunction:: cv.CalcOpticalFlowBM(prev, curr, blockSize, shiftSize, maxRange, usePrevious, velx, vely)-> None
:param prev: First image, 8-bit, single-channel
:param curr: Second image, 8-bit, single-channel
:param blockSize: Size of basic blocks that are compared
:param shiftSize: Block coordinate increments
:param maxRange: Size of the scanned neighborhood in pixels around the block
:param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not.
:param velx: Horizontal component of the optical flow of
.. math::
\left \lfloor \frac{\texttt{prev->width} - \texttt{blockSize.width}}{\texttt{shiftSize.width}} \right \rfloor \times \left \lfloor \frac{\texttt{prev->height} - \texttt{blockSize.height}}{\texttt{shiftSize.height}} \right \rfloor
size, 32-bit floating-point, single-channel
:param vely: Vertical component of the optical flow of the same size ``velx`` , 32-bit floating-point, single-channel
The function calculates the optical flow for overlapped blocks ``blockSize.width x blockSize.height`` pixels each, thus the velocity fields are smaller than the original images. For every block in ``prev``
the functions tries to find a similar block in ``curr`` in some neighborhood of the original block or shifted by ``(velx(x0,y0), vely(x0,y0))`` block as has been calculated by previous function call (if ``usePrevious=1``)
CalcOpticalFlowHS
-----------------
Calculates the optical flow for two images using Horn-Schunck algorithm.
.. ocv:cfunction:: void cvCalcOpticalFlowHS(const CvArr* prev, const CvArr* curr, int usePrevious, CvArr* velx, CvArr* vely, double lambda, CvTermCriteria criteria)
.. ocv:pyoldfunction:: cv.CalcOpticalFlowHS(prev, curr, usePrevious, velx, vely, lambda, criteria)-> None
:param prev: First image, 8-bit, single-channel
:param curr: Second image, 8-bit, single-channel
:param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not.
:param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
:param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
:param lambda: Smoothness weight. The larger it is, the smoother optical flow map you get.
:param criteria: Criteria of termination of velocity computing
The function computes the flow for every pixel of the first input image using the Horn and Schunck algorithm [Horn81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`.
CalcOpticalFlowLK
-----------------
Calculates the optical flow for two images using Lucas-Kanade algorithm.
.. ocv:cfunction:: void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, CvSize winSize, CvArr* velx, CvArr* vely )
.. ocv:pyoldfunction:: cv.CalcOpticalFlowLK(prev, curr, winSize, velx, vely)-> None
:param prev: First image, 8-bit, single-channel
:param curr: Second image, 8-bit, single-channel
:param winSize: Size of the averaging window used for grouping pixels
:param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
:param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel
The function computes the flow for every pixel of the first input image using the Lucas and Kanade algorithm [Lucas81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`.
estimateRigidTransform
--------------------------
Computes an optimal affine transformation between two 2D point sets.

View File

@ -45,304 +45,6 @@
#include "opencv2/core/core.hpp"
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************************\
* Background/foreground segmentation *
\****************************************************************************************/
/* We discriminate between foreground and background pixels
* by building and maintaining a model of the background.
* Any pixel which does not fit this model is then deemed
* to be foreground.
*
* At present we support two core background models,
* one of which has two variations:
*
* o CV_BG_MODEL_FGD: latest and greatest algorithm, described in
*
* Foreground Object Detection from Videos Containing Complex Background.
* Liyuan Li, Weimin Huang, Irene Y.H. Gu, and Qi Tian.
* ACM MM2003 9p
*
* o CV_BG_MODEL_FGD_SIMPLE:
* A code comment describes this as a simplified version of the above,
* but the code is in fact currently identical
*
* o CV_BG_MODEL_MOG: "Mixture of Gaussians", older algorithm, described in
*
* Moving target classification and tracking from real-time video.
* A Lipton, H Fujijoshi, R Patil
* Proceedings IEEE Workshop on Application of Computer Vision pp 8-14 1998
*
* Learning patterns of activity using real-time tracking
* C Stauffer and W Grimson August 2000
* IEEE Transactions on Pattern Analysis and Machine Intelligence 22(8):747-757
*/
#define CV_BG_MODEL_FGD 0
#define CV_BG_MODEL_MOG 1 /* "Mixture of Gaussians". */
#define CV_BG_MODEL_FGD_SIMPLE 2
struct CvBGStatModel;
typedef void (CV_CDECL * CvReleaseBGStatModel)( struct CvBGStatModel** bg_model );
typedef int (CV_CDECL * CvUpdateBGStatModel)( IplImage* curr_frame, struct CvBGStatModel* bg_model,
double learningRate );
#define CV_BG_STAT_MODEL_FIELDS() \
int type; /*type of BG model*/ \
CvReleaseBGStatModel release; \
CvUpdateBGStatModel update; \
IplImage* background; /*8UC3 reference background image*/ \
IplImage* foreground; /*8UC1 foreground image*/ \
IplImage** layers; /*8UC3 reference background image, can be null */ \
int layer_count; /* can be zero */ \
CvMemStorage* storage; /*storage for foreground_regions*/ \
CvSeq* foreground_regions /*foreground object contours*/
typedef struct CvBGStatModel
{
CV_BG_STAT_MODEL_FIELDS();
} CvBGStatModel;
//
// Releases memory used by BGStatModel
CVAPI(void) cvReleaseBGStatModel( CvBGStatModel** bg_model );
// Updates statistical model and returns number of found foreground regions
CVAPI(int) cvUpdateBGStatModel( IplImage* current_frame, CvBGStatModel* bg_model,
double learningRate CV_DEFAULT(-1));
// Performs FG post-processing using segmentation
// (all pixels of a region will be classified as foreground if majority of pixels of the region are FG).
// parameters:
// segments - pointer to result of segmentation (for example MeanShiftSegmentation)
// bg_model - pointer to CvBGStatModel structure
CVAPI(void) cvRefineForegroundMaskBySegm( CvSeq* segments, CvBGStatModel* bg_model );
/* Common use change detection function */
CVAPI(int) cvChangeDetection( IplImage* prev_frame,
IplImage* curr_frame,
IplImage* change_mask );
/*
Interface of ACM MM2003 algorithm
*/
/* Default parameters of foreground detection algorithm: */
#define CV_BGFG_FGD_LC 128
#define CV_BGFG_FGD_N1C 15
#define CV_BGFG_FGD_N2C 25
#define CV_BGFG_FGD_LCC 64
#define CV_BGFG_FGD_N1CC 25
#define CV_BGFG_FGD_N2CC 40
/* Background reference image update parameter: */
#define CV_BGFG_FGD_ALPHA_1 0.1f
/* stat model update parameter
* 0.002f ~ 1K frame(~45sec), 0.005 ~ 18sec (if 25fps and absolutely static BG)
*/
#define CV_BGFG_FGD_ALPHA_2 0.005f
/* start value for alpha parameter (to fast initiate statistic model) */
#define CV_BGFG_FGD_ALPHA_3 0.1f
#define CV_BGFG_FGD_DELTA 2
#define CV_BGFG_FGD_T 0.9f
#define CV_BGFG_FGD_MINAREA 15.f
#define CV_BGFG_FGD_BG_UPDATE_TRESH 0.5f
/* See the above-referenced Li/Huang/Gu/Tian paper
* for a full description of these background-model
* tuning parameters.
*
* Nomenclature: 'c' == "color", a three-component red/green/blue vector.
* We use histograms of these to model the range of
* colors we've seen at a given background pixel.
*
* 'cc' == "color co-occurrence", a six-component vector giving
* RGB color for both this frame and preceding frame.
* We use histograms of these to model the range of
* color CHANGES we've seen at a given background pixel.
*/
typedef struct CvFGDStatModelParams
{
int Lc; /* Quantized levels per 'color' component. Power of two, typically 32, 64 or 128. */
int N1c; /* Number of color vectors used to model normal background color variation at a given pixel. */
int N2c; /* Number of color vectors retained at given pixel. Must be > N1c, typically ~ 5/3 of N1c. */
/* Used to allow the first N1c vectors to adapt over time to changing background. */
int Lcc; /* Quantized levels per 'color co-occurrence' component. Power of two, typically 16, 32 or 64. */
int N1cc; /* Number of color co-occurrence vectors used to model normal background color variation at a given pixel. */
int N2cc; /* Number of color co-occurrence vectors retained at given pixel. Must be > N1cc, typically ~ 5/3 of N1cc. */
/* Used to allow the first N1cc vectors to adapt over time to changing background. */
int is_obj_without_holes;/* If TRUE we ignore holes within foreground blobs. Defaults to TRUE. */
int perform_morphing; /* Number of erode-dilate-erode foreground-blob cleanup iterations. */
/* These erase one-pixel junk blobs and merge almost-touching blobs. Default value is 1. */
float alpha1; /* How quickly we forget old background pixel values seen. Typically set to 0.1 */
float alpha2; /* "Controls speed of feature learning". Depends on T. Typical value circa 0.005. */
float alpha3; /* Alternate to alpha2, used (e.g.) for quicker initial convergence. Typical value 0.1. */
float delta; /* Affects color and color co-occurrence quantization, typically set to 2. */
float T; /* "A percentage value which determines when new features can be recognized as new background." (Typically 0.9).*/
float minArea; /* Discard foreground blobs whose bounding box is smaller than this threshold. */
} CvFGDStatModelParams;
typedef struct CvBGPixelCStatTable
{
float Pv, Pvb;
uchar v[3];
} CvBGPixelCStatTable;
typedef struct CvBGPixelCCStatTable
{
float Pv, Pvb;
uchar v[6];
} CvBGPixelCCStatTable;
typedef struct CvBGPixelStat
{
float Pbc;
float Pbcc;
CvBGPixelCStatTable* ctable;
CvBGPixelCCStatTable* cctable;
uchar is_trained_st_model;
uchar is_trained_dyn_model;
} CvBGPixelStat;
typedef struct CvFGDStatModel
{
CV_BG_STAT_MODEL_FIELDS();
CvBGPixelStat* pixel_stat;
IplImage* Ftd;
IplImage* Fbd;
IplImage* prev_frame;
CvFGDStatModelParams params;
} CvFGDStatModel;
/* Creates FGD model */
CVAPI(CvBGStatModel*) cvCreateFGDStatModel( IplImage* first_frame,
CvFGDStatModelParams* parameters CV_DEFAULT(NULL));
/*
Interface of Gaussian mixture algorithm
"An improved adaptive background mixture model for real-time tracking with shadow detection"
P. KadewTraKuPong and R. Bowden,
Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001."
http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf
*/
/* Note: "MOG" == "Mixture Of Gaussians": */
#define CV_BGFG_MOG_MAX_NGAUSSIANS 500
/* default parameters of gaussian background detection algorithm */
#define CV_BGFG_MOG_BACKGROUND_THRESHOLD 0.7 /* threshold sum of weights for background test */
#define CV_BGFG_MOG_STD_THRESHOLD 2.5 /* lambda=2.5 is 99% */
#define CV_BGFG_MOG_WINDOW_SIZE 200 /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */
#define CV_BGFG_MOG_NGAUSSIANS 5 /* = K = number of Gaussians in mixture */
#define CV_BGFG_MOG_WEIGHT_INIT 0.05
#define CV_BGFG_MOG_SIGMA_INIT 30
#define CV_BGFG_MOG_MINAREA 15.f
#define CV_BGFG_MOG_NCOLORS 3
typedef struct CvGaussBGStatModelParams
{
int win_size; /* = 1/alpha */
int n_gauss;
double bg_threshold, std_threshold, minArea;
double weight_init, variance_init;
}CvGaussBGStatModelParams;
typedef struct CvGaussBGValues
{
int match_sum;
double weight;
double variance[CV_BGFG_MOG_NCOLORS];
double mean[CV_BGFG_MOG_NCOLORS];
} CvGaussBGValues;
typedef struct CvGaussBGPoint
{
CvGaussBGValues* g_values;
} CvGaussBGPoint;
typedef struct CvGaussBGModel
{
CV_BG_STAT_MODEL_FIELDS();
CvGaussBGStatModelParams params;
CvGaussBGPoint* g_point;
int countFrames;
} CvGaussBGModel;
/* Creates Gaussian mixture background model */
CVAPI(CvBGStatModel*) cvCreateGaussianBGModel( IplImage* first_frame,
CvGaussBGStatModelParams* parameters CV_DEFAULT(NULL));
typedef struct CvBGCodeBookElem
{
struct CvBGCodeBookElem* next;
int tLastUpdate;
int stale;
uchar boxMin[3];
uchar boxMax[3];
uchar learnMin[3];
uchar learnMax[3];
} CvBGCodeBookElem;
typedef struct CvBGCodeBookModel
{
CvSize size;
int t;
uchar cbBounds[3];
uchar modMin[3];
uchar modMax[3];
CvBGCodeBookElem** cbmap;
CvMemStorage* storage;
CvBGCodeBookElem* freeList;
} CvBGCodeBookModel;
CVAPI(CvBGCodeBookModel*) cvCreateBGCodeBookModel();
CVAPI(void) cvReleaseBGCodeBookModel( CvBGCodeBookModel** model );
CVAPI(void) cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* image,
CvRect roi CV_DEFAULT(cvRect(0,0,0,0)),
const CvArr* mask CV_DEFAULT(0) );
CVAPI(int) cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* image,
CvArr* fgmask, CvRect roi CV_DEFAULT(cvRect(0,0,0,0)) );
CVAPI(void) cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh,
CvRect roi CV_DEFAULT(cvRect(0,0,0,0)),
const CvArr* mask CV_DEFAULT(0) );
CVAPI(CvSeq*) cvSegmentFGMask( CvArr *fgmask, int poly1Hull0 CV_DEFAULT(1),
float perimScale CV_DEFAULT(4.f),
CvMemStorage* storage CV_DEFAULT(0),
CvPoint offset CV_DEFAULT(cvPoint(0,0)));
#ifdef __cplusplus
}
namespace cv
{
@ -483,6 +185,5 @@ public:
};
}
#endif
#endif

View File

@ -60,21 +60,6 @@ extern "C" {
/************************************ optical flow ***************************************/
/* Calculates optical flow for 2 images using classical Lucas & Kanade algorithm */
CVAPI(void) cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr,
CvSize win_size, CvArr* velx, CvArr* vely );
/* Calculates optical flow for 2 images using block matching algorithm */
CVAPI(void) cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr,
CvSize block_size, CvSize shift_size,
CvSize max_range, int use_previous,
CvArr* velx, CvArr* vely );
/* Calculates Optical flow for 2 images using Horn & Schunck algorithm */
CVAPI(void) cvCalcOpticalFlowHS( const CvArr* prev, const CvArr* curr,
int use_previous, CvArr* velx, CvArr* vely,
double lambda, CvTermCriteria criteria );
#define CV_LKFLOW_PYR_A_READY 1
#define CV_LKFLOW_PYR_B_READY 2
#define CV_LKFLOW_INITIAL_GUESSES 4

View File

@ -67,11 +67,12 @@ void BackgroundSubtractor::getBackgroundImage(OutputArray) const
{
}
static const int defaultNMixtures = CV_BGFG_MOG_NGAUSSIANS;
static const int defaultHistory = CV_BGFG_MOG_WINDOW_SIZE;
static const double defaultBackgroundRatio = CV_BGFG_MOG_BACKGROUND_THRESHOLD;
static const double defaultVarThreshold = CV_BGFG_MOG_STD_THRESHOLD*CV_BGFG_MOG_STD_THRESHOLD;
static const double defaultNoiseSigma = CV_BGFG_MOG_SIGMA_INIT*0.5;
static const int defaultNMixtures = 5;
static const int defaultHistory = 200;
static const double defaultBackgroundRatio = 0.7;
static const double defaultVarThreshold = 2.5*2.5;
static const double defaultNoiseSigma = 30*0.5;
static const double defaultInitialWeight = 0.05;
BackgroundSubtractorMOG::BackgroundSubtractorMOG()
{
@ -140,9 +141,9 @@ static void process8uC1( BackgroundSubtractorMOG& obj, const Mat& image, Mat& fg
int K = obj.nmixtures;
MixData<float>* mptr = (MixData<float>*)obj.bgmodel.data;
const float w0 = (float)CV_BGFG_MOG_WEIGHT_INIT;
const float sk0 = (float)(w0/CV_BGFG_MOG_SIGMA_INIT);
const float var0 = (float)(CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT);
const float w0 = (float)defaultInitialWeight;
const float sk0 = (float)(w0/(defaultNoiseSigma*2));
const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4);
const float minVar = (float)(obj.noiseSigma*obj.noiseSigma);
for( y = 0; y < rows; y++ )
@ -264,9 +265,9 @@ static void process8uC3( BackgroundSubtractorMOG& obj, const Mat& image, Mat& fg
float alpha = (float)learningRate, T = (float)obj.backgroundRatio, vT = (float)obj.varThreshold;
int K = obj.nmixtures;
const float w0 = (float)CV_BGFG_MOG_WEIGHT_INIT;
const float sk0 = (float)(w0/(CV_BGFG_MOG_SIGMA_INIT*sqrt(3.)));
const float var0 = (float)(CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT);
const float w0 = (float)defaultInitialWeight;
const float sk0 = (float)(w0/(defaultNoiseSigma*2*sqrt(3.)));
const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4);
const float minVar = (float)(obj.noiseSigma*obj.noiseSigma);
MixData<Vec3f>* mptr = (MixData<Vec3f>*)obj.bgmodel.data;
@ -411,140 +412,5 @@ void BackgroundSubtractorMOG::operator()(InputArray _image, OutputArray _fgmask,
}
static void CV_CDECL
icvReleaseGaussianBGModel( CvGaussBGModel** bg_model )
{
if( !bg_model )
CV_Error( CV_StsNullPtr, "" );
if( *bg_model )
{
delete (cv::Mat*)((*bg_model)->g_point);
cvReleaseImage( &(*bg_model)->background );
cvReleaseImage( &(*bg_model)->foreground );
cvReleaseMemStorage(&(*bg_model)->storage);
memset( *bg_model, 0, sizeof(**bg_model) );
delete *bg_model;
*bg_model = 0;
}
}
static int CV_CDECL
icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model, double learningRate )
{
int region_count = 0;
cv::Mat image = cv::cvarrToMat(curr_frame), mask = cv::cvarrToMat(bg_model->foreground);
cv::BackgroundSubtractorMOG mog;
mog.bgmodel = *(cv::Mat*)bg_model->g_point;
mog.frameSize = mog.bgmodel.data ? cv::Size(cvGetSize(curr_frame)) : cv::Size();
mog.frameType = image.type();
mog.nframes = bg_model->countFrames;
mog.history = bg_model->params.win_size;
mog.nmixtures = bg_model->params.n_gauss;
mog.varThreshold = bg_model->params.std_threshold*bg_model->params.std_threshold;
mog.backgroundRatio = bg_model->params.bg_threshold;
mog(image, mask, learningRate);
bg_model->countFrames = mog.nframes;
if( ((cv::Mat*)bg_model->g_point)->data != mog.bgmodel.data )
*((cv::Mat*)bg_model->g_point) = mog.bgmodel;
//foreground filtering
//filter small regions
cvClearMemStorage(bg_model->storage);
//cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 );
//cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 );
/*
CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
for( seq = first_seq; seq; seq = seq->h_next )
{
CvContour* cnt = (CvContour*)seq;
if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea )
{
//delete small contour
prev_seq = seq->h_prev;
if( prev_seq )
{
prev_seq->h_next = seq->h_next;
if( seq->h_next ) seq->h_next->h_prev = prev_seq;
}
else
{
first_seq = seq->h_next;
if( seq->h_next ) seq->h_next->h_prev = NULL;
}
}
else
{
region_count++;
}
}
bg_model->foreground_regions = first_seq;
cvZero(bg_model->foreground);
cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);*/
CvMat _mask = mask;
cvCopy(&_mask, bg_model->foreground);
return region_count;
}
CV_IMPL CvBGStatModel*
cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters )
{
CvGaussBGStatModelParams params;
CV_Assert( CV_IS_IMAGE(first_frame) );
//init parameters
if( parameters == NULL )
{ /* These constants are defined in cvaux/include/cvaux.h: */
params.win_size = CV_BGFG_MOG_WINDOW_SIZE;
params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD;
params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD;
params.weight_init = CV_BGFG_MOG_WEIGHT_INIT;
params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT;
params.minArea = CV_BGFG_MOG_MINAREA;
params.n_gauss = CV_BGFG_MOG_NGAUSSIANS;
}
else
params = *parameters;
CvGaussBGModel* bg_model = new CvGaussBGModel;
memset( bg_model, 0, sizeof(*bg_model) );
bg_model->type = CV_BG_MODEL_MOG;
bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel;
bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel;
bg_model->params = params;
//prepare storages
bg_model->g_point = (CvGaussBGPoint*)new cv::Mat();
bg_model->background = cvCreateImage(cvSize(first_frame->width,
first_frame->height), IPL_DEPTH_8U, first_frame->nChannels);
bg_model->foreground = cvCreateImage(cvSize(first_frame->width,
first_frame->height), IPL_DEPTH_8U, 1);
bg_model->storage = cvCreateMemStorage();
bg_model->countFrames = 0;
icvUpdateGaussianBGModel( first_frame, bg_model, 1 );
return (CvBGStatModel*)bg_model;
}
/* End of file. */

View File

@ -196,18 +196,8 @@ typedef struct CvGaussBGStatModel2Data
unsigned char* rnUsedModes;//number of Gaussian components per pixel (maximum 255)
} CvGaussBGStatModel2Data;
//only foreground image is updated
//no filtering included
typedef struct CvGaussBGModel2
{
CV_BG_STAT_MODEL_FIELDS();
CvGaussBGStatModel2Params params;
CvGaussBGStatModel2Data data;
int countFrames;
} CvGaussBGModel2;
CVAPI(CvBGStatModel*) cvCreateGaussianBGModel2( IplImage* first_frame,
CvGaussBGStatModel2Params* params CV_DEFAULT(NULL) );
//shadow detection performed per pixel
// should work for rgb data, could be usefull for gray scale and depth data as well
// See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
@ -941,239 +931,6 @@ void icvUpdatePixelBackgroundGMM2( const CvArr* srcarr, CvArr* dstarr ,
}
//////////////////////////////////////////////
//implementation as part of the CvBGStatModel
static void CV_CDECL icvReleaseGaussianBGModel2( CvGaussBGModel2** bg_model );
static int CV_CDECL icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model );
CV_IMPL CvBGStatModel*
cvCreateGaussianBGModel2( IplImage* first_frame, CvGaussBGStatModel2Params* parameters )
{
CvGaussBGModel2* bg_model = 0;
int w,h;
CV_FUNCNAME( "cvCreateGaussianBGModel2" );
__BEGIN__;
CvGaussBGStatModel2Params params;
if( !CV_IS_IMAGE(first_frame) )
CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
if( first_frame->nChannels>CV_BGFG_MOG2_NDMAX )
CV_ERROR( CV_StsBadArg, "Maxumum number of channels in the image is excedded (change CV_BGFG_MOG2_MAXBANDS constant)!" );
CV_CALL( bg_model = (CvGaussBGModel2*)cvAlloc( sizeof(*bg_model) ));
memset( bg_model, 0, sizeof(*bg_model) );
bg_model->type = CV_BG_MODEL_MOG2;
bg_model->release = (CvReleaseBGStatModel) icvReleaseGaussianBGModel2;
bg_model->update = (CvUpdateBGStatModel) icvUpdateGaussianBGModel2;
//init parameters
if( parameters == NULL )
{
memset(&params, 0, sizeof(params));
/* These constants are defined in cvaux/include/cvaux.h: */
params.bShadowDetection = 1;
params.bPostFiltering=0;
params.minArea=CV_BGFG_MOG2_MINAREA;
//set parameters
// K - max number of Gaussians per pixel
params.nM = CV_BGFG_MOG2_NGAUSSIANS;//4;
// Tb - the threshold - n var
//pGMM->fTb = 4*4;
params.fTb = CV_BGFG_MOG2_STD_THRESHOLD*CV_BGFG_MOG2_STD_THRESHOLD;
// Tbf - the threshold
//pGMM->fTB = 0.9f;//1-cf from the paper
params.fTB = CV_BGFG_MOG2_BACKGROUND_THRESHOLD;
// Tgenerate - the threshold
params.fTg = CV_BGFG_MOG2_STD_THRESHOLD_GENERATE*CV_BGFG_MOG2_STD_THRESHOLD_GENERATE;//update the mode or generate new
//pGMM->fSigma= 11.0f;//sigma for the new mode
params.fVarInit = CV_BGFG_MOG2_VAR_INIT;
params.fVarMax = CV_BGFG_MOG2_VAR_MAX;
params.fVarMin = CV_BGFG_MOG2_VAR_MIN;
// alpha - the learning factor
params.fAlphaT = 1.0f/CV_BGFG_MOG2_WINDOW_SIZE;//0.003f;
// complexity reduction prior constant
params.fCT = CV_BGFG_MOG2_CT;//0.05f;
//shadow
// Shadow detection
params.nShadowDetection = (unsigned char)CV_BGFG_MOG2_SHADOW_VALUE;//value 0 to turn off
params.fTau = CV_BGFG_MOG2_SHADOW_TAU;//0.5f;// Tau - shadow threshold
}
else
{
params = *parameters;
}
bg_model->params = params;
//image data
w = first_frame->width;
h = first_frame->height;
bg_model->params.nWidth = w;
bg_model->params.nHeight = h;
bg_model->params.nND = first_frame->nChannels;
//allocate GMM data
//GMM for each pixel
bg_model->data.rGMM = (CvPBGMMGaussian*) malloc(w*h * params.nM * sizeof(CvPBGMMGaussian));
//used modes per pixel
bg_model->data.rnUsedModes = (unsigned char* ) malloc(w*h);
memset(bg_model->data.rnUsedModes,0,w*h);//no modes used
//prepare storages
CV_CALL( bg_model->background = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, first_frame->nChannels));
CV_CALL( bg_model->foreground = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1));
//for eventual filtering
CV_CALL( bg_model->storage = cvCreateMemStorage());
bg_model->countFrames = 0;
__END__;
if( cvGetErrStatus() < 0 )
{
CvBGStatModel* base_ptr = (CvBGStatModel*)bg_model;
if( bg_model && bg_model->release )
bg_model->release( &base_ptr );
else
cvFree( &bg_model );
bg_model = 0;
}
return (CvBGStatModel*)bg_model;
}
static void CV_CDECL
icvReleaseGaussianBGModel2( CvGaussBGModel2** _bg_model )
{
CV_FUNCNAME( "icvReleaseGaussianBGModel2" );
__BEGIN__;
if( !_bg_model )
CV_ERROR( CV_StsNullPtr, "" );
if( *_bg_model )
{
CvGaussBGModel2* bg_model = *_bg_model;
free (bg_model->data.rGMM);
free (bg_model->data.rnUsedModes);
cvReleaseImage( &bg_model->background );
cvReleaseImage( &bg_model->foreground );
cvReleaseMemStorage(&bg_model->storage);
memset( bg_model, 0, sizeof(*bg_model) );
cvFree( _bg_model );
}
__END__;
}
static int CV_CDECL
icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model )
{
//checks
if ((curr_frame->height!=bg_model->params.nHeight)||(curr_frame->width!=bg_model->params.nWidth)||(curr_frame->nChannels!=bg_model->params.nND))
CV_Error( CV_StsBadSize, "the image not the same size as the reserved GMM background model");
float alpha=bg_model->params.fAlphaT;
bg_model->countFrames++;
//faster initial updates - increase value of alpha
if (bg_model->params.bInit){
float alphaInit=(1.0f/(2*bg_model->countFrames+1));
if (alphaInit>alpha)
{
alpha = alphaInit;
}
else
{
bg_model->params.bInit = 0;
}
}
//update background
//icvUpdatePixelBackgroundGMM2( curr_frame, bg_model->foreground, bg_model->data.rGMM,bg_model->data.rnUsedModes,&(bg_model->params),alpha);
icvUpdatePixelBackgroundGMM2( curr_frame, bg_model->foreground, bg_model->data.rGMM,bg_model->data.rnUsedModes,
bg_model->params.nM,
bg_model->params.fTb,
bg_model->params.fTB,
bg_model->params.fTg,
bg_model->params.fVarInit,
bg_model->params.fVarMax,
bg_model->params.fVarMin,
bg_model->params.fCT,
bg_model->params.fTau,
bg_model->params.bShadowDetection,
bg_model->params.nShadowDetection,
alpha);
//foreground filtering
if (bg_model->params.bPostFiltering==1)
{
int region_count = 0;
CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
//filter small regions
cvClearMemStorage(bg_model->storage);
cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 );
cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 );
cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
for( seq = first_seq; seq; seq = seq->h_next )
{
CvContour* cnt = (CvContour*)seq;
if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea )
{
//delete small contour
prev_seq = seq->h_prev;
if( prev_seq )
{
prev_seq->h_next = seq->h_next;
if( seq->h_next ) seq->h_next->h_prev = prev_seq;
}
else
{
first_seq = seq->h_next;
if( seq->h_next ) seq->h_next->h_prev = NULL;
}
}
else
{
region_count++;
}
}
bg_model->foreground_regions = first_seq;
cvZero(bg_model->foreground);
cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
return region_count;
}
return 1;
}
namespace cv
{

View File

@ -24,6 +24,7 @@
#include "opencv2/video/background_segm.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/legacy/legacy.hpp"
#include <stdio.h>
#include <stdlib.h>

View File

@ -1,5 +1,6 @@
#include "opencv2/video/background_segm.hpp"
#include "opencv2/legacy/blobtrack.hpp"
#include "opencv2/legacy/legacy.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/imgproc/imgproc_c.h>