mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 08:13:04 +04:00
a LOT of obsolete stuff has been moved to the legacy module.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,741 +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
|
||||
//
|
||||
// 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 file implements the foreground/background pixel
|
||||
// discrimination algorithm described in
|
||||
//
|
||||
// Foreground Object Detection from Videos Containing Complex Background
|
||||
// Li, Huan, Gu, Tian 2003 9p
|
||||
// http://muq.org/~cynbe/bib/foreground-object-detection-from-videos-containing-complex-background.pdf
|
||||
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
//#include <algorithm>
|
||||
|
||||
static double* _cv_max_element( double* start, double* end )
|
||||
{
|
||||
double* p = start++;
|
||||
|
||||
for( ; start != end; ++start) {
|
||||
|
||||
if (*p < *start) p = start;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void CV_CDECL icvReleaseFGDStatModel( CvFGDStatModel** model );
|
||||
static int CV_CDECL icvUpdateFGDStatModel( IplImage* curr_frame,
|
||||
CvFGDStatModel* model,
|
||||
double );
|
||||
|
||||
// Function cvCreateFGDStatModel initializes foreground detection process
|
||||
// parameters:
|
||||
// first_frame - frame from video sequence
|
||||
// parameters - (optional) if NULL default parameters of the algorithm will be used
|
||||
// p_model - pointer to CvFGDStatModel structure
|
||||
CV_IMPL CvBGStatModel*
|
||||
cvCreateFGDStatModel( IplImage* first_frame, CvFGDStatModelParams* parameters )
|
||||
{
|
||||
CvFGDStatModel* p_model = 0;
|
||||
|
||||
CV_FUNCNAME( "cvCreateFGDStatModel" );
|
||||
|
||||
__BEGIN__;
|
||||
|
||||
int i, j, k, pixel_count, buf_size;
|
||||
CvFGDStatModelParams params;
|
||||
|
||||
if( !CV_IS_IMAGE(first_frame) )
|
||||
CV_ERROR( CV_StsBadArg, "Invalid or NULL first_frame parameter" );
|
||||
|
||||
if (first_frame->nChannels != 3)
|
||||
CV_ERROR( CV_StsBadArg, "first_frame must have 3 color channels" );
|
||||
|
||||
// Initialize parameters:
|
||||
if( parameters == NULL )
|
||||
{
|
||||
params.Lc = CV_BGFG_FGD_LC;
|
||||
params.N1c = CV_BGFG_FGD_N1C;
|
||||
params.N2c = CV_BGFG_FGD_N2C;
|
||||
|
||||
params.Lcc = CV_BGFG_FGD_LCC;
|
||||
params.N1cc = CV_BGFG_FGD_N1CC;
|
||||
params.N2cc = CV_BGFG_FGD_N2CC;
|
||||
|
||||
params.delta = CV_BGFG_FGD_DELTA;
|
||||
|
||||
params.alpha1 = CV_BGFG_FGD_ALPHA_1;
|
||||
params.alpha2 = CV_BGFG_FGD_ALPHA_2;
|
||||
params.alpha3 = CV_BGFG_FGD_ALPHA_3;
|
||||
|
||||
params.T = CV_BGFG_FGD_T;
|
||||
params.minArea = CV_BGFG_FGD_MINAREA;
|
||||
|
||||
params.is_obj_without_holes = 1;
|
||||
params.perform_morphing = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
params = *parameters;
|
||||
}
|
||||
|
||||
CV_CALL( p_model = (CvFGDStatModel*)cvAlloc( sizeof(*p_model) ));
|
||||
memset( p_model, 0, sizeof(*p_model) );
|
||||
p_model->type = CV_BG_MODEL_FGD;
|
||||
p_model->release = (CvReleaseBGStatModel)icvReleaseFGDStatModel;
|
||||
p_model->update = (CvUpdateBGStatModel)icvUpdateFGDStatModel;;
|
||||
p_model->params = params;
|
||||
|
||||
// Initialize storage pools:
|
||||
pixel_count = first_frame->width * first_frame->height;
|
||||
|
||||
buf_size = pixel_count*sizeof(p_model->pixel_stat[0]);
|
||||
CV_CALL( p_model->pixel_stat = (CvBGPixelStat*)cvAlloc(buf_size) );
|
||||
memset( p_model->pixel_stat, 0, buf_size );
|
||||
|
||||
buf_size = pixel_count*params.N2c*sizeof(p_model->pixel_stat[0].ctable[0]);
|
||||
CV_CALL( p_model->pixel_stat[0].ctable = (CvBGPixelCStatTable*)cvAlloc(buf_size) );
|
||||
memset( p_model->pixel_stat[0].ctable, 0, buf_size );
|
||||
|
||||
buf_size = pixel_count*params.N2cc*sizeof(p_model->pixel_stat[0].cctable[0]);
|
||||
CV_CALL( p_model->pixel_stat[0].cctable = (CvBGPixelCCStatTable*)cvAlloc(buf_size) );
|
||||
memset( p_model->pixel_stat[0].cctable, 0, buf_size );
|
||||
|
||||
for( i = 0, k = 0; i < first_frame->height; i++ ) {
|
||||
for( j = 0; j < first_frame->width; j++, k++ )
|
||||
{
|
||||
p_model->pixel_stat[k].ctable = p_model->pixel_stat[0].ctable + k*params.N2c;
|
||||
p_model->pixel_stat[k].cctable = p_model->pixel_stat[0].cctable + k*params.N2cc;
|
||||
}
|
||||
}
|
||||
|
||||
// Init temporary images:
|
||||
CV_CALL( p_model->Ftd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
|
||||
CV_CALL( p_model->Fbd = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
|
||||
CV_CALL( p_model->foreground = cvCreateImage(cvSize(first_frame->width, first_frame->height), IPL_DEPTH_8U, 1));
|
||||
|
||||
CV_CALL( p_model->background = cvCloneImage(first_frame));
|
||||
CV_CALL( p_model->prev_frame = cvCloneImage(first_frame));
|
||||
CV_CALL( p_model->storage = cvCreateMemStorage());
|
||||
|
||||
__END__;
|
||||
|
||||
if( cvGetErrStatus() < 0 )
|
||||
{
|
||||
CvBGStatModel* base_ptr = (CvBGStatModel*)p_model;
|
||||
|
||||
if( p_model && p_model->release )
|
||||
p_model->release( &base_ptr );
|
||||
else
|
||||
cvFree( &p_model );
|
||||
p_model = 0;
|
||||
}
|
||||
|
||||
return (CvBGStatModel*)p_model;
|
||||
}
|
||||
|
||||
|
||||
static void CV_CDECL
|
||||
icvReleaseFGDStatModel( CvFGDStatModel** _model )
|
||||
{
|
||||
CV_FUNCNAME( "icvReleaseFGDStatModel" );
|
||||
|
||||
__BEGIN__;
|
||||
|
||||
if( !_model )
|
||||
CV_ERROR( CV_StsNullPtr, "" );
|
||||
|
||||
if( *_model )
|
||||
{
|
||||
CvFGDStatModel* model = *_model;
|
||||
if( model->pixel_stat )
|
||||
{
|
||||
cvFree( &model->pixel_stat[0].ctable );
|
||||
cvFree( &model->pixel_stat[0].cctable );
|
||||
cvFree( &model->pixel_stat );
|
||||
}
|
||||
|
||||
cvReleaseImage( &model->Ftd );
|
||||
cvReleaseImage( &model->Fbd );
|
||||
cvReleaseImage( &model->foreground );
|
||||
cvReleaseImage( &model->background );
|
||||
cvReleaseImage( &model->prev_frame );
|
||||
cvReleaseMemStorage(&model->storage);
|
||||
|
||||
cvFree( _model );
|
||||
}
|
||||
|
||||
__END__;
|
||||
}
|
||||
|
||||
// Function cvChangeDetection performs change detection for Foreground detection algorithm
|
||||
// parameters:
|
||||
// prev_frame -
|
||||
// curr_frame -
|
||||
// change_mask -
|
||||
CV_IMPL int
|
||||
cvChangeDetection( IplImage* prev_frame,
|
||||
IplImage* curr_frame,
|
||||
IplImage* change_mask )
|
||||
{
|
||||
int i, j, b, x, y, thres;
|
||||
const int PIXELRANGE=256;
|
||||
|
||||
if( !prev_frame
|
||||
|| !curr_frame
|
||||
|| !change_mask
|
||||
|| prev_frame->nChannels != 3
|
||||
|| curr_frame->nChannels != 3
|
||||
|| change_mask->nChannels != 1
|
||||
|| prev_frame->depth != IPL_DEPTH_8U
|
||||
|| curr_frame->depth != IPL_DEPTH_8U
|
||||
|| change_mask->depth != IPL_DEPTH_8U
|
||||
|| prev_frame->width != curr_frame->width
|
||||
|| prev_frame->height != curr_frame->height
|
||||
|| prev_frame->width != change_mask->width
|
||||
|| prev_frame->height != change_mask->height
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
|
||||
cvZero ( change_mask );
|
||||
|
||||
// All operations per colour
|
||||
for (b=0 ; b<prev_frame->nChannels ; b++) {
|
||||
|
||||
// Create histogram:
|
||||
|
||||
long HISTOGRAM[PIXELRANGE];
|
||||
for (i=0 ; i<PIXELRANGE; i++) HISTOGRAM[i]=0;
|
||||
|
||||
for (y=0 ; y<curr_frame->height ; y++)
|
||||
{
|
||||
uchar* rowStart1 = (uchar*)curr_frame->imageData + y * curr_frame->widthStep + b;
|
||||
uchar* rowStart2 = (uchar*)prev_frame->imageData + y * prev_frame->widthStep + b;
|
||||
for (x=0 ; x<curr_frame->width ; x++, rowStart1+=curr_frame->nChannels, rowStart2+=prev_frame->nChannels) {
|
||||
int diff = abs( int(*rowStart1) - int(*rowStart2) );
|
||||
HISTOGRAM[diff]++;
|
||||
}
|
||||
}
|
||||
|
||||
double relativeVariance[PIXELRANGE];
|
||||
for (i=0 ; i<PIXELRANGE; i++) relativeVariance[i]=0;
|
||||
|
||||
for (thres=PIXELRANGE-2; thres>=0 ; thres--)
|
||||
{
|
||||
// fprintf(stderr, "Iter %d\n", thres);
|
||||
double sum=0;
|
||||
double sqsum=0;
|
||||
int count=0;
|
||||
// fprintf(stderr, "Iter %d entering loop\n", thres);
|
||||
for (j=thres ; j<PIXELRANGE ; j++) {
|
||||
sum += double(j)*double(HISTOGRAM[j]);
|
||||
sqsum += double(j*j)*double(HISTOGRAM[j]);
|
||||
count += HISTOGRAM[j];
|
||||
}
|
||||
count = count == 0 ? 1 : count;
|
||||
// fprintf(stderr, "Iter %d finishing loop\n", thres);
|
||||
double my = sum / count;
|
||||
double sigma = sqrt( sqsum/count - my*my);
|
||||
// fprintf(stderr, "Iter %d sum=%g sqsum=%g count=%d sigma = %g\n", thres, sum, sqsum, count, sigma);
|
||||
// fprintf(stderr, "Writing to %x\n", &(relativeVariance[thres]));
|
||||
relativeVariance[thres] = sigma;
|
||||
// fprintf(stderr, "Iter %d finished\n", thres);
|
||||
}
|
||||
|
||||
// Find maximum:
|
||||
uchar bestThres = 0;
|
||||
|
||||
double* pBestThres = _cv_max_element(relativeVariance, relativeVariance+PIXELRANGE);
|
||||
bestThres = (uchar)(*pBestThres); if (bestThres <10) bestThres=10;
|
||||
|
||||
for (y=0 ; y<prev_frame->height ; y++)
|
||||
{
|
||||
uchar* rowStart1 = (uchar*)(curr_frame->imageData) + y * curr_frame->widthStep + b;
|
||||
uchar* rowStart2 = (uchar*)(prev_frame->imageData) + y * prev_frame->widthStep + b;
|
||||
uchar* rowStart3 = (uchar*)(change_mask->imageData) + y * change_mask->widthStep;
|
||||
for (x = 0; x < curr_frame->width; x++, rowStart1+=curr_frame->nChannels,
|
||||
rowStart2+=prev_frame->nChannels, rowStart3+=change_mask->nChannels) {
|
||||
// OR between different color channels
|
||||
int diff = abs( int(*rowStart1) - int(*rowStart2) );
|
||||
if ( diff > bestThres)
|
||||
*rowStart3 |=255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define MIN_PV 1E-10
|
||||
|
||||
|
||||
#define V_C(k,l) ctable[k].v[l]
|
||||
#define PV_C(k) ctable[k].Pv
|
||||
#define PVB_C(k) ctable[k].Pvb
|
||||
#define V_CC(k,l) cctable[k].v[l]
|
||||
#define PV_CC(k) cctable[k].Pv
|
||||
#define PVB_CC(k) cctable[k].Pvb
|
||||
|
||||
|
||||
// Function cvUpdateFGDStatModel updates statistical model and returns number of foreground regions
|
||||
// parameters:
|
||||
// curr_frame - current frame from video sequence
|
||||
// p_model - pointer to CvFGDStatModel structure
|
||||
static int CV_CDECL
|
||||
icvUpdateFGDStatModel( IplImage* curr_frame, CvFGDStatModel* model, double )
|
||||
{
|
||||
int mask_step = model->Ftd->widthStep;
|
||||
CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
|
||||
IplImage* prev_frame = model->prev_frame;
|
||||
int region_count = 0;
|
||||
int FG_pixels_count = 0;
|
||||
int deltaC = cvRound(model->params.delta * 256 / model->params.Lc);
|
||||
int deltaCC = cvRound(model->params.delta * 256 / model->params.Lcc);
|
||||
int i, j, k, l;
|
||||
|
||||
//clear storages
|
||||
cvClearMemStorage(model->storage);
|
||||
cvZero(model->foreground);
|
||||
|
||||
// From foreground pixel candidates using image differencing
|
||||
// with adaptive thresholding. The algorithm is from:
|
||||
//
|
||||
// Thresholding for Change Detection
|
||||
// Paul L. Rosin 1998 6p
|
||||
// http://www.cis.temple.edu/~latecki/Courses/CIS750-03/Papers/thresh-iccv.pdf
|
||||
//
|
||||
cvChangeDetection( prev_frame, curr_frame, model->Ftd );
|
||||
cvChangeDetection( model->background, curr_frame, model->Fbd );
|
||||
|
||||
for( i = 0; i < model->Ftd->height; i++ )
|
||||
{
|
||||
for( j = 0; j < model->Ftd->width; j++ )
|
||||
{
|
||||
if( ((uchar*)model->Fbd->imageData)[i*mask_step+j] || ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
|
||||
{
|
||||
float Pb = 0;
|
||||
float Pv = 0;
|
||||
float Pvb = 0;
|
||||
|
||||
CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
|
||||
|
||||
CvBGPixelCStatTable* ctable = stat->ctable;
|
||||
CvBGPixelCCStatTable* cctable = stat->cctable;
|
||||
|
||||
uchar* curr_data = (uchar*)(curr_frame->imageData) + i*curr_frame->widthStep + j*3;
|
||||
uchar* prev_data = (uchar*)(prev_frame->imageData) + i*prev_frame->widthStep + j*3;
|
||||
|
||||
int val = 0;
|
||||
|
||||
// Is it a motion pixel?
|
||||
if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] )
|
||||
{
|
||||
if( !stat->is_trained_dyn_model ) {
|
||||
|
||||
val = 1;
|
||||
|
||||
} else {
|
||||
|
||||
// Compare with stored CCt vectors:
|
||||
for( k = 0; PV_CC(k) > model->params.alpha2 && k < model->params.N1cc; k++ )
|
||||
{
|
||||
if ( abs( V_CC(k,0) - prev_data[0]) <= deltaCC &&
|
||||
abs( V_CC(k,1) - prev_data[1]) <= deltaCC &&
|
||||
abs( V_CC(k,2) - prev_data[2]) <= deltaCC &&
|
||||
abs( V_CC(k,3) - curr_data[0]) <= deltaCC &&
|
||||
abs( V_CC(k,4) - curr_data[1]) <= deltaCC &&
|
||||
abs( V_CC(k,5) - curr_data[2]) <= deltaCC)
|
||||
{
|
||||
Pv += PV_CC(k);
|
||||
Pvb += PVB_CC(k);
|
||||
}
|
||||
}
|
||||
Pb = stat->Pbcc;
|
||||
if( 2 * Pvb * Pb <= Pv ) val = 1;
|
||||
}
|
||||
}
|
||||
else if( stat->is_trained_st_model )
|
||||
{
|
||||
// Compare with stored Ct vectors:
|
||||
for( k = 0; PV_C(k) > model->params.alpha2 && k < model->params.N1c; k++ )
|
||||
{
|
||||
if ( abs( V_C(k,0) - curr_data[0]) <= deltaC &&
|
||||
abs( V_C(k,1) - curr_data[1]) <= deltaC &&
|
||||
abs( V_C(k,2) - curr_data[2]) <= deltaC )
|
||||
{
|
||||
Pv += PV_C(k);
|
||||
Pvb += PVB_C(k);
|
||||
}
|
||||
}
|
||||
Pb = stat->Pbc;
|
||||
if( 2 * Pvb * Pb <= Pv ) val = 1;
|
||||
}
|
||||
|
||||
// Update foreground:
|
||||
((uchar*)model->foreground->imageData)[i*mask_step+j] = (uchar)(val*255);
|
||||
FG_pixels_count += val;
|
||||
|
||||
} // end if( change detection...
|
||||
} // for j...
|
||||
} // for i...
|
||||
//end BG/FG classification
|
||||
|
||||
// Foreground segmentation.
|
||||
// Smooth foreground map:
|
||||
if( model->params.perform_morphing ){
|
||||
cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_OPEN, model->params.perform_morphing );
|
||||
cvMorphologyEx( model->foreground, model->foreground, 0, 0, CV_MOP_CLOSE, model->params.perform_morphing );
|
||||
}
|
||||
|
||||
|
||||
if( model->params.minArea > 0 || model->params.is_obj_without_holes ){
|
||||
|
||||
// Discard under-size foreground regions:
|
||||
//
|
||||
cvFindContours( model->foreground, 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 < model->params.minArea ||
|
||||
(model->params.is_obj_without_holes && CV_IS_SEQ_HOLE(seq)) )
|
||||
{
|
||||
// Delete under-size 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++;
|
||||
}
|
||||
}
|
||||
model->foreground_regions = first_seq;
|
||||
cvZero(model->foreground);
|
||||
cvDrawContours(model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
|
||||
|
||||
} else {
|
||||
|
||||
model->foreground_regions = NULL;
|
||||
}
|
||||
|
||||
// Check ALL BG update condition:
|
||||
if( ((float)FG_pixels_count/(model->Ftd->width*model->Ftd->height)) > CV_BGFG_FGD_BG_UPDATE_TRESH )
|
||||
{
|
||||
for( i = 0; i < model->Ftd->height; i++ )
|
||||
for( j = 0; j < model->Ftd->width; j++ )
|
||||
{
|
||||
CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
|
||||
stat->is_trained_st_model = stat->is_trained_dyn_model = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update background model:
|
||||
for( i = 0; i < model->Ftd->height; i++ )
|
||||
{
|
||||
for( j = 0; j < model->Ftd->width; j++ )
|
||||
{
|
||||
CvBGPixelStat* stat = model->pixel_stat + i * model->Ftd->width + j;
|
||||
CvBGPixelCStatTable* ctable = stat->ctable;
|
||||
CvBGPixelCCStatTable* cctable = stat->cctable;
|
||||
|
||||
uchar *curr_data = (uchar*)(curr_frame->imageData)+i*curr_frame->widthStep+j*3;
|
||||
uchar *prev_data = (uchar*)(prev_frame->imageData)+i*prev_frame->widthStep+j*3;
|
||||
|
||||
if( ((uchar*)model->Ftd->imageData)[i*mask_step+j] || !stat->is_trained_dyn_model )
|
||||
{
|
||||
float alpha = stat->is_trained_dyn_model ? model->params.alpha2 : model->params.alpha3;
|
||||
float diff = 0;
|
||||
int dist, min_dist = 2147483647, indx = -1;
|
||||
|
||||
//update Pb
|
||||
stat->Pbcc *= (1.f-alpha);
|
||||
if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
|
||||
{
|
||||
stat->Pbcc += alpha;
|
||||
}
|
||||
|
||||
// Find best Vi match:
|
||||
for(k = 0; PV_CC(k) && k < model->params.N2cc; k++ )
|
||||
{
|
||||
// Exponential decay of memory
|
||||
PV_CC(k) *= (1-alpha);
|
||||
PVB_CC(k) *= (1-alpha);
|
||||
if( PV_CC(k) < MIN_PV )
|
||||
{
|
||||
PV_CC(k) = 0;
|
||||
PVB_CC(k) = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
dist = 0;
|
||||
for( l = 0; l < 3; l++ )
|
||||
{
|
||||
int val = abs( V_CC(k,l) - prev_data[l] );
|
||||
if( val > deltaCC ) break;
|
||||
dist += val;
|
||||
val = abs( V_CC(k,l+3) - curr_data[l] );
|
||||
if( val > deltaCC) break;
|
||||
dist += val;
|
||||
}
|
||||
if( l == 3 && dist < min_dist )
|
||||
{
|
||||
min_dist = dist;
|
||||
indx = k;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( indx < 0 )
|
||||
{ // Replace N2th elem in the table by new feature:
|
||||
indx = model->params.N2cc - 1;
|
||||
PV_CC(indx) = alpha;
|
||||
PVB_CC(indx) = alpha;
|
||||
//udate Vt
|
||||
for( l = 0; l < 3; l++ )
|
||||
{
|
||||
V_CC(indx,l) = prev_data[l];
|
||||
V_CC(indx,l+3) = curr_data[l];
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Update:
|
||||
PV_CC(indx) += alpha;
|
||||
if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
|
||||
{
|
||||
PVB_CC(indx) += alpha;
|
||||
}
|
||||
}
|
||||
|
||||
//re-sort CCt table by Pv
|
||||
for( k = 0; k < indx; k++ )
|
||||
{
|
||||
if( PV_CC(k) <= PV_CC(indx) )
|
||||
{
|
||||
//shift elements
|
||||
CvBGPixelCCStatTable tmp1, tmp2 = cctable[indx];
|
||||
for( l = k; l <= indx; l++ )
|
||||
{
|
||||
tmp1 = cctable[l];
|
||||
cctable[l] = tmp2;
|
||||
tmp2 = tmp1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float sum1=0, sum2=0;
|
||||
//check "once-off" changes
|
||||
for(k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
|
||||
{
|
||||
sum1 += PV_CC(k);
|
||||
sum2 += PVB_CC(k);
|
||||
}
|
||||
if( sum1 > model->params.T ) stat->is_trained_dyn_model = 1;
|
||||
|
||||
diff = sum1 - stat->Pbcc * sum2;
|
||||
// Update stat table:
|
||||
if( diff > model->params.T )
|
||||
{
|
||||
//printf("once off change at motion mode\n");
|
||||
//new BG features are discovered
|
||||
for( k = 0; PV_CC(k) && k < model->params.N1cc; k++ )
|
||||
{
|
||||
PVB_CC(k) =
|
||||
(PV_CC(k)-stat->Pbcc*PVB_CC(k))/(1-stat->Pbcc);
|
||||
}
|
||||
assert(stat->Pbcc<=1 && stat->Pbcc>=0);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle "stationary" pixel:
|
||||
if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] )
|
||||
{
|
||||
float alpha = stat->is_trained_st_model ? model->params.alpha2 : model->params.alpha3;
|
||||
float diff = 0;
|
||||
int dist, min_dist = 2147483647, indx = -1;
|
||||
|
||||
//update Pb
|
||||
stat->Pbc *= (1.f-alpha);
|
||||
if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
|
||||
{
|
||||
stat->Pbc += alpha;
|
||||
}
|
||||
|
||||
//find best Vi match
|
||||
for( k = 0; k < model->params.N2c; k++ )
|
||||
{
|
||||
// Exponential decay of memory
|
||||
PV_C(k) *= (1-alpha);
|
||||
PVB_C(k) *= (1-alpha);
|
||||
if( PV_C(k) < MIN_PV )
|
||||
{
|
||||
PV_C(k) = 0;
|
||||
PVB_C(k) = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
dist = 0;
|
||||
for( l = 0; l < 3; l++ )
|
||||
{
|
||||
int val = abs( V_C(k,l) - curr_data[l] );
|
||||
if( val > deltaC ) break;
|
||||
dist += val;
|
||||
}
|
||||
if( l == 3 && dist < min_dist )
|
||||
{
|
||||
min_dist = dist;
|
||||
indx = k;
|
||||
}
|
||||
}
|
||||
|
||||
if( indx < 0 )
|
||||
{//N2th elem in the table is replaced by a new features
|
||||
indx = model->params.N2c - 1;
|
||||
PV_C(indx) = alpha;
|
||||
PVB_C(indx) = alpha;
|
||||
//udate Vt
|
||||
for( l = 0; l < 3; l++ )
|
||||
{
|
||||
V_C(indx,l) = curr_data[l];
|
||||
}
|
||||
} else
|
||||
{//update
|
||||
PV_C(indx) += alpha;
|
||||
if( !((uchar*)model->foreground->imageData)[i*mask_step+j] )
|
||||
{
|
||||
PVB_C(indx) += alpha;
|
||||
}
|
||||
}
|
||||
|
||||
//re-sort Ct table by Pv
|
||||
for( k = 0; k < indx; k++ )
|
||||
{
|
||||
if( PV_C(k) <= PV_C(indx) )
|
||||
{
|
||||
//shift elements
|
||||
CvBGPixelCStatTable tmp1, tmp2 = ctable[indx];
|
||||
for( l = k; l <= indx; l++ )
|
||||
{
|
||||
tmp1 = ctable[l];
|
||||
ctable[l] = tmp2;
|
||||
tmp2 = tmp1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check "once-off" changes:
|
||||
float sum1=0, sum2=0;
|
||||
for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
|
||||
{
|
||||
sum1 += PV_C(k);
|
||||
sum2 += PVB_C(k);
|
||||
}
|
||||
diff = sum1 - stat->Pbc * sum2;
|
||||
if( sum1 > model->params.T ) stat->is_trained_st_model = 1;
|
||||
|
||||
// Update stat table:
|
||||
if( diff > model->params.T )
|
||||
{
|
||||
//printf("once off change at stat mode\n");
|
||||
//new BG features are discovered
|
||||
for( k = 0; PV_C(k) && k < model->params.N1c; k++ )
|
||||
{
|
||||
PVB_C(k) = (PV_C(k)-stat->Pbc*PVB_C(k))/(1-stat->Pbc);
|
||||
}
|
||||
stat->Pbc = 1 - stat->Pbc;
|
||||
}
|
||||
} // if !(change detection) at pixel (i,j)
|
||||
|
||||
// Update the reference BG image:
|
||||
if( !((uchar*)model->foreground->imageData)[i*mask_step+j])
|
||||
{
|
||||
uchar* ptr = ((uchar*)model->background->imageData) + i*model->background->widthStep+j*3;
|
||||
|
||||
if( !((uchar*)model->Ftd->imageData)[i*mask_step+j] &&
|
||||
!((uchar*)model->Fbd->imageData)[i*mask_step+j] )
|
||||
{
|
||||
// Apply IIR filter:
|
||||
for( l = 0; l < 3; l++ )
|
||||
{
|
||||
int a = cvRound(ptr[l]*(1 - model->params.alpha1) + model->params.alpha1*curr_data[l]);
|
||||
ptr[l] = (uchar)a;
|
||||
//((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l]*=(1 - model->params.alpha1);
|
||||
//((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] += model->params.alpha1*curr_data[l];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Background change detected:
|
||||
for( l = 0; l < 3; l++ )
|
||||
{
|
||||
//((uchar*)model->background->imageData)[i*model->background->widthStep+j*3+l] = curr_data[l];
|
||||
ptr[l] = curr_data[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
} // j
|
||||
} // i
|
||||
|
||||
// Keep previous frame:
|
||||
cvCopy( curr_frame, model->prev_frame );
|
||||
|
||||
return region_count;
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
@@ -1,362 +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
|
||||
//
|
||||
// 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"
|
||||
|
||||
CvBGCodeBookModel* cvCreateBGCodeBookModel()
|
||||
{
|
||||
CvBGCodeBookModel* model = (CvBGCodeBookModel*)cvAlloc( sizeof(*model) );
|
||||
memset( model, 0, sizeof(*model) );
|
||||
model->cbBounds[0] = model->cbBounds[1] = model->cbBounds[2] = 10;
|
||||
model->modMin[0] = 3;
|
||||
model->modMax[0] = 10;
|
||||
model->modMin[1] = model->modMin[2] = 1;
|
||||
model->modMax[1] = model->modMax[2] = 1;
|
||||
model->storage = cvCreateMemStorage();
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
void cvReleaseBGCodeBookModel( CvBGCodeBookModel** model )
|
||||
{
|
||||
if( model && *model )
|
||||
{
|
||||
cvReleaseMemStorage( &(*model)->storage );
|
||||
memset( *model, 0, sizeof(**model) );
|
||||
cvFree( model );
|
||||
}
|
||||
}
|
||||
|
||||
static uchar satTab8u[768];
|
||||
#undef SAT_8U
|
||||
#define SAT_8U(x) satTab8u[(x) + 255]
|
||||
|
||||
static void icvInitSatTab()
|
||||
{
|
||||
static int initialized = 0;
|
||||
if( !initialized )
|
||||
{
|
||||
for( int i = 0; i < 768; i++ )
|
||||
{
|
||||
int v = i - 255;
|
||||
satTab8u[i] = (uchar)(v < 0 ? 0 : v > 255 ? 255 : v);
|
||||
}
|
||||
initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cvBGCodeBookUpdate( CvBGCodeBookModel* model, const CvArr* _image,
|
||||
CvRect roi, const CvArr* _mask )
|
||||
{
|
||||
CV_FUNCNAME( "cvBGCodeBookUpdate" );
|
||||
|
||||
__BEGIN__;
|
||||
|
||||
CvMat stub, *image = cvGetMat( _image, &stub );
|
||||
CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0;
|
||||
int i, x, y, T;
|
||||
int nblocks;
|
||||
uchar cb0, cb1, cb2;
|
||||
CvBGCodeBookElem* freeList;
|
||||
|
||||
CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 &&
|
||||
(!mask || (CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask))) );
|
||||
|
||||
if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
|
||||
{
|
||||
roi.width = image->cols;
|
||||
roi.height = image->rows;
|
||||
}
|
||||
else
|
||||
CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols &&
|
||||
(unsigned)roi.y < (unsigned)image->rows &&
|
||||
roi.width >= 0 && roi.height >= 0 &&
|
||||
roi.x + roi.width <= image->cols &&
|
||||
roi.y + roi.height <= image->rows );
|
||||
|
||||
if( image->cols != model->size.width || image->rows != model->size.height )
|
||||
{
|
||||
cvClearMemStorage( model->storage );
|
||||
model->freeList = 0;
|
||||
cvFree( &model->cbmap );
|
||||
int bufSz = image->cols*image->rows*sizeof(model->cbmap[0]);
|
||||
model->cbmap = (CvBGCodeBookElem**)cvAlloc(bufSz);
|
||||
memset( model->cbmap, 0, bufSz );
|
||||
model->size = cvSize(image->cols, image->rows);
|
||||
}
|
||||
|
||||
icvInitSatTab();
|
||||
|
||||
cb0 = model->cbBounds[0];
|
||||
cb1 = model->cbBounds[1];
|
||||
cb2 = model->cbBounds[2];
|
||||
|
||||
T = ++model->t;
|
||||
freeList = model->freeList;
|
||||
nblocks = (int)((model->storage->block_size - sizeof(CvMemBlock))/sizeof(*freeList));
|
||||
nblocks = MIN( nblocks, 1024 );
|
||||
CV_ASSERT( nblocks > 0 );
|
||||
|
||||
for( y = 0; y < roi.height; y++ )
|
||||
{
|
||||
const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3;
|
||||
const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0;
|
||||
CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x;
|
||||
|
||||
for( x = 0; x < roi.width; x++, p += 3, cb++ )
|
||||
{
|
||||
CvBGCodeBookElem *e, *found = 0;
|
||||
uchar p0, p1, p2, l0, l1, l2, h0, h1, h2;
|
||||
int negRun;
|
||||
|
||||
if( m && m[x] == 0 )
|
||||
continue;
|
||||
|
||||
p0 = p[0]; p1 = p[1]; p2 = p[2];
|
||||
l0 = SAT_8U(p0 - cb0); l1 = SAT_8U(p1 - cb1); l2 = SAT_8U(p2 - cb2);
|
||||
h0 = SAT_8U(p0 + cb0); h1 = SAT_8U(p1 + cb1); h2 = SAT_8U(p2 + cb2);
|
||||
|
||||
for( e = *cb; e != 0; e = e->next )
|
||||
{
|
||||
if( e->learnMin[0] <= p0 && p0 <= e->learnMax[0] &&
|
||||
e->learnMin[1] <= p1 && p1 <= e->learnMax[1] &&
|
||||
e->learnMin[2] <= p2 && p2 <= e->learnMax[2] )
|
||||
{
|
||||
e->tLastUpdate = T;
|
||||
e->boxMin[0] = MIN(e->boxMin[0], p0);
|
||||
e->boxMax[0] = MAX(e->boxMax[0], p0);
|
||||
e->boxMin[1] = MIN(e->boxMin[1], p1);
|
||||
e->boxMax[1] = MAX(e->boxMax[1], p1);
|
||||
e->boxMin[2] = MIN(e->boxMin[2], p2);
|
||||
e->boxMax[2] = MAX(e->boxMax[2], p2);
|
||||
|
||||
// no need to use SAT_8U for updated learnMin[i] & learnMax[i] here,
|
||||
// as the bounding li & hi are already within 0..255.
|
||||
if( e->learnMin[0] > l0 ) e->learnMin[0]--;
|
||||
if( e->learnMax[0] < h0 ) e->learnMax[0]++;
|
||||
if( e->learnMin[1] > l1 ) e->learnMin[1]--;
|
||||
if( e->learnMax[1] < h1 ) e->learnMax[1]++;
|
||||
if( e->learnMin[2] > l2 ) e->learnMin[2]--;
|
||||
if( e->learnMax[2] < h2 ) e->learnMax[2]++;
|
||||
|
||||
found = e;
|
||||
break;
|
||||
}
|
||||
negRun = T - e->tLastUpdate;
|
||||
e->stale = MAX( e->stale, negRun );
|
||||
}
|
||||
|
||||
for( ; e != 0; e = e->next )
|
||||
{
|
||||
negRun = T - e->tLastUpdate;
|
||||
e->stale = MAX( e->stale, negRun );
|
||||
}
|
||||
|
||||
if( !found )
|
||||
{
|
||||
if( !freeList )
|
||||
{
|
||||
freeList = (CvBGCodeBookElem*)cvMemStorageAlloc(model->storage,
|
||||
nblocks*sizeof(*freeList));
|
||||
for( i = 0; i < nblocks-1; i++ )
|
||||
freeList[i].next = &freeList[i+1];
|
||||
freeList[nblocks-1].next = 0;
|
||||
}
|
||||
e = freeList;
|
||||
freeList = freeList->next;
|
||||
|
||||
e->learnMin[0] = l0; e->learnMax[0] = h0;
|
||||
e->learnMin[1] = l1; e->learnMax[1] = h1;
|
||||
e->learnMin[2] = l2; e->learnMax[2] = h2;
|
||||
e->boxMin[0] = e->boxMax[0] = p0;
|
||||
e->boxMin[1] = e->boxMax[1] = p1;
|
||||
e->boxMin[2] = e->boxMax[2] = p2;
|
||||
e->tLastUpdate = T;
|
||||
e->stale = 0;
|
||||
e->next = *cb;
|
||||
*cb = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model->freeList = freeList;
|
||||
|
||||
__END__;
|
||||
}
|
||||
|
||||
|
||||
int cvBGCodeBookDiff( const CvBGCodeBookModel* model, const CvArr* _image,
|
||||
CvArr* _fgmask, CvRect roi )
|
||||
{
|
||||
int maskCount = -1;
|
||||
|
||||
CV_FUNCNAME( "cvBGCodeBookDiff" );
|
||||
|
||||
__BEGIN__;
|
||||
|
||||
CvMat stub, *image = cvGetMat( _image, &stub );
|
||||
CvMat mstub, *mask = cvGetMat( _fgmask, &mstub );
|
||||
int x, y;
|
||||
uchar m0, m1, m2, M0, M1, M2;
|
||||
|
||||
CV_ASSERT( model && CV_MAT_TYPE(image->type) == CV_8UC3 &&
|
||||
image->cols == model->size.width && image->rows == model->size.height &&
|
||||
CV_IS_MASK_ARR(mask) && CV_ARE_SIZES_EQ(image, mask) );
|
||||
|
||||
if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
|
||||
{
|
||||
roi.width = image->cols;
|
||||
roi.height = image->rows;
|
||||
}
|
||||
else
|
||||
CV_ASSERT( (unsigned)roi.x < (unsigned)image->cols &&
|
||||
(unsigned)roi.y < (unsigned)image->rows &&
|
||||
roi.width >= 0 && roi.height >= 0 &&
|
||||
roi.x + roi.width <= image->cols &&
|
||||
roi.y + roi.height <= image->rows );
|
||||
|
||||
m0 = model->modMin[0]; M0 = model->modMax[0];
|
||||
m1 = model->modMin[1]; M1 = model->modMax[1];
|
||||
m2 = model->modMin[2]; M2 = model->modMax[2];
|
||||
|
||||
maskCount = roi.height*roi.width;
|
||||
for( y = 0; y < roi.height; y++ )
|
||||
{
|
||||
const uchar* p = image->data.ptr + image->step*(y + roi.y) + roi.x*3;
|
||||
uchar* m = mask->data.ptr + mask->step*(y + roi.y) + roi.x;
|
||||
CvBGCodeBookElem** cb = model->cbmap + image->cols*(y + roi.y) + roi.x;
|
||||
|
||||
for( x = 0; x < roi.width; x++, p += 3, cb++ )
|
||||
{
|
||||
CvBGCodeBookElem *e;
|
||||
uchar p0 = p[0], p1 = p[1], p2 = p[2];
|
||||
int l0 = p0 + m0, l1 = p1 + m1, l2 = p2 + m2;
|
||||
int h0 = p0 - M0, h1 = p1 - M1, h2 = p2 - M2;
|
||||
m[x] = (uchar)255;
|
||||
|
||||
for( e = *cb; e != 0; e = e->next )
|
||||
{
|
||||
if( e->boxMin[0] <= l0 && h0 <= e->boxMax[0] &&
|
||||
e->boxMin[1] <= l1 && h1 <= e->boxMax[1] &&
|
||||
e->boxMin[2] <= l2 && h2 <= e->boxMax[2] )
|
||||
{
|
||||
m[x] = 0;
|
||||
maskCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__END__;
|
||||
|
||||
return maskCount;
|
||||
}
|
||||
|
||||
void cvBGCodeBookClearStale( CvBGCodeBookModel* model, int staleThresh,
|
||||
CvRect roi, const CvArr* _mask )
|
||||
{
|
||||
CV_FUNCNAME( "cvBGCodeBookClearStale" );
|
||||
|
||||
__BEGIN__;
|
||||
|
||||
CvMat mstub, *mask = _mask ? cvGetMat( _mask, &mstub ) : 0;
|
||||
int x, y, T;
|
||||
CvBGCodeBookElem* freeList;
|
||||
|
||||
CV_ASSERT( model && (!mask || (CV_IS_MASK_ARR(mask) &&
|
||||
mask->cols == model->size.width && mask->rows == model->size.height)) );
|
||||
|
||||
if( roi.x == 0 && roi.y == 0 && roi.width == 0 && roi.height == 0 )
|
||||
{
|
||||
roi.width = model->size.width;
|
||||
roi.height = model->size.height;
|
||||
}
|
||||
else
|
||||
CV_ASSERT( (unsigned)roi.x < (unsigned)mask->cols &&
|
||||
(unsigned)roi.y < (unsigned)mask->rows &&
|
||||
roi.width >= 0 && roi.height >= 0 &&
|
||||
roi.x + roi.width <= mask->cols &&
|
||||
roi.y + roi.height <= mask->rows );
|
||||
|
||||
icvInitSatTab();
|
||||
freeList = model->freeList;
|
||||
T = model->t;
|
||||
|
||||
for( y = 0; y < roi.height; y++ )
|
||||
{
|
||||
const uchar* m = mask ? mask->data.ptr + mask->step*(y + roi.y) + roi.x : 0;
|
||||
CvBGCodeBookElem** cb = model->cbmap + model->size.width*(y + roi.y) + roi.x;
|
||||
|
||||
for( x = 0; x < roi.width; x++, cb++ )
|
||||
{
|
||||
CvBGCodeBookElem *e, first, *prev = &first;
|
||||
|
||||
if( m && m[x] == 0 )
|
||||
continue;
|
||||
|
||||
for( first.next = e = *cb; e != 0; e = prev->next )
|
||||
{
|
||||
if( e->stale > staleThresh )
|
||||
{
|
||||
prev->next = e->next;
|
||||
e->next = freeList;
|
||||
freeList = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
e->stale = 0;
|
||||
e->tLastUpdate = T;
|
||||
prev = e;
|
||||
}
|
||||
}
|
||||
|
||||
*cb = first.next;
|
||||
}
|
||||
}
|
||||
|
||||
model->freeList = freeList;
|
||||
|
||||
__END__;
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
|
||||
@@ -1,138 +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
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
void cvReleaseBGStatModel( CvBGStatModel** bg_model )
|
||||
{
|
||||
if( bg_model && *bg_model && (*bg_model)->release )
|
||||
(*bg_model)->release( bg_model );
|
||||
}
|
||||
|
||||
int cvUpdateBGStatModel( IplImage* current_frame,
|
||||
CvBGStatModel* bg_model,
|
||||
double learningRate )
|
||||
{
|
||||
return bg_model && bg_model->update ? bg_model->update( current_frame, bg_model, learningRate ) : 0;
|
||||
}
|
||||
|
||||
|
||||
// Function cvRefineForegroundMaskBySegm preforms FG post-processing based on segmentation
|
||||
// (all pixels of the segment will be classified as FG 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
|
||||
CV_IMPL void cvRefineForegroundMaskBySegm( CvSeq* segments, CvBGStatModel* bg_model )
|
||||
{
|
||||
IplImage* tmp_image = cvCreateImage(cvSize(bg_model->foreground->width,bg_model->foreground->height),
|
||||
IPL_DEPTH_8U, 1);
|
||||
for( ; segments; segments = ((CvSeq*)segments)->h_next )
|
||||
{
|
||||
CvSeq seq = *segments;
|
||||
seq.v_next = seq.h_next = NULL;
|
||||
cvZero(tmp_image);
|
||||
cvDrawContours( tmp_image, &seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
|
||||
int num1 = cvCountNonZero(tmp_image);
|
||||
cvAnd(tmp_image, bg_model->foreground, tmp_image);
|
||||
int num2 = cvCountNonZero(tmp_image);
|
||||
if( num2 > num1*0.5 )
|
||||
cvDrawContours( bg_model->foreground, &seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);
|
||||
else
|
||||
cvDrawContours( bg_model->foreground, &seq, CV_RGB(0, 0, 0), CV_RGB(0, 0, 0), 10, -1);
|
||||
}
|
||||
cvReleaseImage(&tmp_image);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CV_IMPL CvSeq*
|
||||
cvSegmentFGMask( CvArr* _mask, int poly1Hull0, float perimScale,
|
||||
CvMemStorage* storage, CvPoint offset )
|
||||
{
|
||||
CvMat mstub, *mask = cvGetMat( _mask, &mstub );
|
||||
CvMemStorage* tempStorage = storage ? storage : cvCreateMemStorage();
|
||||
CvSeq *contours, *c;
|
||||
int nContours = 0;
|
||||
CvContourScanner scanner;
|
||||
|
||||
// clean up raw mask
|
||||
cvMorphologyEx( mask, mask, 0, 0, CV_MOP_OPEN, 1 );
|
||||
cvMorphologyEx( mask, mask, 0, 0, CV_MOP_CLOSE, 1 );
|
||||
|
||||
// find contours around only bigger regions
|
||||
scanner = cvStartFindContours( mask, tempStorage,
|
||||
sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, offset );
|
||||
|
||||
while( (c = cvFindNextContour( scanner )) != 0 )
|
||||
{
|
||||
double len = cvContourPerimeter( c );
|
||||
double q = (mask->rows + mask->cols)/perimScale; // calculate perimeter len threshold
|
||||
if( len < q ) //Get rid of blob if it's perimeter is too small
|
||||
cvSubstituteContour( scanner, 0 );
|
||||
else //Smooth it's edges if it's large enough
|
||||
{
|
||||
CvSeq* newC;
|
||||
if( poly1Hull0 ) //Polygonal approximation of the segmentation
|
||||
newC = cvApproxPoly( c, sizeof(CvContour), tempStorage, CV_POLY_APPROX_DP, 2, 0 );
|
||||
else //Convex Hull of the segmentation
|
||||
newC = cvConvexHull2( c, tempStorage, CV_CLOCKWISE, 1 );
|
||||
cvSubstituteContour( scanner, newC );
|
||||
nContours++;
|
||||
}
|
||||
}
|
||||
contours = cvEndFindContours( &scanner );
|
||||
|
||||
// paint the found regions back into the image
|
||||
cvZero( mask );
|
||||
for( c=contours; c != 0; c = c->h_next )
|
||||
cvDrawContours( mask, c, cvScalarAll(255), cvScalarAll(0), -1, CV_FILLED, 8,
|
||||
cvPoint(-offset.x,-offset.y));
|
||||
|
||||
if( tempStorage != storage )
|
||||
{
|
||||
cvReleaseMemStorage( &tempStorage );
|
||||
contours = 0;
|
||||
}
|
||||
|
||||
return contours;
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
|
||||
@@ -67,11 +67,12 @@ void BackgroundSubtractor::getBackgroundImage(OutputArray) const
|
||||
{
|
||||
}
|
||||
|
||||
static const int defaultNMixtures = CV_BGFG_MOG_NGAUSSIANS;
|
||||
static const int defaultHistory = CV_BGFG_MOG_WINDOW_SIZE;
|
||||
static const double defaultBackgroundRatio = CV_BGFG_MOG_BACKGROUND_THRESHOLD;
|
||||
static const double defaultVarThreshold = CV_BGFG_MOG_STD_THRESHOLD*CV_BGFG_MOG_STD_THRESHOLD;
|
||||
static const double defaultNoiseSigma = CV_BGFG_MOG_SIGMA_INIT*0.5;
|
||||
static const int defaultNMixtures = 5;
|
||||
static const int defaultHistory = 200;
|
||||
static const double defaultBackgroundRatio = 0.7;
|
||||
static const double defaultVarThreshold = 2.5*2.5;
|
||||
static const double defaultNoiseSigma = 30*0.5;
|
||||
static const double defaultInitialWeight = 0.05;
|
||||
|
||||
BackgroundSubtractorMOG::BackgroundSubtractorMOG()
|
||||
{
|
||||
@@ -140,9 +141,9 @@ static void process8uC1( BackgroundSubtractorMOG& obj, const Mat& image, Mat& fg
|
||||
int K = obj.nmixtures;
|
||||
MixData<float>* mptr = (MixData<float>*)obj.bgmodel.data;
|
||||
|
||||
const float w0 = (float)CV_BGFG_MOG_WEIGHT_INIT;
|
||||
const float sk0 = (float)(w0/CV_BGFG_MOG_SIGMA_INIT);
|
||||
const float var0 = (float)(CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT);
|
||||
const float w0 = (float)defaultInitialWeight;
|
||||
const float sk0 = (float)(w0/(defaultNoiseSigma*2));
|
||||
const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4);
|
||||
const float minVar = (float)(obj.noiseSigma*obj.noiseSigma);
|
||||
|
||||
for( y = 0; y < rows; y++ )
|
||||
@@ -264,9 +265,9 @@ static void process8uC3( BackgroundSubtractorMOG& obj, const Mat& image, Mat& fg
|
||||
float alpha = (float)learningRate, T = (float)obj.backgroundRatio, vT = (float)obj.varThreshold;
|
||||
int K = obj.nmixtures;
|
||||
|
||||
const float w0 = (float)CV_BGFG_MOG_WEIGHT_INIT;
|
||||
const float sk0 = (float)(w0/(CV_BGFG_MOG_SIGMA_INIT*sqrt(3.)));
|
||||
const float var0 = (float)(CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT);
|
||||
const float w0 = (float)defaultInitialWeight;
|
||||
const float sk0 = (float)(w0/(defaultNoiseSigma*2*sqrt(3.)));
|
||||
const float var0 = (float)(defaultNoiseSigma*defaultNoiseSigma*4);
|
||||
const float minVar = (float)(obj.noiseSigma*obj.noiseSigma);
|
||||
MixData<Vec3f>* mptr = (MixData<Vec3f>*)obj.bgmodel.data;
|
||||
|
||||
@@ -411,140 +412,5 @@ void BackgroundSubtractorMOG::operator()(InputArray _image, OutputArray _fgmask,
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void CV_CDECL
|
||||
icvReleaseGaussianBGModel( CvGaussBGModel** bg_model )
|
||||
{
|
||||
if( !bg_model )
|
||||
CV_Error( CV_StsNullPtr, "" );
|
||||
|
||||
if( *bg_model )
|
||||
{
|
||||
delete (cv::Mat*)((*bg_model)->g_point);
|
||||
cvReleaseImage( &(*bg_model)->background );
|
||||
cvReleaseImage( &(*bg_model)->foreground );
|
||||
cvReleaseMemStorage(&(*bg_model)->storage);
|
||||
memset( *bg_model, 0, sizeof(**bg_model) );
|
||||
delete *bg_model;
|
||||
*bg_model = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int CV_CDECL
|
||||
icvUpdateGaussianBGModel( IplImage* curr_frame, CvGaussBGModel* bg_model, double learningRate )
|
||||
{
|
||||
int region_count = 0;
|
||||
|
||||
cv::Mat image = cv::cvarrToMat(curr_frame), mask = cv::cvarrToMat(bg_model->foreground);
|
||||
|
||||
cv::BackgroundSubtractorMOG mog;
|
||||
mog.bgmodel = *(cv::Mat*)bg_model->g_point;
|
||||
mog.frameSize = mog.bgmodel.data ? cv::Size(cvGetSize(curr_frame)) : cv::Size();
|
||||
mog.frameType = image.type();
|
||||
|
||||
mog.nframes = bg_model->countFrames;
|
||||
mog.history = bg_model->params.win_size;
|
||||
mog.nmixtures = bg_model->params.n_gauss;
|
||||
mog.varThreshold = bg_model->params.std_threshold*bg_model->params.std_threshold;
|
||||
mog.backgroundRatio = bg_model->params.bg_threshold;
|
||||
|
||||
mog(image, mask, learningRate);
|
||||
|
||||
bg_model->countFrames = mog.nframes;
|
||||
if( ((cv::Mat*)bg_model->g_point)->data != mog.bgmodel.data )
|
||||
*((cv::Mat*)bg_model->g_point) = mog.bgmodel;
|
||||
|
||||
//foreground filtering
|
||||
|
||||
//filter small regions
|
||||
cvClearMemStorage(bg_model->storage);
|
||||
|
||||
//cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_OPEN, 1 );
|
||||
//cvMorphologyEx( bg_model->foreground, bg_model->foreground, 0, 0, CV_MOP_CLOSE, 1 );
|
||||
|
||||
/*
|
||||
CvSeq *first_seq = NULL, *prev_seq = NULL, *seq = NULL;
|
||||
cvFindContours( bg_model->foreground, bg_model->storage, &first_seq, sizeof(CvContour), CV_RETR_LIST );
|
||||
for( seq = first_seq; seq; seq = seq->h_next )
|
||||
{
|
||||
CvContour* cnt = (CvContour*)seq;
|
||||
if( cnt->rect.width * cnt->rect.height < bg_model->params.minArea )
|
||||
{
|
||||
//delete small contour
|
||||
prev_seq = seq->h_prev;
|
||||
if( prev_seq )
|
||||
{
|
||||
prev_seq->h_next = seq->h_next;
|
||||
if( seq->h_next ) seq->h_next->h_prev = prev_seq;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_seq = seq->h_next;
|
||||
if( seq->h_next ) seq->h_next->h_prev = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
region_count++;
|
||||
}
|
||||
}
|
||||
bg_model->foreground_regions = first_seq;
|
||||
cvZero(bg_model->foreground);
|
||||
cvDrawContours(bg_model->foreground, first_seq, CV_RGB(0, 0, 255), CV_RGB(0, 0, 255), 10, -1);*/
|
||||
CvMat _mask = mask;
|
||||
cvCopy(&_mask, bg_model->foreground);
|
||||
|
||||
return region_count;
|
||||
}
|
||||
|
||||
CV_IMPL CvBGStatModel*
|
||||
cvCreateGaussianBGModel( IplImage* first_frame, CvGaussBGStatModelParams* parameters )
|
||||
{
|
||||
CvGaussBGStatModelParams params;
|
||||
|
||||
CV_Assert( CV_IS_IMAGE(first_frame) );
|
||||
|
||||
//init parameters
|
||||
if( parameters == NULL )
|
||||
{ /* These constants are defined in cvaux/include/cvaux.h: */
|
||||
params.win_size = CV_BGFG_MOG_WINDOW_SIZE;
|
||||
params.bg_threshold = CV_BGFG_MOG_BACKGROUND_THRESHOLD;
|
||||
|
||||
params.std_threshold = CV_BGFG_MOG_STD_THRESHOLD;
|
||||
params.weight_init = CV_BGFG_MOG_WEIGHT_INIT;
|
||||
|
||||
params.variance_init = CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT;
|
||||
params.minArea = CV_BGFG_MOG_MINAREA;
|
||||
params.n_gauss = CV_BGFG_MOG_NGAUSSIANS;
|
||||
}
|
||||
else
|
||||
params = *parameters;
|
||||
|
||||
CvGaussBGModel* bg_model = new CvGaussBGModel;
|
||||
memset( bg_model, 0, sizeof(*bg_model) );
|
||||
bg_model->type = CV_BG_MODEL_MOG;
|
||||
bg_model->release = (CvReleaseBGStatModel)icvReleaseGaussianBGModel;
|
||||
bg_model->update = (CvUpdateBGStatModel)icvUpdateGaussianBGModel;
|
||||
|
||||
bg_model->params = params;
|
||||
|
||||
//prepare storages
|
||||
bg_model->g_point = (CvGaussBGPoint*)new cv::Mat();
|
||||
|
||||
bg_model->background = cvCreateImage(cvSize(first_frame->width,
|
||||
first_frame->height), IPL_DEPTH_8U, first_frame->nChannels);
|
||||
bg_model->foreground = cvCreateImage(cvSize(first_frame->width,
|
||||
first_frame->height), IPL_DEPTH_8U, 1);
|
||||
|
||||
bg_model->storage = cvCreateMemStorage();
|
||||
|
||||
bg_model->countFrames = 0;
|
||||
|
||||
icvUpdateGaussianBGModel( first_frame, bg_model, 1 );
|
||||
|
||||
return (CvBGStatModel*)bg_model;
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
@@ -1,303 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
|
||||
static inline int cmpBlocks(const uchar* A, const uchar* B, int Bstep, CvSize blockSize )
|
||||
{
|
||||
int x, s = 0;
|
||||
for( ; blockSize.height--; A += blockSize.width, B += Bstep )
|
||||
{
|
||||
for( x = 0; x <= blockSize.width - 4; x += 4 )
|
||||
s += std::abs(A[x] - B[x]) + std::abs(A[x+1] - B[x+1]) +
|
||||
std::abs(A[x+2] - B[x+2]) + std::abs(A[x+3] - B[x+3]);
|
||||
for( ; x < blockSize.width; x++ )
|
||||
s += std::abs(A[x] - B[x]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL void
|
||||
cvCalcOpticalFlowBM( const void* srcarrA, const void* srcarrB,
|
||||
CvSize blockSize, CvSize shiftSize,
|
||||
CvSize maxRange, int usePrevious,
|
||||
void* velarrx, void* velarry )
|
||||
{
|
||||
CvMat stubA, *srcA = cvGetMat( srcarrA, &stubA );
|
||||
CvMat stubB, *srcB = cvGetMat( srcarrB, &stubB );
|
||||
|
||||
CvMat stubx, *velx = cvGetMat( velarrx, &stubx );
|
||||
CvMat stuby, *vely = cvGetMat( velarry, &stuby );
|
||||
|
||||
if( !CV_ARE_TYPES_EQ( srcA, srcB ))
|
||||
CV_Error( CV_StsUnmatchedFormats, "Source images have different formats" );
|
||||
|
||||
if( !CV_ARE_TYPES_EQ( velx, vely ))
|
||||
CV_Error( CV_StsUnmatchedFormats, "Destination images have different formats" );
|
||||
|
||||
CvSize velSize =
|
||||
{
|
||||
(srcA->width - blockSize.width + shiftSize.width)/shiftSize.width,
|
||||
(srcA->height - blockSize.height + shiftSize.height)/shiftSize.height
|
||||
};
|
||||
|
||||
if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
|
||||
!CV_ARE_SIZES_EQ( velx, vely ) ||
|
||||
velx->width != velSize.width ||
|
||||
vely->height != velSize.height )
|
||||
CV_Error( CV_StsUnmatchedSizes, "" );
|
||||
|
||||
if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
|
||||
CV_MAT_TYPE( velx->type ) != CV_32FC1 )
|
||||
CV_Error( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
|
||||
"destination images must have 32fC1 type" );
|
||||
|
||||
if( srcA->step != srcB->step || velx->step != vely->step )
|
||||
CV_Error( CV_BadStep, "two source or two destination images have different steps" );
|
||||
|
||||
const int SMALL_DIFF=2;
|
||||
const int BIG_DIFF=128;
|
||||
|
||||
// scanning scheme coordinates
|
||||
cv::vector<CvPoint> _ss((2 * maxRange.width + 1) * (2 * maxRange.height + 1));
|
||||
CvPoint* ss = &_ss[0];
|
||||
int ss_count = 0;
|
||||
|
||||
int blWidth = blockSize.width, blHeight = blockSize.height;
|
||||
int blSize = blWidth*blHeight;
|
||||
int acceptLevel = blSize * SMALL_DIFF;
|
||||
int escapeLevel = blSize * BIG_DIFF;
|
||||
|
||||
int i, j;
|
||||
|
||||
cv::vector<uchar> _blockA(cvAlign(blSize + 16, 16));
|
||||
uchar* blockA = (uchar*)cvAlignPtr(&_blockA[0], 16);
|
||||
|
||||
// Calculate scanning scheme
|
||||
int min_count = MIN( maxRange.width, maxRange.height );
|
||||
|
||||
// use spiral search pattern
|
||||
//
|
||||
// 9 10 11 12
|
||||
// 8 1 2 13
|
||||
// 7 * 3 14
|
||||
// 6 5 4 15
|
||||
//... 20 19 18 17
|
||||
//
|
||||
|
||||
for( i = 0; i < min_count; i++ )
|
||||
{
|
||||
// four cycles along sides
|
||||
int x = -i-1, y = x;
|
||||
|
||||
// upper side
|
||||
for( j = -i; j <= i + 1; j++, ss_count++ )
|
||||
{
|
||||
ss[ss_count].x = ++x;
|
||||
ss[ss_count].y = y;
|
||||
}
|
||||
|
||||
// right side
|
||||
for( j = -i; j <= i + 1; j++, ss_count++ )
|
||||
{
|
||||
ss[ss_count].x = x;
|
||||
ss[ss_count].y = ++y;
|
||||
}
|
||||
|
||||
// bottom side
|
||||
for( j = -i; j <= i + 1; j++, ss_count++ )
|
||||
{
|
||||
ss[ss_count].x = --x;
|
||||
ss[ss_count].y = y;
|
||||
}
|
||||
|
||||
// left side
|
||||
for( j = -i; j <= i + 1; j++, ss_count++ )
|
||||
{
|
||||
ss[ss_count].x = x;
|
||||
ss[ss_count].y = --y;
|
||||
}
|
||||
}
|
||||
|
||||
// the rest part
|
||||
if( maxRange.width < maxRange.height )
|
||||
{
|
||||
int xleft = -min_count;
|
||||
|
||||
// cycle by neighbor rings
|
||||
for( i = min_count; i < maxRange.height; i++ )
|
||||
{
|
||||
// two cycles by x
|
||||
int y = -(i + 1);
|
||||
int x = xleft;
|
||||
|
||||
// upper side
|
||||
for( j = -maxRange.width; j <= maxRange.width; j++, ss_count++, x++ )
|
||||
{
|
||||
ss[ss_count].x = x;
|
||||
ss[ss_count].y = y;
|
||||
}
|
||||
|
||||
x = xleft;
|
||||
y = -y;
|
||||
// bottom side
|
||||
for( j = -maxRange.width; j <= maxRange.width; j++, ss_count++, x++ )
|
||||
{
|
||||
ss[ss_count].x = x;
|
||||
ss[ss_count].y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( maxRange.width > maxRange.height )
|
||||
{
|
||||
int yupper = -min_count;
|
||||
|
||||
// cycle by neighbor rings
|
||||
for( i = min_count; i < maxRange.width; i++ )
|
||||
{
|
||||
// two cycles by y
|
||||
int x = -(i + 1);
|
||||
int y = yupper;
|
||||
|
||||
// left side
|
||||
for( j = -maxRange.height; j <= maxRange.height; j++, ss_count++, y++ )
|
||||
{
|
||||
ss[ss_count].x = x;
|
||||
ss[ss_count].y = y;
|
||||
}
|
||||
|
||||
y = yupper;
|
||||
x = -x;
|
||||
// right side
|
||||
for( j = -maxRange.height; j <= maxRange.height; j++, ss_count++, y++ )
|
||||
{
|
||||
ss[ss_count].x = x;
|
||||
ss[ss_count].y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int maxX = srcB->cols - blockSize.width, maxY = srcB->rows - blockSize.height;
|
||||
const uchar* Adata = srcA->data.ptr;
|
||||
const uchar* Bdata = srcB->data.ptr;
|
||||
int Astep = srcA->step, Bstep = srcB->step;
|
||||
|
||||
// compute the flow
|
||||
for( i = 0; i < velx->rows; i++ )
|
||||
{
|
||||
float* vx = (float*)(velx->data.ptr + velx->step*i);
|
||||
float* vy = (float*)(vely->data.ptr + vely->step*i);
|
||||
|
||||
for( j = 0; j < velx->cols; j++ )
|
||||
{
|
||||
int X1 = j*shiftSize.width, Y1 = i*shiftSize.height, X2, Y2;
|
||||
int offX = 0, offY = 0;
|
||||
|
||||
if( usePrevious )
|
||||
{
|
||||
offX = cvRound(vx[j]);
|
||||
offY = cvRound(vy[j]);
|
||||
}
|
||||
|
||||
int k;
|
||||
for( k = 0; k < blHeight; k++ )
|
||||
memcpy( blockA + k*blWidth, Adata + Astep*(Y1 + k) + X1, blWidth );
|
||||
|
||||
X2 = X1 + offX;
|
||||
Y2 = Y1 + offY;
|
||||
int dist = INT_MAX;
|
||||
if( 0 <= X2 && X2 <= maxX && 0 <= Y2 && Y2 <= maxY )
|
||||
dist = cmpBlocks( blockA, Bdata + Bstep*Y2 + X2, Bstep, blockSize );
|
||||
|
||||
int countMin = 1;
|
||||
int sumx = offX, sumy = offY;
|
||||
|
||||
if( dist > acceptLevel )
|
||||
{
|
||||
// do brute-force search
|
||||
for( k = 0; k < ss_count; k++ )
|
||||
{
|
||||
int dx = offX + ss[k].x;
|
||||
int dy = offY + ss[k].y;
|
||||
X2 = X1 + dx;
|
||||
Y2 = Y1 + dy;
|
||||
|
||||
if( !(0 <= X2 && X2 <= maxX && 0 <= Y2 && Y2 <= maxY) )
|
||||
continue;
|
||||
|
||||
int tmpDist = cmpBlocks( blockA, Bdata + Bstep*Y2 + X2, Bstep, blockSize );
|
||||
if( tmpDist < acceptLevel )
|
||||
{
|
||||
sumx = dx; sumy = dy;
|
||||
countMin = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if( tmpDist < dist )
|
||||
{
|
||||
dist = tmpDist;
|
||||
sumx = dx; sumy = dy;
|
||||
countMin = 1;
|
||||
}
|
||||
else if( tmpDist == dist )
|
||||
{
|
||||
sumx += dx; sumy += dy;
|
||||
countMin++;
|
||||
}
|
||||
}
|
||||
|
||||
if( dist > escapeLevel )
|
||||
{
|
||||
sumx = offX;
|
||||
sumy = offY;
|
||||
countMin = 1;
|
||||
}
|
||||
}
|
||||
|
||||
vx[j] = (float)sumx/countMin;
|
||||
vy[j] = (float)sumy/countMin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
@@ -1,524 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#include "precomp.hpp"
|
||||
|
||||
#define CONV( A, B, C) ( (float)( A + (B<<1) + C ) )
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float xx;
|
||||
float xy;
|
||||
float yy;
|
||||
float xt;
|
||||
float yt;
|
||||
float alpha; /* alpha = 1 / ( 1/lambda + xx + yy ) */
|
||||
}
|
||||
icvDerProductEx;
|
||||
|
||||
/*F///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Name: icvCalcOpticalFlowHS_8u32fR (Horn & Schunck method )
|
||||
// Purpose: calculate Optical flow for 2 images using Horn & Schunck algorithm
|
||||
// Context:
|
||||
// Parameters:
|
||||
// imgA - pointer to first frame ROI
|
||||
// imgB - pointer to second frame ROI
|
||||
// imgStep - width of single row of source images in bytes
|
||||
// imgSize - size of the source image ROI
|
||||
// usePrevious - use previous (input) velocity field.
|
||||
// velocityX - pointer to horizontal and
|
||||
// velocityY - vertical components of optical flow ROI
|
||||
// velStep - width of single row of velocity frames in bytes
|
||||
// lambda - Lagrangian multiplier
|
||||
// criteria - criteria of termination processmaximum number of iterations
|
||||
//
|
||||
// Returns: CV_OK - all ok
|
||||
// CV_OUTOFMEM_ERR - insufficient memory for function work
|
||||
// CV_NULLPTR_ERR - if one of input pointers is NULL
|
||||
// CV_BADSIZE_ERR - wrong input sizes interrelation
|
||||
//
|
||||
// Notes: 1.Optical flow to be computed for every pixel in ROI
|
||||
// 2.For calculating spatial derivatives we use 3x3 Sobel operator.
|
||||
// 3.We use the following border mode.
|
||||
// The last row or column is replicated for the border
|
||||
// ( IPL_BORDER_REPLICATE in IPL ).
|
||||
//
|
||||
//
|
||||
//F*/
|
||||
static CvStatus CV_STDCALL
|
||||
icvCalcOpticalFlowHS_8u32fR( uchar* imgA,
|
||||
uchar* imgB,
|
||||
int imgStep,
|
||||
CvSize imgSize,
|
||||
int usePrevious,
|
||||
float* velocityX,
|
||||
float* velocityY,
|
||||
int velStep,
|
||||
float lambda,
|
||||
CvTermCriteria criteria )
|
||||
{
|
||||
/* Loops indexes */
|
||||
int i, j, k, address;
|
||||
|
||||
/* Buffers for Sobel calculations */
|
||||
float *MemX[2];
|
||||
float *MemY[2];
|
||||
|
||||
float ConvX, ConvY;
|
||||
float GradX, GradY, GradT;
|
||||
|
||||
int imageWidth = imgSize.width;
|
||||
int imageHeight = imgSize.height;
|
||||
|
||||
int ConvLine;
|
||||
int LastLine;
|
||||
|
||||
int BufferSize;
|
||||
|
||||
float Ilambda = 1 / lambda;
|
||||
int iter = 0;
|
||||
int Stop;
|
||||
|
||||
/* buffers derivatives product */
|
||||
icvDerProductEx *II;
|
||||
|
||||
float *VelBufX[2];
|
||||
float *VelBufY[2];
|
||||
|
||||
/* variables for storing number of first pixel of image line */
|
||||
int Line1;
|
||||
int Line2;
|
||||
int Line3;
|
||||
|
||||
int pixNumber;
|
||||
|
||||
/* auxiliary */
|
||||
int NoMem = 0;
|
||||
|
||||
/* Checking bad arguments */
|
||||
if( imgA == NULL )
|
||||
return CV_NULLPTR_ERR;
|
||||
if( imgB == NULL )
|
||||
return CV_NULLPTR_ERR;
|
||||
|
||||
if( imgSize.width <= 0 )
|
||||
return CV_BADSIZE_ERR;
|
||||
if( imgSize.height <= 0 )
|
||||
return CV_BADSIZE_ERR;
|
||||
if( imgSize.width > imgStep )
|
||||
return CV_BADSIZE_ERR;
|
||||
|
||||
if( (velStep & 3) != 0 )
|
||||
return CV_BADSIZE_ERR;
|
||||
|
||||
velStep /= 4;
|
||||
|
||||
/****************************************************************************************/
|
||||
/* Allocating memory for all buffers */
|
||||
/****************************************************************************************/
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
MemX[k] = (float *) cvAlloc( (imgSize.height) * sizeof( float ));
|
||||
|
||||
if( MemX[k] == NULL )
|
||||
NoMem = 1;
|
||||
MemY[k] = (float *) cvAlloc( (imgSize.width) * sizeof( float ));
|
||||
|
||||
if( MemY[k] == NULL )
|
||||
NoMem = 1;
|
||||
|
||||
VelBufX[k] = (float *) cvAlloc( imageWidth * sizeof( float ));
|
||||
|
||||
if( VelBufX[k] == NULL )
|
||||
NoMem = 1;
|
||||
VelBufY[k] = (float *) cvAlloc( imageWidth * sizeof( float ));
|
||||
|
||||
if( VelBufY[k] == NULL )
|
||||
NoMem = 1;
|
||||
}
|
||||
|
||||
BufferSize = imageHeight * imageWidth;
|
||||
|
||||
II = (icvDerProductEx *) cvAlloc( BufferSize * sizeof( icvDerProductEx ));
|
||||
if( II == NULL )
|
||||
NoMem = 1;
|
||||
|
||||
if( NoMem )
|
||||
{
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
if( MemX[k] )
|
||||
cvFree( &MemX[k] );
|
||||
|
||||
if( MemY[k] )
|
||||
cvFree( &MemY[k] );
|
||||
|
||||
if( VelBufX[k] )
|
||||
cvFree( &VelBufX[k] );
|
||||
|
||||
if( VelBufY[k] )
|
||||
cvFree( &VelBufY[k] );
|
||||
}
|
||||
if( II )
|
||||
cvFree( &II );
|
||||
return CV_OUTOFMEM_ERR;
|
||||
}
|
||||
/****************************************************************************************\
|
||||
* Calculate first line of memX and memY *
|
||||
\****************************************************************************************/
|
||||
MemY[0][0] = MemY[1][0] = CONV( imgA[0], imgA[0], imgA[1] );
|
||||
MemX[0][0] = MemX[1][0] = CONV( imgA[0], imgA[0], imgA[imgStep] );
|
||||
|
||||
for( j = 1; j < imageWidth - 1; j++ )
|
||||
{
|
||||
MemY[0][j] = MemY[1][j] = CONV( imgA[j - 1], imgA[j], imgA[j + 1] );
|
||||
}
|
||||
|
||||
pixNumber = imgStep;
|
||||
for( i = 1; i < imageHeight - 1; i++ )
|
||||
{
|
||||
MemX[0][i] = MemX[1][i] = CONV( imgA[pixNumber - imgStep],
|
||||
imgA[pixNumber], imgA[pixNumber + imgStep] );
|
||||
pixNumber += imgStep;
|
||||
}
|
||||
|
||||
MemY[0][imageWidth - 1] =
|
||||
MemY[1][imageWidth - 1] = CONV( imgA[imageWidth - 2],
|
||||
imgA[imageWidth - 1], imgA[imageWidth - 1] );
|
||||
|
||||
MemX[0][imageHeight - 1] =
|
||||
MemX[1][imageHeight - 1] = CONV( imgA[pixNumber - imgStep],
|
||||
imgA[pixNumber], imgA[pixNumber] );
|
||||
|
||||
|
||||
/****************************************************************************************\
|
||||
* begin scan image, calc derivatives *
|
||||
\****************************************************************************************/
|
||||
|
||||
ConvLine = 0;
|
||||
Line2 = -imgStep;
|
||||
address = 0;
|
||||
LastLine = imgStep * (imageHeight - 1);
|
||||
while( ConvLine < imageHeight )
|
||||
{
|
||||
/*Here we calculate derivatives for line of image */
|
||||
int memYline = (ConvLine + 1) & 1;
|
||||
|
||||
Line2 += imgStep;
|
||||
Line1 = Line2 - ((Line2 == 0) ? 0 : imgStep);
|
||||
Line3 = Line2 + ((Line2 == LastLine) ? 0 : imgStep);
|
||||
|
||||
/* Process first pixel */
|
||||
ConvX = CONV( imgA[Line1 + 1], imgA[Line2 + 1], imgA[Line3 + 1] );
|
||||
ConvY = CONV( imgA[Line3], imgA[Line3], imgA[Line3 + 1] );
|
||||
|
||||
GradY = (ConvY - MemY[memYline][0]) * 0.125f;
|
||||
GradX = (ConvX - MemX[1][ConvLine]) * 0.125f;
|
||||
|
||||
MemY[memYline][0] = ConvY;
|
||||
MemX[1][ConvLine] = ConvX;
|
||||
|
||||
GradT = (float) (imgB[Line2] - imgA[Line2]);
|
||||
|
||||
II[address].xx = GradX * GradX;
|
||||
II[address].xy = GradX * GradY;
|
||||
II[address].yy = GradY * GradY;
|
||||
II[address].xt = GradX * GradT;
|
||||
II[address].yt = GradY * GradT;
|
||||
|
||||
II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
|
||||
address++;
|
||||
|
||||
/* Process middle of line */
|
||||
for( j = 1; j < imageWidth - 1; j++ )
|
||||
{
|
||||
ConvX = CONV( imgA[Line1 + j + 1], imgA[Line2 + j + 1], imgA[Line3 + j + 1] );
|
||||
ConvY = CONV( imgA[Line3 + j - 1], imgA[Line3 + j], imgA[Line3 + j + 1] );
|
||||
|
||||
GradY = (ConvY - MemY[memYline][j]) * 0.125f;
|
||||
GradX = (ConvX - MemX[(j - 1) & 1][ConvLine]) * 0.125f;
|
||||
|
||||
MemY[memYline][j] = ConvY;
|
||||
MemX[(j - 1) & 1][ConvLine] = ConvX;
|
||||
|
||||
GradT = (float) (imgB[Line2 + j] - imgA[Line2 + j]);
|
||||
|
||||
II[address].xx = GradX * GradX;
|
||||
II[address].xy = GradX * GradY;
|
||||
II[address].yy = GradY * GradY;
|
||||
II[address].xt = GradX * GradT;
|
||||
II[address].yt = GradY * GradT;
|
||||
|
||||
II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
|
||||
address++;
|
||||
}
|
||||
/* Process last pixel of line */
|
||||
ConvX = CONV( imgA[Line1 + imageWidth - 1], imgA[Line2 + imageWidth - 1],
|
||||
imgA[Line3 + imageWidth - 1] );
|
||||
|
||||
ConvY = CONV( imgA[Line3 + imageWidth - 2], imgA[Line3 + imageWidth - 1],
|
||||
imgA[Line3 + imageWidth - 1] );
|
||||
|
||||
|
||||
GradY = (ConvY - MemY[memYline][imageWidth - 1]) * 0.125f;
|
||||
GradX = (ConvX - MemX[(imageWidth - 2) & 1][ConvLine]) * 0.125f;
|
||||
|
||||
MemY[memYline][imageWidth - 1] = ConvY;
|
||||
|
||||
GradT = (float) (imgB[Line2 + imageWidth - 1] - imgA[Line2 + imageWidth - 1]);
|
||||
|
||||
II[address].xx = GradX * GradX;
|
||||
II[address].xy = GradX * GradY;
|
||||
II[address].yy = GradY * GradY;
|
||||
II[address].xt = GradX * GradT;
|
||||
II[address].yt = GradY * GradT;
|
||||
|
||||
II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
|
||||
address++;
|
||||
|
||||
ConvLine++;
|
||||
}
|
||||
/****************************************************************************************\
|
||||
* Prepare initial approximation *
|
||||
\****************************************************************************************/
|
||||
if( !usePrevious )
|
||||
{
|
||||
float *vx = velocityX;
|
||||
float *vy = velocityY;
|
||||
|
||||
for( i = 0; i < imageHeight; i++ )
|
||||
{
|
||||
memset( vx, 0, imageWidth * sizeof( float ));
|
||||
memset( vy, 0, imageWidth * sizeof( float ));
|
||||
|
||||
vx += velStep;
|
||||
vy += velStep;
|
||||
}
|
||||
}
|
||||
/****************************************************************************************\
|
||||
* Perform iterations *
|
||||
\****************************************************************************************/
|
||||
iter = 0;
|
||||
Stop = 0;
|
||||
LastLine = velStep * (imageHeight - 1);
|
||||
while( !Stop )
|
||||
{
|
||||
float Eps = 0;
|
||||
address = 0;
|
||||
|
||||
iter++;
|
||||
/****************************************************************************************\
|
||||
* begin scan velocity and update it *
|
||||
\****************************************************************************************/
|
||||
Line2 = -velStep;
|
||||
for( i = 0; i < imageHeight; i++ )
|
||||
{
|
||||
/* Here average velocity */
|
||||
|
||||
float averageX;
|
||||
float averageY;
|
||||
float tmp;
|
||||
|
||||
Line2 += velStep;
|
||||
Line1 = Line2 - ((Line2 == 0) ? 0 : velStep);
|
||||
Line3 = Line2 + ((Line2 == LastLine) ? 0 : velStep);
|
||||
/* Process first pixel */
|
||||
averageX = (velocityX[Line2] +
|
||||
velocityX[Line2 + 1] + velocityX[Line1] + velocityX[Line3]) / 4;
|
||||
|
||||
averageY = (velocityY[Line2] +
|
||||
velocityY[Line2 + 1] + velocityY[Line1] + velocityY[Line3]) / 4;
|
||||
|
||||
VelBufX[i & 1][0] = averageX -
|
||||
(II[address].xx * averageX +
|
||||
II[address].xy * averageY + II[address].xt) * II[address].alpha;
|
||||
|
||||
VelBufY[i & 1][0] = averageY -
|
||||
(II[address].xy * averageX +
|
||||
II[address].yy * averageY + II[address].yt) * II[address].alpha;
|
||||
|
||||
/* update Epsilon */
|
||||
if( criteria.type & CV_TERMCRIT_EPS )
|
||||
{
|
||||
tmp = (float)fabs(velocityX[Line2] - VelBufX[i & 1][0]);
|
||||
Eps = MAX( tmp, Eps );
|
||||
tmp = (float)fabs(velocityY[Line2] - VelBufY[i & 1][0]);
|
||||
Eps = MAX( tmp, Eps );
|
||||
}
|
||||
address++;
|
||||
/* Process middle of line */
|
||||
for( j = 1; j < imageWidth - 1; j++ )
|
||||
{
|
||||
averageX = (velocityX[Line2 + j - 1] +
|
||||
velocityX[Line2 + j + 1] +
|
||||
velocityX[Line1 + j] + velocityX[Line3 + j]) / 4;
|
||||
averageY = (velocityY[Line2 + j - 1] +
|
||||
velocityY[Line2 + j + 1] +
|
||||
velocityY[Line1 + j] + velocityY[Line3 + j]) / 4;
|
||||
|
||||
VelBufX[i & 1][j] = averageX -
|
||||
(II[address].xx * averageX +
|
||||
II[address].xy * averageY + II[address].xt) * II[address].alpha;
|
||||
|
||||
VelBufY[i & 1][j] = averageY -
|
||||
(II[address].xy * averageX +
|
||||
II[address].yy * averageY + II[address].yt) * II[address].alpha;
|
||||
/* update Epsilon */
|
||||
if( criteria.type & CV_TERMCRIT_EPS )
|
||||
{
|
||||
tmp = (float)fabs(velocityX[Line2 + j] - VelBufX[i & 1][j]);
|
||||
Eps = MAX( tmp, Eps );
|
||||
tmp = (float)fabs(velocityY[Line2 + j] - VelBufY[i & 1][j]);
|
||||
Eps = MAX( tmp, Eps );
|
||||
}
|
||||
address++;
|
||||
}
|
||||
/* Process last pixel of line */
|
||||
averageX = (velocityX[Line2 + imageWidth - 2] +
|
||||
velocityX[Line2 + imageWidth - 1] +
|
||||
velocityX[Line1 + imageWidth - 1] +
|
||||
velocityX[Line3 + imageWidth - 1]) / 4;
|
||||
|
||||
averageY = (velocityY[Line2 + imageWidth - 2] +
|
||||
velocityY[Line2 + imageWidth - 1] +
|
||||
velocityY[Line1 + imageWidth - 1] +
|
||||
velocityY[Line3 + imageWidth - 1]) / 4;
|
||||
|
||||
|
||||
VelBufX[i & 1][imageWidth - 1] = averageX -
|
||||
(II[address].xx * averageX +
|
||||
II[address].xy * averageY + II[address].xt) * II[address].alpha;
|
||||
|
||||
VelBufY[i & 1][imageWidth - 1] = averageY -
|
||||
(II[address].xy * averageX +
|
||||
II[address].yy * averageY + II[address].yt) * II[address].alpha;
|
||||
|
||||
/* update Epsilon */
|
||||
if( criteria.type & CV_TERMCRIT_EPS )
|
||||
{
|
||||
tmp = (float)fabs(velocityX[Line2 + imageWidth - 1] -
|
||||
VelBufX[i & 1][imageWidth - 1]);
|
||||
Eps = MAX( tmp, Eps );
|
||||
tmp = (float)fabs(velocityY[Line2 + imageWidth - 1] -
|
||||
VelBufY[i & 1][imageWidth - 1]);
|
||||
Eps = MAX( tmp, Eps );
|
||||
}
|
||||
address++;
|
||||
|
||||
/* store new velocity from old buffer to velocity frame */
|
||||
if( i > 0 )
|
||||
{
|
||||
memcpy( &velocityX[Line1], VelBufX[(i - 1) & 1], imageWidth * sizeof( float ));
|
||||
memcpy( &velocityY[Line1], VelBufY[(i - 1) & 1], imageWidth * sizeof( float ));
|
||||
}
|
||||
} /*for */
|
||||
/* store new velocity from old buffer to velocity frame */
|
||||
memcpy( &velocityX[imageWidth * (imageHeight - 1)],
|
||||
VelBufX[(imageHeight - 1) & 1], imageWidth * sizeof( float ));
|
||||
|
||||
memcpy( &velocityY[imageWidth * (imageHeight - 1)],
|
||||
VelBufY[(imageHeight - 1) & 1], imageWidth * sizeof( float ));
|
||||
|
||||
if( (criteria.type & CV_TERMCRIT_ITER) && (iter == criteria.max_iter) )
|
||||
Stop = 1;
|
||||
if( (criteria.type & CV_TERMCRIT_EPS) && (Eps < criteria.epsilon) )
|
||||
Stop = 1;
|
||||
}
|
||||
/* Free memory */
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
cvFree( &MemX[k] );
|
||||
cvFree( &MemY[k] );
|
||||
cvFree( &VelBufX[k] );
|
||||
cvFree( &VelBufY[k] );
|
||||
}
|
||||
cvFree( &II );
|
||||
|
||||
return CV_OK;
|
||||
} /*icvCalcOpticalFlowHS_8u32fR*/
|
||||
|
||||
|
||||
/*F///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Name: cvCalcOpticalFlowHS
|
||||
// Purpose: Optical flow implementation
|
||||
// Context:
|
||||
// Parameters:
|
||||
// srcA, srcB - source image
|
||||
// velx, vely - destination image
|
||||
// Returns:
|
||||
//
|
||||
// Notes:
|
||||
//F*/
|
||||
CV_IMPL void
|
||||
cvCalcOpticalFlowHS( const void* srcarrA, const void* srcarrB, int usePrevious,
|
||||
void* velarrx, void* velarry,
|
||||
double lambda, CvTermCriteria criteria )
|
||||
{
|
||||
CvMat stubA, *srcA = cvGetMat( srcarrA, &stubA );
|
||||
CvMat stubB, *srcB = cvGetMat( srcarrB, &stubB );
|
||||
CvMat stubx, *velx = cvGetMat( velarrx, &stubx );
|
||||
CvMat stuby, *vely = cvGetMat( velarry, &stuby );
|
||||
|
||||
if( !CV_ARE_TYPES_EQ( srcA, srcB ))
|
||||
CV_Error( CV_StsUnmatchedFormats, "Source images have different formats" );
|
||||
|
||||
if( !CV_ARE_TYPES_EQ( velx, vely ))
|
||||
CV_Error( CV_StsUnmatchedFormats, "Destination images have different formats" );
|
||||
|
||||
if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
|
||||
!CV_ARE_SIZES_EQ( velx, vely ) ||
|
||||
!CV_ARE_SIZES_EQ( srcA, velx ))
|
||||
CV_Error( CV_StsUnmatchedSizes, "" );
|
||||
|
||||
if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
|
||||
CV_MAT_TYPE( velx->type ) != CV_32FC1 )
|
||||
CV_Error( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
|
||||
"destination images must have 32fC1 type" );
|
||||
|
||||
if( srcA->step != srcB->step || velx->step != vely->step )
|
||||
CV_Error( CV_BadStep, "source and destination images have different step" );
|
||||
|
||||
IPPI_CALL( icvCalcOpticalFlowHS_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
|
||||
srcA->step, cvGetMatSize( srcA ), usePrevious,
|
||||
velx->data.fl, vely->data.fl,
|
||||
velx->step, (float)lambda, criteria ));
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
@@ -1,599 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#include "precomp.hpp"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float xx;
|
||||
float xy;
|
||||
float yy;
|
||||
float xt;
|
||||
float yt;
|
||||
}
|
||||
icvDerProduct;
|
||||
|
||||
|
||||
#define CONV( A, B, C) ((float)( A + (B<<1) + C ))
|
||||
/*F///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Name: icvCalcOpticalFlowLK_8u32fR ( Lucas & Kanade method )
|
||||
// Purpose: calculate Optical flow for 2 images using Lucas & Kanade algorithm
|
||||
// Context:
|
||||
// Parameters:
|
||||
// imgA, // pointer to first frame ROI
|
||||
// imgB, // pointer to second frame ROI
|
||||
// imgStep, // width of single row of source images in bytes
|
||||
// imgSize, // size of the source image ROI
|
||||
// winSize, // size of the averaging window used for grouping
|
||||
// velocityX, // pointer to horizontal and
|
||||
// velocityY, // vertical components of optical flow ROI
|
||||
// velStep // width of single row of velocity frames in bytes
|
||||
//
|
||||
// Returns: CV_OK - all ok
|
||||
// CV_OUTOFMEM_ERR - insufficient memory for function work
|
||||
// CV_NULLPTR_ERR - if one of input pointers is NULL
|
||||
// CV_BADSIZE_ERR - wrong input sizes interrelation
|
||||
//
|
||||
// Notes: 1.Optical flow to be computed for every pixel in ROI
|
||||
// 2.For calculating spatial derivatives we use 3x3 Sobel operator.
|
||||
// 3.We use the following border mode.
|
||||
// The last row or column is replicated for the border
|
||||
// ( IPL_BORDER_REPLICATE in IPL ).
|
||||
//
|
||||
//
|
||||
//F*/
|
||||
static CvStatus CV_STDCALL
|
||||
icvCalcOpticalFlowLK_8u32fR( uchar * imgA,
|
||||
uchar * imgB,
|
||||
int imgStep,
|
||||
CvSize imgSize,
|
||||
CvSize winSize,
|
||||
float *velocityX,
|
||||
float *velocityY, int velStep )
|
||||
{
|
||||
/* Loops indexes */
|
||||
int i, j, k;
|
||||
|
||||
/* Gaussian separable kernels */
|
||||
float GaussX[16];
|
||||
float GaussY[16];
|
||||
float *KerX;
|
||||
float *KerY;
|
||||
|
||||
/* Buffers for Sobel calculations */
|
||||
float *MemX[2];
|
||||
float *MemY[2];
|
||||
|
||||
float ConvX, ConvY;
|
||||
float GradX, GradY, GradT;
|
||||
|
||||
int winWidth = winSize.width;
|
||||
int winHeight = winSize.height;
|
||||
|
||||
int imageWidth = imgSize.width;
|
||||
int imageHeight = imgSize.height;
|
||||
|
||||
int HorRadius = (winWidth - 1) >> 1;
|
||||
int VerRadius = (winHeight - 1) >> 1;
|
||||
|
||||
int PixelLine;
|
||||
int ConvLine;
|
||||
|
||||
int BufferAddress;
|
||||
|
||||
int BufferHeight = 0;
|
||||
int BufferWidth;
|
||||
int BufferSize;
|
||||
|
||||
/* buffers derivatives product */
|
||||
icvDerProduct *II;
|
||||
|
||||
/* buffers for gaussian horisontal convolution */
|
||||
icvDerProduct *WII;
|
||||
|
||||
/* variables for storing number of first pixel of image line */
|
||||
int Line1;
|
||||
int Line2;
|
||||
int Line3;
|
||||
|
||||
/* we must have 2*2 linear system coeffs
|
||||
| A1B2 B1 | {u} {C1} {0}
|
||||
| | { } + { } = { }
|
||||
| A2 A1B2 | {v} {C2} {0}
|
||||
*/
|
||||
float A1B2, A2, B1, C1, C2;
|
||||
|
||||
int pixNumber;
|
||||
|
||||
/* auxiliary */
|
||||
int NoMem = 0;
|
||||
|
||||
velStep /= sizeof(velocityX[0]);
|
||||
|
||||
/* Checking bad arguments */
|
||||
if( imgA == NULL )
|
||||
return CV_NULLPTR_ERR;
|
||||
if( imgB == NULL )
|
||||
return CV_NULLPTR_ERR;
|
||||
|
||||
if( imageHeight < winHeight )
|
||||
return CV_BADSIZE_ERR;
|
||||
if( imageWidth < winWidth )
|
||||
return CV_BADSIZE_ERR;
|
||||
|
||||
if( winHeight >= 16 )
|
||||
return CV_BADSIZE_ERR;
|
||||
if( winWidth >= 16 )
|
||||
return CV_BADSIZE_ERR;
|
||||
|
||||
if( !(winHeight & 1) )
|
||||
return CV_BADSIZE_ERR;
|
||||
if( !(winWidth & 1) )
|
||||
return CV_BADSIZE_ERR;
|
||||
|
||||
BufferHeight = winHeight;
|
||||
BufferWidth = imageWidth;
|
||||
|
||||
/****************************************************************************************/
|
||||
/* Computing Gaussian coeffs */
|
||||
/****************************************************************************************/
|
||||
GaussX[0] = 1;
|
||||
GaussY[0] = 1;
|
||||
for( i = 1; i < winWidth; i++ )
|
||||
{
|
||||
GaussX[i] = 1;
|
||||
for( j = i - 1; j > 0; j-- )
|
||||
{
|
||||
GaussX[j] += GaussX[j - 1];
|
||||
}
|
||||
}
|
||||
for( i = 1; i < winHeight; i++ )
|
||||
{
|
||||
GaussY[i] = 1;
|
||||
for( j = i - 1; j > 0; j-- )
|
||||
{
|
||||
GaussY[j] += GaussY[j - 1];
|
||||
}
|
||||
}
|
||||
KerX = &GaussX[HorRadius];
|
||||
KerY = &GaussY[VerRadius];
|
||||
|
||||
/****************************************************************************************/
|
||||
/* Allocating memory for all buffers */
|
||||
/****************************************************************************************/
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
MemX[k] = (float *) cvAlloc( (imgSize.height) * sizeof( float ));
|
||||
|
||||
if( MemX[k] == NULL )
|
||||
NoMem = 1;
|
||||
MemY[k] = (float *) cvAlloc( (imgSize.width) * sizeof( float ));
|
||||
|
||||
if( MemY[k] == NULL )
|
||||
NoMem = 1;
|
||||
}
|
||||
|
||||
BufferSize = BufferHeight * BufferWidth;
|
||||
|
||||
II = (icvDerProduct *) cvAlloc( BufferSize * sizeof( icvDerProduct ));
|
||||
WII = (icvDerProduct *) cvAlloc( BufferSize * sizeof( icvDerProduct ));
|
||||
|
||||
|
||||
if( (II == NULL) || (WII == NULL) )
|
||||
NoMem = 1;
|
||||
|
||||
if( NoMem )
|
||||
{
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
if( MemX[k] )
|
||||
cvFree( &MemX[k] );
|
||||
|
||||
if( MemY[k] )
|
||||
cvFree( &MemY[k] );
|
||||
}
|
||||
if( II )
|
||||
cvFree( &II );
|
||||
if( WII )
|
||||
cvFree( &WII );
|
||||
|
||||
return CV_OUTOFMEM_ERR;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* Calculate first line of memX and memY */
|
||||
/****************************************************************************************/
|
||||
MemY[0][0] = MemY[1][0] = CONV( imgA[0], imgA[0], imgA[1] );
|
||||
MemX[0][0] = MemX[1][0] = CONV( imgA[0], imgA[0], imgA[imgStep] );
|
||||
|
||||
for( j = 1; j < imageWidth - 1; j++ )
|
||||
{
|
||||
MemY[0][j] = MemY[1][j] = CONV( imgA[j - 1], imgA[j], imgA[j + 1] );
|
||||
}
|
||||
|
||||
pixNumber = imgStep;
|
||||
for( i = 1; i < imageHeight - 1; i++ )
|
||||
{
|
||||
MemX[0][i] = MemX[1][i] = CONV( imgA[pixNumber - imgStep],
|
||||
imgA[pixNumber], imgA[pixNumber + imgStep] );
|
||||
pixNumber += imgStep;
|
||||
}
|
||||
|
||||
MemY[0][imageWidth - 1] =
|
||||
MemY[1][imageWidth - 1] = CONV( imgA[imageWidth - 2],
|
||||
imgA[imageWidth - 1], imgA[imageWidth - 1] );
|
||||
|
||||
MemX[0][imageHeight - 1] =
|
||||
MemX[1][imageHeight - 1] = CONV( imgA[pixNumber - imgStep],
|
||||
imgA[pixNumber], imgA[pixNumber] );
|
||||
|
||||
|
||||
/****************************************************************************************/
|
||||
/* begin scan image, calc derivatives and solve system */
|
||||
/****************************************************************************************/
|
||||
|
||||
PixelLine = -VerRadius;
|
||||
ConvLine = 0;
|
||||
BufferAddress = -BufferWidth;
|
||||
|
||||
while( PixelLine < imageHeight )
|
||||
{
|
||||
if( ConvLine < imageHeight )
|
||||
{
|
||||
/*Here we calculate derivatives for line of image */
|
||||
int address;
|
||||
|
||||
i = ConvLine;
|
||||
int L1 = i - 1;
|
||||
int L2 = i;
|
||||
int L3 = i + 1;
|
||||
|
||||
int memYline = L3 & 1;
|
||||
|
||||
if( L1 < 0 )
|
||||
L1 = 0;
|
||||
if( L3 >= imageHeight )
|
||||
L3 = imageHeight - 1;
|
||||
|
||||
BufferAddress += BufferWidth;
|
||||
BufferAddress -= ((BufferAddress >= BufferSize) ? 0xffffffff : 0) & BufferSize;
|
||||
|
||||
address = BufferAddress;
|
||||
|
||||
Line1 = L1 * imgStep;
|
||||
Line2 = L2 * imgStep;
|
||||
Line3 = L3 * imgStep;
|
||||
|
||||
/* Process first pixel */
|
||||
ConvX = CONV( imgA[Line1 + 1], imgA[Line2 + 1], imgA[Line3 + 1] );
|
||||
ConvY = CONV( imgA[Line3], imgA[Line3], imgA[Line3 + 1] );
|
||||
|
||||
GradY = ConvY - MemY[memYline][0];
|
||||
GradX = ConvX - MemX[1][L2];
|
||||
|
||||
MemY[memYline][0] = ConvY;
|
||||
MemX[1][L2] = ConvX;
|
||||
|
||||
GradT = (float) (imgB[Line2] - imgA[Line2]);
|
||||
|
||||
II[address].xx = GradX * GradX;
|
||||
II[address].xy = GradX * GradY;
|
||||
II[address].yy = GradY * GradY;
|
||||
II[address].xt = GradX * GradT;
|
||||
II[address].yt = GradY * GradT;
|
||||
address++;
|
||||
/* Process middle of line */
|
||||
for( j = 1; j < imageWidth - 1; j++ )
|
||||
{
|
||||
ConvX = CONV( imgA[Line1 + j + 1], imgA[Line2 + j + 1], imgA[Line3 + j + 1] );
|
||||
ConvY = CONV( imgA[Line3 + j - 1], imgA[Line3 + j], imgA[Line3 + j + 1] );
|
||||
|
||||
GradY = ConvY - MemY[memYline][j];
|
||||
GradX = ConvX - MemX[(j - 1) & 1][L2];
|
||||
|
||||
MemY[memYline][j] = ConvY;
|
||||
MemX[(j - 1) & 1][L2] = ConvX;
|
||||
|
||||
GradT = (float) (imgB[Line2 + j] - imgA[Line2 + j]);
|
||||
|
||||
II[address].xx = GradX * GradX;
|
||||
II[address].xy = GradX * GradY;
|
||||
II[address].yy = GradY * GradY;
|
||||
II[address].xt = GradX * GradT;
|
||||
II[address].yt = GradY * GradT;
|
||||
|
||||
address++;
|
||||
}
|
||||
/* Process last pixel of line */
|
||||
ConvX = CONV( imgA[Line1 + imageWidth - 1], imgA[Line2 + imageWidth - 1],
|
||||
imgA[Line3 + imageWidth - 1] );
|
||||
|
||||
ConvY = CONV( imgA[Line3 + imageWidth - 2], imgA[Line3 + imageWidth - 1],
|
||||
imgA[Line3 + imageWidth - 1] );
|
||||
|
||||
|
||||
GradY = ConvY - MemY[memYline][imageWidth - 1];
|
||||
GradX = ConvX - MemX[(imageWidth - 2) & 1][L2];
|
||||
|
||||
MemY[memYline][imageWidth - 1] = ConvY;
|
||||
|
||||
GradT = (float) (imgB[Line2 + imageWidth - 1] - imgA[Line2 + imageWidth - 1]);
|
||||
|
||||
II[address].xx = GradX * GradX;
|
||||
II[address].xy = GradX * GradY;
|
||||
II[address].yy = GradY * GradY;
|
||||
II[address].xt = GradX * GradT;
|
||||
II[address].yt = GradY * GradT;
|
||||
address++;
|
||||
|
||||
/* End of derivatives for line */
|
||||
|
||||
/****************************************************************************************/
|
||||
/* ---------Calculating horizontal convolution of processed line----------------------- */
|
||||
/****************************************************************************************/
|
||||
address -= BufferWidth;
|
||||
/* process first HorRadius pixels */
|
||||
for( j = 0; j < HorRadius; j++ )
|
||||
{
|
||||
int jj;
|
||||
|
||||
WII[address].xx = 0;
|
||||
WII[address].xy = 0;
|
||||
WII[address].yy = 0;
|
||||
WII[address].xt = 0;
|
||||
WII[address].yt = 0;
|
||||
|
||||
for( jj = -j; jj <= HorRadius; jj++ )
|
||||
{
|
||||
float Ker = KerX[jj];
|
||||
|
||||
WII[address].xx += II[address + jj].xx * Ker;
|
||||
WII[address].xy += II[address + jj].xy * Ker;
|
||||
WII[address].yy += II[address + jj].yy * Ker;
|
||||
WII[address].xt += II[address + jj].xt * Ker;
|
||||
WII[address].yt += II[address + jj].yt * Ker;
|
||||
}
|
||||
address++;
|
||||
}
|
||||
/* process inner part of line */
|
||||
for( j = HorRadius; j < imageWidth - HorRadius; j++ )
|
||||
{
|
||||
int jj;
|
||||
float Ker0 = KerX[0];
|
||||
|
||||
WII[address].xx = 0;
|
||||
WII[address].xy = 0;
|
||||
WII[address].yy = 0;
|
||||
WII[address].xt = 0;
|
||||
WII[address].yt = 0;
|
||||
|
||||
for( jj = 1; jj <= HorRadius; jj++ )
|
||||
{
|
||||
float Ker = KerX[jj];
|
||||
|
||||
WII[address].xx += (II[address - jj].xx + II[address + jj].xx) * Ker;
|
||||
WII[address].xy += (II[address - jj].xy + II[address + jj].xy) * Ker;
|
||||
WII[address].yy += (II[address - jj].yy + II[address + jj].yy) * Ker;
|
||||
WII[address].xt += (II[address - jj].xt + II[address + jj].xt) * Ker;
|
||||
WII[address].yt += (II[address - jj].yt + II[address + jj].yt) * Ker;
|
||||
}
|
||||
WII[address].xx += II[address].xx * Ker0;
|
||||
WII[address].xy += II[address].xy * Ker0;
|
||||
WII[address].yy += II[address].yy * Ker0;
|
||||
WII[address].xt += II[address].xt * Ker0;
|
||||
WII[address].yt += II[address].yt * Ker0;
|
||||
|
||||
address++;
|
||||
}
|
||||
/* process right side */
|
||||
for( j = imageWidth - HorRadius; j < imageWidth; j++ )
|
||||
{
|
||||
int jj;
|
||||
|
||||
WII[address].xx = 0;
|
||||
WII[address].xy = 0;
|
||||
WII[address].yy = 0;
|
||||
WII[address].xt = 0;
|
||||
WII[address].yt = 0;
|
||||
|
||||
for( jj = -HorRadius; jj < imageWidth - j; jj++ )
|
||||
{
|
||||
float Ker = KerX[jj];
|
||||
|
||||
WII[address].xx += II[address + jj].xx * Ker;
|
||||
WII[address].xy += II[address + jj].xy * Ker;
|
||||
WII[address].yy += II[address + jj].yy * Ker;
|
||||
WII[address].xt += II[address + jj].xt * Ker;
|
||||
WII[address].yt += II[address + jj].yt * Ker;
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
/* Calculating velocity line */
|
||||
/****************************************************************************************/
|
||||
if( PixelLine >= 0 )
|
||||
{
|
||||
int USpace;
|
||||
int BSpace;
|
||||
int address;
|
||||
|
||||
if( PixelLine < VerRadius )
|
||||
USpace = PixelLine;
|
||||
else
|
||||
USpace = VerRadius;
|
||||
|
||||
if( PixelLine >= imageHeight - VerRadius )
|
||||
BSpace = imageHeight - PixelLine - 1;
|
||||
else
|
||||
BSpace = VerRadius;
|
||||
|
||||
address = ((PixelLine - USpace) % BufferHeight) * BufferWidth;
|
||||
for( j = 0; j < imageWidth; j++ )
|
||||
{
|
||||
int addr = address;
|
||||
|
||||
A1B2 = 0;
|
||||
A2 = 0;
|
||||
B1 = 0;
|
||||
C1 = 0;
|
||||
C2 = 0;
|
||||
|
||||
for( i = -USpace; i <= BSpace; i++ )
|
||||
{
|
||||
A2 += WII[addr + j].xx * KerY[i];
|
||||
A1B2 += WII[addr + j].xy * KerY[i];
|
||||
B1 += WII[addr + j].yy * KerY[i];
|
||||
C2 += WII[addr + j].xt * KerY[i];
|
||||
C1 += WII[addr + j].yt * KerY[i];
|
||||
|
||||
addr += BufferWidth;
|
||||
addr -= ((addr >= BufferSize) ? 0xffffffff : 0) & BufferSize;
|
||||
}
|
||||
/****************************************************************************************\
|
||||
* Solve Linear System *
|
||||
\****************************************************************************************/
|
||||
{
|
||||
float delta = (A1B2 * A1B2 - A2 * B1);
|
||||
|
||||
if( delta )
|
||||
{
|
||||
/* system is not singular - solving by Kramer method */
|
||||
float deltaX;
|
||||
float deltaY;
|
||||
float Idelta = 8 / delta;
|
||||
|
||||
deltaX = -(C1 * A1B2 - C2 * B1);
|
||||
deltaY = -(A1B2 * C2 - A2 * C1);
|
||||
|
||||
velocityX[j] = deltaX * Idelta;
|
||||
velocityY[j] = deltaY * Idelta;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* singular system - find optical flow in gradient direction */
|
||||
float Norm = (A1B2 + A2) * (A1B2 + A2) + (B1 + A1B2) * (B1 + A1B2);
|
||||
|
||||
if( Norm )
|
||||
{
|
||||
float IGradNorm = 8 / Norm;
|
||||
float temp = -(C1 + C2) * IGradNorm;
|
||||
|
||||
velocityX[j] = (A1B2 + A2) * temp;
|
||||
velocityY[j] = (B1 + A1B2) * temp;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
velocityX[j] = 0;
|
||||
velocityY[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/****************************************************************************************\
|
||||
* End of Solving Linear System *
|
||||
\****************************************************************************************/
|
||||
} /*for */
|
||||
velocityX += velStep;
|
||||
velocityY += velStep;
|
||||
} /*for */
|
||||
PixelLine++;
|
||||
ConvLine++;
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
for( k = 0; k < 2; k++ )
|
||||
{
|
||||
cvFree( &MemX[k] );
|
||||
cvFree( &MemY[k] );
|
||||
}
|
||||
cvFree( &II );
|
||||
cvFree( &WII );
|
||||
|
||||
return CV_OK;
|
||||
} /*icvCalcOpticalFlowLK_8u32fR*/
|
||||
|
||||
|
||||
/*F///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Name: cvCalcOpticalFlowLK
|
||||
// Purpose: Optical flow implementation
|
||||
// Context:
|
||||
// Parameters:
|
||||
// srcA, srcB - source image
|
||||
// velx, vely - destination image
|
||||
// Returns:
|
||||
//
|
||||
// Notes:
|
||||
//F*/
|
||||
CV_IMPL void
|
||||
cvCalcOpticalFlowLK( const void* srcarrA, const void* srcarrB, CvSize winSize,
|
||||
void* velarrx, void* velarry )
|
||||
{
|
||||
CvMat stubA, *srcA = cvGetMat( srcarrA, &stubA );
|
||||
CvMat stubB, *srcB = cvGetMat( srcarrB, &stubB );
|
||||
CvMat stubx, *velx = cvGetMat( velarrx, &stubx );
|
||||
CvMat stuby, *vely = cvGetMat( velarry, &stuby );
|
||||
|
||||
if( !CV_ARE_TYPES_EQ( srcA, srcB ))
|
||||
CV_Error( CV_StsUnmatchedFormats, "Source images have different formats" );
|
||||
|
||||
if( !CV_ARE_TYPES_EQ( velx, vely ))
|
||||
CV_Error( CV_StsUnmatchedFormats, "Destination images have different formats" );
|
||||
|
||||
if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
|
||||
!CV_ARE_SIZES_EQ( velx, vely ) ||
|
||||
!CV_ARE_SIZES_EQ( srcA, velx ))
|
||||
CV_Error( CV_StsUnmatchedSizes, "" );
|
||||
|
||||
if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
|
||||
CV_MAT_TYPE( velx->type ) != CV_32FC1 )
|
||||
CV_Error( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
|
||||
"destination images must have 32fC1 type" );
|
||||
|
||||
if( srcA->step != srcB->step || velx->step != vely->step )
|
||||
CV_Error( CV_BadStep, "source and destination images have different step" );
|
||||
|
||||
IPPI_CALL( icvCalcOpticalFlowLK_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
|
||||
srcA->step, cvGetMatSize( srcA ), winSize,
|
||||
velx->data.fl, vely->data.fl, velx->step ));
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
@@ -1,355 +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 "test_precomp.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
class CV_OptFlowTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_OptFlowTest();
|
||||
~CV_OptFlowTest();
|
||||
protected:
|
||||
void run(int);
|
||||
|
||||
bool runDense(const Point& shift = Point(3, 0));
|
||||
bool runSparse();
|
||||
};
|
||||
|
||||
CV_OptFlowTest::CV_OptFlowTest() {}
|
||||
CV_OptFlowTest::~CV_OptFlowTest() {}
|
||||
|
||||
|
||||
Mat copnvert2flow(const Mat& velx, const Mat& vely)
|
||||
{
|
||||
Mat flow(velx.size(), CV_32FC2);
|
||||
for(int y = 0 ; y < flow.rows; ++y)
|
||||
for(int x = 0 ; x < flow.cols; ++x)
|
||||
flow.at<Point2f>(y, x) = Point2f(velx.at<float>(y, x), vely.at<float>(y, x));
|
||||
return flow;
|
||||
}
|
||||
|
||||
void calcOpticalFlowLK( const Mat& prev, const Mat& curr, Size winSize, Mat& flow )
|
||||
{
|
||||
Mat velx(prev.size(), CV_32F), vely(prev.size(), CV_32F);
|
||||
CvMat cvvelx = velx; CvMat cvvely = vely;
|
||||
CvMat cvprev = prev; CvMat cvcurr = curr;
|
||||
cvCalcOpticalFlowLK( &cvprev, &cvcurr, winSize, &cvvelx, &cvvely );
|
||||
flow = copnvert2flow(velx, vely);
|
||||
}
|
||||
|
||||
void calcOpticalFlowBM( const Mat& prev, const Mat& curr, Size bSize, Size shiftSize, Size maxRange, int usePrevious, Mat& flow )
|
||||
{
|
||||
Size sz((curr.cols - bSize.width)/shiftSize.width, (curr.rows - bSize.height)/shiftSize.height);
|
||||
Mat velx(sz, CV_32F), vely(sz, CV_32F);
|
||||
|
||||
CvMat cvvelx = velx; CvMat cvvely = vely;
|
||||
CvMat cvprev = prev; CvMat cvcurr = curr;
|
||||
cvCalcOpticalFlowBM( &cvprev, &cvcurr, bSize, shiftSize, maxRange, usePrevious, &cvvelx, &cvvely);
|
||||
flow = copnvert2flow(velx, vely);
|
||||
}
|
||||
|
||||
void calcOpticalFlowHS( const Mat& prev, const Mat& curr, int usePrevious, double lambda, TermCriteria criteria, Mat& flow)
|
||||
{
|
||||
Mat velx(prev.size(), CV_32F), vely(prev.size(), CV_32F);
|
||||
CvMat cvvelx = velx; CvMat cvvely = vely;
|
||||
CvMat cvprev = prev; CvMat cvcurr = curr;
|
||||
cvCalcOpticalFlowHS( &cvprev, &cvcurr, usePrevious, &cvvelx, &cvvely, lambda, criteria );
|
||||
flow = copnvert2flow(velx, vely);
|
||||
}
|
||||
|
||||
void calcAffineFlowPyrLK( const Mat& prev, const Mat& curr,
|
||||
const vector<Point2f>& prev_features, vector<Point2f>& curr_features,
|
||||
vector<uchar>& status, vector<float>& track_error, vector<float>& matrices,
|
||||
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,30, 0.01),
|
||||
Size win_size = Size(15, 15), int level = 3, int flags = 0)
|
||||
{
|
||||
CvMat cvprev = prev;
|
||||
CvMat cvcurr = curr;
|
||||
|
||||
size_t count = prev_features.size();
|
||||
curr_features.resize(count);
|
||||
status.resize(count);
|
||||
track_error.resize(count);
|
||||
matrices.resize(count * 6);
|
||||
|
||||
cvCalcAffineFlowPyrLK( &cvprev, &cvcurr, 0, 0,
|
||||
(const CvPoint2D32f*)&prev_features[0], (CvPoint2D32f*)&curr_features[0], &matrices[0],
|
||||
(int)count, win_size, level, (char*)&status[0], &track_error[0], criteria, flags );
|
||||
}
|
||||
|
||||
double showFlowAndCalcError(const string& name, const Mat& gray, const Mat& flow,
|
||||
const Rect& where, const Point& d,
|
||||
bool showImages = false, bool writeError = false)
|
||||
{
|
||||
const int mult = 16;
|
||||
|
||||
if (showImages)
|
||||
{
|
||||
Mat tmp, cflow;
|
||||
resize(gray, tmp, gray.size() * mult, 0, 0, INTER_NEAREST);
|
||||
cvtColor(tmp, cflow, CV_GRAY2BGR);
|
||||
|
||||
const float m2 = 0.3f;
|
||||
const float minVel = 0.1f;
|
||||
|
||||
for(int y = 0; y < flow.rows; ++y)
|
||||
for(int x = 0; x < flow.cols; ++x)
|
||||
{
|
||||
Point2f f = flow.at<Point2f>(y, x);
|
||||
|
||||
if (f.x * f.x + f.y * f.y > minVel * minVel)
|
||||
{
|
||||
Point p1 = Point(x, y) * mult;
|
||||
Point p2 = Point(cvRound((x + f.x*m2) * mult), cvRound((y + f.y*m2) * mult));
|
||||
|
||||
line(cflow, p1, p2, CV_RGB(0, 255, 0));
|
||||
circle(cflow, Point(x, y) * mult, 2, CV_RGB(255, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
rectangle(cflow, (where.tl() + d) * mult, (where.br() + d - Point(1,1)) * mult, CV_RGB(0, 0, 255));
|
||||
namedWindow(name, 1); imshow(name, cflow);
|
||||
}
|
||||
|
||||
double angle = atan2((float)d.y, (float)d.x);
|
||||
double error = 0;
|
||||
|
||||
bool all = true;
|
||||
Mat inner = flow(where);
|
||||
for(int y = 0; y < inner.rows; ++y)
|
||||
for(int x = 0; x < inner.cols; ++x)
|
||||
{
|
||||
const Point2f f = inner.at<Point2f>(y, x);
|
||||
|
||||
if (f.x == 0 && f.y == 0)
|
||||
continue;
|
||||
|
||||
all = false;
|
||||
|
||||
double a = atan2(f.y, f.x);
|
||||
error += fabs(angle - a);
|
||||
}
|
||||
double res = all ? numeric_limits<double>::max() : error / (inner.cols * inner.rows);
|
||||
|
||||
if (writeError)
|
||||
cout << "Error " + name << " = " << res << endl;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Mat generateImage(const Size& sz, bool doBlur = true)
|
||||
{
|
||||
RNG rng;
|
||||
Mat mat(sz, CV_8U);
|
||||
mat = Scalar(0);
|
||||
for(int y = 0; y < mat.rows; ++y)
|
||||
for(int x = 0; x < mat.cols; ++x)
|
||||
mat.at<uchar>(y, x) = (uchar)rng;
|
||||
if (doBlur)
|
||||
blur(mat, mat, Size(3, 3));
|
||||
return mat;
|
||||
}
|
||||
|
||||
Mat generateSample(const Size& sz)
|
||||
{
|
||||
Mat smpl(sz, CV_8U);
|
||||
smpl = Scalar(0);
|
||||
Point sc(smpl.cols/2, smpl.rows/2);
|
||||
rectangle(smpl, Point(0,0), sc - Point(1,1), Scalar(255), CV_FILLED);
|
||||
rectangle(smpl, sc, Point(smpl.cols, smpl.rows), Scalar(255), CV_FILLED);
|
||||
return smpl;
|
||||
}
|
||||
|
||||
bool CV_OptFlowTest::runDense(const Point& d)
|
||||
{
|
||||
Size matSize(40, 40);
|
||||
Size movSize(8, 8);
|
||||
|
||||
Mat smpl = generateSample(movSize);
|
||||
Mat prev = generateImage(matSize);
|
||||
Mat curr = prev.clone();
|
||||
|
||||
Rect rect(Point(prev.cols/2, prev.rows/2) - Point(movSize.width/2, movSize.height/2), movSize);
|
||||
|
||||
Mat flowLK, flowBM, flowHS, flowFB, flowFB_G, flowBM_received, m1;
|
||||
|
||||
m1 = prev(rect); smpl.copyTo(m1);
|
||||
m1 = curr(Rect(rect.tl() + d, rect.br() + d)); smpl.copyTo(m1);
|
||||
|
||||
calcOpticalFlowLK( prev, curr, Size(15, 15), flowLK);
|
||||
calcOpticalFlowBM( prev, curr, Size(15, 15), Size(1, 1), Size(15, 15), 0, flowBM_received);
|
||||
calcOpticalFlowHS( prev, curr, 0, 5, TermCriteria(TermCriteria::MAX_ITER, 400, 0), flowHS);
|
||||
calcOpticalFlowFarneback( prev, curr, flowFB, 0.5, 3, std::max(d.x, d.y) + 10, 100, 6, 2, 0);
|
||||
calcOpticalFlowFarneback( prev, curr, flowFB_G, 0.5, 3, std::max(d.x, d.y) + 10, 100, 6, 2, OPTFLOW_FARNEBACK_GAUSSIAN);
|
||||
|
||||
flowBM.create(prev.size(), CV_32FC2);
|
||||
flowBM = Scalar(0);
|
||||
Point origin((flowBM.cols - flowBM_received.cols)/2, (flowBM.rows - flowBM_received.rows)/2);
|
||||
Mat wcp = flowBM(Rect(origin, flowBM_received.size()));
|
||||
flowBM_received.copyTo(wcp);
|
||||
|
||||
double errorLK = showFlowAndCalcError("LK", prev, flowLK, rect, d);
|
||||
double errorBM = showFlowAndCalcError("BM", prev, flowBM, rect, d);
|
||||
double errorFB = showFlowAndCalcError("FB", prev, flowFB, rect, d);
|
||||
double errorFBG = showFlowAndCalcError("FBG", prev, flowFB_G, rect, d);
|
||||
double errorHS = showFlowAndCalcError("HS", prev, flowHS, rect, d); (void)errorHS;
|
||||
//waitKey();
|
||||
|
||||
const double thres = 0.2;
|
||||
if (errorLK > thres || errorBM > thres || errorFB > thres || errorFBG > thres /*|| errorHS > thres */)
|
||||
{
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CV_OptFlowTest::runSparse()
|
||||
{
|
||||
Mat prev = imread(string(ts->get_data_path()) + "optflow/rock_1.bmp", 0);
|
||||
Mat next = imread(string(ts->get_data_path()) + "optflow/rock_2.bmp", 0);
|
||||
|
||||
if (prev.empty() || next.empty())
|
||||
{
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return false;
|
||||
}
|
||||
|
||||
Mat cprev, cnext;
|
||||
cvtColor(prev, cprev, CV_GRAY2BGR);
|
||||
cvtColor(next, cnext, CV_GRAY2BGR);
|
||||
|
||||
vector<Point2f> prev_pts;
|
||||
vector<Point2f> next_ptsOpt;
|
||||
vector<Point2f> next_ptsAff;
|
||||
vector<uchar> status_Opt;
|
||||
vector<uchar> status_Aff;
|
||||
vector<float> error;
|
||||
vector<float> matrices;
|
||||
|
||||
Size netSize(10, 10);
|
||||
Point2f center = Point(prev.cols/2, prev.rows/2);
|
||||
|
||||
for(int i = 0 ; i < netSize.width; ++i)
|
||||
for(int j = 0 ; j < netSize.width; ++j)
|
||||
{
|
||||
Point2f p(i * float(prev.cols)/netSize.width, j * float(prev.rows)/netSize.height);
|
||||
prev_pts.push_back((p - center) * 0.5f + center);
|
||||
}
|
||||
|
||||
calcOpticalFlowPyrLK( prev, next, prev_pts, next_ptsOpt, status_Opt, error );
|
||||
calcAffineFlowPyrLK ( prev, next, prev_pts, next_ptsAff, status_Aff, error, matrices);
|
||||
|
||||
const double expected_shift = 25;
|
||||
const double thres = 1;
|
||||
for(size_t i = 0; i < prev_pts.size(); ++i)
|
||||
{
|
||||
circle(cprev, prev_pts[i], 2, CV_RGB(255, 0, 0));
|
||||
|
||||
if (status_Opt[i])
|
||||
{
|
||||
circle(cnext, next_ptsOpt[i], 2, CV_RGB(0, 0, 255));
|
||||
Point2f shift = prev_pts[i] - next_ptsOpt[i];
|
||||
|
||||
double n = sqrt(shift.ddot(shift));
|
||||
if (fabs(n - expected_shift) > thres)
|
||||
{
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_Aff[i])
|
||||
{
|
||||
circle(cnext, next_ptsAff[i], 4, CV_RGB(0, 255, 0));
|
||||
Point2f shift = prev_pts[i] - next_ptsAff[i];
|
||||
|
||||
double n = sqrt(shift.ddot(shift));
|
||||
if (fabs(n - expected_shift) > thres)
|
||||
{
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*namedWindow("P"); imshow("P", cprev);
|
||||
namedWindow("N"); imshow("N", cnext);
|
||||
waitKey();*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CV_OptFlowTest::run( int /* start_from */)
|
||||
{
|
||||
|
||||
if (!runDense(Point(3, 0)))
|
||||
return;
|
||||
|
||||
if (!runDense(Point(0, 3)))
|
||||
return;
|
||||
|
||||
//if (!runDense(Point(3, 3))) return; //probably LK works incorrectly in this case.
|
||||
|
||||
if (!runSparse())
|
||||
return;
|
||||
|
||||
ts->set_failed_test_info(cvtest::TS::OK);
|
||||
}
|
||||
|
||||
|
||||
TEST(Video_OpticalFlow, accuracy) { CV_OptFlowTest test; test.safe_run(); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user