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,
}
};
-
-//----------------------------------- 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
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(); }
float cv::Mesh3D::estimateResolution(float tryRatio)
{
+ #if 0
const int neighbors = 3;
const int minReasonable = 10;
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();
}
//--------------------------------------------------------------------------------
-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
{
public:
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(); }
}
-// 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
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),
/* 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 *
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
+++ /dev/null
-/*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_*/
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 )
{
//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
{
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 )
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;
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;
}
.. toctree::
:maxdepth: 2
+
+ motion_analysis
--- /dev/null
+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`.
+
+
}
+// 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
--- /dev/null
+/*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
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "precomp.hpp"
+
+/////////////////////////////////////// MOG model //////////////////////////////////////////
+
+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 );
+
+#if 0
+ 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);
+#endif
+
+ 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;
+}
+
+
+//////////////////////////////////////////// MOG2 //////////////////////////////////////////////
+
+/*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
+ //
+ // 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*/
+
+/*//Implementation of the Gaussian mixture model background subtraction from:
+ //
+ //"Improved adaptive Gausian mixture model for background subtraction"
+ //Z.Zivkovic
+ //International Conference Pattern Recognition, UK, August, 2004
+ //http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
+ //The code is very fast and performs also shadow detection.
+ //Number of Gausssian components is adapted per pixel.
+ //
+ // and
+ //
+ //"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
+ //Z.Zivkovic, F. van der Heijden
+ //Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
+ //
+ //The algorithm similar to the standard Stauffer&Grimson algorithm with
+ //additional selection of the number of the Gaussian components based on:
+ //
+ //"Recursive unsupervised learning of finite mixture models "
+ //Z.Zivkovic, F.van der Heijden
+ //IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
+ //http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
+ //
+ //
+ //Example usage with as cpp class
+ // BackgroundSubtractorMOG2 bg_model;
+ //For each new image the model is updates using:
+ // bg_model(img, fgmask);
+ //
+ //Example usage as part of the CvBGStatModel:
+ // CvBGStatModel* bg_model = cvCreateGaussianBGModel2( first_frame );
+ //
+ // //update for each frame
+ // cvUpdateBGStatModel( tmp_frame, bg_model );//segmentation result is in bg_model->foreground
+ //
+ // //release at the program termination
+ // cvReleaseBGStatModel( &bg_model );
+ //
+ //Author: Z.Zivkovic, www.zoranz.net
+ //Date: 7-April-2011, Version:1.0
+ ///////////*/
+
+#include "precomp.hpp"
+
+
+/*
+ Interface of Gaussian mixture algorithm from:
+
+ "Improved adaptive Gausian mixture model for background subtraction"
+ Z.Zivkovic
+ International Conference Pattern Recognition, UK, August, 2004
+ http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
+
+ Advantages:
+ -fast - number of Gausssian components is constantly adapted per pixel.
+ -performs also shadow detection (see bgfg_segm_test.cpp example)
+
+ */
+
+
+#define CV_BG_MODEL_MOG2 3 /* "Mixture of Gaussians 2". */
+
+
+/* default parameters of gaussian background detection algorithm */
+#define CV_BGFG_MOG2_STD_THRESHOLD 4.0f /* lambda=2.5 is 99% */
+#define CV_BGFG_MOG2_WINDOW_SIZE 500 /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */
+#define CV_BGFG_MOG2_BACKGROUND_THRESHOLD 0.9f /* threshold sum of weights for background test */
+#define CV_BGFG_MOG2_STD_THRESHOLD_GENERATE 3.0f /* lambda=2.5 is 99% */
+#define CV_BGFG_MOG2_NGAUSSIANS 5 /* = K = number of Gaussians in mixture */
+#define CV_BGFG_MOG2_VAR_INIT 15.0f /* initial variance for new components*/
+#define CV_BGFG_MOG2_VAR_MIN 4.0f
+#define CV_BGFG_MOG2_VAR_MAX 5*CV_BGFG_MOG2_VAR_INIT
+#define CV_BGFG_MOG2_MINAREA 15.0f /* for postfiltering */
+
+/* additional parameters */
+#define CV_BGFG_MOG2_CT 0.05f /* complexity reduction prior constant 0 - no reduction of number of components*/
+#define CV_BGFG_MOG2_SHADOW_VALUE 127 /* value to use in the segmentation mask for shadows, sot 0 not to do shadow detection*/
+#define CV_BGFG_MOG2_SHADOW_TAU 0.5f /* Tau - shadow threshold, see the paper for explanation*/
+
+typedef struct CvGaussBGStatModel2Params
+{
+ //image info
+ int nWidth;
+ int nHeight;
+ int nND;//number of data dimensions (image channels)
+
+ bool bPostFiltering;//defult 1 - do postfiltering - will make shadow detection results also give value 255
+ double minArea; // for postfiltering
+
+ bool bInit;//default 1, faster updates at start
+
+ /////////////////////////
+ //very important parameters - things you will change
+ ////////////////////////
+ float fAlphaT;
+ //alpha - speed of update - if the time interval you want to average over is T
+ //set alpha=1/T. It is also usefull at start to make T slowly increase
+ //from 1 until the desired T
+ float fTb;
+ //Tb - threshold on the squared Mahalan. dist. to decide if it is well described
+ //by the background model or not. Related to Cthr from the paper.
+ //This does not influence the update of the background. A typical value could be 4 sigma
+ //and that is Tb=4*4=16;
+
+ /////////////////////////
+ //less important parameters - things you might change but be carefull
+ ////////////////////////
+ float fTg;
+ //Tg - threshold on the squared Mahalan. dist. to decide
+ //when a sample is close to the existing components. If it is not close
+ //to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
+ //Smaller Tg leads to more generated components and higher Tg might make
+ //lead to small number of components but they can grow too large
+ float fTB;//1-cf from the paper
+ //TB - threshold when the component becomes significant enough to be included into
+ //the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
+ //For alpha=0.001 it means that the mode should exist for approximately 105 frames before
+ //it is considered foreground
+ float fVarInit;
+ float fVarMax;
+ float fVarMin;
+ //initial standard deviation for the newly generated components.
+ //It will will influence the speed of adaptation. A good guess should be made.
+ //A simple way is to estimate the typical standard deviation from the images.
+ //I used here 10 as a reasonable value
+ float fCT;//CT - complexity reduction prior
+ //this is related to the number of samples needed to accept that a component
+ //actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
+ //the standard Stauffer&Grimson algorithm (maybe not exact but very similar)
+
+ //even less important parameters
+ int nM;//max number of modes - const - 4 is usually enough
+
+ //shadow detection parameters
+ bool bShadowDetection;//default 1 - do shadow detection
+ unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result
+ float fTau;
+ // Tau - shadow threshold. The shadow is detected if the pixel is darker
+ //version of the background. Tau is a threshold on how much darker the shadow can be.
+ //Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
+ //See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003.
+} CvGaussBGStatModel2Params;
+
+#define CV_BGFG_MOG2_NDMAX 3
+
+typedef struct CvPBGMMGaussian
+{
+ float weight;
+ float mean[CV_BGFG_MOG2_NDMAX];
+ float variance;
+}CvPBGMMGaussian;
+
+typedef struct CvGaussBGStatModel2Data
+{
+ CvPBGMMGaussian* rGMM; //array for the mixture of Gaussians
+ 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.
+CV_INLINE int _icvRemoveShadowGMM(float* data, int nD,
+ unsigned char nModes,
+ CvPBGMMGaussian* pGMM,
+ float m_fTb,
+ float m_fTB,
+ float m_fTau)
+{
+ float tWeight = 0;
+ float numerator, denominator;
+ // check all the components marked as background:
+ for (int iModes=0;iModes<nModes;iModes++)
+ {
+
+ CvPBGMMGaussian g=pGMM[iModes];
+
+ numerator = 0.0f;
+ denominator = 0.0f;
+ for (int iD=0;iD<nD;iD++)
+ {
+ numerator += data[iD] * g.mean[iD];
+ denominator += g.mean[iD]* g.mean[iD];
+ }
+
+ // no division by zero allowed
+ if (denominator == 0)
+ {
+ return 0;
+ };
+ float a = numerator / denominator;
+
+ // if tau < a < 1 then also check the color distortion
+ if ((a <= 1) && (a >= m_fTau))
+ {
+
+ float dist2a=0.0f;
+
+ for (int iD=0;iD<nD;iD++)
+ {
+ float dD= a*g.mean[iD] - data[iD];
+ dist2a += (dD*dD);
+ }
+
+ if (dist2a<m_fTb*g.variance*a*a)
+ {
+ return 2;
+ }
+ };
+
+ tWeight += g.weight;
+ if (tWeight > m_fTB)
+ {
+ return 0;
+ };
+ };
+ return 0;
+}
+
+//update GMM - the base update function performed per pixel
+//
+//"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
+//Z.Zivkovic, F. van der Heijden
+//Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
+//
+//The algorithm similar to the standard Stauffer&Grimson algorithm with
+//additional selection of the number of the Gaussian components based on:
+//
+//"Recursive unsupervised learning of finite mixture models "
+//Z.Zivkovic, F.van der Heijden
+//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
+//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
+
+CV_INLINE int _icvUpdateGMM(float* data, int nD,
+ unsigned char* pModesUsed,
+ CvPBGMMGaussian* pGMM,
+ int m_nM,
+ float m_fAlphaT,
+ float m_fTb,
+ float m_fTB,
+ float m_fTg,
+ float m_fVarInit,
+ float m_fVarMax,
+ float m_fVarMin,
+ float m_fPrune)
+{
+ //calculate distances to the modes (+ sort)
+ //here we need to go in descending order!!!
+ bool bBackground=0;//return value -> true - the pixel classified as background
+
+ //internal:
+ bool bFitsPDF=0;//if it remains zero a new GMM mode will be added
+ float m_fOneMinAlpha=1-m_fAlphaT;
+ unsigned char nModes=*pModesUsed;//current number of modes in GMM
+ float totalWeight=0.0f;
+
+ //////
+ //go through all modes
+ int iMode=0;
+ CvPBGMMGaussian* pGauss=pGMM;
+ for (;iMode<nModes;iMode++,pGauss++)
+ {
+ float weight = pGauss->weight;//need only weight if fit is found
+ weight=m_fOneMinAlpha*weight+m_fPrune;
+
+ ////
+ //fit not found yet
+ if (!bFitsPDF)
+ {
+ //check if it belongs to some of the remaining modes
+ float var=pGauss->variance;
+
+ //calculate difference and distance
+ float dist2=0.0f;
+#if (CV_BGFG_MOG2_NDMAX==1)
+ float dData=pGauss->mean[0]-data[0];
+ dist2=dData*dData;
+#else
+ float dData[CV_BGFG_MOG2_NDMAX];
+
+ for (int iD=0;iD<nD;iD++)
+ {
+ dData[iD]=pGauss->mean[iD]-data[iD];
+ dist2+=dData[iD]*dData[iD];
+ }
+#endif
+ //background? - m_fTb - usually larger than m_fTg
+ if ((totalWeight<m_fTB)&&(dist2<m_fTb*var))
+ bBackground=1;
+
+ //check fit
+ if (dist2<m_fTg*var)
+ {
+ /////
+ //belongs to the mode - bFitsPDF becomes 1
+ bFitsPDF=1;
+
+ //update distribution
+
+ //update weight
+ weight+=m_fAlphaT;
+
+ float k = m_fAlphaT/weight;
+
+ //update mean
+#if (CV_BGFG_MOG2_NDMAX==1)
+ pGauss->mean[0]-=k*dData;
+#else
+ for (int iD=0;iD<nD;iD++)
+ {
+ pGauss->mean[iD]-=k*dData[iD];
+ }
+#endif
+
+ //update variance
+ float varnew = var + k*(dist2-var);
+ //limit the variance
+ pGauss->variance = MIN(m_fVarMax,MAX(varnew,m_fVarMin));
+
+ //sort
+ //all other weights are at the same place and
+ //only the matched (iModes) is higher -> just find the new place for it
+ for (int iLocal = iMode;iLocal>0;iLocal--)
+ {
+ //check one up
+ if (weight < (pGMM[iLocal-1].weight))
+ {
+ break;
+ }
+ else
+ {
+ //swap one up
+ CvPBGMMGaussian temp = pGMM[iLocal];
+ pGMM[iLocal] = pGMM[iLocal-1];
+ pGMM[iLocal-1] = temp;
+ pGauss--;
+ }
+ }
+ //belongs to the mode - bFitsPDF becomes 1
+ /////
+ }
+ }//!bFitsPDF)
+
+ //check prune
+ if (weight<-m_fPrune)
+ {
+ weight=0.0;
+ nModes--;
+ }
+
+ pGauss->weight=weight;//update weight by the calculated value
+ totalWeight+=weight;
+ }
+ //go through all modes
+ //////
+
+ //renormalize weights
+ for (iMode = 0; iMode < nModes; iMode++)
+ {
+ pGMM[iMode].weight = pGMM[iMode].weight/totalWeight;
+ }
+
+ //make new mode if needed and exit
+ if (!bFitsPDF)
+ {
+ if (nModes==m_nM)
+ {
+ //replace the weakest
+ pGauss=pGMM+m_nM-1;
+ }
+ else
+ {
+ //add a new one
+ pGauss=pGMM+nModes;
+ nModes++;
+ }
+
+ if (nModes==1)
+ {
+ pGauss->weight=1;
+ }
+ else
+ {
+ pGauss->weight=m_fAlphaT;
+
+ //renormalize all weights
+ for (iMode = 0; iMode < nModes-1; iMode++)
+ {
+ pGMM[iMode].weight *=m_fOneMinAlpha;
+ }
+ }
+
+ //init
+ memcpy(pGauss->mean,data,nD*sizeof(float));
+ pGauss->variance=m_fVarInit;
+
+ //sort
+ //find the new place for it
+ for (int iLocal = nModes-1;iLocal>0;iLocal--)
+ {
+ //check one up
+ if (m_fAlphaT < (pGMM[iLocal-1].weight))
+ {
+ break;
+ }
+ else
+ {
+ //swap one up
+ CvPBGMMGaussian temp = pGMM[iLocal];
+ pGMM[iLocal] = pGMM[iLocal-1];
+ pGMM[iLocal-1] = temp;
+ }
+ }
+ }
+
+ //set the number of modes
+ *pModesUsed=nModes;
+
+ return bBackground;
+}
+
+// a bit more efficient implementation for common case of 3 channel (rgb) images
+CV_INLINE int _icvUpdateGMM_C3(float r,float g, float b,
+ unsigned char* pModesUsed,
+ CvPBGMMGaussian* pGMM,
+ int m_nM,
+ float m_fAlphaT,
+ float m_fTb,
+ float m_fTB,
+ float m_fTg,
+ float m_fVarInit,
+ float m_fVarMax,
+ float m_fVarMin,
+ float m_fPrune)
+{
+ //calculate distances to the modes (+ sort)
+ //here we need to go in descending order!!!
+ bool bBackground=0;//return value -> true - the pixel classified as background
+
+ //internal:
+ bool bFitsPDF=0;//if it remains zero a new GMM mode will be added
+ float m_fOneMinAlpha=1-m_fAlphaT;
+ unsigned char nModes=*pModesUsed;//current number of modes in GMM
+ float totalWeight=0.0f;
+
+ //////
+ //go through all modes
+ int iMode=0;
+ CvPBGMMGaussian* pGauss=pGMM;
+ for (;iMode<nModes;iMode++,pGauss++)
+ {
+ float weight = pGauss->weight;//need only weight if fit is found
+ weight=m_fOneMinAlpha*weight+m_fPrune;
+
+ ////
+ //fit not found yet
+ if (!bFitsPDF)
+ {
+ //check if it belongs to some of the remaining modes
+ float var=pGauss->variance;
+
+ //calculate difference and distance
+ float muR = pGauss->mean[0];
+ float muG = pGauss->mean[1];
+ float muB = pGauss->mean[2];
+
+ float dR=muR - r;
+ float dG=muG - g;
+ float dB=muB - b;
+
+ float dist2=(dR*dR+dG*dG+dB*dB);
+
+ //background? - m_fTb - usually larger than m_fTg
+ if ((totalWeight<m_fTB)&&(dist2<m_fTb*var))
+ bBackground=1;
+
+ //check fit
+ if (dist2<m_fTg*var)
+ {
+ /////
+ //belongs to the mode - bFitsPDF becomes 1
+ bFitsPDF=1;
+
+ //update distribution
+
+ //update weight
+ weight+=m_fAlphaT;
+
+ float k = m_fAlphaT/weight;
+
+ //update mean
+ pGauss->mean[0] = muR - k*(dR);
+ pGauss->mean[1] = muG - k*(dG);
+ pGauss->mean[2] = muB - k*(dB);
+
+ //update variance
+ float varnew = var + k*(dist2-var);
+ //limit the variance
+ pGauss->variance = MIN(m_fVarMax,MAX(varnew,m_fVarMin));
+
+ //sort
+ //all other weights are at the same place and
+ //only the matched (iModes) is higher -> just find the new place for it
+ for (int iLocal = iMode;iLocal>0;iLocal--)
+ {
+ //check one up
+ if (weight < (pGMM[iLocal-1].weight))
+ {
+ break;
+ }
+ else
+ {
+ //swap one up
+ CvPBGMMGaussian temp = pGMM[iLocal];
+ pGMM[iLocal] = pGMM[iLocal-1];
+ pGMM[iLocal-1] = temp;
+ pGauss--;
+ }
+ }
+ //belongs to the mode - bFitsPDF becomes 1
+ /////
+ }
+
+ }//!bFitsPDF)
+
+ //check prunning
+ if (weight<-m_fPrune)
+ {
+ weight=0.0;
+ nModes--;
+ }
+
+ pGauss->weight=weight;
+ totalWeight+=weight;
+ }
+ //go through all modes
+ //////
+
+ //renormalize weights
+ for (iMode = 0; iMode < nModes; iMode++)
+ {
+ pGMM[iMode].weight = pGMM[iMode].weight/totalWeight;
+ }
+
+ //make new mode if needed and exit
+ if (!bFitsPDF)
+ {
+ if (nModes==m_nM)
+ {
+ //replace the weakest
+ pGauss=pGMM+m_nM-1;
+ }
+ else
+ {
+ //add a new one
+ pGauss=pGMM+nModes;
+ nModes++;
+ }
+
+ if (nModes==1)
+ {
+ pGauss->weight=1;
+ }
+ else
+ {
+ pGauss->weight=m_fAlphaT;
+
+ //renormalize all weights
+ for (iMode = 0; iMode < nModes-1; iMode++)
+ {
+ pGMM[iMode].weight *=m_fOneMinAlpha;
+ }
+ }
+
+ //init
+ pGauss->mean[0]=r;
+ pGauss->mean[1]=g;
+ pGauss->mean[2]=b;
+
+ pGauss->variance=m_fVarInit;
+
+ //sort
+ //find the new place for it
+ for (int iLocal = nModes-1;iLocal>0;iLocal--)
+ {
+ //check one up
+ if (m_fAlphaT < (pGMM[iLocal-1].weight))
+ {
+ break;
+ }
+ else
+ {
+ //swap one up
+ CvPBGMMGaussian temp = pGMM[iLocal];
+ pGMM[iLocal] = pGMM[iLocal-1];
+ pGMM[iLocal-1] = temp;
+ }
+ }
+ }
+
+ //set the number of modes
+ *pModesUsed=nModes;
+
+ return bBackground;
+}
+
+//the main function to update the background model
+void icvUpdatePixelBackgroundGMM2( const CvArr* srcarr, CvArr* dstarr ,
+ CvPBGMMGaussian *pGMM,
+ unsigned char *pUsedModes,
+ //CvGaussBGStatModel2Params* pGMMPar,
+ int nM,
+ float fTb,
+ float fTB,
+ float fTg,
+ float fVarInit,
+ float fVarMax,
+ float fVarMin,
+ float fCT,
+ float fTau,
+ bool bShadowDetection,
+ unsigned char nShadowDetection,
+ float alpha)
+{
+ CvMat sstub, *src = cvGetMat(srcarr, &sstub);
+ CvMat dstub, *dst = cvGetMat(dstarr, &dstub);
+ CvSize size = cvGetMatSize(src);
+ int nD=CV_MAT_CN(src->type);
+
+ //reshape if possible
+ if( CV_IS_MAT_CONT(src->type & dst->type) )
+ {
+ size.width *= size.height;
+ size.height = 1;
+ }
+
+ int x, y;
+ float data[CV_BGFG_MOG2_NDMAX];
+ float prune=-alpha*fCT;
+
+ //general nD
+
+ if (nD!=3)
+ {
+ switch (CV_MAT_DEPTH(src->type))
+ {
+ case CV_8U:
+ for( y = 0; y < size.height; y++ )
+ {
+ uchar* sptr = src->data.ptr + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
+ //update GMM model
+ int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_16S:
+ for( y = 0; y < size.height; y++ )
+ {
+ short* sptr = src->data.s + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
+ //update GMM model
+ int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_16U:
+ for( y = 0; y < size.height; y++ )
+ {
+ unsigned short* sptr = (unsigned short*) (src->data.s + src->step*y);
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
+ //update GMM model
+ int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_32S:
+ for( y = 0; y < size.height; y++ )
+ {
+ int* sptr = src->data.i + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
+ //update GMM model
+ int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_32F:
+ for( y = 0; y < size.height; y++ )
+ {
+ float* sptr = src->data.fl + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //update GMM model
+ int result = _icvUpdateGMM(sptr,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_64F:
+ for( y = 0; y < size.height; y++ )
+ {
+ double* sptr = src->data.db + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ for (int iD=0;iD<nD;iD++) data[iD]=float(sptr[iD]);
+ //update GMM model
+ int result = _icvUpdateGMM(data,nD,pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ }
+ }else ///if (nD==3) - a bit faster
+ {
+ switch (CV_MAT_DEPTH(src->type))
+ {
+ case CV_8U:
+ for( y = 0; y < size.height; y++ )
+ {
+ uchar* sptr = src->data.ptr + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
+ //update GMM model
+ int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_16S:
+ for( y = 0; y < size.height; y++ )
+ {
+ short* sptr = src->data.s + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
+ //update GMM model
+ int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_16U:
+ for( y = 0; y < size.height; y++ )
+ {
+ unsigned short* sptr = (unsigned short*) src->data.s + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
+ //update GMM model
+ int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_32S:
+ for( y = 0; y < size.height; y++ )
+ {
+ int* sptr = src->data.i + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
+ //update GMM model
+ int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_32F:
+ for( y = 0; y < size.height; y++ )
+ {
+ float* sptr = src->data.fl + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //update GMM model
+ int result = _icvUpdateGMM_C3(sptr[0],sptr[1],sptr[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ case CV_64F:
+ for( y = 0; y < size.height; y++ )
+ {
+ double* sptr = src->data.db + src->step*y;
+ uchar* pDataOutput = dst->data.ptr + dst->step*y;
+ for( x = 0; x < size.width; x++,
+ pGMM+=nM,pUsedModes++,pDataOutput++,sptr+=nD)
+ {
+ //convert data
+ data[0]=float(sptr[0]),data[1]=float(sptr[1]),data[2]=float(sptr[2]);
+ //update GMM model
+ int result = _icvUpdateGMM_C3(data[0],data[1],data[2],pUsedModes,pGMM,nM,alpha, fTb, fTB, fTg, fVarInit, fVarMax, fVarMin,prune);
+ //detect shadows in the foreground
+ if (bShadowDetection)
+ if (result==0) result= _icvRemoveShadowGMM(data,nD,(*pUsedModes),pGMM,fTb,fTB,fTau);
+ //generate output
+ (* pDataOutput)= (result==1) ? 0 : (result==2) ? (nShadowDetection) : 255;
+ }
+ }
+ break;
+ }
+ }//a bit faster for nD=3;
+}
+
+
+//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) );
+
+//////////////////////////////////////////////
+//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(¶ms, 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;
+}
+
+/* End of file. */
+
#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 )
{
--- /dev/null
+/*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(); }
//M*/
#include "test_precomp.hpp"
+#include "opencv2/video/tracking.hpp"
#include <string>
#include <iostream>
#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
--- /dev/null
+/*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(); }
+++ /dev/null
-/*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
-{
-
-}
.. highlight:: cpp
-
calcOpticalFlowPyrLK
------------------------
Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with pyramids.
\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.
#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
{
};
}
-#endif
#endif
/************************************ 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
{
}
-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()
{
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++ )
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;
}
-
-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. */
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.
}
-
-//////////////////////////////////////////////
-//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(¶ms, 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
{
#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>
#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>