From beb7fc3c9222756f423ba5c31f66c11db0d4e13e Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Fri, 30 Mar 2012 12:19:25 +0000 Subject: [PATCH] a LOT of obsolete stuff has been moved to the legacy module. --- .../calib3d/include/opencv2/calib3d/calib3d.hpp | 31 - modules/calib3d/test/test_stereomatching.cpp | 68 - modules/contrib/src/spinimages.cpp | 6 + modules/features2d/test/test_nearestneighbors.cpp | 106 -- .../imgproc/include/opencv2/imgproc/imgproc.hpp | 21 - .../imgproc/include/opencv2/imgproc/imgproc_c.h | 157 --- modules/imgproc/src/_imgproc.h | 47 - modules/imgproc/src/geometry.cpp | 16 - modules/imgproc/src/subdivision2d.cpp | 687 +--------- modules/legacy/doc/legacy.rst | 2 + modules/legacy/doc/motion_analysis.rst | 88 ++ modules/legacy/include/opencv2/legacy/legacy.hpp | 523 +++++++- modules/{imgproc => legacy}/src/_featuretree.h | 0 modules/{imgproc => legacy}/src/_kdtree.hpp | 0 modules/{video => legacy}/src/bgfg_acmmm2003.cpp | 0 modules/{video => legacy}/src/bgfg_codebook.cpp | 0 modules/{video => legacy}/src/bgfg_common.cpp | 0 modules/legacy/src/bgfg_gaussmix.cpp | 1376 ++++++++++++++++++++ modules/{imgproc => legacy}/src/featuretree.cpp | 0 modules/{imgproc => legacy}/src/kdtree.cpp | 0 modules/{imgproc => legacy}/src/lsh.cpp | 0 modules/{video => legacy}/src/optflowbm.cpp | 0 modules/{video => legacy}/src/optflowhs.cpp | 0 modules/{video => legacy}/src/optflowlk.cpp | 0 .../{imgproc => legacy}/src/pyrsegmentation.cpp | 0 modules/{imgproc => legacy}/src/spilltree.cpp | 0 modules/{calib3d => legacy}/src/stereogc.cpp | 0 modules/legacy/src/subdiv2.cpp | 703 ++++++++++ modules/legacy/test/test_nearestneighbors.cpp | 264 ++++ modules/{video => legacy}/test/test_optflow.cpp | 1 + modules/legacy/test/test_precomp.hpp | 1 + .../test/test_pyrsegmentation.cpp | 0 modules/legacy/test/test_stereomatching.cpp | 722 ++++++++++ .../{imgproc => legacy}/test/test_subdivisions.cpp | 0 modules/objdetect/src/planardetect.cpp | 49 - .../doc/motion_analysis_and_object_tracking.rst | 84 -- .../include/opencv2/video/background_segm.hpp | 299 ----- modules/video/include/opencv2/video/tracking.hpp | 15 - modules/video/src/bgfg_gaussmix.cpp | 158 +-- modules/video/src/bgfg_gaussmix2.cpp | 247 +--- samples/c/bgfg_codebook.cpp | 1 + samples/c/blobtrack_sample.cpp | 1 + 42 files changed, 3712 insertions(+), 1961 deletions(-) delete mode 100644 modules/imgproc/src/_imgproc.h create mode 100644 modules/legacy/doc/motion_analysis.rst rename modules/{imgproc => legacy}/src/_featuretree.h (100%) rename modules/{imgproc => legacy}/src/_kdtree.hpp (100%) rename modules/{video => legacy}/src/bgfg_acmmm2003.cpp (100%) rename modules/{video => legacy}/src/bgfg_codebook.cpp (100%) rename modules/{video => legacy}/src/bgfg_common.cpp (100%) create mode 100644 modules/legacy/src/bgfg_gaussmix.cpp rename modules/{imgproc => legacy}/src/featuretree.cpp (100%) rename modules/{imgproc => legacy}/src/kdtree.cpp (100%) rename modules/{imgproc => legacy}/src/lsh.cpp (100%) rename modules/{video => legacy}/src/optflowbm.cpp (100%) rename modules/{video => legacy}/src/optflowhs.cpp (100%) rename modules/{video => legacy}/src/optflowlk.cpp (100%) rename modules/{imgproc => legacy}/src/pyrsegmentation.cpp (100%) rename modules/{imgproc => legacy}/src/spilltree.cpp (100%) rename modules/{calib3d => legacy}/src/stereogc.cpp (100%) create mode 100644 modules/legacy/test/test_nearestneighbors.cpp rename modules/{video => legacy}/test/test_optflow.cpp (99%) rename modules/{imgproc => legacy}/test/test_pyrsegmentation.cpp (100%) create mode 100644 modules/legacy/test/test_stereomatching.cpp rename modules/{imgproc => legacy}/test/test_subdivisions.cpp (100%) delete mode 100644 modules/objdetect/src/planardetect.cpp diff --git a/modules/calib3d/include/opencv2/calib3d/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d/calib3d.hpp index cbe1fe5..966fffe 100644 --- a/modules/calib3d/include/opencv2/calib3d/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d/calib3d.hpp @@ -361,37 +361,6 @@ CVAPI(void) cvValidateDisparity( CvArr* disparity, const CvArr* cost, int minDisparity, int numberOfDisparities, int disp12MaxDiff CV_DEFAULT(1) ); -/* Kolmogorov-Zabin stereo-correspondence algorithm (a.k.a. KZ1) */ -#define CV_STEREO_GC_OCCLUDED SHRT_MAX - -typedef struct CvStereoGCState -{ - int Ithreshold; - int interactionRadius; - float K, lambda, lambda1, lambda2; - int occlusionCost; - int minDisparity; - int numberOfDisparities; - int maxIters; - - CvMat* left; - CvMat* right; - CvMat* dispLeft; - CvMat* dispRight; - CvMat* ptrLeft; - CvMat* ptrRight; - CvMat* vtxBuf; - CvMat* edgeBuf; -} CvStereoGCState; - -CVAPI(CvStereoGCState*) cvCreateStereoGCState( int numberOfDisparities, int maxIters ); -CVAPI(void) cvReleaseStereoGCState( CvStereoGCState** state ); - -CVAPI(void) cvFindStereoCorrespondenceGC( const CvArr* left, const CvArr* right, - CvArr* disparityLeft, CvArr* disparityRight, - CvStereoGCState* state, - int useDisparityGuess CV_DEFAULT(0) ); - /* Reprojects the computed disparity image to the 3D space using the specified 4x4 matrix */ CVAPI(void) cvReprojectImageTo3D( const CvArr* disparityImage, CvArr* _3dImage, const CvMat* Q, diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp index 649f79a..a2ba91f 100755 --- a/modules/calib3d/test/test_stereomatching.cpp +++ b/modules/calib3d/test/test_stereomatching.cpp @@ -706,73 +706,6 @@ protected: } }; - -//----------------------------------- StereoGC test ----------------------------------------------------- - -class CV_StereoGCTest : public CV_StereoMatchingTest -{ -public: - CV_StereoGCTest() - { - name = "stereogc"; - fill(rmsEps.begin(), rmsEps.end(), 3.f); - fracEps[0] = 0.05f; // all - fracEps[1] = 0.05f; // noOccl - fracEps[2] = 0.25f; // occl - fracEps[3] = 0.05f; // textured - fracEps[4] = 0.10f; // textureless - fracEps[5] = 0.10f; // borderedDepthDiscont - } -protected: - struct RunParams - { - int ndisp; - int iterCount; - }; - vector caseRunParams; - - virtual int readRunParams( FileStorage& fs ) - { - int code = CV_StereoMatchingTest::readRunParams(fs); - FileNode fn = fs.getFirstTopLevelNode(); - assert(fn.isSeq()); - for( int i = 0; i < (int)fn.size(); i+=4 ) - { - string caseName = fn[i], datasetName = fn[i+1]; - RunParams params; - string ndisp = fn[i+2]; params.ndisp = atoi(ndisp.c_str()); - string iterCount = fn[i+3]; params.iterCount = atoi(iterCount.c_str()); - caseNames.push_back( caseName ); - caseDatasets.push_back( datasetName ); - caseRunParams.push_back( params ); - } - return code; - } - - virtual int runStereoMatchingAlgorithm( const Mat& _leftImg, const Mat& _rightImg, - Mat& leftDisp, Mat& rightDisp, int caseIdx ) - { - RunParams params = caseRunParams[caseIdx]; - assert( _leftImg.type() == CV_8UC3 && _rightImg.type() == CV_8UC3 ); - Mat leftImg, rightImg, tmp; - cvtColor( _leftImg, leftImg, CV_BGR2GRAY ); - cvtColor( _rightImg, rightImg, CV_BGR2GRAY ); - - leftDisp.create( leftImg.size(), CV_16SC1 ); - rightDisp.create( rightImg.size(), CV_16SC1 ); - - CvMat _limg = leftImg, _rimg = rightImg, _ldisp = leftDisp, _rdisp = rightDisp; - CvStereoGCState *state = cvCreateStereoGCState( params.ndisp, params.iterCount ); - cvFindStereoCorrespondenceGC( &_limg, &_rimg, &_ldisp, &_rdisp, state ); - cvReleaseStereoGCState( &state ); - - leftDisp = - leftDisp; - return 0; - } - -}; - - //----------------------------------- StereoSGBM test ----------------------------------------------------- class CV_StereoSGBMTest : public CV_StereoMatchingTest @@ -829,5 +762,4 @@ protected: TEST(Calib3d_StereoBM, regression) { CV_StereoBMTest test; test.safe_run(); } -TEST(Calib3d_StereoGC, regression) { CV_StereoGCTest test; test.safe_run(); } TEST(Calib3d_StereoSGBM, regression) { CV_StereoSGBMTest test; test.safe_run(); } diff --git a/modules/contrib/src/spinimages.cpp b/modules/contrib/src/spinimages.cpp index 6339684..62f21c6 100644 --- a/modules/contrib/src/spinimages.cpp +++ b/modules/contrib/src/spinimages.cpp @@ -442,6 +442,7 @@ void cv::Mesh3D::clearOctree(){ octree = Octree(); } float cv::Mesh3D::estimateResolution(float tryRatio) { + #if 0 const int neighbors = 3; const int minReasonable = 10; @@ -475,8 +476,13 @@ float cv::Mesh3D::estimateResolution(float tryRatio) sort(dist, less()); 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(); diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index 0a23c52..bdeb8fc 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -156,109 +156,6 @@ void NearestNeighborTest::run( int /*start_from*/ ) { } //-------------------------------------------------------------------------------- -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: @@ -506,9 +403,6 @@ void CV_FlannSavedIndexTest::createModel(const cv::Mat &data) remove( filename.c_str() ); } -TEST(Features2d_LSH, regression) { CV_LSHTest test; test.safe_run(); } -TEST(Features2d_SpillTree, regression) { CV_SpillTreeTest_C test; test.safe_run(); } -TEST(Features2d_KDTree_C, regression) { CV_KDTreeTest_C test; test.safe_run(); } TEST(Features2d_KDTree_CPP, regression) { CV_KDTreeTest_CPP test; test.safe_run(); } TEST(Features2d_FLANN_Linear, regression) { CV_FlannLinearIndexTest test; test.safe_run(); } TEST(Features2d_FLANN_KMeans, regression) { CV_FlannKMeansIndexTest test; test.safe_run(); } diff --git a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp index 1be5cbf..0cc8bbe 100644 --- a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp @@ -1142,27 +1142,6 @@ protected: } -// 2009-01-12, Xavier Delacour - -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 diff --git a/modules/imgproc/include/opencv2/imgproc/imgproc_c.h b/modules/imgproc/include/opencv2/imgproc/imgproc_c.h index 1bc8f2c..440490c 100644 --- a/modules/imgproc/include/opencv2/imgproc/imgproc_c.h +++ b/modules/imgproc/include/opencv2/imgproc/imgproc_c.h @@ -121,15 +121,6 @@ CVAPI(CvMat**) cvCreatePyramid( const CvArr* img, int extra_layers, double rate, CVAPI(void) cvReleasePyramid( CvMat*** pyramid, int extra_layers ); -/* Splits color or grayscale image into multiple connected components - of nearly the same color/brightness using modification of Burt algorithm. - comp with contain a pointer to sequence (CvSeq) - of connected components (CvConnectedComp) */ -CVAPI(void) cvPyrSegmentation( IplImage* src, IplImage* dst, - CvMemStorage* storage, CvSeq** comp, - int level, double threshold1, - double threshold2 ); - /* Filters image using meanshift algorithm */ CVAPI(void) cvPyrMeanShiftFiltering( const CvArr* src, CvArr* dst, double sp, double sr, int max_level CV_DEFAULT(1), @@ -351,99 +342,6 @@ CVAPI(void) cvStartReadChainPoints( CvChain* chain, CvChainPtReader* reader ); /* Retrieves the next chain point */ CVAPI(CvPoint) cvReadChainPoint( CvChainPtReader* reader ); -/****************************************************************************************\ -* Planar subdivisions * -\****************************************************************************************/ - -/* Initializes Delaunay triangulation */ -CVAPI(void) cvInitSubdivDelaunay2D( CvSubdiv2D* subdiv, CvRect rect ); - -/* Creates new subdivision */ -CVAPI(CvSubdiv2D*) cvCreateSubdiv2D( int subdiv_type, int header_size, - int vtx_size, int quadedge_size, - CvMemStorage* storage ); - -/************************* high-level subdivision functions ***************************/ - -/* Simplified Delaunay diagram creation */ -CV_INLINE CvSubdiv2D* cvCreateSubdivDelaunay2D( CvRect rect, CvMemStorage* storage ) -{ - CvSubdiv2D* subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*subdiv), - sizeof(CvSubdiv2DPoint), sizeof(CvQuadEdge2D), storage ); - - cvInitSubdivDelaunay2D( subdiv, rect ); - return subdiv; -} - - -/* Inserts new point to the Delaunay triangulation */ -CVAPI(CvSubdiv2DPoint*) cvSubdivDelaunay2DInsert( CvSubdiv2D* subdiv, CvPoint2D32f pt); - -/* Locates a point within the Delaunay triangulation (finds the edge - the point is left to or belongs to, or the triangulation point the given - point coinsides with */ -CVAPI(CvSubdiv2DPointLocation) cvSubdiv2DLocate( - CvSubdiv2D* subdiv, CvPoint2D32f pt, - CvSubdiv2DEdge* edge, - CvSubdiv2DPoint** vertex CV_DEFAULT(NULL) ); - -/* Calculates Voronoi tesselation (i.e. coordinates of Voronoi points) */ -CVAPI(void) cvCalcSubdivVoronoi2D( CvSubdiv2D* subdiv ); - - -/* Removes all Voronoi points from the tesselation */ -CVAPI(void) cvClearSubdivVoronoi2D( CvSubdiv2D* subdiv ); - - -/* Finds the nearest to the given point vertex in subdivision. */ -CVAPI(CvSubdiv2DPoint*) cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt ); - - -/************ Basic quad-edge navigation and operations ************/ - -CV_INLINE CvSubdiv2DEdge cvSubdiv2DNextEdge( CvSubdiv2DEdge edge ) -{ - return CV_SUBDIV2D_NEXT_EDGE(edge); -} - - -CV_INLINE CvSubdiv2DEdge cvSubdiv2DRotateEdge( CvSubdiv2DEdge edge, int rotate ) -{ - return (edge & ~3) + ((edge + rotate) & 3); -} - -CV_INLINE CvSubdiv2DEdge cvSubdiv2DSymEdge( CvSubdiv2DEdge edge ) -{ - return edge ^ 2; -} - -CV_INLINE CvSubdiv2DEdge cvSubdiv2DGetEdge( CvSubdiv2DEdge edge, CvNextEdgeType type ) -{ - CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3); - edge = e->next[(edge + (int)type) & 3]; - return (edge & ~3) + ((edge + ((int)type >> 4)) & 3); -} - - -CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeOrg( CvSubdiv2DEdge edge ) -{ - CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3); - return (CvSubdiv2DPoint*)e->pt[edge & 3]; -} - - -CV_INLINE CvSubdiv2DPoint* cvSubdiv2DEdgeDst( CvSubdiv2DEdge edge ) -{ - CvQuadEdge2D* e = (CvQuadEdge2D*)(edge & ~3); - return (CvSubdiv2DPoint*)e->pt[(edge + 2) & 3]; -} - - -CV_INLINE double cvTriangleArea( CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c ) -{ - return ((double)b.x - a.x) * ((double)c.y - a.y) - ((double)b.y - a.y) * ((double)c.x - a.x); -} - /****************************************************************************************\ * Contour Processing and Shape Analysis * @@ -718,61 +616,6 @@ CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage, CVAPI(void) cvFitLine( const CvArr* points, int dist_type, double param, double reps, double aeps, float* line ); - -/* Constructs kd-tree from set of feature descriptors */ -CVAPI(struct CvFeatureTree*) cvCreateKDTree(CvMat* desc); - -/* Constructs spill-tree from set of feature descriptors */ -CVAPI(struct CvFeatureTree*) cvCreateSpillTree( const CvMat* raw_data, - const int naive CV_DEFAULT(50), - const double rho CV_DEFAULT(.7), - const double tau CV_DEFAULT(.1) ); - -/* Release feature tree */ -CVAPI(void) cvReleaseFeatureTree(struct CvFeatureTree* tr); - -/* Searches feature tree for k nearest neighbors of given reference points, - searching (in case of kd-tree/bbf) at most emax leaves. */ -CVAPI(void) cvFindFeatures(struct CvFeatureTree* tr, const CvMat* query_points, - CvMat* indices, CvMat* dist, int k, int emax CV_DEFAULT(20)); - -/* Search feature tree for all points that are inlier to given rect region. - Only implemented for kd trees */ -CVAPI(int) cvFindFeaturesBoxed(struct CvFeatureTree* tr, - CvMat* bounds_min, CvMat* bounds_max, - CvMat* out_indices); - - -/* Construct a Locality Sensitive Hash (LSH) table, for indexing d-dimensional vectors of - given type. Vectors will be hashed L times with k-dimensional p-stable (p=2) functions. */ -CVAPI(struct CvLSH*) cvCreateLSH(struct CvLSHOperations* ops, int d, - int L CV_DEFAULT(10), int k CV_DEFAULT(10), - int type CV_DEFAULT(CV_64FC1), double r CV_DEFAULT(4), - int64 seed CV_DEFAULT(-1)); - -/* Construct in-memory LSH table, with n bins. */ -CVAPI(struct CvLSH*) cvCreateMemoryLSH(int d, int n, int L CV_DEFAULT(10), int k CV_DEFAULT(10), - int type CV_DEFAULT(CV_64FC1), double r CV_DEFAULT(4), - int64 seed CV_DEFAULT(-1)); - -/* Free the given LSH structure. */ -CVAPI(void) cvReleaseLSH(struct CvLSH** lsh); - -/* Return the number of vectors in the LSH. */ -CVAPI(unsigned int) LSHSize(struct CvLSH* lsh); - -/* Add vectors to the LSH structure, optionally returning indices. */ -CVAPI(void) cvLSHAdd(struct CvLSH* lsh, const CvMat* data, CvMat* indices CV_DEFAULT(0)); - -/* Remove vectors from LSH, as addressed by given indices. */ -CVAPI(void) cvLSHRemove(struct CvLSH* lsh, const CvMat* indices); - -/* Query the LSH n times for at most k nearest points; data is n x d, - indices and dist are n x k. At most emax stored points will be accessed. */ -CVAPI(void) cvLSHQuery(struct CvLSH* lsh, const CvMat* query_points, - CvMat* indices, CvMat* dist, int k, int emax); - - #ifdef __cplusplus } #endif diff --git a/modules/imgproc/src/_imgproc.h b/modules/imgproc/src/_imgproc.h deleted file mode 100644 index 9800a4e..0000000 --- a/modules/imgproc/src/_imgproc.h +++ /dev/null @@ -1,47 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// Intel License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of Intel Corporation may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef _CV_IMG_PROC_H_ -#define _CV_IMG_PROC_H_ - - - -#endif /*_CV_INTERNAL_H_*/ diff --git a/modules/imgproc/src/geometry.cpp b/modules/imgproc/src/geometry.cpp index 95aa540..8c82e64 100644 --- a/modules/imgproc/src/geometry.cpp +++ b/modules/imgproc/src/geometry.cpp @@ -109,22 +109,6 @@ icvIntersectLines( double x1, double dx1, double y1, double dy1, void -icvCreateCenterNormalLine( CvSubdiv2DEdge edge, double *_a, double *_b, double *_c ) -{ - CvPoint2D32f org = cvSubdiv2DEdgeOrg( edge )->pt; - CvPoint2D32f dst = cvSubdiv2DEdgeDst( edge )->pt; - - double a = dst.x - org.x; - double b = dst.y - org.y; - double c = -(a * (dst.x + org.x) + b * (dst.y + org.y)); - - *_a = a + a; - *_b = b + b; - *_c = c; -} - - -void icvIntersectLines3( double *a0, double *b0, double *c0, double *a1, double *b1, double *c1, CvPoint2D32f * point ) { diff --git a/modules/imgproc/src/subdivision2d.cpp b/modules/imgproc/src/subdivision2d.cpp index 2331d6c..2cfc489 100644 --- a/modules/imgproc/src/subdivision2d.cpp +++ b/modules/imgproc/src/subdivision2d.cpp @@ -40,675 +40,6 @@ //M*/ #include "precomp.hpp" -CV_IMPL CvSubdiv2D * -cvCreateSubdiv2D( int subdiv_type, int header_size, - int vtx_size, int quadedge_size, CvMemStorage * storage ) -{ - if( !storage ) - CV_Error( CV_StsNullPtr, "" ); - - if( header_size < (int)sizeof( CvSubdiv2D ) || - quadedge_size < (int)sizeof( CvQuadEdge2D ) || - vtx_size < (int)sizeof( CvSubdiv2DPoint )) - CV_Error( CV_StsBadSize, "" ); - - return (CvSubdiv2D *)cvCreateGraph( subdiv_type, header_size, - vtx_size, quadedge_size, storage ); -} - - -/****************************************************************************************\ -* Quad Edge algebra * -\****************************************************************************************/ - -static CvSubdiv2DEdge -cvSubdiv2DMakeEdge( CvSubdiv2D * subdiv ) -{ - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - CvQuadEdge2D* edge = (CvQuadEdge2D*)cvSetNew( (CvSet*)subdiv->edges ); - memset( edge->pt, 0, sizeof( edge->pt )); - CvSubdiv2DEdge edgehandle = (CvSubdiv2DEdge) edge; - - edge->next[0] = edgehandle; - edge->next[1] = edgehandle + 3; - edge->next[2] = edgehandle + 2; - edge->next[3] = edgehandle + 1; - - subdiv->quad_edges++; - return edgehandle; -} - - -static CvSubdiv2DPoint * -cvSubdiv2DAddPoint( CvSubdiv2D * subdiv, CvPoint2D32f pt, int is_virtual ) -{ - CvSubdiv2DPoint* subdiv_point = (CvSubdiv2DPoint*)cvSetNew( (CvSet*)subdiv ); - if( subdiv_point ) - { - memset( subdiv_point, 0, subdiv->elem_size ); - subdiv_point->pt = pt; - subdiv_point->first = 0; - subdiv_point->flags |= is_virtual ? CV_SUBDIV2D_VIRTUAL_POINT_FLAG : 0; - subdiv_point->id = -1; - } - - return subdiv_point; -} - - -static void -cvSubdiv2DSplice( CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB ) -{ - CvSubdiv2DEdge *a_next = &CV_SUBDIV2D_NEXT_EDGE( edgeA ); - CvSubdiv2DEdge *b_next = &CV_SUBDIV2D_NEXT_EDGE( edgeB ); - CvSubdiv2DEdge a_rot = cvSubdiv2DRotateEdge( *a_next, 1 ); - CvSubdiv2DEdge b_rot = cvSubdiv2DRotateEdge( *b_next, 1 ); - CvSubdiv2DEdge *a_rot_next = &CV_SUBDIV2D_NEXT_EDGE( a_rot ); - CvSubdiv2DEdge *b_rot_next = &CV_SUBDIV2D_NEXT_EDGE( b_rot ); - CvSubdiv2DEdge t; - - CV_SWAP( *a_next, *b_next, t ); - CV_SWAP( *a_rot_next, *b_rot_next, t ); -} - - -static void -cvSubdiv2DSetEdgePoints( CvSubdiv2DEdge edge, - CvSubdiv2DPoint * org_pt, CvSubdiv2DPoint * dst_pt ) -{ - CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3); - - if( !quadedge ) - CV_Error( CV_StsNullPtr, "" ); - - quadedge->pt[edge & 3] = org_pt; - quadedge->pt[(edge + 2) & 3] = dst_pt; -} - - -static void -cvSubdiv2DDeleteEdge( CvSubdiv2D * subdiv, CvSubdiv2DEdge edge ) -{ - CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3); - - if( !subdiv || !quadedge ) - CV_Error( CV_StsNullPtr, "" ); - - cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG )); - - CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge ); - cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG )); - - cvSetRemoveByPtr( (CvSet*)(subdiv->edges), quadedge ); - subdiv->quad_edges--; -} - - -static CvSubdiv2DEdge -cvSubdiv2DConnectEdges( CvSubdiv2D * subdiv, CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB ) -{ - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - CvSubdiv2DEdge new_edge = cvSubdiv2DMakeEdge( subdiv ); - - cvSubdiv2DSplice( new_edge, cvSubdiv2DGetEdge( edgeA, CV_NEXT_AROUND_LEFT )); - cvSubdiv2DSplice( cvSubdiv2DSymEdge( new_edge ), edgeB ); - - CvSubdiv2DPoint* dstA = cvSubdiv2DEdgeDst( edgeA ); - CvSubdiv2DPoint* orgB = cvSubdiv2DEdgeOrg( edgeB ); - cvSubdiv2DSetEdgePoints( new_edge, dstA, orgB ); - - return new_edge; -} - - -static void -cvSubdiv2DSwapEdges( CvSubdiv2DEdge edge ) -{ - CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge ); - CvSubdiv2DEdge a = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG ); - CvSubdiv2DEdge b = cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG ); - CvSubdiv2DPoint *dstB, *dstA; - - cvSubdiv2DSplice( edge, a ); - cvSubdiv2DSplice( sym_edge, b ); - - dstA = cvSubdiv2DEdgeDst( a ); - dstB = cvSubdiv2DEdgeDst( b ); - cvSubdiv2DSetEdgePoints( edge, dstA, dstB ); - - cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( a, CV_NEXT_AROUND_LEFT )); - cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( b, CV_NEXT_AROUND_LEFT )); -} - - -static int -icvIsRightOf( CvPoint2D32f& pt, CvSubdiv2DEdge edge ) -{ - CvSubdiv2DPoint *org = cvSubdiv2DEdgeOrg(edge), *dst = cvSubdiv2DEdgeDst(edge); - double cw_area = cvTriangleArea( pt, dst->pt, org->pt ); - - return (cw_area > 0) - (cw_area < 0); -} - - -CV_IMPL CvSubdiv2DPointLocation -cvSubdiv2DLocate( CvSubdiv2D * subdiv, CvPoint2D32f pt, - CvSubdiv2DEdge * _edge, CvSubdiv2DPoint ** _point ) -{ - CvSubdiv2DPoint *point = 0; - int right_of_curr = 0; - - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - if( !CV_IS_SUBDIV2D(subdiv) ) - CV_Error( CV_StsBadFlag, "" ); - - int i, max_edges = subdiv->quad_edges * 4; - CvSubdiv2DEdge edge = subdiv->recent_edge; - - if( max_edges == 0 ) - CV_Error( CV_StsBadSize, "" ); - CV_Assert(edge != 0); - - if( pt.x < subdiv->topleft.x || pt.y < subdiv->topleft.y || - pt.x >= subdiv->bottomright.x || pt.y >= subdiv->bottomright.y ) - CV_Error( CV_StsOutOfRange, "" ); - - CvSubdiv2DPointLocation location = CV_PTLOC_ERROR; - - right_of_curr = icvIsRightOf( pt, edge ); - if( right_of_curr > 0 ) - { - edge = cvSubdiv2DSymEdge( edge ); - right_of_curr = -right_of_curr; - } - - for( i = 0; i < max_edges; i++ ) - { - CvSubdiv2DEdge onext_edge = cvSubdiv2DNextEdge( edge ); - CvSubdiv2DEdge dprev_edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_DST ); - - int right_of_onext = icvIsRightOf( pt, onext_edge ); - int right_of_dprev = icvIsRightOf( pt, dprev_edge ); - - if( right_of_dprev > 0 ) - { - if( right_of_onext > 0 || (right_of_onext == 0 && right_of_curr == 0) ) - { - location = CV_PTLOC_INSIDE; - goto exit; - } - else - { - right_of_curr = right_of_onext; - edge = onext_edge; - } - } - else - { - if( right_of_onext > 0 ) - { - if( right_of_dprev == 0 && right_of_curr == 0 ) - { - location = CV_PTLOC_INSIDE; - goto exit; - } - else - { - right_of_curr = right_of_dprev; - edge = dprev_edge; - } - } - else if( right_of_curr == 0 && - icvIsRightOf( cvSubdiv2DEdgeDst( onext_edge )->pt, edge ) >= 0 ) - { - edge = cvSubdiv2DSymEdge( edge ); - } - else - { - right_of_curr = right_of_onext; - edge = onext_edge; - } - } - } -exit: - - subdiv->recent_edge = edge; - - if( location == CV_PTLOC_INSIDE ) - { - double t1, t2, t3; - CvPoint2D32f org_pt = cvSubdiv2DEdgeOrg( edge )->pt; - CvPoint2D32f dst_pt = cvSubdiv2DEdgeDst( edge )->pt; - - t1 = fabs( pt.x - org_pt.x ); - t1 += fabs( pt.y - org_pt.y ); - t2 = fabs( pt.x - dst_pt.x ); - t2 += fabs( pt.y - dst_pt.y ); - t3 = fabs( org_pt.x - dst_pt.x ); - t3 += fabs( org_pt.y - dst_pt.y ); - - if( t1 < FLT_EPSILON ) - { - location = CV_PTLOC_VERTEX; - point = cvSubdiv2DEdgeOrg( edge ); - edge = 0; - } - else if( t2 < FLT_EPSILON ) - { - location = CV_PTLOC_VERTEX; - point = cvSubdiv2DEdgeDst( edge ); - edge = 0; - } - else if( (t1 < t3 || t2 < t3) && - fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON ) - { - location = CV_PTLOC_ON_EDGE; - point = 0; - } - } - - if( location == CV_PTLOC_ERROR ) - { - edge = 0; - point = 0; - } - - if( _edge ) - *_edge = edge; - if( _point ) - *_point = point; - - return location; -} - - -CV_INLINE int -icvIsPtInCircle3( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c ) -{ - const double eps = FLT_EPSILON*0.125; - double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt ); - val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt ); - val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt ); - val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c ); - - return val > eps ? 1 : val < -eps ? -1 : 0; -} - - -CV_IMPL CvSubdiv2DPoint * -cvSubdivDelaunay2DInsert( CvSubdiv2D * subdiv, CvPoint2D32f pt ) -{ - CvSubdiv2DPointLocation location = CV_PTLOC_ERROR; - - CvSubdiv2DPoint *curr_point = 0, *first_point = 0; - CvSubdiv2DEdge curr_edge = 0, deleted_edge = 0, base_edge = 0; - int i, max_edges; - - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - if( !CV_IS_SUBDIV2D(subdiv) ) - CV_Error( CV_StsBadFlag, "" ); - - location = cvSubdiv2DLocate( subdiv, pt, &curr_edge, &curr_point ); - - switch (location) - { - case CV_PTLOC_ERROR: - CV_Error( CV_StsBadSize, "" ); - - case CV_PTLOC_OUTSIDE_RECT: - CV_Error( CV_StsOutOfRange, "" ); - - case CV_PTLOC_VERTEX: - break; - - case CV_PTLOC_ON_EDGE: - deleted_edge = curr_edge; - subdiv->recent_edge = curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG ); - cvSubdiv2DDeleteEdge( subdiv, deleted_edge ); - /* no break */ - - case CV_PTLOC_INSIDE: - - assert( curr_edge != 0 ); - subdiv->is_geometry_valid = 0; - - curr_point = cvSubdiv2DAddPoint( subdiv, pt, 0 ); - base_edge = cvSubdiv2DMakeEdge( subdiv ); - first_point = cvSubdiv2DEdgeOrg( curr_edge ); - cvSubdiv2DSetEdgePoints( base_edge, first_point, curr_point ); - cvSubdiv2DSplice( base_edge, curr_edge ); - - do - { - base_edge = cvSubdiv2DConnectEdges( subdiv, curr_edge, - cvSubdiv2DSymEdge( base_edge )); - curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG ); - } - while( cvSubdiv2DEdgeDst( curr_edge ) != first_point ); - - curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG ); - - max_edges = subdiv->quad_edges * 4; - - for( i = 0; i < max_edges; i++ ) - { - CvSubdiv2DPoint *temp_dst = 0, *curr_org = 0, *curr_dst = 0; - CvSubdiv2DEdge temp_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG ); - - temp_dst = cvSubdiv2DEdgeDst( temp_edge ); - curr_org = cvSubdiv2DEdgeOrg( curr_edge ); - curr_dst = cvSubdiv2DEdgeDst( curr_edge ); - - if( icvIsRightOf( temp_dst->pt, curr_edge ) > 0 && - icvIsPtInCircle3( curr_org->pt, temp_dst->pt, - curr_dst->pt, curr_point->pt ) < 0 ) - { - cvSubdiv2DSwapEdges( curr_edge ); - curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG ); - } - else if( curr_org == first_point ) - { - break; - } - else - { - curr_edge = cvSubdiv2DGetEdge( cvSubdiv2DNextEdge( curr_edge ), - CV_PREV_AROUND_LEFT ); - } - } - break; - default: - CV_Error_(CV_StsError, ("cvSubdiv2DLocate returned invalid location = %d", location) ); - } - - return curr_point; -} - - -CV_IMPL void -cvInitSubdivDelaunay2D( CvSubdiv2D * subdiv, CvRect rect ) -{ - float big_coord = 3.f * MAX( rect.width, rect.height ); - CvPoint2D32f ppA, ppB, ppC; - CvSubdiv2DPoint *pA, *pB, *pC; - CvSubdiv2DEdge edge_AB, edge_BC, edge_CA; - float rx = (float) rect.x; - float ry = (float) rect.y; - - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - cvClearSet( (CvSet *) (subdiv->edges) ); - cvClearSet( (CvSet *) subdiv ); - - subdiv->quad_edges = 0; - subdiv->recent_edge = 0; - subdiv->is_geometry_valid = 0; - - subdiv->topleft = cvPoint2D32f( rx, ry ); - subdiv->bottomright = cvPoint2D32f( rx + rect.width, ry + rect.height ); - - ppA = cvPoint2D32f( rx + big_coord, ry ); - ppB = cvPoint2D32f( rx, ry + big_coord ); - ppC = cvPoint2D32f( rx - big_coord, ry - big_coord ); - - pA = cvSubdiv2DAddPoint( subdiv, ppA, 0 ); - pB = cvSubdiv2DAddPoint( subdiv, ppB, 0 ); - pC = cvSubdiv2DAddPoint( subdiv, ppC, 0 ); - - edge_AB = cvSubdiv2DMakeEdge( subdiv ); - edge_BC = cvSubdiv2DMakeEdge( subdiv ); - edge_CA = cvSubdiv2DMakeEdge( subdiv ); - - cvSubdiv2DSetEdgePoints( edge_AB, pA, pB ); - cvSubdiv2DSetEdgePoints( edge_BC, pB, pC ); - cvSubdiv2DSetEdgePoints( edge_CA, pC, pA ); - - cvSubdiv2DSplice( edge_AB, cvSubdiv2DSymEdge( edge_CA )); - cvSubdiv2DSplice( edge_BC, cvSubdiv2DSymEdge( edge_AB )); - cvSubdiv2DSplice( edge_CA, cvSubdiv2DSymEdge( edge_BC )); - - subdiv->recent_edge = edge_AB; -} - - -CV_IMPL void -cvClearSubdivVoronoi2D( CvSubdiv2D * subdiv ) -{ - int elem_size; - int i, total; - CvSeqReader reader; - - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - /* clear pointers to voronoi points */ - total = subdiv->edges->total; - elem_size = subdiv->edges->elem_size; - - cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 ); - - for( i = 0; i < total; i++ ) - { - CvQuadEdge2D *quadedge = (CvQuadEdge2D *) reader.ptr; - - quadedge->pt[1] = quadedge->pt[3] = 0; - CV_NEXT_SEQ_ELEM( elem_size, reader ); - } - - /* remove voronoi points */ - total = subdiv->total; - elem_size = subdiv->elem_size; - - cvStartReadSeq( (CvSeq *) subdiv, &reader, 0 ); - - for( i = 0; i < total; i++ ) - { - CvSubdiv2DPoint *pt = (CvSubdiv2DPoint *) reader.ptr; - - /* check for virtual point. it is also check that the point exists */ - if( pt->flags & CV_SUBDIV2D_VIRTUAL_POINT_FLAG ) - { - cvSetRemoveByPtr( (CvSet*)subdiv, pt ); - } - CV_NEXT_SEQ_ELEM( elem_size, reader ); - } - - subdiv->is_geometry_valid = 0; -} - - -CV_IMPL void -cvCalcSubdivVoronoi2D( CvSubdiv2D * subdiv ) -{ - CvSeqReader reader; - int i, total, elem_size; - - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - /* check if it is already calculated */ - if( subdiv->is_geometry_valid ) - return; - - total = subdiv->edges->total; - elem_size = subdiv->edges->elem_size; - - cvClearSubdivVoronoi2D( subdiv ); - - cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 ); - - if( total <= 3 ) - return; - - /* skip first three edges (bounding triangle) */ - for( i = 0; i < 3; i++ ) - CV_NEXT_SEQ_ELEM( elem_size, reader ); - - /* loop through all quad-edges */ - for( ; i < total; i++ ) - { - CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (reader.ptr); - - if( CV_IS_SET_ELEM( quadedge )) - { - CvSubdiv2DEdge edge0 = (CvSubdiv2DEdge) quadedge, edge1, edge2; - double a0, b0, c0, a1, b1, c1; - CvPoint2D32f virt_point; - CvSubdiv2DPoint *voronoi_point; - - if( !quadedge->pt[3] ) - { - edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_LEFT ); - edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_LEFT ); - - icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 ); - icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 ); - - icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point ); - if( fabs( virt_point.x ) < FLT_MAX * 0.5 && - fabs( virt_point.y ) < FLT_MAX * 0.5 ) - { - voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 ); - - quadedge->pt[3] = - ((CvQuadEdge2D *) (edge1 & ~3))->pt[3 - (edge1 & 2)] = - ((CvQuadEdge2D *) (edge2 & ~3))->pt[3 - (edge2 & 2)] = voronoi_point; - } - } - - if( !quadedge->pt[1] ) - { - edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_RIGHT ); - edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_RIGHT ); - - icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 ); - icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 ); - - icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point ); - - if( fabs( virt_point.x ) < FLT_MAX * 0.5 && - fabs( virt_point.y ) < FLT_MAX * 0.5 ) - { - voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 ); - - quadedge->pt[1] = - ((CvQuadEdge2D *) (edge1 & ~3))->pt[1 + (edge1 & 2)] = - ((CvQuadEdge2D *) (edge2 & ~3))->pt[1 + (edge2 & 2)] = voronoi_point; - } - } - } - - CV_NEXT_SEQ_ELEM( elem_size, reader ); - } - - subdiv->is_geometry_valid = 1; -} - - -static int -icvIsRightOf2( const CvPoint2D32f& pt, const CvPoint2D32f& org, const CvPoint2D32f& diff ) -{ - double cw_area = ((double)org.x - pt.x)*diff.y - ((double)org.y - pt.y)*diff.x; - return (cw_area > 0) - (cw_area < 0); -} - - -CV_IMPL CvSubdiv2DPoint* -cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt ) -{ - CvSubdiv2DPoint* point = 0; - CvPoint2D32f start; - CvPoint2D32f diff; - CvSubdiv2DPointLocation loc; - CvSubdiv2DEdge edge; - int i; - - if( !subdiv ) - CV_Error( CV_StsNullPtr, "" ); - - if( !CV_IS_SUBDIV2D( subdiv )) - CV_Error( CV_StsNullPtr, "" ); - - if( subdiv->edges->active_count <= 3 ) - return 0; - - if( !subdiv->is_geometry_valid ) - cvCalcSubdivVoronoi2D( subdiv ); - - loc = cvSubdiv2DLocate( subdiv, pt, &edge, &point ); - - switch( loc ) - { - case CV_PTLOC_ON_EDGE: - case CV_PTLOC_INSIDE: - break; - default: - return point; - } - - point = 0; - - start = cvSubdiv2DEdgeOrg( edge )->pt; - diff.x = pt.x - start.x; - diff.y = pt.y - start.y; - - edge = cvSubdiv2DRotateEdge( edge, 1 ); - - for( i = 0; i < subdiv->total; i++ ) - { - CvPoint2D32f t; - - for(;;) - { - assert( cvSubdiv2DEdgeDst( edge )); - - t = cvSubdiv2DEdgeDst( edge )->pt; - if( icvIsRightOf2( t, start, diff ) >= 0 ) - break; - - edge = cvSubdiv2DGetEdge( edge, CV_NEXT_AROUND_LEFT ); - } - - for(;;) - { - assert( cvSubdiv2DEdgeOrg( edge )); - - t = cvSubdiv2DEdgeOrg( edge )->pt; - if( icvIsRightOf2( t, start, diff ) < 0 ) - break; - - edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_LEFT ); - } - - { - CvPoint2D32f tempDiff = cvSubdiv2DEdgeDst( edge )->pt; - t = cvSubdiv2DEdgeOrg( edge )->pt; - tempDiff.x -= t.x; - tempDiff.y -= t.y; - - if( icvIsRightOf2( pt, t, tempDiff ) >= 0 ) - { - point = cvSubdiv2DEdgeOrg( cvSubdiv2DRotateEdge( edge, 3 )); - break; - } - } - - edge = cvSubdiv2DSymEdge( edge ); - } - - return point; -} - - namespace cv { @@ -879,17 +210,21 @@ void Subdiv2D::swapEdges( int edge ) splice(sedge, getEdge(b, NEXT_AROUND_LEFT)); } +static double triangleArea( Point2f a, Point2f b, Point2f c ) +{ + return ((double)b.x - a.x) * ((double)c.y - a.y) - ((double)b.y - a.y) * ((double)c.x - a.x); +} + int Subdiv2D::isRightOf(Point2f pt, int edge) const { Point2f org, dst; edgeOrg(edge, &org); edgeDst(edge, &dst); - double cw_area = cvTriangleArea( pt, dst, org ); + double cw_area = triangleArea( pt, dst, org ); return (cw_area > 0) - (cw_area < 0); } - int Subdiv2D::newEdge() { if( freeQEdge <= 0 ) @@ -1039,7 +374,7 @@ int Subdiv2D::locate(Point2f pt, int& _edge, int& _vertex) edge = 0; } else if( (t1 < t3 || t2 < t3) && - fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON ) + fabs( triangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON ) { location = PTLOC_ON_EDGE; vertex = 0; @@ -1063,10 +398,10 @@ inline int isPtInCircle3( Point2f pt, Point2f a, Point2f b, Point2f c) { const double eps = FLT_EPSILON*0.125; - double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt ); - val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt ); - val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt ); - val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c ); + double val = ((double)a.x * a.x + (double)a.y * a.y) * triangleArea( b, c, pt ); + val -= ((double)b.x * b.x + (double)b.y * b.y) * triangleArea( a, c, pt ); + val += ((double)c.x * c.x + (double)c.y * c.y) * triangleArea( a, b, pt ); + val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * triangleArea( a, b, c ); return val > eps ? 1 : val < -eps ? -1 : 0; } diff --git a/modules/legacy/doc/legacy.rst b/modules/legacy/doc/legacy.rst index 3692abf..12cfdb8 100644 --- a/modules/legacy/doc/legacy.rst +++ b/modules/legacy/doc/legacy.rst @@ -6,3 +6,5 @@ legacy. Deprecated stuff .. toctree:: :maxdepth: 2 + + motion_analysis diff --git a/modules/legacy/doc/motion_analysis.rst b/modules/legacy/doc/motion_analysis.rst new file mode 100644 index 0000000..b4f9da2 --- /dev/null +++ b/modules/legacy/doc/motion_analysis.rst @@ -0,0 +1,88 @@ +Motion Analysis +=============== + +.. highlight:: cpp + + +CalcOpticalFlowBM +----------------- +Calculates the optical flow for two images by using the block matching method. + +.. ocv:cfunction:: void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, CvSize blockSize, CvSize shiftSize, CvSize maxRange, int usePrevious, CvArr* velx, CvArr* vely ) + +.. ocv:pyoldfunction:: cv.CalcOpticalFlowBM(prev, curr, blockSize, shiftSize, maxRange, usePrevious, velx, vely)-> None + + :param prev: First image, 8-bit, single-channel + + :param curr: Second image, 8-bit, single-channel + + :param blockSize: Size of basic blocks that are compared + + :param shiftSize: Block coordinate increments + + :param maxRange: Size of the scanned neighborhood in pixels around the block + + :param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not. + + :param velx: Horizontal component of the optical flow of + + .. math:: + + \left \lfloor \frac{\texttt{prev->width} - \texttt{blockSize.width}}{\texttt{shiftSize.width}} \right \rfloor \times \left \lfloor \frac{\texttt{prev->height} - \texttt{blockSize.height}}{\texttt{shiftSize.height}} \right \rfloor + + size, 32-bit floating-point, single-channel + + :param vely: Vertical component of the optical flow of the same size ``velx`` , 32-bit floating-point, single-channel + + +The function calculates the optical flow for overlapped blocks ``blockSize.width x blockSize.height`` pixels each, thus the velocity fields are smaller than the original images. For every block in ``prev`` +the functions tries to find a similar block in ``curr`` in some neighborhood of the original block or shifted by ``(velx(x0,y0), vely(x0,y0))`` block as has been calculated by previous function call (if ``usePrevious=1``) + + +CalcOpticalFlowHS +----------------- +Calculates the optical flow for two images using Horn-Schunck algorithm. + +.. ocv:cfunction:: void cvCalcOpticalFlowHS(const CvArr* prev, const CvArr* curr, int usePrevious, CvArr* velx, CvArr* vely, double lambda, CvTermCriteria criteria) + +.. ocv:pyoldfunction:: cv.CalcOpticalFlowHS(prev, curr, usePrevious, velx, vely, lambda, criteria)-> None + + :param prev: First image, 8-bit, single-channel + + :param curr: Second image, 8-bit, single-channel + + :param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not. + + :param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel + + :param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel + + :param lambda: Smoothness weight. The larger it is, the smoother optical flow map you get. + + :param criteria: Criteria of termination of velocity computing + +The function computes the flow for every pixel of the first input image using the Horn and Schunck algorithm [Horn81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`. + + +CalcOpticalFlowLK +----------------- + +Calculates the optical flow for two images using Lucas-Kanade algorithm. + +.. ocv:cfunction:: void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, CvSize winSize, CvArr* velx, CvArr* vely ) + +.. ocv:pyoldfunction:: cv.CalcOpticalFlowLK(prev, curr, winSize, velx, vely)-> None + + :param prev: First image, 8-bit, single-channel + + :param curr: Second image, 8-bit, single-channel + + :param winSize: Size of the averaging window used for grouping pixels + + :param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel + + :param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel + +The function computes the flow for every pixel of the first input image using the Lucas and Kanade algorithm [Lucas81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`. + + diff --git a/modules/legacy/include/opencv2/legacy/legacy.hpp b/modules/legacy/include/opencv2/legacy/legacy.hpp index c0d1872..8eec455 100644 --- a/modules/legacy/include/opencv2/legacy/legacy.hpp +++ b/modules/legacy/include/opencv2/legacy/legacy.hpp @@ -2797,8 +2797,529 @@ protected: } +// 2009-01-12, Xavier Delacour -//#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 diff --git a/modules/imgproc/src/_featuretree.h b/modules/legacy/src/_featuretree.h similarity index 100% rename from modules/imgproc/src/_featuretree.h rename to modules/legacy/src/_featuretree.h diff --git a/modules/imgproc/src/_kdtree.hpp b/modules/legacy/src/_kdtree.hpp similarity index 100% rename from modules/imgproc/src/_kdtree.hpp rename to modules/legacy/src/_kdtree.hpp diff --git a/modules/video/src/bgfg_acmmm2003.cpp b/modules/legacy/src/bgfg_acmmm2003.cpp similarity index 100% rename from modules/video/src/bgfg_acmmm2003.cpp rename to modules/legacy/src/bgfg_acmmm2003.cpp diff --git a/modules/video/src/bgfg_codebook.cpp b/modules/legacy/src/bgfg_codebook.cpp similarity index 100% rename from modules/video/src/bgfg_codebook.cpp rename to modules/legacy/src/bgfg_codebook.cpp diff --git a/modules/video/src/bgfg_common.cpp b/modules/legacy/src/bgfg_common.cpp similarity index 100% rename from modules/video/src/bgfg_common.cpp rename to modules/legacy/src/bgfg_common.cpp diff --git a/modules/legacy/src/bgfg_gaussmix.cpp b/modules/legacy/src/bgfg_gaussmix.cpp new file mode 100644 index 0000000..f3cb98c --- /dev/null +++ b/modules/legacy/src/bgfg_gaussmix.cpp @@ -0,0 +1,1376 @@ +/*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= m_fTau)) + { + + float dist2a=0.0f; + + for (int iD=0;iD 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 (;iModeweight;//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;iDmean[iD]-data[iD]; + dist2+=dData[iD]*dData[iD]; + } +#endif + //background? - m_fTb - usually larger than m_fTg + if ((totalWeightmean[0]-=k*dData; +#else + for (int iD=0;iDmean[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 (;iModeweight;//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 ((totalWeightmean[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;iDdata.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;iDdata.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;iDdata.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;iDdata.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;iDtype)) + { + 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. */ + diff --git a/modules/imgproc/src/featuretree.cpp b/modules/legacy/src/featuretree.cpp similarity index 100% rename from modules/imgproc/src/featuretree.cpp rename to modules/legacy/src/featuretree.cpp diff --git a/modules/imgproc/src/kdtree.cpp b/modules/legacy/src/kdtree.cpp similarity index 100% rename from modules/imgproc/src/kdtree.cpp rename to modules/legacy/src/kdtree.cpp diff --git a/modules/imgproc/src/lsh.cpp b/modules/legacy/src/lsh.cpp similarity index 100% rename from modules/imgproc/src/lsh.cpp rename to modules/legacy/src/lsh.cpp diff --git a/modules/video/src/optflowbm.cpp b/modules/legacy/src/optflowbm.cpp similarity index 100% rename from modules/video/src/optflowbm.cpp rename to modules/legacy/src/optflowbm.cpp diff --git a/modules/video/src/optflowhs.cpp b/modules/legacy/src/optflowhs.cpp similarity index 100% rename from modules/video/src/optflowhs.cpp rename to modules/legacy/src/optflowhs.cpp diff --git a/modules/video/src/optflowlk.cpp b/modules/legacy/src/optflowlk.cpp similarity index 100% rename from modules/video/src/optflowlk.cpp rename to modules/legacy/src/optflowlk.cpp diff --git a/modules/imgproc/src/pyrsegmentation.cpp b/modules/legacy/src/pyrsegmentation.cpp similarity index 100% rename from modules/imgproc/src/pyrsegmentation.cpp rename to modules/legacy/src/pyrsegmentation.cpp diff --git a/modules/imgproc/src/spilltree.cpp b/modules/legacy/src/spilltree.cpp similarity index 100% rename from modules/imgproc/src/spilltree.cpp rename to modules/legacy/src/spilltree.cpp diff --git a/modules/calib3d/src/stereogc.cpp b/modules/legacy/src/stereogc.cpp similarity index 100% rename from modules/calib3d/src/stereogc.cpp rename to modules/legacy/src/stereogc.cpp diff --git a/modules/legacy/src/subdiv2.cpp b/modules/legacy/src/subdiv2.cpp index 4f44dd9..c940c65 100644 --- a/modules/legacy/src/subdiv2.cpp +++ b/modules/legacy/src/subdiv2.cpp @@ -41,6 +41,709 @@ #include "precomp.hpp" +CV_IMPL CvSubdiv2D * +cvCreateSubdiv2D( int subdiv_type, int header_size, + int vtx_size, int quadedge_size, CvMemStorage * storage ) +{ + if( !storage ) + CV_Error( CV_StsNullPtr, "" ); + + if( header_size < (int)sizeof( CvSubdiv2D ) || + quadedge_size < (int)sizeof( CvQuadEdge2D ) || + vtx_size < (int)sizeof( CvSubdiv2DPoint )) + CV_Error( CV_StsBadSize, "" ); + + return (CvSubdiv2D *)cvCreateGraph( subdiv_type, header_size, + vtx_size, quadedge_size, storage ); +} + + +/****************************************************************************************\ +* Quad Edge algebra * +\****************************************************************************************/ + +static CvSubdiv2DEdge +cvSubdiv2DMakeEdge( CvSubdiv2D * subdiv ) +{ + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + CvQuadEdge2D* edge = (CvQuadEdge2D*)cvSetNew( (CvSet*)subdiv->edges ); + memset( edge->pt, 0, sizeof( edge->pt )); + CvSubdiv2DEdge edgehandle = (CvSubdiv2DEdge) edge; + + edge->next[0] = edgehandle; + edge->next[1] = edgehandle + 3; + edge->next[2] = edgehandle + 2; + edge->next[3] = edgehandle + 1; + + subdiv->quad_edges++; + return edgehandle; +} + + +static CvSubdiv2DPoint * +cvSubdiv2DAddPoint( CvSubdiv2D * subdiv, CvPoint2D32f pt, int is_virtual ) +{ + CvSubdiv2DPoint* subdiv_point = (CvSubdiv2DPoint*)cvSetNew( (CvSet*)subdiv ); + if( subdiv_point ) + { + memset( subdiv_point, 0, subdiv->elem_size ); + subdiv_point->pt = pt; + subdiv_point->first = 0; + subdiv_point->flags |= is_virtual ? CV_SUBDIV2D_VIRTUAL_POINT_FLAG : 0; + subdiv_point->id = -1; + } + + return subdiv_point; +} + + +static void +cvSubdiv2DSplice( CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB ) +{ + CvSubdiv2DEdge *a_next = &CV_SUBDIV2D_NEXT_EDGE( edgeA ); + CvSubdiv2DEdge *b_next = &CV_SUBDIV2D_NEXT_EDGE( edgeB ); + CvSubdiv2DEdge a_rot = cvSubdiv2DRotateEdge( *a_next, 1 ); + CvSubdiv2DEdge b_rot = cvSubdiv2DRotateEdge( *b_next, 1 ); + CvSubdiv2DEdge *a_rot_next = &CV_SUBDIV2D_NEXT_EDGE( a_rot ); + CvSubdiv2DEdge *b_rot_next = &CV_SUBDIV2D_NEXT_EDGE( b_rot ); + CvSubdiv2DEdge t; + + CV_SWAP( *a_next, *b_next, t ); + CV_SWAP( *a_rot_next, *b_rot_next, t ); +} + + +static void +cvSubdiv2DSetEdgePoints( CvSubdiv2DEdge edge, + CvSubdiv2DPoint * org_pt, CvSubdiv2DPoint * dst_pt ) +{ + CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3); + + if( !quadedge ) + CV_Error( CV_StsNullPtr, "" ); + + quadedge->pt[edge & 3] = org_pt; + quadedge->pt[(edge + 2) & 3] = dst_pt; +} + + +static void +cvSubdiv2DDeleteEdge( CvSubdiv2D * subdiv, CvSubdiv2DEdge edge ) +{ + CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (edge & ~3); + + if( !subdiv || !quadedge ) + CV_Error( CV_StsNullPtr, "" ); + + cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG )); + + CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge ); + cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG )); + + cvSetRemoveByPtr( (CvSet*)(subdiv->edges), quadedge ); + subdiv->quad_edges--; +} + + +static CvSubdiv2DEdge +cvSubdiv2DConnectEdges( CvSubdiv2D * subdiv, CvSubdiv2DEdge edgeA, CvSubdiv2DEdge edgeB ) +{ + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + CvSubdiv2DEdge new_edge = cvSubdiv2DMakeEdge( subdiv ); + + cvSubdiv2DSplice( new_edge, cvSubdiv2DGetEdge( edgeA, CV_NEXT_AROUND_LEFT )); + cvSubdiv2DSplice( cvSubdiv2DSymEdge( new_edge ), edgeB ); + + CvSubdiv2DPoint* dstA = cvSubdiv2DEdgeDst( edgeA ); + CvSubdiv2DPoint* orgB = cvSubdiv2DEdgeOrg( edgeB ); + cvSubdiv2DSetEdgePoints( new_edge, dstA, orgB ); + + return new_edge; +} + + +static void +cvSubdiv2DSwapEdges( CvSubdiv2DEdge edge ) +{ + CvSubdiv2DEdge sym_edge = cvSubdiv2DSymEdge( edge ); + CvSubdiv2DEdge a = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_ORG ); + CvSubdiv2DEdge b = cvSubdiv2DGetEdge( sym_edge, CV_PREV_AROUND_ORG ); + CvSubdiv2DPoint *dstB, *dstA; + + cvSubdiv2DSplice( edge, a ); + cvSubdiv2DSplice( sym_edge, b ); + + dstA = cvSubdiv2DEdgeDst( a ); + dstB = cvSubdiv2DEdgeDst( b ); + cvSubdiv2DSetEdgePoints( edge, dstA, dstB ); + + cvSubdiv2DSplice( edge, cvSubdiv2DGetEdge( a, CV_NEXT_AROUND_LEFT )); + cvSubdiv2DSplice( sym_edge, cvSubdiv2DGetEdge( b, CV_NEXT_AROUND_LEFT )); +} + + +static int +icvIsRightOf( CvPoint2D32f& pt, CvSubdiv2DEdge edge ) +{ + CvSubdiv2DPoint *org = cvSubdiv2DEdgeOrg(edge), *dst = cvSubdiv2DEdgeDst(edge); + double cw_area = cvTriangleArea( pt, dst->pt, org->pt ); + + return (cw_area > 0) - (cw_area < 0); +} + + +CV_IMPL CvSubdiv2DPointLocation +cvSubdiv2DLocate( CvSubdiv2D * subdiv, CvPoint2D32f pt, + CvSubdiv2DEdge * _edge, CvSubdiv2DPoint ** _point ) +{ + CvSubdiv2DPoint *point = 0; + int right_of_curr = 0; + + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + if( !CV_IS_SUBDIV2D(subdiv) ) + CV_Error( CV_StsBadFlag, "" ); + + int i, max_edges = subdiv->quad_edges * 4; + CvSubdiv2DEdge edge = subdiv->recent_edge; + + if( max_edges == 0 ) + CV_Error( CV_StsBadSize, "" ); + CV_Assert(edge != 0); + + if( pt.x < subdiv->topleft.x || pt.y < subdiv->topleft.y || + pt.x >= subdiv->bottomright.x || pt.y >= subdiv->bottomright.y ) + CV_Error( CV_StsOutOfRange, "" ); + + CvSubdiv2DPointLocation location = CV_PTLOC_ERROR; + + right_of_curr = icvIsRightOf( pt, edge ); + if( right_of_curr > 0 ) + { + edge = cvSubdiv2DSymEdge( edge ); + right_of_curr = -right_of_curr; + } + + for( i = 0; i < max_edges; i++ ) + { + CvSubdiv2DEdge onext_edge = cvSubdiv2DNextEdge( edge ); + CvSubdiv2DEdge dprev_edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_DST ); + + int right_of_onext = icvIsRightOf( pt, onext_edge ); + int right_of_dprev = icvIsRightOf( pt, dprev_edge ); + + if( right_of_dprev > 0 ) + { + if( right_of_onext > 0 || (right_of_onext == 0 && right_of_curr == 0) ) + { + location = CV_PTLOC_INSIDE; + goto exit; + } + else + { + right_of_curr = right_of_onext; + edge = onext_edge; + } + } + else + { + if( right_of_onext > 0 ) + { + if( right_of_dprev == 0 && right_of_curr == 0 ) + { + location = CV_PTLOC_INSIDE; + goto exit; + } + else + { + right_of_curr = right_of_dprev; + edge = dprev_edge; + } + } + else if( right_of_curr == 0 && + icvIsRightOf( cvSubdiv2DEdgeDst( onext_edge )->pt, edge ) >= 0 ) + { + edge = cvSubdiv2DSymEdge( edge ); + } + else + { + right_of_curr = right_of_onext; + edge = onext_edge; + } + } + } +exit: + + subdiv->recent_edge = edge; + + if( location == CV_PTLOC_INSIDE ) + { + double t1, t2, t3; + CvPoint2D32f org_pt = cvSubdiv2DEdgeOrg( edge )->pt; + CvPoint2D32f dst_pt = cvSubdiv2DEdgeDst( edge )->pt; + + t1 = fabs( pt.x - org_pt.x ); + t1 += fabs( pt.y - org_pt.y ); + t2 = fabs( pt.x - dst_pt.x ); + t2 += fabs( pt.y - dst_pt.y ); + t3 = fabs( org_pt.x - dst_pt.x ); + t3 += fabs( org_pt.y - dst_pt.y ); + + if( t1 < FLT_EPSILON ) + { + location = CV_PTLOC_VERTEX; + point = cvSubdiv2DEdgeOrg( edge ); + edge = 0; + } + else if( t2 < FLT_EPSILON ) + { + location = CV_PTLOC_VERTEX; + point = cvSubdiv2DEdgeDst( edge ); + edge = 0; + } + else if( (t1 < t3 || t2 < t3) && + fabs( cvTriangleArea( pt, org_pt, dst_pt )) < FLT_EPSILON ) + { + location = CV_PTLOC_ON_EDGE; + point = 0; + } + } + + if( location == CV_PTLOC_ERROR ) + { + edge = 0; + point = 0; + } + + if( _edge ) + *_edge = edge; + if( _point ) + *_point = point; + + return location; +} + + +CV_INLINE int +icvIsPtInCircle3( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b, CvPoint2D32f c ) +{ + const double eps = FLT_EPSILON*0.125; + double val = ((double)a.x * a.x + (double)a.y * a.y) * cvTriangleArea( b, c, pt ); + val -= ((double)b.x * b.x + (double)b.y * b.y) * cvTriangleArea( a, c, pt ); + val += ((double)c.x * c.x + (double)c.y * c.y) * cvTriangleArea( a, b, pt ); + val -= ((double)pt.x * pt.x + (double)pt.y * pt.y) * cvTriangleArea( a, b, c ); + + return val > eps ? 1 : val < -eps ? -1 : 0; +} + + +CV_IMPL CvSubdiv2DPoint * +cvSubdivDelaunay2DInsert( CvSubdiv2D * subdiv, CvPoint2D32f pt ) +{ + CvSubdiv2DPointLocation location = CV_PTLOC_ERROR; + + CvSubdiv2DPoint *curr_point = 0, *first_point = 0; + CvSubdiv2DEdge curr_edge = 0, deleted_edge = 0, base_edge = 0; + int i, max_edges; + + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + if( !CV_IS_SUBDIV2D(subdiv) ) + CV_Error( CV_StsBadFlag, "" ); + + location = cvSubdiv2DLocate( subdiv, pt, &curr_edge, &curr_point ); + + switch (location) + { + case CV_PTLOC_ERROR: + CV_Error( CV_StsBadSize, "" ); + + case CV_PTLOC_OUTSIDE_RECT: + CV_Error( CV_StsOutOfRange, "" ); + + case CV_PTLOC_VERTEX: + break; + + case CV_PTLOC_ON_EDGE: + deleted_edge = curr_edge; + subdiv->recent_edge = curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG ); + cvSubdiv2DDeleteEdge( subdiv, deleted_edge ); + /* no break */ + + case CV_PTLOC_INSIDE: + + assert( curr_edge != 0 ); + subdiv->is_geometry_valid = 0; + + curr_point = cvSubdiv2DAddPoint( subdiv, pt, 0 ); + base_edge = cvSubdiv2DMakeEdge( subdiv ); + first_point = cvSubdiv2DEdgeOrg( curr_edge ); + cvSubdiv2DSetEdgePoints( base_edge, first_point, curr_point ); + cvSubdiv2DSplice( base_edge, curr_edge ); + + do + { + base_edge = cvSubdiv2DConnectEdges( subdiv, curr_edge, + cvSubdiv2DSymEdge( base_edge )); + curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG ); + } + while( cvSubdiv2DEdgeDst( curr_edge ) != first_point ); + + curr_edge = cvSubdiv2DGetEdge( base_edge, CV_PREV_AROUND_ORG ); + + max_edges = subdiv->quad_edges * 4; + + for( i = 0; i < max_edges; i++ ) + { + CvSubdiv2DPoint *temp_dst = 0, *curr_org = 0, *curr_dst = 0; + CvSubdiv2DEdge temp_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG ); + + temp_dst = cvSubdiv2DEdgeDst( temp_edge ); + curr_org = cvSubdiv2DEdgeOrg( curr_edge ); + curr_dst = cvSubdiv2DEdgeDst( curr_edge ); + + if( icvIsRightOf( temp_dst->pt, curr_edge ) > 0 && + icvIsPtInCircle3( curr_org->pt, temp_dst->pt, + curr_dst->pt, curr_point->pt ) < 0 ) + { + cvSubdiv2DSwapEdges( curr_edge ); + curr_edge = cvSubdiv2DGetEdge( curr_edge, CV_PREV_AROUND_ORG ); + } + else if( curr_org == first_point ) + { + break; + } + else + { + curr_edge = cvSubdiv2DGetEdge( cvSubdiv2DNextEdge( curr_edge ), + CV_PREV_AROUND_LEFT ); + } + } + break; + default: + CV_Error_(CV_StsError, ("cvSubdiv2DLocate returned invalid location = %d", location) ); + } + + return curr_point; +} + + +CV_IMPL void +cvInitSubdivDelaunay2D( CvSubdiv2D * subdiv, CvRect rect ) +{ + float big_coord = 3.f * MAX( rect.width, rect.height ); + CvPoint2D32f ppA, ppB, ppC; + CvSubdiv2DPoint *pA, *pB, *pC; + CvSubdiv2DEdge edge_AB, edge_BC, edge_CA; + float rx = (float) rect.x; + float ry = (float) rect.y; + + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + cvClearSet( (CvSet *) (subdiv->edges) ); + cvClearSet( (CvSet *) subdiv ); + + subdiv->quad_edges = 0; + subdiv->recent_edge = 0; + subdiv->is_geometry_valid = 0; + + subdiv->topleft = cvPoint2D32f( rx, ry ); + subdiv->bottomright = cvPoint2D32f( rx + rect.width, ry + rect.height ); + + ppA = cvPoint2D32f( rx + big_coord, ry ); + ppB = cvPoint2D32f( rx, ry + big_coord ); + ppC = cvPoint2D32f( rx - big_coord, ry - big_coord ); + + pA = cvSubdiv2DAddPoint( subdiv, ppA, 0 ); + pB = cvSubdiv2DAddPoint( subdiv, ppB, 0 ); + pC = cvSubdiv2DAddPoint( subdiv, ppC, 0 ); + + edge_AB = cvSubdiv2DMakeEdge( subdiv ); + edge_BC = cvSubdiv2DMakeEdge( subdiv ); + edge_CA = cvSubdiv2DMakeEdge( subdiv ); + + cvSubdiv2DSetEdgePoints( edge_AB, pA, pB ); + cvSubdiv2DSetEdgePoints( edge_BC, pB, pC ); + cvSubdiv2DSetEdgePoints( edge_CA, pC, pA ); + + cvSubdiv2DSplice( edge_AB, cvSubdiv2DSymEdge( edge_CA )); + cvSubdiv2DSplice( edge_BC, cvSubdiv2DSymEdge( edge_AB )); + cvSubdiv2DSplice( edge_CA, cvSubdiv2DSymEdge( edge_BC )); + + subdiv->recent_edge = edge_AB; +} + + +CV_IMPL void +cvClearSubdivVoronoi2D( CvSubdiv2D * subdiv ) +{ + int elem_size; + int i, total; + CvSeqReader reader; + + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + /* clear pointers to voronoi points */ + total = subdiv->edges->total; + elem_size = subdiv->edges->elem_size; + + cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 ); + + for( i = 0; i < total; i++ ) + { + CvQuadEdge2D *quadedge = (CvQuadEdge2D *) reader.ptr; + + quadedge->pt[1] = quadedge->pt[3] = 0; + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + + /* remove voronoi points */ + total = subdiv->total; + elem_size = subdiv->elem_size; + + cvStartReadSeq( (CvSeq *) subdiv, &reader, 0 ); + + for( i = 0; i < total; i++ ) + { + CvSubdiv2DPoint *pt = (CvSubdiv2DPoint *) reader.ptr; + + /* check for virtual point. it is also check that the point exists */ + if( pt->flags & CV_SUBDIV2D_VIRTUAL_POINT_FLAG ) + { + cvSetRemoveByPtr( (CvSet*)subdiv, pt ); + } + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + + subdiv->is_geometry_valid = 0; +} + + +static void +icvCreateCenterNormalLine( CvSubdiv2DEdge edge, double *_a, double *_b, double *_c ) +{ + CvPoint2D32f org = cvSubdiv2DEdgeOrg( edge )->pt; + CvPoint2D32f dst = cvSubdiv2DEdgeDst( edge )->pt; + + double a = dst.x - org.x; + double b = dst.y - org.y; + double c = -(a * (dst.x + org.x) + b * (dst.y + org.y)); + + *_a = a + a; + *_b = b + b; + *_c = c; +} + + +static void +icvIntersectLines3( double *a0, double *b0, double *c0, + double *a1, double *b1, double *c1, CvPoint2D32f * point ) +{ + double det = a0[0] * b1[0] - a1[0] * b0[0]; + + if( det != 0 ) + { + det = 1. / det; + point->x = (float) ((b0[0] * c1[0] - b1[0] * c0[0]) * det); + point->y = (float) ((a1[0] * c0[0] - a0[0] * c1[0]) * det); + } + else + { + point->x = point->y = FLT_MAX; + } +} + + +CV_IMPL void +cvCalcSubdivVoronoi2D( CvSubdiv2D * subdiv ) +{ + CvSeqReader reader; + int i, total, elem_size; + + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + /* check if it is already calculated */ + if( subdiv->is_geometry_valid ) + return; + + total = subdiv->edges->total; + elem_size = subdiv->edges->elem_size; + + cvClearSubdivVoronoi2D( subdiv ); + + cvStartReadSeq( (CvSeq *) (subdiv->edges), &reader, 0 ); + + if( total <= 3 ) + return; + + /* skip first three edges (bounding triangle) */ + for( i = 0; i < 3; i++ ) + CV_NEXT_SEQ_ELEM( elem_size, reader ); + + /* loop through all quad-edges */ + for( ; i < total; i++ ) + { + CvQuadEdge2D *quadedge = (CvQuadEdge2D *) (reader.ptr); + + if( CV_IS_SET_ELEM( quadedge )) + { + CvSubdiv2DEdge edge0 = (CvSubdiv2DEdge) quadedge, edge1, edge2; + double a0, b0, c0, a1, b1, c1; + CvPoint2D32f virt_point; + CvSubdiv2DPoint *voronoi_point; + + if( !quadedge->pt[3] ) + { + edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_LEFT ); + edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_LEFT ); + + icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 ); + icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 ); + + icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point ); + if( fabs( virt_point.x ) < FLT_MAX * 0.5 && + fabs( virt_point.y ) < FLT_MAX * 0.5 ) + { + voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 ); + + quadedge->pt[3] = + ((CvQuadEdge2D *) (edge1 & ~3))->pt[3 - (edge1 & 2)] = + ((CvQuadEdge2D *) (edge2 & ~3))->pt[3 - (edge2 & 2)] = voronoi_point; + } + } + + if( !quadedge->pt[1] ) + { + edge1 = cvSubdiv2DGetEdge( edge0, CV_NEXT_AROUND_RIGHT ); + edge2 = cvSubdiv2DGetEdge( edge1, CV_NEXT_AROUND_RIGHT ); + + icvCreateCenterNormalLine( edge0, &a0, &b0, &c0 ); + icvCreateCenterNormalLine( edge1, &a1, &b1, &c1 ); + + icvIntersectLines3( &a0, &b0, &c0, &a1, &b1, &c1, &virt_point ); + + if( fabs( virt_point.x ) < FLT_MAX * 0.5 && + fabs( virt_point.y ) < FLT_MAX * 0.5 ) + { + voronoi_point = cvSubdiv2DAddPoint( subdiv, virt_point, 1 ); + + quadedge->pt[1] = + ((CvQuadEdge2D *) (edge1 & ~3))->pt[1 + (edge1 & 2)] = + ((CvQuadEdge2D *) (edge2 & ~3))->pt[1 + (edge2 & 2)] = voronoi_point; + } + } + } + + CV_NEXT_SEQ_ELEM( elem_size, reader ); + } + + subdiv->is_geometry_valid = 1; +} + + +static int +icvIsRightOf2( const CvPoint2D32f& pt, const CvPoint2D32f& org, const CvPoint2D32f& diff ) +{ + double cw_area = ((double)org.x - pt.x)*diff.y - ((double)org.y - pt.y)*diff.x; + return (cw_area > 0) - (cw_area < 0); +} + + +CV_IMPL CvSubdiv2DPoint* +cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt ) +{ + CvSubdiv2DPoint* point = 0; + CvPoint2D32f start; + CvPoint2D32f diff; + CvSubdiv2DPointLocation loc; + CvSubdiv2DEdge edge; + int i; + + if( !subdiv ) + CV_Error( CV_StsNullPtr, "" ); + + if( !CV_IS_SUBDIV2D( subdiv )) + CV_Error( CV_StsNullPtr, "" ); + + if( subdiv->edges->active_count <= 3 ) + return 0; + + if( !subdiv->is_geometry_valid ) + cvCalcSubdivVoronoi2D( subdiv ); + + loc = cvSubdiv2DLocate( subdiv, pt, &edge, &point ); + + switch( loc ) + { + case CV_PTLOC_ON_EDGE: + case CV_PTLOC_INSIDE: + break; + default: + return point; + } + + point = 0; + + start = cvSubdiv2DEdgeOrg( edge )->pt; + diff.x = pt.x - start.x; + diff.y = pt.y - start.y; + + edge = cvSubdiv2DRotateEdge( edge, 1 ); + + for( i = 0; i < subdiv->total; i++ ) + { + CvPoint2D32f t; + + for(;;) + { + assert( cvSubdiv2DEdgeDst( edge )); + + t = cvSubdiv2DEdgeDst( edge )->pt; + if( icvIsRightOf2( t, start, diff ) >= 0 ) + break; + + edge = cvSubdiv2DGetEdge( edge, CV_NEXT_AROUND_LEFT ); + } + + for(;;) + { + assert( cvSubdiv2DEdgeOrg( edge )); + + t = cvSubdiv2DEdgeOrg( edge )->pt; + if( icvIsRightOf2( t, start, diff ) < 0 ) + break; + + edge = cvSubdiv2DGetEdge( edge, CV_PREV_AROUND_LEFT ); + } + + { + CvPoint2D32f tempDiff = cvSubdiv2DEdgeDst( edge )->pt; + t = cvSubdiv2DEdgeOrg( edge )->pt; + tempDiff.x -= t.x; + tempDiff.y -= t.y; + + if( icvIsRightOf2( pt, t, tempDiff ) >= 0 ) + { + point = cvSubdiv2DEdgeOrg( cvSubdiv2DRotateEdge( edge, 3 )); + break; + } + } + + edge = cvSubdiv2DSymEdge( edge ); + } + + return point; +} + CV_IMPL int icvSubdiv2DCheck( CvSubdiv2D* subdiv ) { diff --git a/modules/legacy/test/test_nearestneighbors.cpp b/modules/legacy/test/test_nearestneighbors.cpp new file mode 100644 index 0000000..b3e4735 --- /dev/null +++ b/modules/legacy/test/test_nearestneighbors.cpp @@ -0,0 +1,264 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" + +#include +#include +#include + +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 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(pi, d) = data.at(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(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(); } diff --git a/modules/video/test/test_optflow.cpp b/modules/legacy/test/test_optflow.cpp similarity index 99% rename from modules/video/test/test_optflow.cpp rename to modules/legacy/test/test_optflow.cpp index 38a24a8..2ff1330 100644 --- a/modules/video/test/test_optflow.cpp +++ b/modules/legacy/test/test_optflow.cpp @@ -41,6 +41,7 @@ //M*/ #include "test_precomp.hpp" +#include "opencv2/video/tracking.hpp" #include #include diff --git a/modules/legacy/test/test_precomp.hpp b/modules/legacy/test/test_precomp.hpp index f28d167..06b45a7 100644 --- a/modules/legacy/test/test_precomp.hpp +++ b/modules/legacy/test/test_precomp.hpp @@ -6,6 +6,7 @@ #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/highgui/highgui.hpp" #include "opencv2/highgui/highgui_c.h" +#include "opencv2/legacy/legacy.hpp" #include #endif diff --git a/modules/imgproc/test/test_pyrsegmentation.cpp b/modules/legacy/test/test_pyrsegmentation.cpp similarity index 100% rename from modules/imgproc/test/test_pyrsegmentation.cpp rename to modules/legacy/test/test_pyrsegmentation.cpp diff --git a/modules/legacy/test/test_stereomatching.cpp b/modules/legacy/test/test_stereomatching.cpp new file mode 100644 index 0000000..21834b0 --- /dev/null +++ b/modules/legacy/test/test_stereomatching.cpp @@ -0,0 +1,722 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +/* + This is a regression test for stereo matching algorithms. This test gets some quality metrics + discribed in "A Taxonomy and Evaluation of Dense Two-Frame Stereo Correspondence Algorithms". + Daniel Scharstein, Richard Szeliski +*/ + +#include "test_precomp.hpp" +#include +#include + +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(leftY,leftX) ) + continue; + float leftDispVal = leftDisp.at(leftY, leftX); + int rightX = leftX - cvRound(leftDispVal), rightY = leftY; + if( rightX >= 0) + rightDisp.at(rightY,rightX) = max(rightDisp.at(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(leftY,leftX) ) + continue; + float leftDispVal = leftDisp.at(leftY, leftX); + int rightX = leftX - cvRound(leftDispVal), rightY = leftY; + if( rightX < 0 && occludedMask ) + occludedMask->at(leftY, leftX) = 255; + else + { + if( !rightUnknDispMask.empty() && rightUnknDispMask.at(rightY,rightX) ) + continue; + float rightDispVal = rightDisp.at(rightY, rightX); + if( rightDispVal > leftDispVal + dispThresh ) + { + if( occludedMask ) + occludedMask->at(leftY, leftX) = 255; + } + else + { + if( nonOccludedMask ) + nonOccludedMask->at(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::min()), unknDispMask ); + Mat maxNeighbDisp; dilate( curDisp, maxNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) ); + if( !unknDispMask.empty() ) + curDisp.setTo( Scalar(numeric_limits::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& errors, FileStorage* fs = 0 ); + void readErrors( FileNode& fn, const string& errName, vector& errors ); + int compareErrors( const vector& calcErrors, const vector& validErrors, + const vector& 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 rmsEps; + vector fracEps; + + struct DatasetParams + { + int dispScaleFactor; + int dispUnknVal; + }; + map datasetsParams; + + vector caseNames; + vector 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& rms, vector& 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::epsilon(); + assert(leftUnknMask.type() == CV_8UC1); + if( !trueRightDisp.empty() ) + { + absdiff( trueRightDisp, Scalar(params.dispUnknVal), rightUnknMask ); + rightUnknMask = rightUnknMask < numeric_limits::epsilon(); + assert(leftUnknMask.type() == CV_8UC1); + } + + // calculate errors + vector 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 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& errors, FileStorage* fs ) +{ + assert( (int)errors.size() == ERROR_KINDS_COUNT ); + vector::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& errors ) +{ + errors.resize( ERROR_KINDS_COUNT ); + vector::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& calcErrors, const vector& validErrors, + const vector& 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::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 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(); } diff --git a/modules/imgproc/test/test_subdivisions.cpp b/modules/legacy/test/test_subdivisions.cpp similarity index 100% rename from modules/imgproc/test/test_subdivisions.cpp rename to modules/legacy/test/test_subdivisions.cpp diff --git a/modules/objdetect/src/planardetect.cpp b/modules/objdetect/src/planardetect.cpp deleted file mode 100644 index 2fcbff7..0000000 --- a/modules/objdetect/src/planardetect.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "precomp.hpp" -#include - -namespace cv -{ - -} diff --git a/modules/video/doc/motion_analysis_and_object_tracking.rst b/modules/video/doc/motion_analysis_and_object_tracking.rst index 4c66367..e9178bd 100644 --- a/modules/video/doc/motion_analysis_and_object_tracking.rst +++ b/modules/video/doc/motion_analysis_and_object_tracking.rst @@ -4,7 +4,6 @@ Motion Analysis and Object Tracking .. highlight:: cpp - calcOpticalFlowPyrLK ------------------------ Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with pyramids. @@ -86,89 +85,6 @@ The function finds an optical flow for each ``prevImg`` pixel using the [Farneba \texttt{prevImg} (y,x) \sim \texttt{nextImg} ( y + \texttt{flow} (y,x)[1], x + \texttt{flow} (y,x)[0]) - -CalcOpticalFlowBM ------------------ -Calculates the optical flow for two images by using the block matching method. - -.. ocv:cfunction:: void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, CvSize blockSize, CvSize shiftSize, CvSize maxRange, int usePrevious, CvArr* velx, CvArr* vely ) - -.. ocv:pyoldfunction:: cv.CalcOpticalFlowBM(prev, curr, blockSize, shiftSize, maxRange, usePrevious, velx, vely)-> None - - :param prev: First image, 8-bit, single-channel - - :param curr: Second image, 8-bit, single-channel - - :param blockSize: Size of basic blocks that are compared - - :param shiftSize: Block coordinate increments - - :param maxRange: Size of the scanned neighborhood in pixels around the block - - :param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not. - - :param velx: Horizontal component of the optical flow of - - .. math:: - - \left \lfloor \frac{\texttt{prev->width} - \texttt{blockSize.width}}{\texttt{shiftSize.width}} \right \rfloor \times \left \lfloor \frac{\texttt{prev->height} - \texttt{blockSize.height}}{\texttt{shiftSize.height}} \right \rfloor - - size, 32-bit floating-point, single-channel - - :param vely: Vertical component of the optical flow of the same size ``velx`` , 32-bit floating-point, single-channel - - -The function calculates the optical flow for overlapped blocks ``blockSize.width x blockSize.height`` pixels each, thus the velocity fields are smaller than the original images. For every block in ``prev`` -the functions tries to find a similar block in ``curr`` in some neighborhood of the original block or shifted by ``(velx(x0,y0), vely(x0,y0))`` block as has been calculated by previous function call (if ``usePrevious=1``) - - -CalcOpticalFlowHS ------------------ -Calculates the optical flow for two images using Horn-Schunck algorithm. - -.. ocv:cfunction:: void cvCalcOpticalFlowHS(const CvArr* prev, const CvArr* curr, int usePrevious, CvArr* velx, CvArr* vely, double lambda, CvTermCriteria criteria) - -.. ocv:pyoldfunction:: cv.CalcOpticalFlowHS(prev, curr, usePrevious, velx, vely, lambda, criteria)-> None - - :param prev: First image, 8-bit, single-channel - - :param curr: Second image, 8-bit, single-channel - - :param usePrevious: Flag that specifies whether to use the input velocity as initial approximations or not. - - :param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel - - :param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel - - :param lambda: Smoothness weight. The larger it is, the smoother optical flow map you get. - - :param criteria: Criteria of termination of velocity computing - -The function computes the flow for every pixel of the first input image using the Horn and Schunck algorithm [Horn81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`. - - -CalcOpticalFlowLK ------------------ - -Calculates the optical flow for two images using Lucas-Kanade algorithm. - -.. ocv:cfunction:: void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, CvSize winSize, CvArr* velx, CvArr* vely ) - -.. ocv:pyoldfunction:: cv.CalcOpticalFlowLK(prev, curr, winSize, velx, vely)-> None - - :param prev: First image, 8-bit, single-channel - - :param curr: Second image, 8-bit, single-channel - - :param winSize: Size of the averaging window used for grouping pixels - - :param velx: Horizontal component of the optical flow of the same size as input images, 32-bit floating-point, single-channel - - :param vely: Vertical component of the optical flow of the same size as input images, 32-bit floating-point, single-channel - -The function computes the flow for every pixel of the first input image using the Lucas and Kanade algorithm [Lucas81]_. The function is obsolete. To track sparse features, use :ocv:func:`calcOpticalFlowPyrLK`. To track all the pixels, use :ocv:func:`calcOpticalFlowFarneback`. - - estimateRigidTransform -------------------------- Computes an optimal affine transformation between two 2D point sets. diff --git a/modules/video/include/opencv2/video/background_segm.hpp b/modules/video/include/opencv2/video/background_segm.hpp index 6a1b313..7f81d6c 100644 --- a/modules/video/include/opencv2/video/background_segm.hpp +++ b/modules/video/include/opencv2/video/background_segm.hpp @@ -45,304 +45,6 @@ #include "opencv2/core/core.hpp" -#ifdef __cplusplus -extern "C" { -#endif - -/****************************************************************************************\ -* Background/foreground segmentation * -\****************************************************************************************/ - -/* We discriminate between foreground and background pixels - * by building and maintaining a model of the background. - * Any pixel which does not fit this model is then deemed - * to be foreground. - * - * At present we support two core background models, - * one of which has two variations: - * - * o CV_BG_MODEL_FGD: latest and greatest algorithm, described in - * - * Foreground Object Detection from Videos Containing Complex Background. - * Liyuan Li, Weimin Huang, Irene Y.H. Gu, and Qi Tian. - * ACM MM2003 9p - * - * o CV_BG_MODEL_FGD_SIMPLE: - * A code comment describes this as a simplified version of the above, - * but the code is in fact currently identical - * - * o CV_BG_MODEL_MOG: "Mixture of Gaussians", older algorithm, described in - * - * Moving target classification and tracking from real-time video. - * A Lipton, H Fujijoshi, R Patil - * Proceedings IEEE Workshop on Application of Computer Vision pp 8-14 1998 - * - * Learning patterns of activity using real-time tracking - * C Stauffer and W Grimson August 2000 - * IEEE Transactions on Pattern Analysis and Machine Intelligence 22(8):747-757 - */ - - -#define CV_BG_MODEL_FGD 0 -#define CV_BG_MODEL_MOG 1 /* "Mixture of Gaussians". */ -#define CV_BG_MODEL_FGD_SIMPLE 2 - -struct CvBGStatModel; - -typedef void (CV_CDECL * CvReleaseBGStatModel)( struct CvBGStatModel** bg_model ); -typedef int (CV_CDECL * CvUpdateBGStatModel)( IplImage* curr_frame, struct CvBGStatModel* bg_model, - double learningRate ); - -#define CV_BG_STAT_MODEL_FIELDS() \ - int type; /*type of BG model*/ \ - CvReleaseBGStatModel release; \ - CvUpdateBGStatModel update; \ - IplImage* background; /*8UC3 reference background image*/ \ - IplImage* foreground; /*8UC1 foreground image*/ \ - IplImage** layers; /*8UC3 reference background image, can be null */ \ - int layer_count; /* can be zero */ \ - CvMemStorage* storage; /*storage for foreground_regions*/ \ - CvSeq* foreground_regions /*foreground object contours*/ - -typedef struct CvBGStatModel -{ - CV_BG_STAT_MODEL_FIELDS(); -} CvBGStatModel; - -// - -// Releases memory used by BGStatModel -CVAPI(void) cvReleaseBGStatModel( CvBGStatModel** bg_model ); - -// Updates statistical model and returns number of found foreground regions -CVAPI(int) cvUpdateBGStatModel( IplImage* current_frame, CvBGStatModel* bg_model, - double learningRate CV_DEFAULT(-1)); - -// Performs FG post-processing using segmentation -// (all pixels of a region will be classified as foreground if majority of pixels of the region are FG). -// parameters: -// segments - pointer to result of segmentation (for example MeanShiftSegmentation) -// bg_model - pointer to CvBGStatModel structure -CVAPI(void) cvRefineForegroundMaskBySegm( CvSeq* segments, CvBGStatModel* bg_model ); - -/* Common use change detection function */ -CVAPI(int) cvChangeDetection( IplImage* prev_frame, - IplImage* curr_frame, - IplImage* change_mask ); - -/* - Interface of ACM MM2003 algorithm -*/ - -/* Default parameters of foreground detection algorithm: */ -#define CV_BGFG_FGD_LC 128 -#define CV_BGFG_FGD_N1C 15 -#define CV_BGFG_FGD_N2C 25 - -#define CV_BGFG_FGD_LCC 64 -#define CV_BGFG_FGD_N1CC 25 -#define CV_BGFG_FGD_N2CC 40 - -/* Background reference image update parameter: */ -#define CV_BGFG_FGD_ALPHA_1 0.1f - -/* stat model update parameter - * 0.002f ~ 1K frame(~45sec), 0.005 ~ 18sec (if 25fps and absolutely static BG) - */ -#define CV_BGFG_FGD_ALPHA_2 0.005f - -/* start value for alpha parameter (to fast initiate statistic model) */ -#define CV_BGFG_FGD_ALPHA_3 0.1f - -#define CV_BGFG_FGD_DELTA 2 - -#define CV_BGFG_FGD_T 0.9f - -#define CV_BGFG_FGD_MINAREA 15.f - -#define CV_BGFG_FGD_BG_UPDATE_TRESH 0.5f - -/* See the above-referenced Li/Huang/Gu/Tian paper - * for a full description of these background-model - * tuning parameters. - * - * Nomenclature: 'c' == "color", a three-component red/green/blue vector. - * We use histograms of these to model the range of - * colors we've seen at a given background pixel. - * - * 'cc' == "color co-occurrence", a six-component vector giving - * RGB color for both this frame and preceding frame. - * We use histograms of these to model the range of - * color CHANGES we've seen at a given background pixel. - */ -typedef struct CvFGDStatModelParams -{ - int Lc; /* Quantized levels per 'color' component. Power of two, typically 32, 64 or 128. */ - int N1c; /* Number of color vectors used to model normal background color variation at a given pixel. */ - int N2c; /* Number of color vectors retained at given pixel. Must be > N1c, typically ~ 5/3 of N1c. */ - /* Used to allow the first N1c vectors to adapt over time to changing background. */ - - int Lcc; /* Quantized levels per 'color co-occurrence' component. Power of two, typically 16, 32 or 64. */ - int N1cc; /* Number of color co-occurrence vectors used to model normal background color variation at a given pixel. */ - int N2cc; /* Number of color co-occurrence vectors retained at given pixel. Must be > N1cc, typically ~ 5/3 of N1cc. */ - /* Used to allow the first N1cc vectors to adapt over time to changing background. */ - - int is_obj_without_holes;/* If TRUE we ignore holes within foreground blobs. Defaults to TRUE. */ - int perform_morphing; /* Number of erode-dilate-erode foreground-blob cleanup iterations. */ - /* These erase one-pixel junk blobs and merge almost-touching blobs. Default value is 1. */ - - float alpha1; /* How quickly we forget old background pixel values seen. Typically set to 0.1 */ - float alpha2; /* "Controls speed of feature learning". Depends on T. Typical value circa 0.005. */ - float alpha3; /* Alternate to alpha2, used (e.g.) for quicker initial convergence. Typical value 0.1. */ - - float delta; /* Affects color and color co-occurrence quantization, typically set to 2. */ - float T; /* "A percentage value which determines when new features can be recognized as new background." (Typically 0.9).*/ - float minArea; /* Discard foreground blobs whose bounding box is smaller than this threshold. */ -} CvFGDStatModelParams; - -typedef struct CvBGPixelCStatTable -{ - float Pv, Pvb; - uchar v[3]; -} CvBGPixelCStatTable; - -typedef struct CvBGPixelCCStatTable -{ - float Pv, Pvb; - uchar v[6]; -} CvBGPixelCCStatTable; - -typedef struct CvBGPixelStat -{ - float Pbc; - float Pbcc; - CvBGPixelCStatTable* ctable; - CvBGPixelCCStatTable* cctable; - uchar is_trained_st_model; - uchar is_trained_dyn_model; -} CvBGPixelStat; - - -typedef struct CvFGDStatModel -{ - CV_BG_STAT_MODEL_FIELDS(); - CvBGPixelStat* pixel_stat; - IplImage* Ftd; - IplImage* Fbd; - IplImage* prev_frame; - CvFGDStatModelParams params; -} CvFGDStatModel; - -/* Creates FGD model */ -CVAPI(CvBGStatModel*) cvCreateFGDStatModel( IplImage* first_frame, - CvFGDStatModelParams* parameters CV_DEFAULT(NULL)); - -/* - Interface of Gaussian mixture algorithm - - "An improved adaptive background mixture model for real-time tracking with shadow detection" - P. KadewTraKuPong and R. Bowden, - Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001." - http://personal.ee.surrey.ac.uk/Personal/R.Bowden/publications/avbs01/avbs01.pdf -*/ - -/* Note: "MOG" == "Mixture Of Gaussians": */ - -#define CV_BGFG_MOG_MAX_NGAUSSIANS 500 - -/* default parameters of gaussian background detection algorithm */ -#define CV_BGFG_MOG_BACKGROUND_THRESHOLD 0.7 /* threshold sum of weights for background test */ -#define CV_BGFG_MOG_STD_THRESHOLD 2.5 /* lambda=2.5 is 99% */ -#define CV_BGFG_MOG_WINDOW_SIZE 200 /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */ -#define CV_BGFG_MOG_NGAUSSIANS 5 /* = K = number of Gaussians in mixture */ -#define CV_BGFG_MOG_WEIGHT_INIT 0.05 -#define CV_BGFG_MOG_SIGMA_INIT 30 -#define CV_BGFG_MOG_MINAREA 15.f - - -#define CV_BGFG_MOG_NCOLORS 3 - -typedef struct CvGaussBGStatModelParams -{ - int win_size; /* = 1/alpha */ - int n_gauss; - double bg_threshold, std_threshold, minArea; - double weight_init, variance_init; -}CvGaussBGStatModelParams; - -typedef struct CvGaussBGValues -{ - int match_sum; - double weight; - double variance[CV_BGFG_MOG_NCOLORS]; - double mean[CV_BGFG_MOG_NCOLORS]; -} CvGaussBGValues; - -typedef struct CvGaussBGPoint -{ - CvGaussBGValues* g_values; -} CvGaussBGPoint; - - -typedef struct CvGaussBGModel -{ - CV_BG_STAT_MODEL_FIELDS(); - CvGaussBGStatModelParams params; - CvGaussBGPoint* g_point; - int countFrames; -} CvGaussBGModel; - - -/* Creates Gaussian mixture background model */ -CVAPI(CvBGStatModel*) cvCreateGaussianBGModel( IplImage* first_frame, - CvGaussBGStatModelParams* parameters CV_DEFAULT(NULL)); - - -typedef struct CvBGCodeBookElem -{ - struct CvBGCodeBookElem* next; - int tLastUpdate; - int stale; - uchar boxMin[3]; - uchar boxMax[3]; - uchar learnMin[3]; - uchar learnMax[3]; -} CvBGCodeBookElem; - -typedef struct CvBGCodeBookModel -{ - CvSize size; - int t; - uchar cbBounds[3]; - uchar modMin[3]; - uchar modMax[3]; - CvBGCodeBookElem** cbmap; - CvMemStorage* storage; - CvBGCodeBookElem* freeList; -} CvBGCodeBookModel; - -CVAPI(CvBGCodeBookModel*) cvCreateBGCodeBookModel(); -CVAPI(void) cvReleaseBGCodeBookModel( CvBGCodeBookModel** model ); - -CVAPI(void) cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* image, - CvRect roi CV_DEFAULT(cvRect(0,0,0,0)), - const CvArr* mask CV_DEFAULT(0) ); - -CVAPI(int) cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* image, - CvArr* fgmask, CvRect roi CV_DEFAULT(cvRect(0,0,0,0)) ); - -CVAPI(void) cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh, - CvRect roi CV_DEFAULT(cvRect(0,0,0,0)), - const CvArr* mask CV_DEFAULT(0) ); - -CVAPI(CvSeq*) cvSegmentFGMask( CvArr *fgmask, int poly1Hull0 CV_DEFAULT(1), - float perimScale CV_DEFAULT(4.f), - CvMemStorage* storage CV_DEFAULT(0), - CvPoint offset CV_DEFAULT(cvPoint(0,0))); - -#ifdef __cplusplus -} - namespace cv { @@ -483,6 +185,5 @@ public: }; } -#endif #endif diff --git a/modules/video/include/opencv2/video/tracking.hpp b/modules/video/include/opencv2/video/tracking.hpp index 5dd6ce2..91d332c 100644 --- a/modules/video/include/opencv2/video/tracking.hpp +++ b/modules/video/include/opencv2/video/tracking.hpp @@ -60,21 +60,6 @@ extern "C" { /************************************ optical flow ***************************************/ -/* Calculates optical flow for 2 images using classical Lucas & Kanade algorithm */ -CVAPI(void) cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, - CvSize win_size, CvArr* velx, CvArr* vely ); - -/* Calculates optical flow for 2 images using block matching algorithm */ -CVAPI(void) cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, - CvSize block_size, CvSize shift_size, - CvSize max_range, int use_previous, - CvArr* velx, CvArr* vely ); - -/* Calculates Optical flow for 2 images using Horn & Schunck algorithm */ -CVAPI(void) cvCalcOpticalFlowHS( const CvArr* prev, const CvArr* curr, - int use_previous, CvArr* velx, CvArr* vely, - double lambda, CvTermCriteria criteria ); - #define CV_LKFLOW_PYR_A_READY 1 #define CV_LKFLOW_PYR_B_READY 2 #define CV_LKFLOW_INITIAL_GUESSES 4 diff --git a/modules/video/src/bgfg_gaussmix.cpp b/modules/video/src/bgfg_gaussmix.cpp index 5407c25..8a7c355 100644 --- a/modules/video/src/bgfg_gaussmix.cpp +++ b/modules/video/src/bgfg_gaussmix.cpp @@ -67,11 +67,12 @@ void BackgroundSubtractor::getBackgroundImage(OutputArray) const { } -static const int defaultNMixtures = CV_BGFG_MOG_NGAUSSIANS; -static const int defaultHistory = CV_BGFG_MOG_WINDOW_SIZE; -static const double defaultBackgroundRatio = CV_BGFG_MOG_BACKGROUND_THRESHOLD; -static const double defaultVarThreshold = CV_BGFG_MOG_STD_THRESHOLD*CV_BGFG_MOG_STD_THRESHOLD; -static const double defaultNoiseSigma = CV_BGFG_MOG_SIGMA_INIT*0.5; +static const int defaultNMixtures = 5; +static const int defaultHistory = 200; +static const double defaultBackgroundRatio = 0.7; +static const double defaultVarThreshold = 2.5*2.5; +static const double defaultNoiseSigma = 30*0.5; +static const double defaultInitialWeight = 0.05; BackgroundSubtractorMOG::BackgroundSubtractorMOG() { @@ -140,9 +141,9 @@ static void process8uC1( BackgroundSubtractorMOG& obj, const Mat& image, Mat& fg int K = obj.nmixtures; MixData* mptr = (MixData*)obj.bgmodel.data; - const float w0 = (float)CV_BGFG_MOG_WEIGHT_INIT; - const float sk0 = (float)(w0/CV_BGFG_MOG_SIGMA_INIT); - const float var0 = (float)(CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT); + const float w0 = (float)defaultInitialWeight; + const float sk0 = (float)(w0/(defaultNoiseSigma*2)); + const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4); const float minVar = (float)(obj.noiseSigma*obj.noiseSigma); for( y = 0; y < rows; y++ ) @@ -264,9 +265,9 @@ static void process8uC3( BackgroundSubtractorMOG& obj, const Mat& image, Mat& fg float alpha = (float)learningRate, T = (float)obj.backgroundRatio, vT = (float)obj.varThreshold; int K = obj.nmixtures; - const float w0 = (float)CV_BGFG_MOG_WEIGHT_INIT; - const float sk0 = (float)(w0/(CV_BGFG_MOG_SIGMA_INIT*sqrt(3.))); - const float var0 = (float)(CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT); + const float w0 = (float)defaultInitialWeight; + const float sk0 = (float)(w0/(defaultNoiseSigma*2*sqrt(3.))); + const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4); const float minVar = (float)(obj.noiseSigma*obj.noiseSigma); MixData* mptr = (MixData*)obj.bgmodel.data; @@ -411,140 +412,5 @@ void BackgroundSubtractorMOG::operator()(InputArray _image, OutputArray _fgmask, } - -static void CV_CDECL -icvReleaseGaussianBGModel( CvGaussBGModel** bg_model ) -{ - if( !bg_model ) - CV_Error( CV_StsNullPtr, "" ); - - if( *bg_model ) - { - delete (cv::Mat*)((*bg_model)->g_point); - cvReleaseImage( &(*bg_model)->background ); - cvReleaseImage( &(*bg_model)->foreground ); - cvReleaseMemStorage(&(*bg_model)->storage); - memset( *bg_model, 0, sizeof(**bg_model) ); - delete *bg_model; - *bg_model = 0; - } -} - - -static int CV_CDECL -icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model, double learningRate ) -{ - int region_count = 0; - - cv::Mat image = cv::cvarrToMat(curr_frame), mask = cv::cvarrToMat(bg_model->foreground); - - cv::BackgroundSubtractorMOG mog; - mog.bgmodel = *(cv::Mat*)bg_model->g_point; - mog.frameSize = mog.bgmodel.data ? cv::Size(cvGetSize(curr_frame)) : cv::Size(); - mog.frameType = image.type(); - - mog.nframes = bg_model->countFrames; - mog.history = bg_model->params.win_size; - mog.nmixtures = bg_model->params.n_gauss; - mog.varThreshold = bg_model->params.std_threshold*bg_model->params.std_threshold; - mog.backgroundRatio = bg_model->params.bg_threshold; - - mog(image, mask, learningRate); - - bg_model->countFrames = mog.nframes; - if( ((cv::Mat*)bg_model->g_point)->data != mog.bgmodel.data ) - *((cv::Mat*)bg_model->g_point) = mog.bgmodel; - - //foreground filtering - - //filter small regions - cvClearMemStorage(bg_model->storage); - - //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 ); - //cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 ); - - /* - CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL; - cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST ); - for( seq = first_seq; seq; seq = seq->h_next ) - { - CvContour* cnt = (CvContour*)seq; - if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea ) - { - //delete small contour - prev_seq = seq->h_prev; - if( prev_seq ) - { - prev_seq->h_next = seq->h_next; - if( seq->h_next ) seq->h_next->h_prev = prev_seq; - } - else - { - first_seq = seq->h_next; - if( seq->h_next ) seq->h_next->h_prev = NULL; - } - } - else - { - region_count++; - } - } - bg_model->foreground_regions = first_seq; - cvZero(bg_model->foreground); - cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);*/ - CvMat _mask = mask; - cvCopy(&_mask, bg_model->foreground); - - return region_count; -} - -CV_IMPL CvBGStatModel* -cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters ) -{ - CvGaussBGStatModelParams params; - - CV_Assert( CV_IS_IMAGE(first_frame) ); - - //init parameters - if( parameters == NULL ) - { /* These constants are defined in cvaux/include/cvaux.h: */ - params.win_size = CV_BGFG_MOG_WINDOW_SIZE; - params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD; - - params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD; - params.weight_init = CV_BGFG_MOG_WEIGHT_INIT; - - params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT; - params.minArea = CV_BGFG_MOG_MINAREA; - params.n_gauss = CV_BGFG_MOG_NGAUSSIANS; - } - else - params = *parameters; - - CvGaussBGModel* bg_model = new CvGaussBGModel; - memset( bg_model, 0, sizeof(*bg_model) ); - bg_model->type = CV_BG_MODEL_MOG; - bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel; - bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel; - - bg_model->params = params; - - //prepare storages - bg_model->g_point = (CvGaussBGPoint*)new cv::Mat(); - - bg_model->background = cvCreateImage(cvSize(first_frame->width, - first_frame->height), IPL_DEPTH_8U, first_frame->nChannels); - bg_model->foreground = cvCreateImage(cvSize(first_frame->width, - first_frame->height), IPL_DEPTH_8U, 1); - - bg_model->storage = cvCreateMemStorage(); - - bg_model->countFrames = 0; - - icvUpdateGaussianBGModel( first_frame, bg_model, 1 ); - - return (CvBGStatModel*)bg_model; -} - /* End of file. */ diff --git a/modules/video/src/bgfg_gaussmix2.cpp b/modules/video/src/bgfg_gaussmix2.cpp index 65d646c..fd42253 100644 --- a/modules/video/src/bgfg_gaussmix2.cpp +++ b/modules/video/src/bgfg_gaussmix2.cpp @@ -196,18 +196,8 @@ typedef struct CvGaussBGStatModel2Data unsigned char* rnUsedModes;//number of Gaussian components per pixel (maximum 255) } CvGaussBGStatModel2Data; -//only foreground image is updated -//no filtering included -typedef struct CvGaussBGModel2 -{ - CV_BG_STAT_MODEL_FIELDS(); - CvGaussBGStatModel2Params params; - CvGaussBGStatModel2Data data; - int countFrames; -} CvGaussBGModel2; - -CVAPI(CvBGStatModel*) cvCreateGaussianBGModel2( IplImage* first_frame, - CvGaussBGStatModel2Params* params CV_DEFAULT(NULL) ); + + //shadow detection performed per pixel // should work for rgb data, could be usefull for gray scale and depth data as well // See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003. @@ -941,239 +931,6 @@ void icvUpdatePixelBackgroundGMM2( const CvArr* srcarr, CvArr* dstarr , } - -////////////////////////////////////////////// -//implementation as part of the CvBGStatModel -static void CV_CDECL icvReleaseGaussianBGModel2( CvGaussBGModel2** bg_model ); -static int CV_CDECL icvUpdateGaussianBGModel2( IplImage* curr_frame, CvGaussBGModel2* bg_model ); - - -CV_IMPL CvBGStatModel* -cvCreateGaussianBGModel2( IplImage* first_frame, CvGaussBGStatModel2Params* parameters ) -{ - CvGaussBGModel2* bg_model = 0; - int w,h; - - CV_FUNCNAME( "cvCreateGaussianBGModel2" ); - - __BEGIN__; - - CvGaussBGStatModel2Params params; - - if( !CV_IS_IMAGE(first_frame) ) - CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" ); - - if( first_frame->nChannels>CV_BGFG_MOG2_NDMAX ) - CV_ERROR( CV_StsBadArg, "Maxumum number of channels in the image is excedded (change CV_BGFG_MOG2_MAXBANDS constant)!" ); - - - CV_CALL( bg_model = (CvGaussBGModel2*)cvAlloc( sizeof(*bg_model) )); - memset( bg_model, 0, sizeof(*bg_model) ); - bg_model->type = CV_BG_MODEL_MOG2; - bg_model->release = (CvReleaseBGStatModel) icvReleaseGaussianBGModel2; - bg_model->update = (CvUpdateBGStatModel) icvUpdateGaussianBGModel2; - - //init parameters - if( parameters == NULL ) - { - memset(¶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 { diff --git a/samples/c/bgfg_codebook.cpp b/samples/c/bgfg_codebook.cpp index 83c82d4..48df51c 100644 --- a/samples/c/bgfg_codebook.cpp +++ b/samples/c/bgfg_codebook.cpp @@ -24,6 +24,7 @@ #include "opencv2/video/background_segm.hpp" #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/highgui/highgui.hpp" +#include "opencv2/legacy/legacy.hpp" #include #include diff --git a/samples/c/blobtrack_sample.cpp b/samples/c/blobtrack_sample.cpp index a7b7866..7020b1b 100644 --- a/samples/c/blobtrack_sample.cpp +++ b/samples/c/blobtrack_sample.cpp @@ -1,5 +1,6 @@ #include "opencv2/video/background_segm.hpp" #include "opencv2/legacy/blobtrack.hpp" +#include "opencv2/legacy/legacy.hpp" #include "opencv2/highgui/highgui.hpp" #include -- 2.7.4