feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

View File

@@ -0,0 +1,12 @@
set(the_description "Video Analysis")
ocv_define_module(video
opencv_imgproc
OPTIONAL
opencv_calib3d
opencv_dnn
WRAP
java
objc
python
js
)

View File

@@ -0,0 +1,44 @@
@article{AAM,
title={Adaptive appearance modeling for video tracking: survey and evaluation},
author={Salti, Samuele and Cavallaro, Andrea and Di Stefano, Luigi},
journal={Image Processing, IEEE Transactions on},
volume={21},
number={10},
pages={4334--4348},
year={2012},
publisher={IEEE}
}
@article{AMVOT,
title={A survey of appearance models in visual object tracking},
author={Li, Xi and Hu, Weiming and Shen, Chunhua and Zhang, Zhongfei and Dick, Anthony and Hengel, Anton Van Den},
journal={ACM Transactions on Intelligent Systems and Technology (TIST)},
volume={4},
number={4},
pages={58},
year={2013},
publisher={ACM}
}
@inproceedings{GOTURN,
title={Learning to Track at 100 FPS with Deep Regression Networks},
author={Held, David and Thrun, Sebastian and Savarese, Silvio},
booktitle={European Conference Computer Vision (ECCV)},
year={2016}
}
@inproceedings{Kroeger2016,
author={Till Kroeger and Radu Timofte and Dengxin Dai and Luc Van Gool},
title={Fast Optical Flow using Dense Inverse Search},
booktitle={Proceedings of the European Conference on Computer Vision ({ECCV})},
year={2016}
}
@inproceedings{MIL,
title={Visual tracking with online multiple instance learning},
author={Babenko, Boris and Yang, Ming-Hsuan and Belongie, Serge},
booktitle={Computer Vision and Pattern Recognition, 2009. CVPR 2009. IEEE Conference on},
pages={983--990},
year={2009},
organization={IEEE}
}

View File

@@ -0,0 +1,59 @@
/*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.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef OPENCV_VIDEO_HPP
#define OPENCV_VIDEO_HPP
/**
@defgroup video Video Analysis
@{
@defgroup video_motion Motion Analysis
@defgroup video_track Object Tracking
@defgroup video_c C API
@}
*/
#include "opencv2/video/tracking.hpp"
#include "opencv2/video/background_segm.hpp"
#endif //OPENCV_VIDEO_HPP

View File

@@ -0,0 +1,317 @@
/*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.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef OPENCV_BACKGROUND_SEGM_HPP
#define OPENCV_BACKGROUND_SEGM_HPP
#include "opencv2/core.hpp"
namespace cv
{
//! @addtogroup video_motion
//! @{
/** @brief Base class for background/foreground segmentation. :
The class is only used to define the common interface for the whole family of background/foreground
segmentation algorithms.
*/
class CV_EXPORTS_W BackgroundSubtractor : public Algorithm
{
public:
/** @brief Computes a foreground mask.
@param image Next video frame.
@param fgmask The output foreground mask as an 8-bit binary image.
@param learningRate The value between 0 and 1 that indicates how fast the background model is
learnt. Negative parameter value makes the algorithm to use some automatically chosen learning
rate. 0 means that the background model is not updated at all, 1 means that the background model
is completely reinitialized from the last frame.
*/
CV_WRAP virtual void apply(InputArray image, OutputArray fgmask, double learningRate=-1) = 0;
/** @brief Computes a background image.
@param backgroundImage The output background image.
@note Sometimes the background image can be very blurry, as it contain the average background
statistics.
*/
CV_WRAP virtual void getBackgroundImage(OutputArray backgroundImage) const = 0;
};
/** @brief Gaussian Mixture-based Background/Foreground Segmentation Algorithm.
The class implements the Gaussian mixture model background subtraction described in @cite Zivkovic2004
and @cite Zivkovic2006 .
*/
class CV_EXPORTS_W BackgroundSubtractorMOG2 : public BackgroundSubtractor
{
public:
/** @brief Returns the number of last frames that affect the background model
*/
CV_WRAP virtual int getHistory() const = 0;
/** @brief Sets the number of last frames that affect the background model
*/
CV_WRAP virtual void setHistory(int history) = 0;
/** @brief Returns the number of gaussian components in the background model
*/
CV_WRAP virtual int getNMixtures() const = 0;
/** @brief Sets the number of gaussian components in the background model.
The model needs to be reinitalized to reserve memory.
*/
CV_WRAP virtual void setNMixtures(int nmixtures) = 0;//needs reinitialization!
/** @brief Returns the "background ratio" parameter of the algorithm
If a foreground pixel keeps semi-constant value for about backgroundRatio\*history frames, it's
considered background and added to the model as a center of a new component. It corresponds to TB
parameter in the paper.
*/
CV_WRAP virtual double getBackgroundRatio() const = 0;
/** @brief Sets the "background ratio" parameter of the algorithm
*/
CV_WRAP virtual void setBackgroundRatio(double ratio) = 0;
/** @brief Returns the variance threshold for the pixel-model match
The main threshold on the squared Mahalanobis distance to decide if the sample is well described by
the background model or not. Related to Cthr from the paper.
*/
CV_WRAP virtual double getVarThreshold() const = 0;
/** @brief Sets the variance threshold for the pixel-model match
*/
CV_WRAP virtual void setVarThreshold(double varThreshold) = 0;
/** @brief Returns the variance threshold for the pixel-model match used for new mixture component generation
Threshold for the squared Mahalanobis distance that helps decide when a sample is close to the
existing components (corresponds to Tg in the paper). If a pixel is not close to any component, it
is considered foreground or added as a new component. 3 sigma =\> Tg=3\*3=9 is default. A smaller Tg
value generates more components. A higher Tg value may result in a small number of components but
they can grow too large.
*/
CV_WRAP virtual double getVarThresholdGen() const = 0;
/** @brief Sets the variance threshold for the pixel-model match used for new mixture component generation
*/
CV_WRAP virtual void setVarThresholdGen(double varThresholdGen) = 0;
/** @brief Returns the initial variance of each gaussian component
*/
CV_WRAP virtual double getVarInit() const = 0;
/** @brief Sets the initial variance of each gaussian component
*/
CV_WRAP virtual void setVarInit(double varInit) = 0;
CV_WRAP virtual double getVarMin() const = 0;
CV_WRAP virtual void setVarMin(double varMin) = 0;
CV_WRAP virtual double getVarMax() const = 0;
CV_WRAP virtual void setVarMax(double varMax) = 0;
/** @brief Returns the complexity reduction threshold
This parameter defines the number of samples needed to accept to prove the component exists. CT=0.05
is a default value for all the samples. By setting CT=0 you get an algorithm very similar to the
standard Stauffer&Grimson algorithm.
*/
CV_WRAP virtual double getComplexityReductionThreshold() const = 0;
/** @brief Sets the complexity reduction threshold
*/
CV_WRAP virtual void setComplexityReductionThreshold(double ct) = 0;
/** @brief Returns the shadow detection flag
If true, the algorithm detects shadows and marks them. See createBackgroundSubtractorMOG2 for
details.
*/
CV_WRAP virtual bool getDetectShadows() const = 0;
/** @brief Enables or disables shadow detection
*/
CV_WRAP virtual void setDetectShadows(bool detectShadows) = 0;
/** @brief Returns the shadow value
Shadow value is the value used to mark shadows in the foreground mask. Default value is 127. Value 0
in the mask always means background, 255 means foreground.
*/
CV_WRAP virtual int getShadowValue() const = 0;
/** @brief Sets the shadow value
*/
CV_WRAP virtual void setShadowValue(int value) = 0;
/** @brief Returns the shadow threshold
A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in
the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel
is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara,
*Detecting Moving Shadows...*, IEEE PAMI,2003.
*/
CV_WRAP virtual double getShadowThreshold() const = 0;
/** @brief Sets the shadow threshold
*/
CV_WRAP virtual void setShadowThreshold(double threshold) = 0;
/** @brief Computes a foreground mask.
@param image Next video frame. Floating point frame will be used without scaling and should be in range \f$[0,255]\f$.
@param fgmask The output foreground mask as an 8-bit binary image.
@param learningRate The value between 0 and 1 that indicates how fast the background model is
learnt. Negative parameter value makes the algorithm to use some automatically chosen learning
rate. 0 means that the background model is not updated at all, 1 means that the background model
is completely reinitialized from the last frame.
*/
CV_WRAP virtual void apply(InputArray image, OutputArray fgmask, double learningRate=-1) CV_OVERRIDE = 0;
};
/** @brief Creates MOG2 Background Subtractor
@param history Length of the history.
@param varThreshold Threshold on the squared Mahalanobis distance between the pixel and the model
to decide whether a pixel is well described by the background model. This parameter does not
affect the background update.
@param detectShadows If true, the algorithm will detect shadows and mark them. It decreases the
speed a bit, so if you do not need this feature, set the parameter to false.
*/
CV_EXPORTS_W Ptr<BackgroundSubtractorMOG2>
createBackgroundSubtractorMOG2(int history=500, double varThreshold=16,
bool detectShadows=true);
/** @brief K-nearest neighbours - based Background/Foreground Segmentation Algorithm.
The class implements the K-nearest neighbours background subtraction described in @cite Zivkovic2006 .
Very efficient if number of foreground pixels is low.
*/
class CV_EXPORTS_W BackgroundSubtractorKNN : public BackgroundSubtractor
{
public:
/** @brief Returns the number of last frames that affect the background model
*/
CV_WRAP virtual int getHistory() const = 0;
/** @brief Sets the number of last frames that affect the background model
*/
CV_WRAP virtual void setHistory(int history) = 0;
/** @brief Returns the number of data samples in the background model
*/
CV_WRAP virtual int getNSamples() const = 0;
/** @brief Sets the number of data samples in the background model.
The model needs to be reinitalized to reserve memory.
*/
CV_WRAP virtual void setNSamples(int _nN) = 0;//needs reinitialization!
/** @brief Returns the threshold on the squared distance between the pixel and the sample
The threshold on the squared distance between the pixel and the sample to decide whether a pixel is
close to a data sample.
*/
CV_WRAP virtual double getDist2Threshold() const = 0;
/** @brief Sets the threshold on the squared distance
*/
CV_WRAP virtual void setDist2Threshold(double _dist2Threshold) = 0;
/** @brief Returns the number of neighbours, the k in the kNN.
K is the number of samples that need to be within dist2Threshold in order to decide that that
pixel is matching the kNN background model.
*/
CV_WRAP virtual int getkNNSamples() const = 0;
/** @brief Sets the k in the kNN. How many nearest neighbours need to match.
*/
CV_WRAP virtual void setkNNSamples(int _nkNN) = 0;
/** @brief Returns the shadow detection flag
If true, the algorithm detects shadows and marks them. See createBackgroundSubtractorKNN for
details.
*/
CV_WRAP virtual bool getDetectShadows() const = 0;
/** @brief Enables or disables shadow detection
*/
CV_WRAP virtual void setDetectShadows(bool detectShadows) = 0;
/** @brief Returns the shadow value
Shadow value is the value used to mark shadows in the foreground mask. Default value is 127. Value 0
in the mask always means background, 255 means foreground.
*/
CV_WRAP virtual int getShadowValue() const = 0;
/** @brief Sets the shadow value
*/
CV_WRAP virtual void setShadowValue(int value) = 0;
/** @brief Returns the shadow threshold
A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in
the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel
is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara,
*Detecting Moving Shadows...*, IEEE PAMI,2003.
*/
CV_WRAP virtual double getShadowThreshold() const = 0;
/** @brief Sets the shadow threshold
*/
CV_WRAP virtual void setShadowThreshold(double threshold) = 0;
};
/** @brief Creates KNN Background Subtractor
@param history Length of the history.
@param dist2Threshold Threshold on the squared distance between the pixel and the sample to decide
whether a pixel is close to that sample. This parameter does not affect the background update.
@param detectShadows If true, the algorithm will detect shadows and mark them. It decreases the
speed a bit, so if you do not need this feature, set the parameter to false.
*/
CV_EXPORTS_W Ptr<BackgroundSubtractorKNN>
createBackgroundSubtractorKNN(int history=500, double dist2Threshold=400.0,
bool detectShadows=true);
//! @} video_motion
} // cv
#endif

View File

@@ -0,0 +1,406 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_VIDEO_DETAIL_TRACKING_HPP
#define OPENCV_VIDEO_DETAIL_TRACKING_HPP
/*
* Partially based on:
* ====================================================================================================================
* - [AAM] S. Salti, A. Cavallaro, L. Di Stefano, Adaptive Appearance Modeling for Video Tracking: Survey and Evaluation
* - [AMVOT] X. Li, W. Hu, C. Shen, Z. Zhang, A. Dick, A. van den Hengel, A Survey of Appearance Models in Visual Object Tracking
*
* This Tracking API has been designed with PlantUML. If you modify this API please change UML files under modules/tracking/doc/uml
*
*/
#include "opencv2/core.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
/** @addtogroup tracking_detail
@{
*/
/************************************ TrackerFeature Base Classes ************************************/
/** @brief Abstract base class for TrackerFeature that represents the feature.
*/
class CV_EXPORTS TrackerFeature
{
public:
virtual ~TrackerFeature();
/** @brief Compute the features in the images collection
@param images The images
@param response The output response
*/
void compute(const std::vector<Mat>& images, Mat& response);
protected:
virtual bool computeImpl(const std::vector<Mat>& images, Mat& response) = 0;
};
/** @brief Class that manages the extraction and selection of features
@cite AAM Feature Extraction and Feature Set Refinement (Feature Processing and Feature Selection).
See table I and section III C @cite AMVOT Appearance modelling -\> Visual representation (Table II,
section 3.1 - 3.2)
TrackerFeatureSet is an aggregation of TrackerFeature
@sa
TrackerFeature
*/
class CV_EXPORTS TrackerFeatureSet
{
public:
TrackerFeatureSet();
~TrackerFeatureSet();
/** @brief Extract features from the images collection
@param images The input images
*/
void extraction(const std::vector<Mat>& images);
/** @brief Add TrackerFeature in the collection. Return true if TrackerFeature is added, false otherwise
@param feature The TrackerFeature class
*/
bool addTrackerFeature(const Ptr<TrackerFeature>& feature);
/** @brief Get the TrackerFeature collection (TrackerFeature name, TrackerFeature pointer)
*/
const std::vector<Ptr<TrackerFeature>>& getTrackerFeatures() const;
/** @brief Get the responses
@note Be sure to call extraction before getResponses Example TrackerFeatureSet::getResponses
*/
const std::vector<Mat>& getResponses() const;
private:
void clearResponses();
bool blockAddTrackerFeature;
std::vector<Ptr<TrackerFeature>> features; // list of features
std::vector<Mat> responses; // list of response after compute
};
/************************************ TrackerSampler Base Classes ************************************/
/** @brief Abstract base class for TrackerSamplerAlgorithm that represents the algorithm for the specific
sampler.
*/
class CV_EXPORTS TrackerSamplerAlgorithm
{
public:
virtual ~TrackerSamplerAlgorithm();
/** @brief Computes the regions starting from a position in an image.
Return true if samples are computed, false otherwise
@param image The current frame
@param boundingBox The bounding box from which regions can be calculated
@param sample The computed samples @cite AAM Fig. 1 variable Sk
*/
virtual bool sampling(const Mat& image, const Rect& boundingBox, std::vector<Mat>& sample) = 0;
};
/**
* \brief Class that manages the sampler in order to select regions for the update the model of the tracker
* [AAM] Sampling e Labeling. See table I and section III B
*/
/** @brief Class that manages the sampler in order to select regions for the update the model of the tracker
@cite AAM Sampling e Labeling. See table I and section III B
TrackerSampler is an aggregation of TrackerSamplerAlgorithm
@sa
TrackerSamplerAlgorithm
*/
class CV_EXPORTS TrackerSampler
{
public:
TrackerSampler();
~TrackerSampler();
/** @brief Computes the regions starting from a position in an image
@param image The current frame
@param boundingBox The bounding box from which regions can be calculated
*/
void sampling(const Mat& image, Rect boundingBox);
/** @brief Return the collection of the TrackerSamplerAlgorithm
*/
const std::vector<Ptr<TrackerSamplerAlgorithm>>& getSamplers() const;
/** @brief Return the samples from all TrackerSamplerAlgorithm, @cite AAM Fig. 1 variable Sk
*/
const std::vector<Mat>& getSamples() const;
/** @brief Add TrackerSamplerAlgorithm in the collection. Return true if sampler is added, false otherwise
@param sampler The TrackerSamplerAlgorithm
*/
bool addTrackerSamplerAlgorithm(const Ptr<TrackerSamplerAlgorithm>& sampler);
private:
std::vector<Ptr<TrackerSamplerAlgorithm>> samplers;
std::vector<Mat> samples;
bool blockAddTrackerSampler;
void clearSamples();
};
/************************************ TrackerModel Base Classes ************************************/
/** @brief Abstract base class for TrackerTargetState that represents a possible state of the target.
See @cite AAM \f$\hat{x}^{i}_{k}\f$ all the states candidates.
Inherits this class with your Target state, In own implementation you can add scale variation,
width, height, orientation, etc.
*/
class CV_EXPORTS TrackerTargetState
{
public:
virtual ~TrackerTargetState() {};
/** @brief Get the position
* @return The position
*/
Point2f getTargetPosition() const;
/** @brief Set the position
* @param position The position
*/
void setTargetPosition(const Point2f& position);
/** @brief Get the width of the target
* @return The width of the target
*/
int getTargetWidth() const;
/** @brief Set the width of the target
* @param width The width of the target
*/
void setTargetWidth(int width);
/** @brief Get the height of the target
* @return The height of the target
*/
int getTargetHeight() const;
/** @brief Set the height of the target
* @param height The height of the target
*/
void setTargetHeight(int height);
protected:
Point2f targetPosition;
int targetWidth;
int targetHeight;
};
/** @brief Represents the model of the target at frame \f$k\f$ (all states and scores)
See @cite AAM The set of the pair \f$\langle \hat{x}^{i}_{k}, C^{i}_{k} \rangle\f$
@sa TrackerTargetState
*/
typedef std::vector<std::pair<Ptr<TrackerTargetState>, float>> ConfidenceMap;
/** @brief Represents the estimate states for all frames
@cite AAM \f$x_{k}\f$ is the trajectory of the target up to time \f$k\f$
@sa TrackerTargetState
*/
typedef std::vector<Ptr<TrackerTargetState>> Trajectory;
/** @brief Abstract base class for TrackerStateEstimator that estimates the most likely target state.
See @cite AAM State estimator
See @cite AMVOT Statistical modeling (Fig. 3), Table III (generative) - IV (discriminative) - V (hybrid)
*/
class CV_EXPORTS TrackerStateEstimator
{
public:
virtual ~TrackerStateEstimator();
/** @brief Estimate the most likely target state, return the estimated state
@param confidenceMaps The overall appearance model as a list of :cConfidenceMap
*/
Ptr<TrackerTargetState> estimate(const std::vector<ConfidenceMap>& confidenceMaps);
/** @brief Update the ConfidenceMap with the scores
@param confidenceMaps The overall appearance model as a list of :cConfidenceMap
*/
void update(std::vector<ConfidenceMap>& confidenceMaps);
/** @brief Create TrackerStateEstimator by tracker state estimator type
@param trackeStateEstimatorType The TrackerStateEstimator name
The modes available now:
- "BOOSTING" -- Boosting-based discriminative appearance models. See @cite AMVOT section 4.4
The modes available soon:
- "SVM" -- SVM-based discriminative appearance models. See @cite AMVOT section 4.5
*/
static Ptr<TrackerStateEstimator> create(const String& trackeStateEstimatorType);
/** @brief Get the name of the specific TrackerStateEstimator
*/
String getClassName() const;
protected:
virtual Ptr<TrackerTargetState> estimateImpl(const std::vector<ConfidenceMap>& confidenceMaps) = 0;
virtual void updateImpl(std::vector<ConfidenceMap>& confidenceMaps) = 0;
String className;
};
/** @brief Abstract class that represents the model of the target.
It must be instantiated by specialized tracker
See @cite AAM Ak
Inherits this with your TrackerModel
*/
class CV_EXPORTS TrackerModel
{
public:
TrackerModel();
virtual ~TrackerModel();
/** @brief Set TrackerEstimator, return true if the tracker state estimator is added, false otherwise
@param trackerStateEstimator The TrackerStateEstimator
@note You can add only one TrackerStateEstimator
*/
bool setTrackerStateEstimator(Ptr<TrackerStateEstimator> trackerStateEstimator);
/** @brief Estimate the most likely target location
@cite AAM ME, Model Estimation table I
@param responses Features extracted from TrackerFeatureSet
*/
void modelEstimation(const std::vector<Mat>& responses);
/** @brief Update the model
@cite AAM MU, Model Update table I
*/
void modelUpdate();
/** @brief Run the TrackerStateEstimator, return true if is possible to estimate a new state, false otherwise
*/
bool runStateEstimator();
/** @brief Set the current TrackerTargetState in the Trajectory
@param lastTargetState The current TrackerTargetState
*/
void setLastTargetState(const Ptr<TrackerTargetState>& lastTargetState);
/** @brief Get the last TrackerTargetState from Trajectory
*/
Ptr<TrackerTargetState> getLastTargetState() const;
/** @brief Get the list of the ConfidenceMap
*/
const std::vector<ConfidenceMap>& getConfidenceMaps() const;
/** @brief Get the last ConfidenceMap for the current frame
*/
const ConfidenceMap& getLastConfidenceMap() const;
/** @brief Get the TrackerStateEstimator
*/
Ptr<TrackerStateEstimator> getTrackerStateEstimator() const;
private:
void clearCurrentConfidenceMap();
protected:
std::vector<ConfidenceMap> confidenceMaps;
Ptr<TrackerStateEstimator> stateEstimator;
ConfidenceMap currentConfidenceMap;
Trajectory trajectory;
int maxCMLength;
virtual void modelEstimationImpl(const std::vector<Mat>& responses) = 0;
virtual void modelUpdateImpl() = 0;
};
/************************************ Specific TrackerStateEstimator Classes ************************************/
// None
/************************************ Specific TrackerSamplerAlgorithm Classes ************************************/
/** @brief TrackerSampler based on CSC (current state centered), used by MIL algorithm TrackerMIL
*/
class CV_EXPORTS TrackerSamplerCSC : public TrackerSamplerAlgorithm
{
public:
~TrackerSamplerCSC();
enum MODE
{
MODE_INIT_POS = 1, //!< mode for init positive samples
MODE_INIT_NEG = 2, //!< mode for init negative samples
MODE_TRACK_POS = 3, //!< mode for update positive samples
MODE_TRACK_NEG = 4, //!< mode for update negative samples
MODE_DETECT = 5 //!< mode for detect samples
};
struct CV_EXPORTS Params
{
Params();
float initInRad; //!< radius for gathering positive instances during init
float trackInPosRad; //!< radius for gathering positive instances during tracking
float searchWinSize; //!< size of search window
int initMaxNegNum; //!< # negative samples to use during init
int trackMaxPosNum; //!< # positive samples to use during training
int trackMaxNegNum; //!< # negative samples to use during training
};
/** @brief Constructor
@param parameters TrackerSamplerCSC parameters TrackerSamplerCSC::Params
*/
TrackerSamplerCSC(const TrackerSamplerCSC::Params& parameters = TrackerSamplerCSC::Params());
/** @brief Set the sampling mode of TrackerSamplerCSC
@param samplingMode The sampling mode
The modes are:
- "MODE_INIT_POS = 1" -- for the positive sampling in initialization step
- "MODE_INIT_NEG = 2" -- for the negative sampling in initialization step
- "MODE_TRACK_POS = 3" -- for the positive sampling in update step
- "MODE_TRACK_NEG = 4" -- for the negative sampling in update step
- "MODE_DETECT = 5" -- for the sampling in detection step
*/
void setMode(int samplingMode);
bool sampling(const Mat& image, const Rect& boundingBox, std::vector<Mat>& sample) CV_OVERRIDE;
private:
Params params;
int mode;
RNG rng;
std::vector<Mat> sampleImage(const Mat& img, int x, int y, int w, int h, float inrad, float outrad = 0, int maxnum = 1000000);
};
//! @}
}}} // namespace cv::detail::tracking
#endif // OPENCV_VIDEO_DETAIL_TRACKING_HPP

View File

@@ -0,0 +1,16 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_VIDEO_LEGACY_CONSTANTS_H
#define OPENCV_VIDEO_LEGACY_CONSTANTS_H
enum
{
CV_LKFLOW_PYR_A_READY = 1,
CV_LKFLOW_PYR_B_READY = 2,
CV_LKFLOW_INITIAL_GUESSES = 4,
CV_LKFLOW_GET_MIN_EIGENVALS = 8
};
#endif // OPENCV_VIDEO_LEGACY_CONSTANTS_H

View File

@@ -0,0 +1,857 @@
/*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.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef OPENCV_TRACKING_HPP
#define OPENCV_TRACKING_HPP
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
namespace cv
{
//! @addtogroup video_track
//! @{
enum { OPTFLOW_USE_INITIAL_FLOW = 4,
OPTFLOW_LK_GET_MIN_EIGENVALS = 8,
OPTFLOW_FARNEBACK_GAUSSIAN = 256
};
/** @brief Finds an object center, size, and orientation.
@param probImage Back projection of the object histogram. See calcBackProject.
@param window Initial search window.
@param criteria Stop criteria for the underlying meanShift.
returns
(in old interfaces) Number of iterations CAMSHIFT took to converge
The function implements the CAMSHIFT object tracking algorithm @cite Bradski98 . First, it finds an
object center using meanShift and then adjusts the window size and finds the optimal rotation. The
function returns the rotated rectangle structure that includes the object position, size, and
orientation. The next position of the search window can be obtained with RotatedRect::boundingRect()
See the OpenCV sample camshiftdemo.c that tracks colored objects.
@note
- (Python) A sample explaining the camshift tracking algorithm can be found at
opencv_source_code/samples/python/camshift.py
*/
CV_EXPORTS_W RotatedRect CamShift( InputArray probImage, CV_IN_OUT Rect& window,
TermCriteria criteria );
/** @example samples/cpp/camshiftdemo.cpp
An example using the mean-shift tracking algorithm
*/
/** @brief Finds an object on a back projection image.
@param probImage Back projection of the object histogram. See calcBackProject for details.
@param window Initial search window.
@param criteria Stop criteria for the iterative search algorithm.
returns
: Number of iterations CAMSHIFT took to converge.
The function implements the iterative object search algorithm. It takes the input back projection of
an object and the initial position. The mass center in window of the back projection image is
computed and the search window center shifts to the mass center. The procedure is repeated until the
specified number of iterations criteria.maxCount is done or until the window center shifts by less
than criteria.epsilon. The algorithm is used inside CamShift and, unlike CamShift , the search
window size or orientation do not change during the search. You can simply pass the output of
calcBackProject to this function. But better results can be obtained if you pre-filter the back
projection and remove the noise. For example, you can do this by retrieving connected components
with findContours , throwing away contours with small area ( contourArea ), and rendering the
remaining contours with drawContours.
*/
CV_EXPORTS_W int meanShift( InputArray probImage, CV_IN_OUT Rect& window, TermCriteria criteria );
/** @brief Constructs the image pyramid which can be passed to calcOpticalFlowPyrLK.
@param img 8-bit input image.
@param pyramid output pyramid.
@param winSize window size of optical flow algorithm. Must be not less than winSize argument of
calcOpticalFlowPyrLK. It is needed to calculate required padding for pyramid levels.
@param maxLevel 0-based maximal pyramid level number.
@param withDerivatives set to precompute gradients for the every pyramid level. If pyramid is
constructed without the gradients then calcOpticalFlowPyrLK will calculate them internally.
@param pyrBorder the border mode for pyramid layers.
@param derivBorder the border mode for gradients.
@param tryReuseInputImage put ROI of input image into the pyramid if possible. You can pass false
to force data copying.
@return number of levels in constructed pyramid. Can be less than maxLevel.
*/
CV_EXPORTS_W int buildOpticalFlowPyramid( InputArray img, OutputArrayOfArrays pyramid,
Size winSize, int maxLevel, bool withDerivatives = true,
int pyrBorder = BORDER_REFLECT_101,
int derivBorder = BORDER_CONSTANT,
bool tryReuseInputImage = true );
/** @example samples/cpp/lkdemo.cpp
An example using the Lucas-Kanade optical flow algorithm
*/
/** @brief Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with
pyramids.
@param prevImg first 8-bit input image or pyramid constructed by buildOpticalFlowPyramid.
@param nextImg second input image or pyramid of the same size and the same type as prevImg.
@param prevPts vector of 2D points for which the flow needs to be found; point coordinates must be
single-precision floating-point numbers.
@param nextPts output vector of 2D points (with single-precision floating-point coordinates)
containing the calculated new positions of input features in the second image; when
OPTFLOW_USE_INITIAL_FLOW flag is passed, the vector must have the same size as in the input.
@param status output status vector (of unsigned chars); each element of the vector is set to 1 if
the flow for the corresponding features has been found, otherwise, it is set to 0.
@param err output vector of errors; each element of the vector is set to an error for the
corresponding feature, type of the error measure can be set in flags parameter; if the flow wasn't
found then the error is not defined (use the status parameter to find such cases).
@param winSize size of the search window at each pyramid level.
@param maxLevel 0-based maximal pyramid level number; if set to 0, pyramids are not used (single
level), if set to 1, two levels are used, and so on; if pyramids are passed to input then
algorithm will use as many levels as pyramids have but no more than maxLevel.
@param criteria parameter, specifying the termination criteria of the iterative search algorithm
(after the specified maximum number of iterations criteria.maxCount or when the search window
moves by less than criteria.epsilon.
@param flags operation flags:
- **OPTFLOW_USE_INITIAL_FLOW** uses initial estimations, stored in nextPts; if the flag is
not set, then prevPts is copied to nextPts and is considered the initial estimate.
- **OPTFLOW_LK_GET_MIN_EIGENVALS** use minimum eigen values as an error measure (see
minEigThreshold description); if the flag is not set, then L1 distance between patches
around the original and a moved point, divided by number of pixels in a window, is used as a
error measure.
@param minEigThreshold the algorithm calculates the minimum eigen value of a 2x2 normal matrix of
optical flow equations (this matrix is called a spatial gradient matrix in @cite Bouguet00), divided
by number of pixels in a window; if this value is less than minEigThreshold, then a corresponding
feature is filtered out and its flow is not processed, so it allows to remove bad points and get a
performance boost.
The function implements a sparse iterative version of the Lucas-Kanade optical flow in pyramids. See
@cite Bouguet00 . The function is parallelized with the TBB library.
@note
- An example using the Lucas-Kanade optical flow algorithm can be found at
opencv_source_code/samples/cpp/lkdemo.cpp
- (Python) An example using the Lucas-Kanade optical flow algorithm can be found at
opencv_source_code/samples/python/lk_track.py
- (Python) An example using the Lucas-Kanade tracker for homography matching can be found at
opencv_source_code/samples/python/lk_homography.py
*/
CV_EXPORTS_W void calcOpticalFlowPyrLK( InputArray prevImg, InputArray nextImg,
InputArray prevPts, InputOutputArray nextPts,
OutputArray status, OutputArray err,
Size winSize = Size(21,21), int maxLevel = 3,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
int flags = 0, double minEigThreshold = 1e-4 );
/** @brief Computes a dense optical flow using the Gunnar Farneback's algorithm.
@param prev first 8-bit single-channel input image.
@param next second input image of the same size and the same type as prev.
@param flow computed flow image that has the same size as prev and type CV_32FC2.
@param pyr_scale parameter, specifying the image scale (\<1) to build pyramids for each image;
pyr_scale=0.5 means a classical pyramid, where each next layer is twice smaller than the previous
one.
@param levels number of pyramid layers including the initial image; levels=1 means that no extra
layers are created and only the original images are used.
@param winsize averaging window size; larger values increase the algorithm robustness to image
noise and give more chances for fast motion detection, but yield more blurred motion field.
@param iterations number of iterations the algorithm does at each pyramid level.
@param poly_n size of the pixel neighborhood used to find polynomial expansion in each pixel;
larger values mean that the image will be approximated with smoother surfaces, yielding more
robust algorithm and more blurred motion field, typically poly_n =5 or 7.
@param poly_sigma standard deviation of the Gaussian that is used to smooth derivatives used as a
basis for the polynomial expansion; for poly_n=5, you can set poly_sigma=1.1, for poly_n=7, a
good value would be poly_sigma=1.5.
@param flags operation flags that can be a combination of the following:
- **OPTFLOW_USE_INITIAL_FLOW** uses the input flow as an initial flow approximation.
- **OPTFLOW_FARNEBACK_GAUSSIAN** uses the Gaussian \f$\texttt{winsize}\times\texttt{winsize}\f$
filter instead of a box filter of the same size for optical flow estimation; usually, this
option gives z more accurate flow than with a box filter, at the cost of lower speed;
normally, winsize for a Gaussian window should be set to a larger value to achieve the same
level of robustness.
The function finds an optical flow for each prev pixel using the @cite Farneback2003 algorithm so that
\f[\texttt{prev} (y,x) \sim \texttt{next} ( y + \texttt{flow} (y,x)[1], x + \texttt{flow} (y,x)[0])\f]
@note
- An example using the optical flow algorithm described by Gunnar Farneback can be found at
opencv_source_code/samples/cpp/fback.cpp
- (Python) An example using the optical flow algorithm described by Gunnar Farneback can be
found at opencv_source_code/samples/python/opt_flow.py
*/
CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next, InputOutputArray flow,
double pyr_scale, int levels, int winsize,
int iterations, int poly_n, double poly_sigma,
int flags );
/** @brief Computes an optimal affine transformation between two 2D point sets.
@param src First input 2D point set stored in std::vector or Mat, or an image stored in Mat.
@param dst Second input 2D point set of the same size and the same type as A, or another image.
@param fullAffine If true, the function finds an optimal affine transformation with no additional
restrictions (6 degrees of freedom). Otherwise, the class of transformations to choose from is
limited to combinations of translation, rotation, and uniform scaling (4 degrees of freedom).
The function finds an optimal affine transform *[A|b]* (a 2 x 3 floating-point matrix) that
approximates best the affine transformation between:
* Two point sets
* Two raster images. In this case, the function first finds some features in the src image and
finds the corresponding features in dst image. After that, the problem is reduced to the first
case.
In case of point sets, the problem is formulated as follows: you need to find a 2x2 matrix *A* and
2x1 vector *b* so that:
\f[[A^*|b^*] = arg \min _{[A|b]} \sum _i \| \texttt{dst}[i] - A { \texttt{src}[i]}^T - b \| ^2\f]
where src[i] and dst[i] are the i-th points in src and dst, respectively
\f$[A|b]\f$ can be either arbitrary (when fullAffine=true ) or have a form of
\f[\begin{bmatrix} a_{11} & a_{12} & b_1 \\ -a_{12} & a_{11} & b_2 \end{bmatrix}\f]
when fullAffine=false.
@deprecated Use cv::estimateAffine2D, cv::estimateAffinePartial2D instead. If you are using this function
with images, extract points using cv::calcOpticalFlowPyrLK and then use the estimation functions.
@sa
estimateAffine2D, estimateAffinePartial2D, getAffineTransform, getPerspectiveTransform, findHomography
*/
CV_DEPRECATED CV_EXPORTS Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine );
enum
{
MOTION_TRANSLATION = 0,
MOTION_EUCLIDEAN = 1,
MOTION_AFFINE = 2,
MOTION_HOMOGRAPHY = 3
};
/** @brief Computes the Enhanced Correlation Coefficient value between two images @cite EP08 .
@param templateImage single-channel template image; CV_8U or CV_32F array.
@param inputImage single-channel input image to be warped to provide an image similar to
templateImage, same type as templateImage.
@param inputMask An optional mask to indicate valid values of inputImage.
@sa
findTransformECC
*/
CV_EXPORTS_W double computeECC(InputArray templateImage, InputArray inputImage, InputArray inputMask = noArray());
/** @example samples/cpp/image_alignment.cpp
An example using the image alignment ECC algorithm
*/
/** @brief Finds the geometric transform (warp) between two images in terms of the ECC criterion @cite EP08 .
@param templateImage single-channel template image; CV_8U or CV_32F array.
@param inputImage single-channel input image which should be warped with the final warpMatrix in
order to provide an image similar to templateImage, same type as templateImage.
@param warpMatrix floating-point \f$2\times 3\f$ or \f$3\times 3\f$ mapping matrix (warp).
@param motionType parameter, specifying the type of motion:
- **MOTION_TRANSLATION** sets a translational motion model; warpMatrix is \f$2\times 3\f$ with
the first \f$2\times 2\f$ part being the unity matrix and the rest two parameters being
estimated.
- **MOTION_EUCLIDEAN** sets a Euclidean (rigid) transformation as motion model; three
parameters are estimated; warpMatrix is \f$2\times 3\f$.
- **MOTION_AFFINE** sets an affine motion model (DEFAULT); six parameters are estimated;
warpMatrix is \f$2\times 3\f$.
- **MOTION_HOMOGRAPHY** sets a homography as a motion model; eight parameters are
estimated;\`warpMatrix\` is \f$3\times 3\f$.
@param criteria parameter, specifying the termination criteria of the ECC algorithm;
criteria.epsilon defines the threshold of the increment in the correlation coefficient between two
iterations (a negative criteria.epsilon makes criteria.maxcount the only termination criterion).
Default values are shown in the declaration above.
@param inputMask An optional mask to indicate valid values of inputImage.
@param gaussFiltSize An optional value indicating size of gaussian blur filter; (DEFAULT: 5)
The function estimates the optimum transformation (warpMatrix) with respect to ECC criterion
(@cite EP08), that is
\f[\texttt{warpMatrix} = \arg\max_{W} \texttt{ECC}(\texttt{templateImage}(x,y),\texttt{inputImage}(x',y'))\f]
where
\f[\begin{bmatrix} x' \\ y' \end{bmatrix} = W \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}\f]
(the equation holds with homogeneous coordinates for homography). It returns the final enhanced
correlation coefficient, that is the correlation coefficient between the template image and the
final warped input image. When a \f$3\times 3\f$ matrix is given with motionType =0, 1 or 2, the third
row is ignored.
Unlike findHomography and estimateRigidTransform, the function findTransformECC implements an
area-based alignment that builds on intensity similarities. In essence, the function updates the
initial transformation that roughly aligns the images. If this information is missing, the identity
warp (unity matrix) is used as an initialization. Note that if images undergo strong
displacements/rotations, an initial transformation that roughly aligns the images is necessary
(e.g., a simple euclidean/similarity transform that allows for the images showing the same image
content approximately). Use inverse warping in the second image to take an image close to the first
one, i.e. use the flag WARP_INVERSE_MAP with warpAffine or warpPerspective. See also the OpenCV
sample image_alignment.cpp that demonstrates the use of the function. Note that the function throws
an exception if algorithm does not converges.
@sa
computeECC, estimateAffine2D, estimateAffinePartial2D, findHomography
*/
CV_EXPORTS_W double findTransformECC( InputArray templateImage, InputArray inputImage,
InputOutputArray warpMatrix, int motionType,
TermCriteria criteria,
InputArray inputMask, int gaussFiltSize);
/** @overload */
CV_EXPORTS_W
double findTransformECC(InputArray templateImage, InputArray inputImage,
InputOutputArray warpMatrix, int motionType = MOTION_AFFINE,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001),
InputArray inputMask = noArray());
/** @example samples/cpp/kalman.cpp
An example using the standard Kalman filter
*/
/** @brief Kalman filter class.
The class implements a standard Kalman filter <http://en.wikipedia.org/wiki/Kalman_filter>,
@cite Welch95 . However, you can modify transitionMatrix, controlMatrix, and measurementMatrix to get
an extended Kalman filter functionality.
@note In C API when CvKalman\* kalmanFilter structure is not needed anymore, it should be released
with cvReleaseKalman(&kalmanFilter)
*/
class CV_EXPORTS_W KalmanFilter
{
public:
CV_WRAP KalmanFilter();
/** @overload
@param dynamParams Dimensionality of the state.
@param measureParams Dimensionality of the measurement.
@param controlParams Dimensionality of the control vector.
@param type Type of the created matrices that should be CV_32F or CV_64F.
*/
CV_WRAP KalmanFilter( int dynamParams, int measureParams, int controlParams = 0, int type = CV_32F );
/** @brief Re-initializes Kalman filter. The previous content is destroyed.
@param dynamParams Dimensionality of the state.
@param measureParams Dimensionality of the measurement.
@param controlParams Dimensionality of the control vector.
@param type Type of the created matrices that should be CV_32F or CV_64F.
*/
void init( int dynamParams, int measureParams, int controlParams = 0, int type = CV_32F );
/** @brief Computes a predicted state.
@param control The optional input control
*/
CV_WRAP const Mat& predict( const Mat& control = Mat() );
/** @brief Updates the predicted state from the measurement.
@param measurement The measured system parameters
*/
CV_WRAP const Mat& correct( const Mat& measurement );
CV_PROP_RW Mat statePre; //!< predicted state (x'(k)): x(k)=A*x(k-1)+B*u(k)
CV_PROP_RW Mat statePost; //!< corrected state (x(k)): x(k)=x'(k)+K(k)*(z(k)-H*x'(k))
CV_PROP_RW Mat transitionMatrix; //!< state transition matrix (A)
CV_PROP_RW Mat controlMatrix; //!< control matrix (B) (not used if there is no control)
CV_PROP_RW Mat measurementMatrix; //!< measurement matrix (H)
CV_PROP_RW Mat processNoiseCov; //!< process noise covariance matrix (Q)
CV_PROP_RW Mat measurementNoiseCov;//!< measurement noise covariance matrix (R)
CV_PROP_RW Mat errorCovPre; //!< priori error estimate covariance matrix (P'(k)): P'(k)=A*P(k-1)*At + Q)*/
CV_PROP_RW Mat gain; //!< Kalman gain matrix (K(k)): K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R)
CV_PROP_RW Mat errorCovPost; //!< posteriori error estimate covariance matrix (P(k)): P(k)=(I-K(k)*H)*P'(k)
// temporary matrices
Mat temp1;
Mat temp2;
Mat temp3;
Mat temp4;
Mat temp5;
};
/** @brief Read a .flo file
@param path Path to the file to be loaded
The function readOpticalFlow loads a flow field from a file and returns it as a single matrix.
Resulting Mat has a type CV_32FC2 - floating-point, 2-channel. First channel corresponds to the
flow in the horizontal direction (u), second - vertical (v).
*/
CV_EXPORTS_W Mat readOpticalFlow( const String& path );
/** @brief Write a .flo to disk
@param path Path to the file to be written
@param flow Flow field to be stored
The function stores a flow field in a file, returns true on success, false otherwise.
The flow field must be a 2-channel, floating-point matrix (CV_32FC2). First channel corresponds
to the flow in the horizontal direction (u), second - vertical (v).
*/
CV_EXPORTS_W bool writeOpticalFlow( const String& path, InputArray flow );
/**
Base class for dense optical flow algorithms
*/
class CV_EXPORTS_W DenseOpticalFlow : public Algorithm
{
public:
/** @brief Calculates an optical flow.
@param I0 first 8-bit single-channel input image.
@param I1 second input image of the same size and the same type as prev.
@param flow computed flow image that has the same size as prev and type CV_32FC2.
*/
CV_WRAP virtual void calc( InputArray I0, InputArray I1, InputOutputArray flow ) = 0;
/** @brief Releases all inner buffers.
*/
CV_WRAP virtual void collectGarbage() = 0;
};
/** @brief Base interface for sparse optical flow algorithms.
*/
class CV_EXPORTS_W SparseOpticalFlow : public Algorithm
{
public:
/** @brief Calculates a sparse optical flow.
@param prevImg First input image.
@param nextImg Second input image of the same size and the same type as prevImg.
@param prevPts Vector of 2D points for which the flow needs to be found.
@param nextPts Output vector of 2D points containing the calculated new positions of input features in the second image.
@param status Output status vector. Each element of the vector is set to 1 if the
flow for the corresponding features has been found. Otherwise, it is set to 0.
@param err Optional output vector that contains error response for each point (inverse confidence).
*/
CV_WRAP virtual void calc(InputArray prevImg, InputArray nextImg,
InputArray prevPts, InputOutputArray nextPts,
OutputArray status,
OutputArray err = cv::noArray()) = 0;
};
/** @brief Class computing a dense optical flow using the Gunnar Farneback's algorithm.
*/
class CV_EXPORTS_W FarnebackOpticalFlow : public DenseOpticalFlow
{
public:
CV_WRAP virtual int getNumLevels() const = 0;
CV_WRAP virtual void setNumLevels(int numLevels) = 0;
CV_WRAP virtual double getPyrScale() const = 0;
CV_WRAP virtual void setPyrScale(double pyrScale) = 0;
CV_WRAP virtual bool getFastPyramids() const = 0;
CV_WRAP virtual void setFastPyramids(bool fastPyramids) = 0;
CV_WRAP virtual int getWinSize() const = 0;
CV_WRAP virtual void setWinSize(int winSize) = 0;
CV_WRAP virtual int getNumIters() const = 0;
CV_WRAP virtual void setNumIters(int numIters) = 0;
CV_WRAP virtual int getPolyN() const = 0;
CV_WRAP virtual void setPolyN(int polyN) = 0;
CV_WRAP virtual double getPolySigma() const = 0;
CV_WRAP virtual void setPolySigma(double polySigma) = 0;
CV_WRAP virtual int getFlags() const = 0;
CV_WRAP virtual void setFlags(int flags) = 0;
CV_WRAP static Ptr<FarnebackOpticalFlow> create(
int numLevels = 5,
double pyrScale = 0.5,
bool fastPyramids = false,
int winSize = 13,
int numIters = 10,
int polyN = 5,
double polySigma = 1.1,
int flags = 0);
};
/** @brief Variational optical flow refinement
This class implements variational refinement of the input flow field, i.e.
it uses input flow to initialize the minimization of the following functional:
\f$E(U) = \int_{\Omega} \delta \Psi(E_I) + \gamma \Psi(E_G) + \alpha \Psi(E_S) \f$,
where \f$E_I,E_G,E_S\f$ are color constancy, gradient constancy and smoothness terms
respectively. \f$\Psi(s^2)=\sqrt{s^2+\epsilon^2}\f$ is a robust penalizer to limit the
influence of outliers. A complete formulation and a description of the minimization
procedure can be found in @cite Brox2004
*/
class CV_EXPORTS_W VariationalRefinement : public DenseOpticalFlow
{
public:
/** @brief @ref calc function overload to handle separate horizontal (u) and vertical (v) flow components
(to avoid extra splits/merges) */
CV_WRAP virtual void calcUV(InputArray I0, InputArray I1, InputOutputArray flow_u, InputOutputArray flow_v) = 0;
/** @brief Number of outer (fixed-point) iterations in the minimization procedure.
@see setFixedPointIterations */
CV_WRAP virtual int getFixedPointIterations() const = 0;
/** @copybrief getFixedPointIterations @see getFixedPointIterations */
CV_WRAP virtual void setFixedPointIterations(int val) = 0;
/** @brief Number of inner successive over-relaxation (SOR) iterations
in the minimization procedure to solve the respective linear system.
@see setSorIterations */
CV_WRAP virtual int getSorIterations() const = 0;
/** @copybrief getSorIterations @see getSorIterations */
CV_WRAP virtual void setSorIterations(int val) = 0;
/** @brief Relaxation factor in SOR
@see setOmega */
CV_WRAP virtual float getOmega() const = 0;
/** @copybrief getOmega @see getOmega */
CV_WRAP virtual void setOmega(float val) = 0;
/** @brief Weight of the smoothness term
@see setAlpha */
CV_WRAP virtual float getAlpha() const = 0;
/** @copybrief getAlpha @see getAlpha */
CV_WRAP virtual void setAlpha(float val) = 0;
/** @brief Weight of the color constancy term
@see setDelta */
CV_WRAP virtual float getDelta() const = 0;
/** @copybrief getDelta @see getDelta */
CV_WRAP virtual void setDelta(float val) = 0;
/** @brief Weight of the gradient constancy term
@see setGamma */
CV_WRAP virtual float getGamma() const = 0;
/** @copybrief getGamma @see getGamma */
CV_WRAP virtual void setGamma(float val) = 0;
/** @brief Creates an instance of VariationalRefinement
*/
CV_WRAP static Ptr<VariationalRefinement> create();
};
/** @brief DIS optical flow algorithm.
This class implements the Dense Inverse Search (DIS) optical flow algorithm. More
details about the algorithm can be found at @cite Kroeger2016 . Includes three presets with preselected
parameters to provide reasonable trade-off between speed and quality. However, even the slowest preset is
still relatively fast, use DeepFlow if you need better quality and don't care about speed.
This implementation includes several additional features compared to the algorithm described in the paper,
including spatial propagation of flow vectors (@ref getUseSpatialPropagation), as well as an option to
utilize an initial flow approximation passed to @ref calc (which is, essentially, temporal propagation,
if the previous frame's flow field is passed).
*/
class CV_EXPORTS_W DISOpticalFlow : public DenseOpticalFlow
{
public:
enum
{
PRESET_ULTRAFAST = 0,
PRESET_FAST = 1,
PRESET_MEDIUM = 2
};
/** @brief Finest level of the Gaussian pyramid on which the flow is computed (zero level
corresponds to the original image resolution). The final flow is obtained by bilinear upscaling.
@see setFinestScale */
CV_WRAP virtual int getFinestScale() const = 0;
/** @copybrief getFinestScale @see getFinestScale */
CV_WRAP virtual void setFinestScale(int val) = 0;
/** @brief Size of an image patch for matching (in pixels). Normally, default 8x8 patches work well
enough in most cases.
@see setPatchSize */
CV_WRAP virtual int getPatchSize() const = 0;
/** @copybrief getPatchSize @see getPatchSize */
CV_WRAP virtual void setPatchSize(int val) = 0;
/** @brief Stride between neighbor patches. Must be less than patch size. Lower values correspond
to higher flow quality.
@see setPatchStride */
CV_WRAP virtual int getPatchStride() const = 0;
/** @copybrief getPatchStride @see getPatchStride */
CV_WRAP virtual void setPatchStride(int val) = 0;
/** @brief Maximum number of gradient descent iterations in the patch inverse search stage. Higher values
may improve quality in some cases.
@see setGradientDescentIterations */
CV_WRAP virtual int getGradientDescentIterations() const = 0;
/** @copybrief getGradientDescentIterations @see getGradientDescentIterations */
CV_WRAP virtual void setGradientDescentIterations(int val) = 0;
/** @brief Number of fixed point iterations of variational refinement per scale. Set to zero to
disable variational refinement completely. Higher values will typically result in more smooth and
high-quality flow.
@see setGradientDescentIterations */
CV_WRAP virtual int getVariationalRefinementIterations() const = 0;
/** @copybrief getGradientDescentIterations @see getGradientDescentIterations */
CV_WRAP virtual void setVariationalRefinementIterations(int val) = 0;
/** @brief Weight of the smoothness term
@see setVariationalRefinementAlpha */
CV_WRAP virtual float getVariationalRefinementAlpha() const = 0;
/** @copybrief getVariationalRefinementAlpha @see getVariationalRefinementAlpha */
CV_WRAP virtual void setVariationalRefinementAlpha(float val) = 0;
/** @brief Weight of the color constancy term
@see setVariationalRefinementDelta */
CV_WRAP virtual float getVariationalRefinementDelta() const = 0;
/** @copybrief getVariationalRefinementDelta @see getVariationalRefinementDelta */
CV_WRAP virtual void setVariationalRefinementDelta(float val) = 0;
/** @brief Weight of the gradient constancy term
@see setVariationalRefinementGamma */
CV_WRAP virtual float getVariationalRefinementGamma() const = 0;
/** @copybrief getVariationalRefinementGamma @see getVariationalRefinementGamma */
CV_WRAP virtual void setVariationalRefinementGamma(float val) = 0;
/** @brief Whether to use mean-normalization of patches when computing patch distance. It is turned on
by default as it typically provides a noticeable quality boost because of increased robustness to
illumination variations. Turn it off if you are certain that your sequence doesn't contain any changes
in illumination.
@see setUseMeanNormalization */
CV_WRAP virtual bool getUseMeanNormalization() const = 0;
/** @copybrief getUseMeanNormalization @see getUseMeanNormalization */
CV_WRAP virtual void setUseMeanNormalization(bool val) = 0;
/** @brief Whether to use spatial propagation of good optical flow vectors. This option is turned on by
default, as it tends to work better on average and can sometimes help recover from major errors
introduced by the coarse-to-fine scheme employed by the DIS optical flow algorithm. Turning this
option off can make the output flow field a bit smoother, however.
@see setUseSpatialPropagation */
CV_WRAP virtual bool getUseSpatialPropagation() const = 0;
/** @copybrief getUseSpatialPropagation @see getUseSpatialPropagation */
CV_WRAP virtual void setUseSpatialPropagation(bool val) = 0;
/** @brief Creates an instance of DISOpticalFlow
@param preset one of PRESET_ULTRAFAST, PRESET_FAST and PRESET_MEDIUM
*/
CV_WRAP static Ptr<DISOpticalFlow> create(int preset = DISOpticalFlow::PRESET_FAST);
};
/** @brief Class used for calculating a sparse optical flow.
The class can calculate an optical flow for a sparse feature set using the
iterative Lucas-Kanade method with pyramids.
@sa calcOpticalFlowPyrLK
*/
class CV_EXPORTS_W SparsePyrLKOpticalFlow : public SparseOpticalFlow
{
public:
CV_WRAP virtual Size getWinSize() const = 0;
CV_WRAP virtual void setWinSize(Size winSize) = 0;
CV_WRAP virtual int getMaxLevel() const = 0;
CV_WRAP virtual void setMaxLevel(int maxLevel) = 0;
CV_WRAP virtual TermCriteria getTermCriteria() const = 0;
CV_WRAP virtual void setTermCriteria(TermCriteria& crit) = 0;
CV_WRAP virtual int getFlags() const = 0;
CV_WRAP virtual void setFlags(int flags) = 0;
CV_WRAP virtual double getMinEigThreshold() const = 0;
CV_WRAP virtual void setMinEigThreshold(double minEigThreshold) = 0;
CV_WRAP static Ptr<SparsePyrLKOpticalFlow> create(
Size winSize = Size(21, 21),
int maxLevel = 3, TermCriteria crit =
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
int flags = 0,
double minEigThreshold = 1e-4);
};
/** @brief Base abstract class for the long-term tracker
*/
class CV_EXPORTS_W Tracker
{
protected:
Tracker();
public:
virtual ~Tracker();
/** @brief Initialize the tracker with a known bounding box that surrounded the target
@param image The initial frame
@param boundingBox The initial bounding box
*/
CV_WRAP virtual
void init(InputArray image, const Rect& boundingBox) = 0;
/** @brief Update the tracker, find the new most likely bounding box for the target
@param image The current frame
@param boundingBox The bounding box that represent the new target location, if true was returned, not
modified otherwise
@return True means that target was located and false means that tracker cannot locate target in
current frame. Note, that latter *does not* imply that tracker has failed, maybe target is indeed
missing from the frame (say, out of sight)
*/
CV_WRAP virtual
bool update(InputArray image, CV_OUT Rect& boundingBox) = 0;
};
/** @brief The MIL algorithm trains a classifier in an online manner to separate the object from the
background.
Multiple Instance Learning avoids the drift problem for a robust tracking. The implementation is
based on @cite MIL .
Original code can be found here <http://vision.ucsd.edu/~bbabenko/project_miltrack.shtml>
*/
class CV_EXPORTS_W TrackerMIL : public Tracker
{
protected:
TrackerMIL(); // use ::create()
public:
virtual ~TrackerMIL() CV_OVERRIDE;
struct CV_EXPORTS_W_SIMPLE Params
{
CV_WRAP Params();
//parameters for sampler
CV_PROP_RW float samplerInitInRadius; //!< radius for gathering positive instances during init
CV_PROP_RW int samplerInitMaxNegNum; //!< # negative samples to use during init
CV_PROP_RW float samplerSearchWinSize; //!< size of search window
CV_PROP_RW float samplerTrackInRadius; //!< radius for gathering positive instances during tracking
CV_PROP_RW int samplerTrackMaxPosNum; //!< # positive samples to use during tracking
CV_PROP_RW int samplerTrackMaxNegNum; //!< # negative samples to use during tracking
CV_PROP_RW int featureSetNumFeatures; //!< # features
};
/** @brief Create MIL tracker instance
* @param parameters MIL parameters TrackerMIL::Params
*/
static CV_WRAP
Ptr<TrackerMIL> create(const TrackerMIL::Params &parameters = TrackerMIL::Params());
//void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
//bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE;
};
/** @brief the GOTURN (Generic Object Tracking Using Regression Networks) tracker
*
* GOTURN (@cite GOTURN) is kind of trackers based on Convolutional Neural Networks (CNN). While taking all advantages of CNN trackers,
* GOTURN is much faster due to offline training without online fine-tuning nature.
* GOTURN tracker addresses the problem of single target tracking: given a bounding box label of an object in the first frame of the video,
* we track that object through the rest of the video. NOTE: Current method of GOTURN does not handle occlusions; however, it is fairly
* robust to viewpoint changes, lighting changes, and deformations.
* Inputs of GOTURN are two RGB patches representing Target and Search patches resized to 227x227.
* Outputs of GOTURN are predicted bounding box coordinates, relative to Search patch coordinate system, in format X1,Y1,X2,Y2.
* Original paper is here: <http://davheld.github.io/GOTURN/GOTURN.pdf>
* As long as original authors implementation: <https://github.com/davheld/GOTURN#train-the-tracker>
* Implementation of training algorithm is placed in separately here due to 3d-party dependencies:
* <https://github.com/Auron-X/GOTURN_Training_Toolkit>
* GOTURN architecture goturn.prototxt and trained model goturn.caffemodel are accessible on opencv_extra GitHub repository.
*/
class CV_EXPORTS_W TrackerGOTURN : public Tracker
{
protected:
TrackerGOTURN(); // use ::create()
public:
virtual ~TrackerGOTURN() CV_OVERRIDE;
struct CV_EXPORTS_W_SIMPLE Params
{
CV_WRAP Params();
CV_PROP_RW std::string modelTxt;
CV_PROP_RW std::string modelBin;
};
/** @brief Constructor
@param parameters GOTURN parameters TrackerGOTURN::Params
*/
static CV_WRAP
Ptr<TrackerGOTURN> create(const TrackerGOTURN::Params& parameters = TrackerGOTURN::Params());
//void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
//bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE;
};
class CV_EXPORTS_W TrackerDaSiamRPN : public Tracker
{
protected:
TrackerDaSiamRPN(); // use ::create()
public:
virtual ~TrackerDaSiamRPN() CV_OVERRIDE;
struct CV_EXPORTS_W_SIMPLE Params
{
CV_WRAP Params();
CV_PROP_RW std::string model;
CV_PROP_RW std::string kernel_cls1;
CV_PROP_RW std::string kernel_r1;
CV_PROP_RW int backend;
CV_PROP_RW int target;
};
/** @brief Constructor
@param parameters DaSiamRPN parameters TrackerDaSiamRPN::Params
*/
static CV_WRAP
Ptr<TrackerDaSiamRPN> create(const TrackerDaSiamRPN::Params& parameters = TrackerDaSiamRPN::Params());
/** @brief Return tracking score
*/
CV_WRAP virtual float getTrackingScore() = 0;
//void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
//bool update(InputArray image, CV_OUT Rect& boundingBox) CV_OVERRIDE;
};
//! @} video_track
} // cv
#endif

View File

@@ -0,0 +1,48 @@
/*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.
// Copyright (C) 2013, OpenCV Foundation, 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*/
#ifdef __OPENCV_BUILD
#error this is a compatibility header which should not be used inside the OpenCV library
#endif
#include "opencv2/video.hpp"

View File

@@ -0,0 +1,16 @@
{
"missing_consts": {
"Video" : {
"private" : [
["CV_LKFLOW_INITIAL_GUESSES", 4 ],
["CV_LKFLOW_GET_MIN_EIGENVALS", 8 ]
]
}
},
"func_arg_fix" : {
"calcOpticalFlowPyrLK" : { "prevPts" : {"ctype" : "vector_Point2f"},
"nextPts" : {"ctype" : "vector_Point2f"},
"status" : {"ctype" : "vector_uchar"},
"err" : {"ctype" : "vector_float"} }
}
}

View File

@@ -0,0 +1,43 @@
package org.opencv.test.video;
import org.opencv.test.OpenCVTestCase;
public class BackgroundSubtractorMOGTest extends OpenCVTestCase {
public void testApplyMatMat() {
fail("Not yet implemented");
/*
BackgroundSubtractorMOG backGroundSubtract = new BackgroundSubtractorMOG();
Point bottomRight = new Point(rgbLena.cols() / 2, rgbLena.rows() / 2);
Point topLeft = new Point(0, 0);
Scalar color = new Scalar(128);
Mat mask = new Mat(rgbLena.size(), CvType.CV_16UC3, new Scalar(1));
Imgproc.rectangle(rgbLena, bottomRight, topLeft, color, Imgproc.FILLED);
backGroundSubtract.apply(rgbLena, mask);
Mat truth = new Mat(rgbLena.size(), rgbLena.type(), new Scalar(0));
Imgproc.rectangle(truth, bottomRight, topLeft, color, Imgproc.FILLED);
assertMatEqual(truth, rgbLena);
*/
}
public void testApplyMatMatDouble() {
fail("Not yet implemented");
}
public void testBackgroundSubtractorMOG() {
fail("Not yet implemented");
}
public void testBackgroundSubtractorMOGIntIntDouble() {
fail("Not yet implemented");
}
public void testBackgroundSubtractorMOGIntIntDoubleDouble() {
fail("Not yet implemented");
}
}

View File

@@ -0,0 +1,38 @@
package org.opencv.test.video;
import org.opencv.test.OpenCVTestCase;
import org.opencv.video.KalmanFilter;
public class KalmanFilterTest extends OpenCVTestCase {
public void testCorrect() {
fail("Not yet implemented");
}
public void testKalmanFilter() {
KalmanFilter kf = new KalmanFilter();
assertNotNull(kf);
}
public void testKalmanFilterIntInt() {
fail("Not yet implemented");
}
public void testKalmanFilterIntIntInt() {
fail("Not yet implemented");
}
public void testKalmanFilterIntIntIntInt() {
fail("Not yet implemented");
}
public void testPredict() {
fail("Not yet implemented");
}
public void testPredictMat() {
fail("Not yet implemented");
}
}

View File

@@ -0,0 +1,39 @@
package org.opencv.test.video;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.CvException;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.test.OpenCVTestCase;
import org.opencv.video.Tracker;
import org.opencv.video.TrackerGOTURN;
import org.opencv.video.TrackerMIL;
public class TrackerCreateTest extends OpenCVTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
}
public void testCreateTrackerGOTURN() {
try {
Tracker tracker = TrackerGOTURN.create();
assert(tracker != null);
} catch (CvException e) {
// expected, model files may be missing
}
}
public void testCreateTrackerMIL() {
Tracker tracker = TrackerMIL.create();
assert(tracker != null);
Mat mat = new Mat(100, 100, CvType.CV_8UC1);
Rect rect = new Rect(10, 10, 30, 30);
tracker.init(mat, rect); // should not crash (https://github.com/opencv/opencv/issues/19915)
}
}

View File

@@ -0,0 +1,99 @@
package org.opencv.test.video;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.test.OpenCVTestCase;
import org.opencv.video.Video;
public class VideoTest extends OpenCVTestCase {
private MatOfFloat err = null;
private int h;
private MatOfPoint2f nextPts = null;
private MatOfPoint2f prevPts = null;
private int shift1;
private int shift2;
private MatOfByte status = null;
private Mat subLena1 = null;
private Mat subLena2 = null;
private int w;
@Override
protected void setUp() throws Exception {
super.setUp();
shift1 = 10;
shift2 = 17;
w = (int)(rgbLena.cols() / 2);
h = (int)(rgbLena.rows() / 2);
subLena1 = rgbLena.submat(shift1, h + shift1, shift1, w + shift1);
subLena2 = rgbLena.submat(shift2, h + shift2, shift2, w + shift2);
prevPts = new MatOfPoint2f(new Point(11d, 8d), new Point(5d, 5d), new Point(10d, 10d));
nextPts = new MatOfPoint2f();
status = new MatOfByte();
err = new MatOfFloat();
}
public void testCalcGlobalOrientation() {
fail("Not yet implemented");
}
public void testCalcMotionGradientMatMatMatDoubleDouble() {
fail("Not yet implemented");
}
public void testCalcMotionGradientMatMatMatDoubleDoubleInt() {
fail("Not yet implemented");
}
public void testCalcOpticalFlowFarneback() {
fail("Not yet implemented");
}
public void testCalcOpticalFlowPyrLKMatMatListOfPointListOfPointListOfByteListOfFloat() {
Video.calcOpticalFlowPyrLK(subLena1, subLena2, prevPts, nextPts, status, err);
assertEquals(3, Core.countNonZero(status));
}
public void testCalcOpticalFlowPyrLKMatMatListOfPointListOfPointListOfByteListOfFloatSize() {
Size sz = new Size(3, 3);
Video.calcOpticalFlowPyrLK(subLena1, subLena2, prevPts, nextPts, status, err, sz, 3);
assertEquals(0, Core.countNonZero(status));
}
public void testCalcOpticalFlowPyrLKMatMatListOfPointListOfPointListOfByteListOfFloatSizeIntTermCriteriaDoubleIntDouble() {
fail("Not yet implemented");
}
public void testCamShift() {
fail("Not yet implemented");
}
public void testEstimateRigidTransform() {
fail("Not yet implemented");
}
public void testMeanShift() {
fail("Not yet implemented");
}
public void testSegmentMotion() {
fail("Not yet implemented");
}
public void testUpdateMotionHistory() {
fail("Not yet implemented");
}
}

View File

@@ -0,0 +1,5 @@
#ifdef HAVE_OPENCV_VIDEO
typedef TrackerMIL::Params TrackerMIL_Params;
typedef TrackerGOTURN::Params TrackerGOTURN_Params;
typedef TrackerDaSiamRPN::Params TrackerDaSiamRPN_Params;
#endif

View File

@@ -0,0 +1,100 @@
#!/usr/bin/env python
'''
Lucas-Kanade homography tracker test
===============================
Uses goodFeaturesToTrack for track initialization and back-tracking for match verification
between frames. Finds homography between reference and current views.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
#local modules
from tst_scene_render import TestSceneRender
from tests_common import NewOpenCVTests, isPointInRect
lk_params = dict( winSize = (19, 19),
maxLevel = 2,
criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
feature_params = dict( maxCorners = 1000,
qualityLevel = 0.01,
minDistance = 8,
blockSize = 19 )
def checkedTrace(img0, img1, p0, back_threshold = 1.0):
p1, _st, _err = cv.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
p0r, _st, _err = cv.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
d = abs(p0-p0r).reshape(-1, 2).max(-1)
status = d < back_threshold
return p1, status
class lk_homography_test(NewOpenCVTests):
render = None
framesCounter = 0
frame = frame0 = None
p0 = None
p1 = None
gray0 = gray1 = None
numFeaturesInRectOnStart = 0
def test_lk_homography(self):
self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'),
self.get_sample('samples/data/box.png'), noise = 0.1, speed = 1.0)
frame = self.render.getNextFrame()
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
self.frame0 = frame.copy()
self.p0 = cv.goodFeaturesToTrack(frame_gray, **feature_params)
isForegroundHomographyFound = False
if self.p0 is not None:
self.p1 = self.p0
self.gray0 = frame_gray
self.gray1 = frame_gray
currRect = self.render.getCurrentRect()
for (x,y) in self.p0[:,0]:
if isPointInRect((x,y), currRect):
self.numFeaturesInRectOnStart += 1
while self.framesCounter < 200:
self.framesCounter += 1
frame = self.render.getNextFrame()
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
if self.p0 is not None:
p2, trace_status = checkedTrace(self.gray1, frame_gray, self.p1)
self.p1 = p2[trace_status].copy()
self.p0 = self.p0[trace_status].copy()
self.gray1 = frame_gray
if len(self.p0) < 4:
self.p0 = None
continue
_H, status = cv.findHomography(self.p0, self.p1, cv.RANSAC, 5.0)
goodPointsInRect = 0
goodPointsOutsideRect = 0
for (_x0, _y0), (x1, y1), good in zip(self.p0[:,0], self.p1[:,0], status[:,0]):
if good:
if isPointInRect((x1,y1), self.render.getCurrentRect()):
goodPointsInRect += 1
else: goodPointsOutsideRect += 1
if goodPointsOutsideRect < goodPointsInRect:
isForegroundHomographyFound = True
self.assertGreater(float(goodPointsInRect) / (self.numFeaturesInRectOnStart + 1), 0.6)
else:
self.p0 = cv.goodFeaturesToTrack(frame_gray, **feature_params)
self.assertEqual(isForegroundHomographyFound, True)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@@ -0,0 +1,115 @@
#!/usr/bin/env python
'''
Lucas-Kanade tracker
====================
Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack
for track initialization and back-tracking for match verification
between frames.
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
#local modules
from tst_scene_render import TestSceneRender
from tests_common import NewOpenCVTests, intersectionRate, isPointInRect
lk_params = dict( winSize = (15, 15),
maxLevel = 2,
criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
feature_params = dict( maxCorners = 500,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
def getRectFromPoints(points):
distances = []
for point in points:
distances.append(cv.norm(point, cv.NORM_L2))
x0, y0 = points[np.argmin(distances)]
x1, y1 = points[np.argmax(distances)]
return np.array([x0, y0, x1, y1])
class lk_track_test(NewOpenCVTests):
track_len = 10
detect_interval = 5
tracks = []
frame_idx = 0
render = None
def test_lk_track(self):
self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), self.get_sample('samples/data/box.png'))
self.runTracker()
def runTracker(self):
foregroundPointsNum = 0
while True:
frame = self.render.getNextFrame()
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
if len(self.tracks) > 0:
img0, img1 = self.prev_gray, frame_gray
p0 = np.float32([tr[-1][0] for tr in self.tracks]).reshape(-1, 1, 2)
p1, _st, _err = cv.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
p0r, _st, _err = cv.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
d = abs(p0-p0r).reshape(-1, 2).max(-1)
good = d < 1
new_tracks = []
for tr, (x, y), good_flag in zip(self.tracks, p1.reshape(-1, 2), good):
if not good_flag:
continue
tr.append([(x, y), self.frame_idx])
if len(tr) > self.track_len:
del tr[0]
new_tracks.append(tr)
self.tracks = new_tracks
if self.frame_idx % self.detect_interval == 0:
goodTracksCount = 0
for tr in self.tracks:
oldRect = self.render.getRectInTime(self.render.timeStep * tr[0][1])
newRect = self.render.getRectInTime(self.render.timeStep * tr[-1][1])
if isPointInRect(tr[0][0], oldRect) and isPointInRect(tr[-1][0], newRect):
goodTracksCount += 1
if self.frame_idx == self.detect_interval:
foregroundPointsNum = goodTracksCount
fgIndex = float(foregroundPointsNum) / (foregroundPointsNum + 1)
fgRate = float(goodTracksCount) / (len(self.tracks) + 1)
if self.frame_idx > 0:
self.assertGreater(fgIndex, 0.9)
self.assertGreater(fgRate, 0.2)
mask = np.zeros_like(frame_gray)
mask[:] = 255
for x, y in [np.int32(tr[-1][0]) for tr in self.tracks]:
cv.circle(mask, (x, y), 5, 0, -1)
p = cv.goodFeaturesToTrack(frame_gray, mask = mask, **feature_params)
if p is not None:
for x, y in np.float32(p).reshape(-1, 2):
self.tracks.append([[(x, y), self.frame_idx]])
self.frame_idx += 1
self.prev_gray = frame_gray
if self.frame_idx > 300:
break
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python
import os
import numpy as np
import cv2 as cv
from tests_common import NewOpenCVTests, unittest
class tracking_test(NewOpenCVTests):
def test_createTracker(self):
t = cv.TrackerMIL_create()
try:
t = cv.TrackerGOTURN_create()
except cv.error as e:
pass # may fail due to missing DL model files
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@@ -0,0 +1,95 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
#ifdef HAVE_OPENCL
#include "../perf_bgfg_utils.hpp"
namespace cvtest {
namespace ocl {
//////////////////////////// KNN//////////////////////////
typedef tuple<string, int> VideoKNNParamType;
typedef TestBaseWithParam<VideoKNNParamType> KNN_Apply;
typedef TestBaseWithParam<VideoKNNParamType> KNN_GetBackgroundImage;
using namespace opencv_test;
OCL_PERF_TEST_P(KNN_Apply, KNN, Combine(Values("cv/video/768x576.avi", "cv/video/1920x1080.avi"), Values(1,3)))
{
VideoKNNParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = get<1>(params);
int nFrame = 5;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer);
UMat u_foreground;
OCL_TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorKNN> knn = createBackgroundSubtractorKNN();
knn->setDetectShadows(false);
u_foreground.release();
for (int i = 0; i < nFrame; i++)
{
knn->apply(frame_buffer[i], u_foreground);
}
}
SANITY_CHECK_NOTHING();
}
OCL_PERF_TEST_P(KNN_GetBackgroundImage, KNN, Values(
std::make_pair<string, int>("cv/video/768x576.avi", 5),
std::make_pair<string, int>("cv/video/1920x1080.avi", 5)))
{
VideoKNNParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = 3;
const int skipFrames = get<1>(params);
int nFrame = 10;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer, skipFrames);
UMat u_foreground, u_background;
OCL_TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorKNN> knn = createBackgroundSubtractorKNN();
knn->setDetectShadows(false);
u_foreground.release();
u_background.release();
for (int i = 0; i < nFrame; i++)
{
knn->apply(frame_buffer[i], u_foreground);
}
knn->getBackgroundImage(u_background);
}
#ifdef DEBUG_BGFG
imwrite(format("fg_%d_%d_knn_ocl.png", frame_buffer[0].rows, cn), u_foreground.getMat(ACCESS_READ));
imwrite(format("bg_%d_%d_knn_ocl.png", frame_buffer[0].rows, cn), u_background.getMat(ACCESS_READ));
#endif
SANITY_CHECK_NOTHING();
}
}}// namespace cvtest::ocl
#endif

View File

@@ -0,0 +1,95 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
#ifdef HAVE_OPENCL
#include "../perf_bgfg_utils.hpp"
namespace opencv_test {
namespace ocl {
//////////////////////////// Mog2//////////////////////////
typedef tuple<string, int> VideoMOG2ParamType;
typedef TestBaseWithParam<VideoMOG2ParamType> MOG2_Apply;
typedef TestBaseWithParam<VideoMOG2ParamType> MOG2_GetBackgroundImage;
using namespace opencv_test;
OCL_PERF_TEST_P(MOG2_Apply, Mog2, Combine(Values("cv/video/768x576.avi", "cv/video/1920x1080.avi"), Values(1,3)))
{
VideoMOG2ParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = get<1>(params);
int nFrame = 5;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer);
UMat u_foreground;
OCL_TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2();
mog2->setDetectShadows(false);
u_foreground.release();
for (int i = 0; i < nFrame; i++)
{
mog2->apply(frame_buffer[i], u_foreground);
}
}
SANITY_CHECK_NOTHING();
}
OCL_PERF_TEST_P(MOG2_GetBackgroundImage, Mog2, Values(
std::make_pair<string, int>("cv/video/768x576.avi", 5),
std::make_pair<string, int>("cv/video/1920x1080.avi", 5)))
{
VideoMOG2ParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = 3;
const int skipFrames = get<1>(params);
int nFrame = 10;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer, skipFrames);
UMat u_foreground, u_background;
OCL_TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2();
mog2->setDetectShadows(false);
u_foreground.release();
u_background.release();
for (int i = 0; i < nFrame; i++)
{
mog2->apply(frame_buffer[i], u_foreground);
}
mog2->getBackgroundImage(u_background);
}
#ifdef DEBUG_BGFG
imwrite(format("fg_%d_%d_mog2_ocl.png", frame_buffer[0].rows, cn), u_foreground.getMat(ACCESS_READ));
imwrite(format("bg_%d_%d_mog2_ocl.png", frame_buffer[0].rows, cn), u_background.getMat(ACCESS_READ));
#endif
SANITY_CHECK_NOTHING();
}
}}// namespace opencv_test::ocl
#endif

View File

@@ -0,0 +1,73 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
namespace opencv_test { namespace {
#ifdef HAVE_OPENCL
void MakeArtificialExample(UMat &dst_frame1, UMat &dst_frame2);
typedef tuple<String, Size> DISParams;
typedef TestBaseWithParam<DISParams> DenseOpticalFlow_DIS;
OCL_PERF_TEST_P(DenseOpticalFlow_DIS, perf,
Combine(Values("PRESET_ULTRAFAST", "PRESET_FAST", "PRESET_MEDIUM"), Values(szVGA, sz720p, sz1080p)))
{
DISParams params = GetParam();
// use strings to print preset names in the perf test results:
String preset_string = get<0>(params);
int preset = DISOpticalFlow::PRESET_FAST;
if (preset_string == "PRESET_ULTRAFAST")
preset = DISOpticalFlow::PRESET_ULTRAFAST;
else if (preset_string == "PRESET_FAST")
preset = DISOpticalFlow::PRESET_FAST;
else if (preset_string == "PRESET_MEDIUM")
preset = DISOpticalFlow::PRESET_MEDIUM;
Size sz = get<1>(params);
UMat frame1(sz, CV_8U);
UMat frame2(sz, CV_8U);
UMat flow;
MakeArtificialExample(frame1, frame2);
Ptr<DenseOpticalFlow> algo = DISOpticalFlow::create(preset);
PERF_SAMPLE_BEGIN()
{
algo->calc(frame1, frame2, flow);
}
PERF_SAMPLE_END()
SANITY_CHECK_NOTHING();
}
void MakeArtificialExample(UMat &dst_frame1, UMat &dst_frame2)
{
int src_scale = 2;
int OF_scale = 6;
double sigma = dst_frame1.cols / 300;
UMat tmp(Size(dst_frame1.cols / (1 << src_scale), dst_frame1.rows / (1 << src_scale)), CV_8U);
randu(tmp, 0, 255);
resize(tmp, dst_frame1, dst_frame1.size(), 0.0, 0.0, INTER_LINEAR_EXACT);
resize(tmp, dst_frame2, dst_frame2.size(), 0.0, 0.0, INTER_LINEAR_EXACT);
Mat displacement_field(Size(dst_frame1.cols / (1 << OF_scale), dst_frame1.rows / (1 << OF_scale)),
CV_32FC2);
randn(displacement_field, 0.0, sigma);
resize(displacement_field, displacement_field, dst_frame2.size(), 0.0, 0.0, INTER_CUBIC);
for (int i = 0; i < displacement_field.rows; i++)
for (int j = 0; j < displacement_field.cols; j++)
displacement_field.at<Vec2f>(i, j) += Vec2f((float)j, (float)i);
remap(dst_frame2, dst_frame2, displacement_field, Mat(), INTER_LINEAR, BORDER_REPLICATE);
}
#endif // HAVE_OPENCL
}} // namespace

View File

@@ -0,0 +1,36 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
#if 0 //def HAVE_OPENCL
namespace opencv_test {
namespace ocl {
///////////// UpdateMotionHistory ////////////////////////
typedef TestBaseWithParam<Size> UpdateMotionHistoryFixture;
OCL_PERF_TEST_P(UpdateMotionHistoryFixture, UpdateMotionHistory, OCL_TEST_SIZES)
{
const Size size = GetParam();
checkDeviceMaxMemoryAllocSize(size, CV_32FC1);
UMat silhouette(size, CV_8UC1), mhi(size, CV_32FC1);
randu(silhouette, -5, 5);
declare.in(mhi, WARMUP_RNG);
OCL_TEST_CYCLE() cv::updateMotionHistory(silhouette, mhi, 1, 0.5);
SANITY_CHECK(mhi);
}
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@@ -0,0 +1,112 @@
/*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) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Fangfang Bai, fangfang@multicorewareinc.com
// Jin Ma, jin@multicorewareinc.com
//
// 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 "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
///////////// FarnebackOpticalFlow ////////////////////////
CV_ENUM(farneFlagType, 0, OPTFLOW_FARNEBACK_GAUSSIAN)
typedef tuple< tuple<int, double>, farneFlagType, bool > FarnebackOpticalFlowParams;
typedef TestBaseWithParam<FarnebackOpticalFlowParams> FarnebackOpticalFlowFixture;
OCL_PERF_TEST_P(FarnebackOpticalFlowFixture, FarnebackOpticalFlow,
::testing::Combine(
::testing::Values(
make_tuple<int, double>(5, 1.1),
make_tuple<int, double>(7, 1.5)
),
farneFlagType::all(),
::testing::Bool()
)
)
{
Mat frame0 = imread(getDataPath("gpu/opticalflow/rubberwhale1.png"), cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame0.empty()) << "can't load rubberwhale1.png";
Mat frame1 = imread(getDataPath("gpu/opticalflow/rubberwhale2.png"), cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame1.empty()) << "can't load rubberwhale2.png";
const Size srcSize = frame0.size();
const int numLevels = 5;
const int winSize = 13;
const int numIters = 10;
const FarnebackOpticalFlowParams params = GetParam();
const tuple<int, double> polyParams = get<0>(params);
const int polyN = get<0>(polyParams);
const double polySigma = get<1>(polyParams);
const double pyrScale = 0.5;
int flags = get<1>(params);
const bool useInitFlow = get<2>(params);
const double eps = 0.1;
UMat uFrame0; frame0.copyTo(uFrame0);
UMat uFrame1; frame1.copyTo(uFrame1);
UMat uFlow(srcSize, CV_32FC2);
declare.in(uFrame0, uFrame1, WARMUP_READ).out(uFlow, WARMUP_READ);
if (useInitFlow)
{
cv::calcOpticalFlowFarneback(uFrame0, uFrame1, uFlow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags);
flags |= OPTFLOW_USE_INITIAL_FLOW;
}
OCL_TEST_CYCLE()
cv::calcOpticalFlowFarneback(uFrame0, uFrame1, uFlow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags);
SANITY_CHECK(uFlow, eps, ERROR_RELATIVE);
}
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@@ -0,0 +1,104 @@
/*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) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Fangfang Bai, fangfang@multicorewareinc.com
// Jin Ma, jin@multicorewareinc.com
//
// 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 "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
typedef tuple< int > PyrLKOpticalFlowParams;
typedef TestBaseWithParam<PyrLKOpticalFlowParams> PyrLKOpticalFlowFixture;
OCL_PERF_TEST_P(PyrLKOpticalFlowFixture, PyrLKOpticalFlow,
::testing::Values(1000, 2000, 4000)
)
{
Mat frame0 = imread(getDataPath("gpu/opticalflow/rubberwhale1.png"), cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame0.empty()) << "can't load rubberwhale1.png";
Mat frame1 = imread(getDataPath("gpu/opticalflow/rubberwhale2.png"), cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame1.empty()) << "can't load rubberwhale2.png";
UMat uFrame0; frame0.copyTo(uFrame0);
UMat uFrame1; frame1.copyTo(uFrame1);
const Size winSize = Size(21, 21);
const int maxLevel = 3;
const TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01);
const int flags = 0;
const float minEigThreshold = 1e-4f;
const double eps = 1.0;
const PyrLKOpticalFlowParams params = GetParam();
const int pointsCount = get<0>(params);
// SKIP unstable tests
#ifdef __linux__
if (cvtest::skipUnstableTests && ocl::useOpenCL())
{
if (ocl::Device::getDefault().isIntel())
throw ::perf::TestBase::PerfSkipTestException();
}
#endif
vector<Point2f> pts;
goodFeaturesToTrack(frame0, pts, pointsCount, 0.01, 0.0);
Mat ptsMat(1, static_cast<int>(pts.size()), CV_32FC2, (void *)&pts[0]);
declare.in(uFrame0, uFrame1, WARMUP_READ);
UMat uNextPts, uStatus, uErr;
OCL_TEST_CYCLE()
cv::calcOpticalFlowPyrLK(uFrame0, uFrame1, pts, uNextPts, uStatus, uErr, winSize, maxLevel, criteria, flags, minEigThreshold);
SANITY_CHECK(uNextPts, eps);
}
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@@ -0,0 +1,88 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "perf_precomp.hpp"
#include "perf_bgfg_utils.hpp"
namespace opencv_test { namespace {
//////////////////////////// KNN//////////////////////////
typedef tuple<std::string, int> VideoKNNParamType;
typedef TestBaseWithParam<VideoKNNParamType> KNN_Apply;
typedef TestBaseWithParam<VideoKNNParamType> KNN_GetBackgroundImage;
PERF_TEST_P(KNN_Apply, KNN, Combine(Values("cv/video/768x576.avi", "cv/video/1920x1080.avi"), Values(1,3)))
{
VideoKNNParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = get<1>(params);
int nFrame = 5;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer);
Mat foreground;
TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorKNN> knn = createBackgroundSubtractorKNN();
knn->setDetectShadows(false);
foreground.release();
for (int i = 0; i < nFrame; i++)
{
knn->apply(frame_buffer[i], foreground);
}
}
SANITY_CHECK_NOTHING();
}
PERF_TEST_P(KNN_GetBackgroundImage, KNN, Values(
std::make_pair<string, int>("cv/video/768x576.avi", 5),
std::make_pair<string, int>("cv/video/1920x1080.avi", 5)))
{
VideoKNNParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = 3;
const int skipFrames = get<1>(params);
int nFrame = 10;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer, skipFrames);
Mat foreground, background;
TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorKNN> knn = createBackgroundSubtractorKNN();
knn->setDetectShadows(false);
foreground.release();
background.release();
for (int i = 0; i < nFrame; i++)
{
knn->apply(frame_buffer[i], foreground);
}
knn->getBackgroundImage(background);
}
#ifdef DEBUG_BGFG
imwrite(format("fg_%d_%d_knn.png", frame_buffer[0].rows, cn), foreground);
imwrite(format("bg_%d_%d_knn.png", frame_buffer[0].rows, cn), background);
#endif
SANITY_CHECK_NOTHING();
}
}}// namespace

View File

@@ -0,0 +1,88 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "perf_precomp.hpp"
#include "perf_bgfg_utils.hpp"
namespace opencv_test { namespace {
//////////////////////////// Mog2//////////////////////////
typedef tuple<std::string, int> VideoMOG2ParamType;
typedef TestBaseWithParam<VideoMOG2ParamType> MOG2_Apply;
typedef TestBaseWithParam<VideoMOG2ParamType> MOG2_GetBackgroundImage;
PERF_TEST_P(MOG2_Apply, Mog2, Combine(Values("cv/video/768x576.avi", "cv/video/1920x1080.avi"), Values(1,3)))
{
VideoMOG2ParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = get<1>(params);
int nFrame = 5;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer);
Mat foreground;
TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2();
mog2->setDetectShadows(false);
foreground.release();
for (int i = 0; i < nFrame; i++)
{
mog2->apply(frame_buffer[i], foreground);
}
}
SANITY_CHECK_NOTHING();
}
PERF_TEST_P(MOG2_GetBackgroundImage, Mog2, Values(
std::make_pair<string, int>("cv/video/768x576.avi", 5),
std::make_pair<string, int>("cv/video/1920x1080.avi", 5)))
{
VideoMOG2ParamType params = GetParam();
const string inputFile = getDataPath(get<0>(params));
const int cn = 3;
const int skipFrames = get<1>(params);
int nFrame = 10;
vector<Mat> frame_buffer(nFrame);
cv::VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
prepareData(cap, cn, frame_buffer, skipFrames);
Mat foreground, background;
TEST_CYCLE()
{
Ptr<cv::BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2();
mog2->setDetectShadows(false);
foreground.release();
background.release();
for (int i = 0; i < nFrame; i++)
{
mog2->apply(frame_buffer[i], foreground);
}
mog2->getBackgroundImage(background);
}
#ifdef DEBUG_BGFG
imwrite(format("fg_%d_%d_mog2.png", frame_buffer[0].rows, cn), foreground);
imwrite(format("bg_%d_%d_mog2.png", frame_buffer[0].rows, cn), background);
#endif
SANITY_CHECK_NOTHING();
}
}}// namespace

View File

@@ -0,0 +1,48 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
namespace opencv_test {
//#define DEBUG_BGFG
using namespace testing;
using namespace cvtest;
using namespace perf;
namespace {
using namespace cv;
static void cvtFrameFmt(std::vector<Mat>& input, std::vector<Mat>& output)
{
for(int i = 0; i< (int)(input.size()); i++)
{
cvtColor(input[i], output[i], COLOR_RGB2GRAY);
}
}
static void prepareData(VideoCapture& cap, int cn, std::vector<Mat>& frame_buffer, int skipFrames = 0)
{
std::vector<Mat> frame_buffer_init;
int nFrame = (int)frame_buffer.size();
for (int i = 0; i < skipFrames; i++)
{
cv::Mat frame;
cap >> frame;
}
for (int i = 0; i < nFrame; i++)
{
cv::Mat frame;
cap >> frame;
ASSERT_FALSE(frame.empty());
frame_buffer_init.push_back(frame);
}
if (cn == 1)
cvtFrameFmt(frame_buffer_init, frame_buffer);
else
frame_buffer.swap(frame_buffer_init);
}
}}

View File

@@ -0,0 +1,66 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
void MakeArtificialExample(Mat &dst_frame1, Mat &dst_frame2);
typedef tuple<String, Size> DISParams;
typedef TestBaseWithParam<DISParams> DenseOpticalFlow_DIS;
PERF_TEST_P(DenseOpticalFlow_DIS, perf,
Combine(Values("PRESET_ULTRAFAST", "PRESET_FAST", "PRESET_MEDIUM"), Values(szVGA, sz720p, sz1080p)))
{
DISParams params = GetParam();
// use strings to print preset names in the perf test results:
String preset_string = get<0>(params);
int preset = DISOpticalFlow::PRESET_FAST;
if (preset_string == "PRESET_ULTRAFAST")
preset = DISOpticalFlow::PRESET_ULTRAFAST;
else if (preset_string == "PRESET_FAST")
preset = DISOpticalFlow::PRESET_FAST;
else if (preset_string == "PRESET_MEDIUM")
preset = DISOpticalFlow::PRESET_MEDIUM;
Size sz = get<1>(params);
Mat frame1(sz, CV_8U);
Mat frame2(sz, CV_8U);
Mat flow;
MakeArtificialExample(frame1, frame2);
TEST_CYCLE_N(10)
{
Ptr<DenseOpticalFlow> algo = DISOpticalFlow::create(preset);
algo->calc(frame1, frame2, flow);
}
SANITY_CHECK_NOTHING();
}
void MakeArtificialExample(Mat &dst_frame1, Mat &dst_frame2)
{
int src_scale = 2;
int OF_scale = 6;
double sigma = dst_frame1.cols / 300;
Mat tmp(Size(dst_frame1.cols / (1 << src_scale), dst_frame1.rows / (1 << src_scale)), CV_8U);
randu(tmp, 0, 255);
resize(tmp, dst_frame1, dst_frame1.size(), 0.0, 0.0, INTER_LINEAR_EXACT);
resize(tmp, dst_frame2, dst_frame2.size(), 0.0, 0.0, INTER_LINEAR_EXACT);
Mat displacement_field(Size(dst_frame1.cols / (1 << OF_scale), dst_frame1.rows / (1 << OF_scale)),
CV_32FC2);
randn(displacement_field, 0.0, sigma);
resize(displacement_field, displacement_field, dst_frame2.size(), 0.0, 0.0, INTER_CUBIC);
for (int i = 0; i < displacement_field.rows; i++)
for (int j = 0; j < displacement_field.cols; j++)
displacement_field.at<Vec2f>(i, j) += Vec2f((float)j, (float)i);
remap(dst_frame2, dst_frame2, displacement_field, Mat(), INTER_LINEAR, BORDER_REPLICATE);
}
}} // namespace

View File

@@ -0,0 +1,71 @@
#include "perf_precomp.hpp"
namespace opencv_test
{
using namespace perf;
CV_ENUM(MotionType, MOTION_TRANSLATION, MOTION_EUCLIDEAN, MOTION_AFFINE, MOTION_HOMOGRAPHY)
typedef tuple<MotionType> MotionType_t;
typedef perf::TestBaseWithParam<MotionType_t> TransformationType;
PERF_TEST_P(TransformationType, findTransformECC, /*testing::ValuesIn(MotionType::all())*/
testing::Values((int) MOTION_TRANSLATION, (int) MOTION_EUCLIDEAN,
(int) MOTION_AFFINE, (int) MOTION_HOMOGRAPHY)
)
{
Mat img = imread(getDataPath("cv/shared/fruits_ecc.png"),0);
Mat templateImage;
int transform_type = get<0>(GetParam());
Mat warpMat;
Mat warpGround;
double angle;
switch (transform_type) {
case MOTION_TRANSLATION:
warpGround = (Mat_<float>(2,3) << 1.f, 0.f, 7.234f,
0.f, 1.f, 11.839f);
warpAffine(img, templateImage, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
case MOTION_EUCLIDEAN:
angle = CV_PI/30;
warpGround = (Mat_<float>(2,3) << (float)cos(angle), (float)-sin(angle), 12.123f,
(float)sin(angle), (float)cos(angle), 14.789f);
warpAffine(img, templateImage, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
case MOTION_AFFINE:
warpGround = (Mat_<float>(2,3) << 0.98f, 0.03f, 15.523f,
-0.02f, 0.95f, 10.456f);
warpAffine(img, templateImage, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
case MOTION_HOMOGRAPHY:
warpGround = (Mat_<float>(3,3) << 0.98f, 0.03f, 15.523f,
-0.02f, 0.95f, 10.456f,
0.0002f, 0.0003f, 1.f);
warpPerspective(img, templateImage, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
}
TEST_CYCLE()
{
if (transform_type<3)
warpMat = Mat::eye(2,3, CV_32F);
else
warpMat = Mat::eye(3,3, CV_32F);
findTransformECC(templateImage, img, warpMat, transform_type,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 5, -1));
}
SANITY_CHECK(warpMat, 3e-3);
}
} // namespace

View File

@@ -0,0 +1,22 @@
#include "perf_precomp.hpp"
#if defined(HAVE_HPX)
#include <hpx/hpx_main.hpp>
#endif
static
void initTests()
{
const char* extraTestDataPath =
#ifdef WINRT
NULL;
#else
getenv("OPENCV_DNN_TEST_DATA_PATH");
#endif
if (extraTestDataPath)
cvtest::addDataSearchPath(extraTestDataPath);
cvtest::addDataSearchSubDirectory(""); // override "cv" prefix below to access without "../dnn" hacks
}
CV_PERF_TEST_MAIN(video, initTests())

View File

@@ -0,0 +1,269 @@
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
using namespace perf;
typedef tuple<std::string, int, int, tuple<int,int>, int> Path_Idx_Cn_NPoints_WSize_t;
typedef TestBaseWithParam<Path_Idx_Cn_NPoints_WSize_t> Path_Idx_Cn_NPoints_WSize;
void FormTrackingPointsArray(vector<Point2f>& points, int width, int height, int nPointsX, int nPointsY)
{
int stepX = width / nPointsX;
int stepY = height / nPointsY;
if (stepX < 1 || stepY < 1) FAIL() << "Specified points number is too big";
points.clear();
points.reserve(nPointsX * nPointsY);
for( int x = stepX / 2; x < width; x += stepX )
{
for( int y = stepY / 2; y < height; y += stepY )
{
Point2f pt(static_cast<float>(x), static_cast<float>(y));
points.push_back(pt);
}
}
}
PERF_TEST_P(Path_Idx_Cn_NPoints_WSize, OpticalFlowPyrLK_full, testing::Combine(
testing::Values<std::string>("cv/optflow/frames/VGA_%02d.png", "cv/optflow/frames/720p_%02d.png"),
testing::Range(1, 3),
testing::Values(1, 3, 4),
testing::Values(make_tuple(9, 9), make_tuple(15, 15)),
testing::Values(7, 11)
)
)
{
string filename1 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam())));
string filename2 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam()) + 1));
Mat img1 = imread(filename1);
Mat img2 = imread(filename2);
if (img1.empty()) FAIL() << "Unable to load source image " << filename1;
if (img2.empty()) FAIL() << "Unable to load source image " << filename2;
int cn = get<2>(GetParam());
int nPointsX = std::min(get<0>(get<3>(GetParam())), img1.cols);
int nPointsY = std::min(get<1>(get<3>(GetParam())), img1.rows);
int winSize = get<4>(GetParam());
int maxLevel = 2;
TermCriteria criteria(TermCriteria::COUNT|TermCriteria::EPS, 7, 0.001);
int flags = 0;
double minEigThreshold = 1e-4;
Mat frame1, frame2;
switch(cn)
{
case 1:
cvtColor(img1, frame1, COLOR_BGR2GRAY, cn);
cvtColor(img2, frame2, COLOR_BGR2GRAY, cn);
break;
case 3:
frame1 = img1;
frame2 = img2;
break;
case 4:
cvtColor(img1, frame1, COLOR_BGR2BGRA, cn);
cvtColor(img2, frame2, COLOR_BGR2BGRA, cn);
break;
default:
FAIL() << "Unexpected number of channels: " << cn;
}
vector<Point2f> inPoints;
vector<Point2f> outPoints;
vector<uchar> status;
vector<float> err;
FormTrackingPointsArray(inPoints, frame1.cols, frame1.rows, nPointsX, nPointsY);
outPoints.resize(inPoints.size());
status.resize(inPoints.size());
err.resize(inPoints.size());
declare.in(frame1, frame2, inPoints).out(outPoints);
TEST_CYCLE_N(30)
{
calcOpticalFlowPyrLK(frame1, frame2, inPoints, outPoints, status, err,
Size(winSize, winSize), maxLevel, criteria,
flags, minEigThreshold);
}
SANITY_CHECK_NOTHING();
}
typedef tuple<std::string, int, tuple<int, int>, int> Path_Idx_NPoints_WSize_t;
typedef TestBaseWithParam<Path_Idx_NPoints_WSize_t> Path_Idx_NPoints_WSize;
PERF_TEST_P(Path_Idx_NPoints_WSize, DISABLED_OpticalFlowPyrLK_ovx, testing::Combine(
testing::Values<std::string>("cv/optflow/frames/VGA_%02d.png", "cv/optflow/frames/720p_%02d.png"),
testing::Range(1, 3),
testing::Values(make_tuple(9, 9), make_tuple(15, 15)),
testing::Values(7, 11)
)
)
{
string filename1 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam())));
string filename2 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam()) + 1));
Mat img1 = imread(filename1);
Mat img2 = imread(filename2);
if (img1.empty()) FAIL() << "Unable to load source image " << filename1;
if (img2.empty()) FAIL() << "Unable to load source image " << filename2;
int nPointsX = std::min(get<0>(get<2>(GetParam())), img1.cols);
int nPointsY = std::min(get<1>(get<2>(GetParam())), img1.rows);
int winSize = get<3>(GetParam());
int maxLevel = 2;
TermCriteria criteria(TermCriteria::COUNT|TermCriteria::EPS, 7, 0.001);
int flags = 0;
double minEigThreshold = 1e-4;
Mat frame1, frame2;
cvtColor(img1, frame1, COLOR_BGR2GRAY, 1);
cvtColor(img2, frame2, COLOR_BGR2GRAY, 1);
vector<Point2f> inPoints;
vector<Point2f> outPoints;
vector<uchar> status;
FormTrackingPointsArray(inPoints, frame1.cols, frame1.rows, nPointsX, nPointsY);
outPoints.resize(inPoints.size());
status.resize(inPoints.size());
declare.in(frame1, frame2, inPoints).out(outPoints);
TEST_CYCLE_N(30)
{
calcOpticalFlowPyrLK(frame1, frame2, inPoints, outPoints, status, cv::noArray(),
Size(winSize, winSize), maxLevel, criteria,
flags, minEigThreshold);
}
SANITY_CHECK_NOTHING();
}
typedef tuple<std::string, int, int, tuple<int,int>, int, bool> Path_Idx_Cn_NPoints_WSize_Deriv_t;
typedef TestBaseWithParam<Path_Idx_Cn_NPoints_WSize_Deriv_t> Path_Idx_Cn_NPoints_WSize_Deriv;
PERF_TEST_P(Path_Idx_Cn_NPoints_WSize_Deriv, OpticalFlowPyrLK_self, testing::Combine(
testing::Values<std::string>("cv/optflow/frames/VGA_%02d.png", "cv/optflow/frames/720p_%02d.png"),
testing::Range(1, 3),
testing::Values(1, 3, 4),
testing::Values(make_tuple(9, 9), make_tuple(15, 15)),
testing::Values(7, 11),
testing::Bool()
)
)
{
string filename1 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam())));
string filename2 = getDataPath(cv::format(get<0>(GetParam()).c_str(), get<1>(GetParam()) + 1));
Mat img1 = imread(filename1);
Mat img2 = imread(filename2);
if (img1.empty()) FAIL() << "Unable to load source image " << filename1;
if (img2.empty()) FAIL() << "Unable to load source image " << filename2;
int cn = get<2>(GetParam());
int nPointsX = std::min(get<0>(get<3>(GetParam())), img1.cols);
int nPointsY = std::min(get<1>(get<3>(GetParam())), img1.rows);
int winSize = get<4>(GetParam());
bool withDerivatives = get<5>(GetParam());
int maxLevel = 2;
TermCriteria criteria(TermCriteria::COUNT|TermCriteria::EPS, 7, 0.001);
int flags = 0;
double minEigThreshold = 1e-4;
Mat frame1, frame2;
switch(cn)
{
case 1:
cvtColor(img1, frame1, COLOR_BGR2GRAY, cn);
cvtColor(img2, frame2, COLOR_BGR2GRAY, cn);
break;
case 3:
frame1 = img1;
frame2 = img2;
break;
case 4:
cvtColor(img1, frame1, COLOR_BGR2BGRA, cn);
cvtColor(img2, frame2, COLOR_BGR2BGRA, cn);
break;
default:
FAIL() << "Unexpected number of channels: " << cn;
}
vector<Point2f> inPoints;
vector<Point2f> outPoints;
vector<uchar> status;
vector<float> err;
FormTrackingPointsArray(inPoints, frame1.cols, frame1.rows, nPointsX, nPointsY);
outPoints.resize(inPoints.size());
status.resize(inPoints.size());
err.resize(inPoints.size());
std::vector<Mat> pyramid1, pyramid2;
maxLevel = buildOpticalFlowPyramid(frame1, pyramid1, Size(winSize, winSize), maxLevel, withDerivatives);
maxLevel = buildOpticalFlowPyramid(frame2, pyramid2, Size(winSize, winSize), maxLevel, withDerivatives);
declare.in(pyramid1, pyramid2, inPoints).out(outPoints);
declare.time(400);
int runs = 3;
TEST_CYCLE_MULTIRUN(runs)
{
calcOpticalFlowPyrLK(pyramid1, pyramid2, inPoints, outPoints, status, err,
Size(winSize, winSize), maxLevel, criteria,
flags, minEigThreshold);
}
SANITY_CHECK_NOTHING();
}
CV_ENUM(PyrBorderMode, BORDER_DEFAULT, BORDER_TRANSPARENT)
typedef tuple<std::string, int, bool, PyrBorderMode, bool> Path_Win_Deriv_Border_Reuse_t;
typedef TestBaseWithParam<Path_Win_Deriv_Border_Reuse_t> Path_Win_Deriv_Border_Reuse;
PERF_TEST_P(Path_Win_Deriv_Border_Reuse, OpticalFlowPyrLK_pyr, testing::Combine(
testing::Values<std::string>("cv/optflow/frames/720p_01.png"),
testing::Values(7, 11),
testing::Bool(),
PyrBorderMode::all(),
testing::Bool()
)
)
{
string filename = getDataPath(get<0>(GetParam()));
Mat img = imread(filename);
Size winSize(get<1>(GetParam()), get<1>(GetParam()));
bool withDerivatives = get<2>(GetParam());
int derivBorder = get<3>(GetParam());
int pyrBorder = derivBorder;
if(derivBorder != BORDER_TRANSPARENT)
{
derivBorder = BORDER_CONSTANT;
pyrBorder = BORDER_REFLECT_101;
}
bool tryReuseInputImage = get<4>(GetParam());
std::vector<Mat> pyramid;
img.adjustROI(winSize.height, winSize.height, winSize.width, winSize.width);
int maxLevel = buildOpticalFlowPyramid(img, pyramid, winSize, 1000, withDerivatives, BORDER_CONSTANT, BORDER_CONSTANT, tryReuseInputImage);
declare.in(img).out(pyramid);
TEST_CYCLE()
{
buildOpticalFlowPyramid(img, pyramid, winSize, maxLevel, withDerivatives, pyrBorder, derivBorder, tryReuseInputImage);
}
size_t expected_layers = ((size_t)maxLevel + 1) * (withDerivatives ? 2 : 1);
ASSERT_EQ(expected_layers, pyramid.size());
SANITY_CHECK_NOTHING();
}
}} // namespace

View File

@@ -0,0 +1,16 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef __OPENCV_VIDEO_PRECOMP_HPP__
#define __OPENCV_VIDEO_PRECOMP_HPP__
#include "opencv2/ts.hpp"
#include <opencv2/video.hpp>
#include "opencv2/ts/ts_perf.hpp"
namespace cvtest
{
using namespace perf;
}
#endif

View File

@@ -0,0 +1,104 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
using namespace perf;
typedef tuple<string, int, Rect> TrackingParams_t;
std::vector<TrackingParams_t> getTrackingParams()
{
std::vector<TrackingParams_t> params {
TrackingParams_t("david/data/david.webm", 300, Rect(163,62,47,56)),
TrackingParams_t("dudek/data/dudek.webm", 1, Rect(123,87,132,176)),
TrackingParams_t("faceocc2/data/faceocc2.webm", 1, Rect(118,57,82,98))
};
return params;
}
class Tracking : public perf::TestBaseWithParam<TrackingParams_t>
{
public:
template<typename ROI_t = Rect2d, typename Tracker>
void runTrackingTest(const Ptr<Tracker>& tracker, const TrackingParams_t& params);
};
template<typename ROI_t, typename Tracker>
void Tracking::runTrackingTest(const Ptr<Tracker>& tracker, const TrackingParams_t& params)
{
const int N = 10;
string video = get<0>(params);
int startFrame = get<1>(params);
//int endFrame = startFrame + N;
Rect boundingBox = get<2>(params);
string videoPath = findDataFile(std::string("cv/tracking/") + video);
VideoCapture c;
c.open(videoPath);
if (!c.isOpened())
throw SkipTestException("Can't open video file");
#if 0
// c.set(CAP_PROP_POS_FRAMES, startFrame);
#else
if (startFrame)
std::cout << "startFrame = " << startFrame << std::endl;
for (int i = 0; i < startFrame; i++)
{
Mat dummy_frame;
c >> dummy_frame;
ASSERT_FALSE(dummy_frame.empty()) << i << ": " << videoPath;
}
#endif
// decode frames into memory (don't measure decoding performance)
std::vector<Mat> frames;
for (int i = 0; i < N; ++i)
{
Mat frame;
c >> frame;
ASSERT_FALSE(frame.empty()) << "i=" << i;
frames.push_back(frame);
}
std::cout << "frame size = " << frames[0].size() << std::endl;
PERF_SAMPLE_BEGIN();
{
tracker->init(frames[0], (ROI_t)boundingBox);
for (int i = 1; i < N; ++i)
{
ROI_t rc;
tracker->update(frames[i], rc);
ASSERT_FALSE(rc.empty());
}
}
PERF_SAMPLE_END();
SANITY_CHECK_NOTHING();
}
//==================================================================================================
PERF_TEST_P(Tracking, MIL, testing::ValuesIn(getTrackingParams()))
{
auto tracker = TrackerMIL::create();
runTrackingTest<Rect>(tracker, GetParam());
}
PERF_TEST_P(Tracking, GOTURN, testing::ValuesIn(getTrackingParams()))
{
std::string model = cvtest::findDataFile("dnn/gsoc2016-goturn/goturn.prototxt");
std::string weights = cvtest::findDataFile("dnn/gsoc2016-goturn/goturn.caffemodel", false);
TrackerGOTURN::Params params;
params.modelTxt = model;
params.modelBin = weights;
auto tracker = TrackerGOTURN::create(params);
runTrackingTest<Rect>(tracker, GetParam());
}
}} // namespace

View File

@@ -0,0 +1,40 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
typedef tuple<Size, int, int> VarRefParams;
typedef TestBaseWithParam<VarRefParams> DenseOpticalFlow_VariationalRefinement;
PERF_TEST_P(DenseOpticalFlow_VariationalRefinement, perf, Combine(Values(szQVGA, szVGA), Values(5, 10), Values(5, 10)))
{
VarRefParams params = GetParam();
Size sz = get<0>(params);
int sorIter = get<1>(params);
int fixedPointIter = get<2>(params);
Mat frame1(sz, CV_8U);
Mat frame2(sz, CV_8U);
Mat flow(sz, CV_32FC2);
randu(frame1, 0, 255);
randu(frame2, 0, 255);
flow.setTo(0.0f);
TEST_CYCLE_N(10)
{
Ptr<VariationalRefinement> var = VariationalRefinement::create();
var->setAlpha(20.0f);
var->setGamma(10.0f);
var->setDelta(5.0f);
var->setSorIterations(sorIter);
var->setFixedPointIterations(fixedPointIter);
var->calc(frame1, frame2, flow);
}
SANITY_CHECK_NOTHING();
}
}} // namespace

View File

@@ -0,0 +1,881 @@
/*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, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, 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 <math.h>
#include "precomp.hpp"
#include "opencl_kernels_video.hpp"
namespace cv
{
/*!
The class implements the following algorithm:
"Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction"
Z.Zivkovic, F. van der Heijden
Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006
http://www.zoranz.net/Publications/zivkovicPRL2006.pdf
*/
// default parameters of gaussian background detection algorithm
static const int defaultHistory2 = 500; // Learning rate; alpha = 1/defaultHistory2
static const int defaultNsamples = 7; // number of samples saved in memory
static const float defaultDist2Threshold = 20.0f*20.0f;//threshold on distance from the sample
// additional parameters
static const unsigned char defaultnShadowDetection2 = (unsigned char)127; // value to use in the segmentation mask for shadows, set 0 not to do shadow detection
static const float defaultfTau = 0.5f; // Tau - shadow threshold, see the paper for explanation
class BackgroundSubtractorKNNImpl CV_FINAL : public BackgroundSubtractorKNN
{
public:
//! the default constructor
BackgroundSubtractorKNNImpl()
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = defaultHistory2;
//set parameters
// N - the number of samples stored in memory per model
nN = defaultNsamples;
//kNN - k nearest neighbour - number on NN for detecting background - default K=[0.1*nN]
nkNN=MAX(1,cvRound(0.1*nN*3+0.40));
//Tb - Threshold Tb*kernelwidth
fTb = defaultDist2Threshold;
// Shadow detection
bShadowDetection = 1;//turn on
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;// Tau - shadow threshold
name_ = "BackgroundSubtractor.KNN";
nLongCounter = 0;
nMidCounter = 0;
nShortCounter = 0;
#ifdef HAVE_OPENCL
opencl_ON = true;
#endif
}
//! the full constructor that takes the length of the history,
// the number of gaussian mixtures, the background ratio parameter and the noise strength
BackgroundSubtractorKNNImpl(int _history, float _dist2Threshold, bool _bShadowDetection=true)
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = _history > 0 ? _history : defaultHistory2;
//set parameters
// N - the number of samples stored in memory per model
nN = defaultNsamples;
//kNN - k nearest neighbour - number on NN for detecting background - default K=[0.1*nN]
nkNN=MAX(1,cvRound(0.1*nN*3+0.40));
//Tb - Threshold Tb*kernelwidth
fTb = _dist2Threshold>0? _dist2Threshold : defaultDist2Threshold;
bShadowDetection = _bShadowDetection;
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;
name_ = "BackgroundSubtractor.KNN";
nLongCounter = 0;
nMidCounter = 0;
nShortCounter = 0;
#ifdef HAVE_OPENCL
opencl_ON = true;
#endif
}
//! the destructor
~BackgroundSubtractorKNNImpl() CV_OVERRIDE {}
//! the update operator
void apply(InputArray image, OutputArray fgmask, double learningRate) CV_OVERRIDE;
//! computes a background image which are the mean of all background gaussians
virtual void getBackgroundImage(OutputArray backgroundImage) const CV_OVERRIDE;
//! re-initialization method
void initialize(Size _frameSize, int _frameType)
{
frameSize = _frameSize;
frameType = _frameType;
nframes = 0;
int nchannels = CV_MAT_CN(frameType);
CV_Assert( nchannels <= CV_CN_MAX );
// Reserve memory for the model
int size=frameSize.height*frameSize.width;
//Reset counters
nShortCounter = 0;
nMidCounter = 0;
nLongCounter = 0;
#ifdef HAVE_OPENCL
if (ocl::isOpenCLActivated() && opencl_ON)
{
create_ocl_apply_kernel();
kernel_getBg.create("getBackgroundImage2_kernel", ocl::video::bgfg_knn_oclsrc, format( "-D CN=%d -D NSAMPLES=%d", nchannels, nN));
if (kernel_apply.empty() || kernel_getBg.empty())
opencl_ON = false;
}
else opencl_ON = false;
if (opencl_ON)
{
u_flag.create(frameSize.height * nN * 3, frameSize.width, CV_8UC1);
u_flag.setTo(Scalar::all(0));
if (nchannels==3)
nchannels=4;
u_sample.create(frameSize.height * nN * 3, frameSize.width, CV_32FC(nchannels));
u_sample.setTo(Scalar::all(0));
u_aModelIndexShort.create(frameSize.height, frameSize.width, CV_8UC1);
u_aModelIndexShort.setTo(Scalar::all(0));
u_aModelIndexMid.create(frameSize.height, frameSize.width, CV_8UC1);
u_aModelIndexMid.setTo(Scalar::all(0));
u_aModelIndexLong.create(frameSize.height, frameSize.width, CV_8UC1);
u_aModelIndexLong.setTo(Scalar::all(0));
u_nNextShortUpdate.create(frameSize.height, frameSize.width, CV_8UC1);
u_nNextShortUpdate.setTo(Scalar::all(0));
u_nNextMidUpdate.create(frameSize.height, frameSize.width, CV_8UC1);
u_nNextMidUpdate.setTo(Scalar::all(0));
u_nNextLongUpdate.create(frameSize.height, frameSize.width, CV_8UC1);
u_nNextLongUpdate.setTo(Scalar::all(0));
}
else
#endif
{
// for each sample of 3 speed pixel models each pixel bg model we store ...
// values + flag (nchannels+1 values)
bgmodel.create( 1,(nN * 3) * (nchannels+1)* size,CV_8U);
bgmodel = Scalar::all(0);
//index through the three circular lists
aModelIndexShort.create(1,size,CV_8U);
aModelIndexMid.create(1,size,CV_8U);
aModelIndexLong.create(1,size,CV_8U);
//when to update next
nNextShortUpdate.create(1,size,CV_8U);
nNextMidUpdate.create(1,size,CV_8U);
nNextLongUpdate.create(1,size,CV_8U);
aModelIndexShort = Scalar::all(0);//random? //((m_nN)*rand())/(RAND_MAX+1);//0...m_nN-1
aModelIndexMid = Scalar::all(0);
aModelIndexLong = Scalar::all(0);
nNextShortUpdate = Scalar::all(0);
nNextMidUpdate = Scalar::all(0);
nNextLongUpdate = Scalar::all(0);
}
}
virtual int getHistory() const CV_OVERRIDE { return history; }
virtual void setHistory(int _nframes) CV_OVERRIDE { history = _nframes; }
virtual int getNSamples() const CV_OVERRIDE { return nN; }
virtual void setNSamples(int _nN) CV_OVERRIDE { nN = _nN; }//needs reinitialization!
virtual int getkNNSamples() const CV_OVERRIDE { return nkNN; }
virtual void setkNNSamples(int _nkNN) CV_OVERRIDE { nkNN = _nkNN; }
virtual double getDist2Threshold() const CV_OVERRIDE { return fTb; }
virtual void setDist2Threshold(double _dist2Threshold) CV_OVERRIDE { fTb = (float)_dist2Threshold; }
virtual bool getDetectShadows() const CV_OVERRIDE { return bShadowDetection; }
virtual void setDetectShadows(bool detectshadows) CV_OVERRIDE
{
if (bShadowDetection == detectshadows)
return;
bShadowDetection = detectshadows;
#ifdef HAVE_OPENCL
if (!kernel_apply.empty())
{
create_ocl_apply_kernel();
CV_Assert( !kernel_apply.empty() );
}
#endif
}
virtual int getShadowValue() const CV_OVERRIDE { return nShadowDetection; }
virtual void setShadowValue(int value) CV_OVERRIDE { nShadowDetection = (uchar)value; }
virtual double getShadowThreshold() const CV_OVERRIDE { return fTau; }
virtual void setShadowThreshold(double value) CV_OVERRIDE { fTau = (float)value; }
virtual void write(FileStorage& fs) const CV_OVERRIDE
{
writeFormat(fs);
fs << "name" << name_
<< "history" << history
<< "nsamples" << nN
<< "nKNN" << nkNN
<< "dist2Threshold" << fTb
<< "detectShadows" << (int)bShadowDetection
<< "shadowValue" << (int)nShadowDetection
<< "shadowThreshold" << fTau;
}
virtual void read(const FileNode& fn) CV_OVERRIDE
{
CV_Assert( (String)fn["name"] == name_ );
history = (int)fn["history"];
nN = (int)fn["nsamples"];
nkNN = (int)fn["nKNN"];
fTb = (float)fn["dist2Threshold"];
bShadowDetection = (int)fn["detectShadows"] != 0;
nShadowDetection = saturate_cast<uchar>((int)fn["shadowValue"]);
fTau = (float)fn["shadowThreshold"];
}
protected:
Size frameSize;
int frameType;
int nframes;
/////////////////////////
//very important parameters - things you will change
////////////////////////
int history;
//alpha=1/history - speed of update - if the time interval you want to average over is T
//set alpha=1/history. It is also useful at start to make T slowly increase
//from 1 until the desired T
float fTb;
//Tb - threshold on the squared distance from the sample used to decide if it is well described
//by the background model or not. A typical value could be 2 sigma
//and that is Tb=2*2*10*10 =400; where we take typical pixel level sigma=10
/////////////////////////
//less important parameters - things you might change but be careful
////////////////////////
int nN;//totlal number of samples
int nkNN;//number on NN for detecting background - default K=[0.1*nN]
//shadow detection parameters
bool bShadowDetection;//default 1 - do shadow detection
unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result - 127 default value
float fTau;
// Tau - shadow threshold. The shadow is detected if the pixel is darker
//version of the background. Tau is a threshold on how much darker the shadow can be.
//Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
//See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003.
//model data
int nLongCounter;//circular counter
int nMidCounter;
int nShortCounter;
Mat bgmodel; // model data pixel values
Mat aModelIndexShort;// index into the models
Mat aModelIndexMid;
Mat aModelIndexLong;
Mat nNextShortUpdate;//random update points per model
Mat nNextMidUpdate;
Mat nNextLongUpdate;
#ifdef HAVE_OPENCL
mutable bool opencl_ON;
UMat u_flag;
UMat u_sample;
UMat u_aModelIndexShort;
UMat u_aModelIndexMid;
UMat u_aModelIndexLong;
UMat u_nNextShortUpdate;
UMat u_nNextMidUpdate;
UMat u_nNextLongUpdate;
mutable ocl::Kernel kernel_apply;
mutable ocl::Kernel kernel_getBg;
#endif
String name_;
#ifdef HAVE_OPENCL
bool ocl_getBackgroundImage(OutputArray backgroundImage) const;
bool ocl_apply(InputArray _image, OutputArray _fgmask, double learningRate=-1);
void create_ocl_apply_kernel();
#endif
};
CV_INLINE void
_cvUpdatePixelBackgroundNP(int x_idx, const uchar* data, int nchannels, int m_nN,
uchar* m_aModel,
uchar* m_nNextLongUpdate,
uchar* m_nNextMidUpdate,
uchar* m_nNextShortUpdate,
uchar* m_aModelIndexLong,
uchar* m_aModelIndexMid,
uchar* m_aModelIndexShort,
int m_nLongCounter,
int m_nMidCounter,
int m_nShortCounter,
uchar include
)
{
// hold the offset
int ndata=1+nchannels;
long offsetLong = ndata * (m_aModelIndexLong[x_idx] + m_nN * 2);
long offsetMid = ndata * (m_aModelIndexMid[x_idx] + m_nN * 1);
long offsetShort = ndata * (m_aModelIndexShort[x_idx]);
// Long update?
if (m_nNextLongUpdate[x_idx] == m_nLongCounter)
{
// add the oldest pixel from Mid to the list of values (for each color)
memcpy(&m_aModel[offsetLong],&m_aModel[offsetMid],ndata*sizeof(unsigned char));
// increase the index
m_aModelIndexLong[x_idx] = (m_aModelIndexLong[x_idx] >= (m_nN-1)) ? 0 : (m_aModelIndexLong[x_idx] + 1);
};
// Mid update?
if (m_nNextMidUpdate[x_idx] == m_nMidCounter)
{
// add this pixel to the list of values (for each color)
memcpy(&m_aModel[offsetMid],&m_aModel[offsetShort],ndata*sizeof(unsigned char));
// increase the index
m_aModelIndexMid[x_idx] = (m_aModelIndexMid[x_idx] >= (m_nN-1)) ? 0 : (m_aModelIndexMid[x_idx] + 1);
};
// Short update?
if (m_nNextShortUpdate[x_idx] == m_nShortCounter)
{
// add this pixel to the list of values (for each color)
memcpy(&m_aModel[offsetShort],data,nchannels*sizeof(unsigned char));
//set the include flag
m_aModel[offsetShort+nchannels]=include;
// increase the index
m_aModelIndexShort[x_idx] = (m_aModelIndexShort[x_idx] >= (m_nN-1)) ? 0 : (m_aModelIndexShort[x_idx] + 1);
};
}
CV_INLINE int
_cvCheckPixelBackgroundNP(const uchar* data, int nchannels,
int m_nN,
uchar* m_aModel,
float m_fTb,
int m_nkNN,
float tau,
bool m_bShadowDetection,
uchar& include)
{
int Pbf = 0; // the total probability that this pixel is background
int Pb = 0; //background model probability
float dData[CV_CN_MAX];
//uchar& include=data[nchannels];
include=0;//do we include this pixel into background model?
int ndata=nchannels+1;
// now increase the probability for each pixel
for (int n = 0; n < m_nN*3; n++)
{
uchar* mean_m = &m_aModel[n*ndata];
//calculate difference and distance
float dist2;
if( nchannels == 3 )
{
dData[0] = (float)mean_m[0] - data[0];
dData[1] = (float)mean_m[1] - data[1];
dData[2] = (float)mean_m[2] - data[2];
dist2 = dData[0]*dData[0] + dData[1]*dData[1] + dData[2]*dData[2];
}
else
{
dist2 = 0.f;
for( int c = 0; c < nchannels; c++ )
{
dData[c] = (float)mean_m[c] - data[c];
dist2 += dData[c]*dData[c];
}
}
if (dist2<m_fTb)
{
Pbf++;//all
//background only
//if(m_aModel[subPosPixel + nchannels])//indicator
if(mean_m[nchannels])//indicator
{
Pb++;
if (Pb >= m_nkNN)//Tb
{
include=1;//include
return 1;//background ->exit
};
}
};
};
//include?
if (Pbf>=m_nkNN)//m_nTbf)
{
include=1;
}
int Ps = 0; // the total probability that this pixel is background shadow
// Detected as moving object, perform shadow detection
if (m_bShadowDetection)
{
for (int n = 0; n < m_nN*3; n++)
{
//long subPosPixel = posPixel + n*ndata;
uchar* mean_m = &m_aModel[n*ndata];
if(mean_m[nchannels])//check only background
{
float numerator = 0.0f;
float denominator = 0.0f;
for( int c = 0; c < nchannels; c++ )
{
numerator += (float)data[c] * mean_m[c];
denominator += (float)mean_m[c] * mean_m[c];
}
// no division by zero allowed
if( denominator == 0 )
return 0;
// if tau < a < 1 then also check the color distortion
if( numerator <= denominator && numerator >= tau*denominator )
{
float a = numerator / denominator;
float dist2a = 0.0f;
for( int c = 0; c < nchannels; c++ )
{
float dD= a*mean_m[c] - data[c];
dist2a += dD*dD;
}
if (dist2a<m_fTb*a*a)
{
Ps++;
if (Ps >= m_nkNN)//shadow
return 2;
};
};
};
};
}
return 0;
}
class KNNInvoker : public ParallelLoopBody
{
public:
KNNInvoker(const Mat& _src, Mat& _dst,
uchar* _bgmodel,
uchar* _nNextLongUpdate,
uchar* _nNextMidUpdate,
uchar* _nNextShortUpdate,
uchar* _aModelIndexLong,
uchar* _aModelIndexMid,
uchar* _aModelIndexShort,
int _nLongCounter,
int _nMidCounter,
int _nShortCounter,
int _nN,
float _fTb,
int _nkNN,
float _fTau,
bool _bShadowDetection,
uchar _nShadowDetection)
{
src = &_src;
dst = &_dst;
m_aModel0 = _bgmodel;
m_nNextLongUpdate0 = _nNextLongUpdate;
m_nNextMidUpdate0 = _nNextMidUpdate;
m_nNextShortUpdate0 = _nNextShortUpdate;
m_aModelIndexLong0 = _aModelIndexLong;
m_aModelIndexMid0 = _aModelIndexMid;
m_aModelIndexShort0 = _aModelIndexShort;
m_nLongCounter = _nLongCounter;
m_nMidCounter = _nMidCounter;
m_nShortCounter = _nShortCounter;
m_nN = _nN;
m_fTb = _fTb;
m_fTau = _fTau;
m_nkNN = _nkNN;
m_bShadowDetection = _bShadowDetection;
m_nShadowDetection = _nShadowDetection;
}
void operator()(const Range& range) const CV_OVERRIDE
{
int y0 = range.start, y1 = range.end;
int ncols = src->cols, nchannels = src->channels();
int ndata=nchannels+1;
for ( int y = y0; y < y1; y++ )
{
const uchar* data = src->ptr(y);
uchar* m_aModel = m_aModel0 + ncols*m_nN*3*ndata*y;
uchar* m_nNextLongUpdate = m_nNextLongUpdate0 + ncols*y;
uchar* m_nNextMidUpdate = m_nNextMidUpdate0 + ncols*y;
uchar* m_nNextShortUpdate = m_nNextShortUpdate0 + ncols*y;
uchar* m_aModelIndexLong = m_aModelIndexLong0 + ncols*y;
uchar* m_aModelIndexMid = m_aModelIndexMid0 + ncols*y;
uchar* m_aModelIndexShort = m_aModelIndexShort0 + ncols*y;
uchar* mask = dst->ptr(y);
for ( int x = 0; x < ncols; x++ )
{
//update model+ background subtract
uchar include=0;
int result= _cvCheckPixelBackgroundNP(data, nchannels,
m_nN, m_aModel, m_fTb,m_nkNN, m_fTau,m_bShadowDetection,include);
_cvUpdatePixelBackgroundNP(x,data,nchannels,
m_nN, m_aModel,
m_nNextLongUpdate,
m_nNextMidUpdate,
m_nNextShortUpdate,
m_aModelIndexLong,
m_aModelIndexMid,
m_aModelIndexShort,
m_nLongCounter,
m_nMidCounter,
m_nShortCounter,
include
);
switch (result)
{
case 0:
//foreground
mask[x] = 255;
break;
case 1:
//background
mask[x] = 0;
break;
case 2:
//shadow
mask[x] = m_nShadowDetection;
break;
}
data += nchannels;
m_aModel += m_nN*3*ndata;
}
}
}
const Mat* src;
Mat* dst;
uchar* m_aModel0;
uchar* m_nNextLongUpdate0;
uchar* m_nNextMidUpdate0;
uchar* m_nNextShortUpdate0;
uchar* m_aModelIndexLong0;
uchar* m_aModelIndexMid0;
uchar* m_aModelIndexShort0;
int m_nLongCounter;
int m_nMidCounter;
int m_nShortCounter;
int m_nN;
float m_fTb;
float m_fTau;
int m_nkNN;
bool m_bShadowDetection;
uchar m_nShadowDetection;
};
#ifdef HAVE_OPENCL
bool BackgroundSubtractorKNNImpl::ocl_apply(InputArray _image, OutputArray _fgmask, double learningRate)
{
bool needToInitialize = nframes == 0 || learningRate >= 1 || _image.size() != frameSize || _image.type() != frameType;
if( needToInitialize )
initialize(_image.size(), _image.type());
++nframes;
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history );
CV_Assert(learningRate >= 0);
_fgmask.create(_image.size(), CV_8U);
UMat fgmask = _fgmask.getUMat();
UMat frame = _image.getUMat();
//recalculate update rates - in case alpha is changed
// calculate update parameters (using alpha)
int Kshort,Kmid,Klong;
//approximate exponential learning curve
Kshort=(int)(log(0.7)/log(1-learningRate))+1;//Kshort
Kmid=(int)(log(0.4)/log(1-learningRate))-Kshort+1;//Kmid
Klong=(int)(log(0.1)/log(1-learningRate))-Kshort-Kmid+1;//Klong
//refresh rates
int nShortUpdate = (Kshort/nN)+1;
int nMidUpdate = (Kmid/nN)+1;
int nLongUpdate = (Klong/nN)+1;
int idxArg = 0;
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::ReadOnly(frame));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadOnly(u_nNextLongUpdate));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadOnly(u_nNextMidUpdate));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadOnly(u_nNextShortUpdate));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_aModelIndexLong));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_aModelIndexMid));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_aModelIndexShort));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_flag));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_sample));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::WriteOnlyNoSize(fgmask));
idxArg = kernel_apply.set(idxArg, nLongCounter);
idxArg = kernel_apply.set(idxArg, nMidCounter);
idxArg = kernel_apply.set(idxArg, nShortCounter);
idxArg = kernel_apply.set(idxArg, fTb);
idxArg = kernel_apply.set(idxArg, nkNN);
idxArg = kernel_apply.set(idxArg, fTau);
if (bShadowDetection)
kernel_apply.set(idxArg, nShadowDetection);
size_t globalsize[2] = {(size_t)frame.cols, (size_t)frame.rows};
if(!kernel_apply.run(2, globalsize, NULL, true))
return false;
nShortCounter++;//0,1,...,nShortUpdate-1
nMidCounter++;
nLongCounter++;
if (nShortCounter >= nShortUpdate)
{
nShortCounter = 0;
randu(u_nNextShortUpdate, Scalar::all(0), Scalar::all(nShortUpdate));
}
if (nMidCounter >= nMidUpdate)
{
nMidCounter = 0;
randu(u_nNextMidUpdate, Scalar::all(0), Scalar::all(nMidUpdate));
}
if (nLongCounter >= nLongUpdate)
{
nLongCounter = 0;
randu(u_nNextLongUpdate, Scalar::all(0), Scalar::all(nLongUpdate));
}
return true;
}
bool BackgroundSubtractorKNNImpl::ocl_getBackgroundImage(OutputArray _backgroundImage) const
{
_backgroundImage.create(frameSize, frameType);
UMat dst = _backgroundImage.getUMat();
int idxArg = 0;
idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::PtrReadOnly(u_flag));
idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::PtrReadOnly(u_sample));
idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::WriteOnly(dst));
size_t globalsize[2] = {(size_t)dst.cols, (size_t)dst.rows};
return kernel_getBg.run(2, globalsize, NULL, false);
}
void BackgroundSubtractorKNNImpl::create_ocl_apply_kernel()
{
int nchannels = CV_MAT_CN(frameType);
String opts = format("-D CN=%d -D NSAMPLES=%d%s", nchannels, nN, bShadowDetection ? " -D SHADOW_DETECT" : "");
kernel_apply.create("knn_kernel", ocl::video::bgfg_knn_oclsrc, opts);
}
#endif
void BackgroundSubtractorKNNImpl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
{
CV_INSTRUMENT_REGION();
#ifdef HAVE_OPENCL
if (opencl_ON)
{
#ifndef __APPLE__
CV_OCL_RUN(_fgmask.isUMat() && OCL_PERFORMANCE_CHECK(!ocl::Device::getDefault().isIntel() || _image.channels() == 1),
ocl_apply(_image, _fgmask, learningRate))
#else
CV_OCL_RUN(_fgmask.isUMat() && OCL_PERFORMANCE_CHECK(!ocl::Device::getDefault().isIntel()),
ocl_apply(_image, _fgmask, learningRate))
#endif
opencl_ON = false;
nframes = 0;
}
#endif
bool needToInitialize = nframes == 0 || learningRate >= 1 || _image.size() != frameSize || _image.type() != frameType;
if( needToInitialize )
initialize(_image.size(), _image.type());
Mat image = _image.getMat();
_fgmask.create( image.size(), CV_8U );
Mat fgmask = _fgmask.getMat();
++nframes;
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history );
CV_Assert(learningRate >= 0);
//recalculate update rates - in case alpha is changed
// calculate update parameters (using alpha)
int Kshort,Kmid,Klong;
//approximate exponential learning curve
Kshort=(int)(log(0.7)/log(1-learningRate))+1;//Kshort
Kmid=(int)(log(0.4)/log(1-learningRate))-Kshort+1;//Kmid
Klong=(int)(log(0.1)/log(1-learningRate))-Kshort-Kmid+1;//Klong
//refresh rates
int nShortUpdate = (Kshort/nN)+1;
int nMidUpdate = (Kmid/nN)+1;
int nLongUpdate = (Klong/nN)+1;
parallel_for_(Range(0, image.rows),
KNNInvoker(image, fgmask,
bgmodel.ptr(),
nNextLongUpdate.ptr(),
nNextMidUpdate.ptr(),
nNextShortUpdate.ptr(),
aModelIndexLong.ptr(),
aModelIndexMid.ptr(),
aModelIndexShort.ptr(),
nLongCounter,
nMidCounter,
nShortCounter,
nN,
fTb,
nkNN,
fTau,
bShadowDetection,
nShadowDetection),
image.total()/(double)(1 << 16));
nShortCounter++;//0,1,...,nShortUpdate-1
nMidCounter++;
nLongCounter++;
if (nShortCounter >= nShortUpdate)
{
nShortCounter = 0;
randu(nNextShortUpdate, Scalar::all(0), Scalar::all(nShortUpdate));
}
if (nMidCounter >= nMidUpdate)
{
nMidCounter = 0;
randu(nNextMidUpdate, Scalar::all(0), Scalar::all(nMidUpdate));
}
if (nLongCounter >= nLongUpdate)
{
nLongCounter = 0;
randu(nNextLongUpdate, Scalar::all(0), Scalar::all(nLongUpdate));
}
}
void BackgroundSubtractorKNNImpl::getBackgroundImage(OutputArray backgroundImage) const
{
CV_INSTRUMENT_REGION();
#ifdef HAVE_OPENCL
if (opencl_ON)
{
CV_OCL_RUN(opencl_ON, ocl_getBackgroundImage(backgroundImage))
opencl_ON = false;
}
#endif
int nchannels = CV_MAT_CN(frameType);
//CV_Assert( nchannels == 3 );
Mat meanBackground(frameSize, CV_8UC3, Scalar::all(0));
int ndata=nchannels+1;
int modelstep=(ndata * nN * 3);
const uchar* pbgmodel=bgmodel.ptr(0);
for(int row=0; row<meanBackground.rows; row++)
{
for(int col=0; col<meanBackground.cols; col++)
{
for (int n = 0; n < nN*3; n++)
{
const uchar* mean_m = &pbgmodel[n*ndata];
if (mean_m[nchannels])
{
meanBackground.at<Vec3b>(row, col) = Vec3b(mean_m);
break;
}
}
pbgmodel=pbgmodel+modelstep;
}
}
switch(CV_MAT_CN(frameType))
{
case 1:
{
std::vector<Mat> channels;
split(meanBackground, channels);
channels[0].copyTo(backgroundImage);
break;
}
case 3:
{
meanBackground.copyTo(backgroundImage);
break;
}
default:
CV_Error(Error::StsUnsupportedFormat, "");
}
}
Ptr<BackgroundSubtractorKNN> createBackgroundSubtractorKNN(int _history, double _threshold2,
bool _bShadowDetection)
{
return makePtr<BackgroundSubtractorKNNImpl>(_history, (float)_threshold2, _bShadowDetection);
}
}
/* End of file. */

View File

@@ -0,0 +1,965 @@
/*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, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, 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*/
/*//Implementation of the Gaussian mixture model background subtraction from:
//
//"Improved adaptive Gaussian mixture model for background subtraction"
//Z.Zivkovic
//International Conference Pattern Recognition, UK, August, 2004
//http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
//The code is very fast and performs also shadow detection.
//Number of Gausssian components is adapted per pixel.
//
// and
//
//"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
//Z.Zivkovic, F. van der Heijden
//Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
//
//The algorithm similar to the standard Stauffer&Grimson algorithm with
//additional selection of the number of the Gaussian components based on:
//
//"Recursive unsupervised learning of finite mixture models "
//Z.Zivkovic, F.van der Heijden
//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
//
//
//Example usage with as cpp class
// BackgroundSubtractorMOG2 bg_model;
//For each new image the model is updates using:
// bg_model(img, fgmask);
//
//Example usage as part of the CvBGStatModel:
// CvBGStatModel* bg_model = cvCreateGaussianBGModel2( first_frame );
//
// //update for each frame
// cvUpdateBGStatModel( tmp_frame, bg_model );//segmentation result is in bg_model->foreground
//
// //release at the program termination
// cvReleaseBGStatModel( &bg_model );
//
//Author: Z.Zivkovic, www.zoranz.net
//Date: 7-April-2011, Version:1.0
///////////*/
#include "precomp.hpp"
#include "opencl_kernels_video.hpp"
namespace cv
{
/*
Interface of Gaussian mixture algorithm from:
"Improved adaptive Gaussian mixture model for background subtraction"
Z.Zivkovic
International Conference Pattern Recognition, UK, August, 2004
http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf
Advantages:
-fast - number of Gausssian components is constantly adapted per pixel.
-performs also shadow detection (see bgfg_segm_test.cpp example)
*/
// default parameters of gaussian background detection algorithm
static const int defaultHistory2 = 500; // Learning rate; alpha = 1/defaultHistory2
static const float defaultVarThreshold2 = 4.0f*4.0f;
static const int defaultNMixtures2 = 5; // maximal number of Gaussians in mixture
static const float defaultBackgroundRatio2 = 0.9f; // threshold sum of weights for background test
static const float defaultVarThresholdGen2 = 3.0f*3.0f;
static const float defaultVarInit2 = 15.0f; // initial variance for new components
static const float defaultVarMax2 = 5*defaultVarInit2;
static const float defaultVarMin2 = 4.0f;
// additional parameters
static const float defaultfCT2 = 0.05f; // complexity reduction prior constant 0 - no reduction of number of components
static const unsigned char defaultnShadowDetection2 = (unsigned char)127; // value to use in the segmentation mask for shadows, set 0 not to do shadow detection
static const float defaultfTau = 0.5f; // Tau - shadow threshold, see the paper for explanation
class BackgroundSubtractorMOG2Impl CV_FINAL : public BackgroundSubtractorMOG2
{
public:
//! the default constructor
BackgroundSubtractorMOG2Impl()
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = defaultHistory2;
varThreshold = defaultVarThreshold2;
bShadowDetection = 1;
nmixtures = defaultNMixtures2;
backgroundRatio = defaultBackgroundRatio2;
fVarInit = defaultVarInit2;
fVarMax = defaultVarMax2;
fVarMin = defaultVarMin2;
varThresholdGen = defaultVarThresholdGen2;
fCT = defaultfCT2;
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;
#ifdef HAVE_OPENCL
opencl_ON = true;
#endif
}
//! the full constructor that takes the length of the history,
// the number of gaussian mixtures, the background ratio parameter and the noise strength
BackgroundSubtractorMOG2Impl(int _history, float _varThreshold, bool _bShadowDetection=true)
{
frameSize = Size(0,0);
frameType = 0;
nframes = 0;
history = _history > 0 ? _history : defaultHistory2;
varThreshold = (_varThreshold>0)? _varThreshold : defaultVarThreshold2;
bShadowDetection = _bShadowDetection;
nmixtures = defaultNMixtures2;
backgroundRatio = defaultBackgroundRatio2;
fVarInit = defaultVarInit2;
fVarMax = defaultVarMax2;
fVarMin = defaultVarMin2;
varThresholdGen = defaultVarThresholdGen2;
fCT = defaultfCT2;
nShadowDetection = defaultnShadowDetection2;
fTau = defaultfTau;
name_ = "BackgroundSubtractor.MOG2";
#ifdef HAVE_OPENCL
opencl_ON = true;
#endif
}
//! the destructor
~BackgroundSubtractorMOG2Impl() CV_OVERRIDE {}
//! the update operator
void apply(InputArray image, OutputArray fgmask, double learningRate) CV_OVERRIDE;
//! computes a background image which are the mean of all background gaussians
virtual void getBackgroundImage(OutputArray backgroundImage) const CV_OVERRIDE;
//! re-initialization method
void initialize(Size _frameSize, int _frameType)
{
frameSize = _frameSize;
frameType = _frameType;
nframes = 0;
int nchannels = CV_MAT_CN(frameType);
CV_Assert( nchannels <= CV_CN_MAX );
CV_Assert( nmixtures <= 255);
#ifdef HAVE_OPENCL
if (ocl::isOpenCLActivated() && opencl_ON)
{
create_ocl_apply_kernel();
bool isFloat = CV_MAKETYPE(CV_32F,nchannels) == frameType;
kernel_getBg.create("getBackgroundImage2_kernel", ocl::video::bgfg_mog2_oclsrc, format( "-D CN=%d -D FL=%d -D NMIXTURES=%d", nchannels, isFloat, nmixtures));
if (kernel_apply.empty() || kernel_getBg.empty())
opencl_ON = false;
}
else opencl_ON = false;
if (opencl_ON)
{
u_weight.create(frameSize.height * nmixtures, frameSize.width, CV_32FC1);
u_weight.setTo(Scalar::all(0));
u_variance.create(frameSize.height * nmixtures, frameSize.width, CV_32FC1);
u_variance.setTo(Scalar::all(0));
if (nchannels==3)
nchannels=4;
u_mean.create(frameSize.height * nmixtures, frameSize.width, CV_32FC(nchannels)); //4 channels
u_mean.setTo(Scalar::all(0));
//make the array for keeping track of the used modes per pixel - all zeros at start
u_bgmodelUsedModes.create(frameSize, CV_8UC1);
u_bgmodelUsedModes.setTo(cv::Scalar::all(0));
}
else
#endif
{
// for each gaussian mixture of each pixel bg model we store ...
// the mixture weight (w),
// the mean (nchannels values) and
// the covariance
bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + nchannels), CV_32F );
//make the array for keeping track of the used modes per pixel - all zeros at start
bgmodelUsedModes.create(frameSize,CV_8U);
bgmodelUsedModes = Scalar::all(0);
}
}
virtual int getHistory() const CV_OVERRIDE { return history; }
virtual void setHistory(int _nframes) CV_OVERRIDE { history = _nframes; }
virtual int getNMixtures() const CV_OVERRIDE { return nmixtures; }
virtual void setNMixtures(int nmix) CV_OVERRIDE { nmixtures = nmix; }
virtual double getBackgroundRatio() const CV_OVERRIDE { return backgroundRatio; }
virtual void setBackgroundRatio(double _backgroundRatio) CV_OVERRIDE { backgroundRatio = (float)_backgroundRatio; }
virtual double getVarThreshold() const CV_OVERRIDE { return varThreshold; }
virtual void setVarThreshold(double _varThreshold) CV_OVERRIDE { varThreshold = _varThreshold; }
virtual double getVarThresholdGen() const CV_OVERRIDE { return varThresholdGen; }
virtual void setVarThresholdGen(double _varThresholdGen) CV_OVERRIDE { varThresholdGen = (float)_varThresholdGen; }
virtual double getVarInit() const CV_OVERRIDE { return fVarInit; }
virtual void setVarInit(double varInit) CV_OVERRIDE { fVarInit = (float)varInit; }
virtual double getVarMin() const CV_OVERRIDE { return fVarMin; }
virtual void setVarMin(double varMin) CV_OVERRIDE { fVarMin = (float)varMin; }
virtual double getVarMax() const CV_OVERRIDE { return fVarMax; }
virtual void setVarMax(double varMax) CV_OVERRIDE { fVarMax = (float)varMax; }
virtual double getComplexityReductionThreshold() const CV_OVERRIDE { return fCT; }
virtual void setComplexityReductionThreshold(double ct) CV_OVERRIDE { fCT = (float)ct; }
virtual bool getDetectShadows() const CV_OVERRIDE { return bShadowDetection; }
virtual void setDetectShadows(bool detectshadows) CV_OVERRIDE
{
if (bShadowDetection == detectshadows)
return;
bShadowDetection = detectshadows;
#ifdef HAVE_OPENCL
if (!kernel_apply.empty())
{
create_ocl_apply_kernel();
CV_Assert( !kernel_apply.empty() );
}
#endif
}
virtual int getShadowValue() const CV_OVERRIDE { return nShadowDetection; }
virtual void setShadowValue(int value) CV_OVERRIDE { nShadowDetection = (uchar)value; }
virtual double getShadowThreshold() const CV_OVERRIDE { return fTau; }
virtual void setShadowThreshold(double value) CV_OVERRIDE { fTau = (float)value; }
virtual void write(FileStorage& fs) const CV_OVERRIDE
{
writeFormat(fs);
fs << "name" << name_
<< "history" << history
<< "nmixtures" << nmixtures
<< "backgroundRatio" << backgroundRatio
<< "varThreshold" << varThreshold
<< "varThresholdGen" << varThresholdGen
<< "varInit" << fVarInit
<< "varMin" << fVarMin
<< "varMax" << fVarMax
<< "complexityReductionThreshold" << fCT
<< "detectShadows" << (int)bShadowDetection
<< "shadowValue" << (int)nShadowDetection
<< "shadowThreshold" << fTau;
}
virtual void read(const FileNode& fn) CV_OVERRIDE
{
CV_Assert( (String)fn["name"] == name_ );
history = (int)fn["history"];
nmixtures = (int)fn["nmixtures"];
backgroundRatio = (float)fn["backgroundRatio"];
varThreshold = (double)fn["varThreshold"];
varThresholdGen = (float)fn["varThresholdGen"];
fVarInit = (float)fn["varInit"];
fVarMin = (float)fn["varMin"];
fVarMax = (float)fn["varMax"];
fCT = (float)fn["complexityReductionThreshold"];
bShadowDetection = (int)fn["detectShadows"] != 0;
nShadowDetection = saturate_cast<uchar>((int)fn["shadowValue"]);
fTau = (float)fn["shadowThreshold"];
}
protected:
Size frameSize;
int frameType;
Mat bgmodel;
Mat bgmodelUsedModes;//keep track of number of modes per pixel
#ifdef HAVE_OPENCL
//for OCL
mutable bool opencl_ON;
UMat u_weight;
UMat u_variance;
UMat u_mean;
UMat u_bgmodelUsedModes;
mutable ocl::Kernel kernel_apply;
mutable ocl::Kernel kernel_getBg;
#endif
int nframes;
int history;
int nmixtures;
//! here it is the maximum allowed number of mixture components.
//! Actual number is determined dynamically per pixel
double varThreshold;
// threshold on the squared Mahalanobis distance to decide if it is well described
// by the background model or not. Related to Cthr from the paper.
// This does not influence the update of the background. A typical value could be 4 sigma
// and that is varThreshold=4*4=16; Corresponds to Tb in the paper.
/////////////////////////
// less important parameters - things you might change but be careful
////////////////////////
float backgroundRatio;
// corresponds to fTB=1-cf from the paper
// TB - threshold when the component becomes significant enough to be included into
// the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
// For alpha=0.001 it means that the mode should exist for approximately 105 frames before
// it is considered foreground
// float noiseSigma;
float varThresholdGen;
//correspondts to Tg - threshold on the squared Mahalan. dist. to decide
//when a sample is close to the existing components. If it is not close
//to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
//Smaller Tg leads to more generated components and higher Tg might make
//lead to small number of components but they can grow too large
float fVarInit;
float fVarMin;
float fVarMax;
//initial variance for the newly generated components.
//It will will influence the speed of adaptation. A good guess should be made.
//A simple way is to estimate the typical standard deviation from the images.
//I used here 10 as a reasonable value
// min and max can be used to further control the variance
float fCT;//CT - complexity reduction prior
//this is related to the number of samples needed to accept that a component
//actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
//the standard Stauffer&Grimson algorithm (maybe not exact but very similar)
//shadow detection parameters
bool bShadowDetection;//default 1 - do shadow detection
unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result - 127 default value
float fTau;
// Tau - shadow threshold. The shadow is detected if the pixel is darker
//version of the background. Tau is a threshold on how much darker the shadow can be.
//Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
//See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003.
String name_;
template <typename T, int CN>
void getBackgroundImage_intern(OutputArray backgroundImage) const;
#ifdef HAVE_OPENCL
bool ocl_getBackgroundImage(OutputArray backgroundImage) const;
bool ocl_apply(InputArray _image, OutputArray _fgmask, double learningRate=-1);
void create_ocl_apply_kernel();
#endif
};
struct GaussBGStatModel2Params
{
//image info
int nWidth;
int nHeight;
int nND;//number of data dimensions (image channels)
bool bPostFiltering;//default 1 - do postfiltering - will make shadow detection results also give value 255
double minArea; // for postfiltering
bool bInit;//default 1, faster updates at start
/////////////////////////
//very important parameters - things you will change
////////////////////////
float fAlphaT;
//alpha - speed of update - if the time interval you want to average over is T
//set alpha=1/T. It is also useful at start to make T slowly increase
//from 1 until the desired T
float fTb;
//Tb - threshold on the squared Mahalan. dist. to decide if it is well described
//by the background model or not. Related to Cthr from the paper.
//This does not influence the update of the background. A typical value could be 4 sigma
//and that is Tb=4*4=16;
/////////////////////////
//less important parameters - things you might change but be careful
////////////////////////
float fTg;
//Tg - threshold on the squared Mahalan. dist. to decide
//when a sample is close to the existing components. If it is not close
//to any a new component will be generated. I use 3 sigma => Tg=3*3=9.
//Smaller Tg leads to more generated components and higher Tg might make
//lead to small number of components but they can grow too large
float fTB;//1-cf from the paper
//TB - threshold when the component becomes significant enough to be included into
//the background model. It is the TB=1-cf from the paper. So I use cf=0.1 => TB=0.
//For alpha=0.001 it means that the mode should exist for approximately 105 frames before
//it is considered foreground
float fVarInit;
float fVarMax;
float fVarMin;
//initial standard deviation for the newly generated components.
//It will will influence the speed of adaptation. A good guess should be made.
//A simple way is to estimate the typical standard deviation from the images.
//I used here 10 as a reasonable value
float fCT;//CT - complexity reduction prior
//this is related to the number of samples needed to accept that a component
//actually exists. We use CT=0.05 of all the samples. By setting CT=0 you get
//the standard Stauffer&Grimson algorithm (maybe not exact but very similar)
//even less important parameters
int nM;//max number of modes - const - 4 is usually enough
//shadow detection parameters
bool bShadowDetection;//default 1 - do shadow detection
unsigned char nShadowDetection;//do shadow detection - insert this value as the detection result
float fTau;
// Tau - shadow threshold. The shadow is detected if the pixel is darker
//version of the background. Tau is a threshold on how much darker the shadow can be.
//Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow
//See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003.
};
struct GMM
{
float weight;
float variance;
};
// shadow detection performed per pixel
// should work for rgb data, could be useful for gray scale and depth data as well
// See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003.
CV_INLINE bool
detectShadowGMM(const float* data, int nchannels, int nmodes,
const GMM* gmm, const float* mean,
float Tb, float TB, float tau)
{
float tWeight = 0;
// check all the components marked as background:
for( int mode = 0; mode < nmodes; mode++, mean += nchannels )
{
GMM g = gmm[mode];
float numerator = 0.0f;
float denominator = 0.0f;
for( int c = 0; c < nchannels; c++ )
{
numerator += data[c] * mean[c];
denominator += mean[c] * mean[c];
}
// no division by zero allowed
if( denominator == 0 )
return false;
// if tau < a < 1 then also check the color distortion
if( numerator <= denominator && numerator >= tau*denominator )
{
float a = numerator / denominator;
float dist2a = 0.0f;
for( int c = 0; c < nchannels; c++ )
{
float dD= a*mean[c] - data[c];
dist2a += dD*dD;
}
if (dist2a < Tb*g.variance*a*a)
return true;
};
tWeight += g.weight;
if( tWeight > TB )
return false;
};
return false;
}
//update GMM - the base update function performed per pixel
//
//"Efficient Adaptive Density Estimapion per Image Pixel for the Task of Background Subtraction"
//Z.Zivkovic, F. van der Heijden
//Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
//
//The algorithm similar to the standard Stauffer&Grimson algorithm with
//additional selection of the number of the Gaussian components based on:
//
//"Recursive unsupervised learning of finite mixture models "
//Z.Zivkovic, F.van der Heijden
//IEEE Trans. on Pattern Analysis and Machine Intelligence, vol.26, no.5, pages 651-656, 2004
//http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf
class MOG2Invoker : public ParallelLoopBody
{
public:
MOG2Invoker(const Mat& _src, Mat& _dst,
GMM* _gmm, float* _mean,
uchar* _modesUsed,
int _nmixtures, float _alphaT,
float _Tb, float _TB, float _Tg,
float _varInit, float _varMin, float _varMax,
float _prune, float _tau, bool _detectShadows,
uchar _shadowVal)
{
src = &_src;
dst = &_dst;
gmm0 = _gmm;
mean0 = _mean;
modesUsed0 = _modesUsed;
nmixtures = _nmixtures;
alphaT = _alphaT;
Tb = _Tb;
TB = _TB;
Tg = _Tg;
varInit = _varInit;
varMin = MIN(_varMin, _varMax);
varMax = MAX(_varMin, _varMax);
prune = _prune;
tau = _tau;
detectShadows = _detectShadows;
shadowVal = _shadowVal;
}
void operator()(const Range& range) const CV_OVERRIDE
{
int y0 = range.start, y1 = range.end;
int ncols = src->cols, nchannels = src->channels();
AutoBuffer<float> buf(src->cols*nchannels);
float alpha1 = 1.f - alphaT;
float dData[CV_CN_MAX];
for( int y = y0; y < y1; y++ )
{
const float* data = buf.data();
if( src->depth() != CV_32F )
src->row(y).convertTo(Mat(1, ncols, CV_32FC(nchannels), (void*)data), CV_32F);
else
data = src->ptr<float>(y);
float* mean = mean0 + ncols*nmixtures*nchannels*y;
GMM* gmm = gmm0 + ncols*nmixtures*y;
uchar* modesUsed = modesUsed0 + ncols*y;
uchar* mask = dst->ptr(y);
for( int x = 0; x < ncols; x++, data += nchannels, gmm += nmixtures, mean += nmixtures*nchannels )
{
//calculate distances to the modes (+ sort)
//here we need to go in descending order!!!
bool background = false;//return value -> true - the pixel classified as background
//internal:
bool fitsPDF = false;//if it remains zero a new GMM mode will be added
int nmodes = modesUsed[x];//current number of modes in GMM
float totalWeight = 0.f;
float* mean_m = mean;
//////
//go through all modes
for( int mode = 0; mode < nmodes; mode++, mean_m += nchannels )
{
float weight = alpha1*gmm[mode].weight + prune;//need only weight if fit is found
int swap_count = 0;
////
//fit not found yet
if( !fitsPDF )
{
//check if it belongs to some of the remaining modes
float var = gmm[mode].variance;
//calculate difference and distance
float dist2;
if( nchannels == 3 )
{
dData[0] = mean_m[0] - data[0];
dData[1] = mean_m[1] - data[1];
dData[2] = mean_m[2] - data[2];
dist2 = dData[0]*dData[0] + dData[1]*dData[1] + dData[2]*dData[2];
}
else
{
dist2 = 0.f;
for( int c = 0; c < nchannels; c++ )
{
dData[c] = mean_m[c] - data[c];
dist2 += dData[c]*dData[c];
}
}
//background? - Tb - usually larger than Tg
if( totalWeight < TB && dist2 < Tb*var )
background = true;
//check fit
if( dist2 < Tg*var )
{
/////
//belongs to the mode
fitsPDF = true;
//update distribution
//update weight
weight += alphaT;
float k = alphaT/weight;
//update mean
for( int c = 0; c < nchannels; c++ )
mean_m[c] -= k*dData[c];
//update variance
float varnew = var + k*(dist2-var);
//limit the variance
varnew = MAX(varnew, varMin);
varnew = MIN(varnew, varMax);
gmm[mode].variance = varnew;
//sort
//all other weights are at the same place and
//only the matched (iModes) is higher -> just find the new place for it
for( int i = mode; i > 0; i-- )
{
//check one up
if( weight < gmm[i-1].weight )
break;
swap_count++;
//swap one up
std::swap(gmm[i], gmm[i-1]);
for( int c = 0; c < nchannels; c++ )
std::swap(mean[i*nchannels + c], mean[(i-1)*nchannels + c]);
}
//belongs to the mode - bFitsPDF becomes 1
/////
}
}//!bFitsPDF)
//check prune
if( weight < -prune )
{
weight = 0.0;
nmodes--;
}
gmm[mode-swap_count].weight = weight;//update weight by the calculated value
totalWeight += weight;
}
//go through all modes
//////
// Renormalize weights. In the special case that the pixel does
// not agree with any modes, set weights to zero (a new mode will be added below).
float invWeight = 0.f;
if (std::abs(totalWeight) > FLT_EPSILON) {
invWeight = 1.f/totalWeight;
}
for( int mode = 0; mode < nmodes; mode++ )
{
gmm[mode].weight *= invWeight;
}
//make new mode if needed and exit
if( !fitsPDF && alphaT > 0.f )
{
// replace the weakest or add a new one
int mode = nmodes == nmixtures ? nmixtures-1 : nmodes++;
if (nmodes==1)
gmm[mode].weight = 1.f;
else
{
gmm[mode].weight = alphaT;
// renormalize all other weights
for( int i = 0; i < nmodes-1; i++ )
gmm[i].weight *= alpha1;
}
// init
for( int c = 0; c < nchannels; c++ )
mean[mode*nchannels + c] = data[c];
gmm[mode].variance = varInit;
//sort
//find the new place for it
for( int i = nmodes - 1; i > 0; i-- )
{
// check one up
if( alphaT < gmm[i-1].weight )
break;
// swap one up
std::swap(gmm[i], gmm[i-1]);
for( int c = 0; c < nchannels; c++ )
std::swap(mean[i*nchannels + c], mean[(i-1)*nchannels + c]);
}
}
//set the number of modes
modesUsed[x] = uchar(nmodes);
mask[x] = background ? 0 :
detectShadows && detectShadowGMM(data, nchannels, nmodes, gmm, mean, Tb, TB, tau) ?
shadowVal : 255;
}
}
}
const Mat* src;
Mat* dst;
GMM* gmm0;
float* mean0;
uchar* modesUsed0;
int nmixtures;
float alphaT, Tb, TB, Tg;
float varInit, varMin, varMax, prune, tau;
bool detectShadows;
uchar shadowVal;
};
#ifdef HAVE_OPENCL
bool BackgroundSubtractorMOG2Impl::ocl_apply(InputArray _image, OutputArray _fgmask, double learningRate)
{
bool needToInitialize = nframes == 0 || learningRate >= 1 || _image.size() != frameSize || _image.type() != frameType;
if( needToInitialize )
initialize(_image.size(), _image.type());
++nframes;
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history );
CV_Assert(learningRate >= 0);
_fgmask.create(_image.size(), CV_8U);
UMat fgmask = _fgmask.getUMat();
const double alpha1 = 1.0f - learningRate;
UMat frame = _image.getUMat();
float varMax = MAX(fVarMin, fVarMax);
float varMin = MIN(fVarMin, fVarMax);
int idxArg = 0;
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::ReadOnly(frame));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_bgmodelUsedModes));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_weight));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_mean));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::PtrReadWrite(u_variance));
idxArg = kernel_apply.set(idxArg, ocl::KernelArg::WriteOnlyNoSize(fgmask));
idxArg = kernel_apply.set(idxArg, (float)learningRate); //alphaT
idxArg = kernel_apply.set(idxArg, (float)alpha1);
idxArg = kernel_apply.set(idxArg, (float)(-learningRate*fCT)); //prune
idxArg = kernel_apply.set(idxArg, (float)varThreshold); //c_Tb
idxArg = kernel_apply.set(idxArg, backgroundRatio); //c_TB
idxArg = kernel_apply.set(idxArg, varThresholdGen); //c_Tg
idxArg = kernel_apply.set(idxArg, varMin);
idxArg = kernel_apply.set(idxArg, varMax);
idxArg = kernel_apply.set(idxArg, fVarInit);
idxArg = kernel_apply.set(idxArg, fTau);
if (bShadowDetection)
kernel_apply.set(idxArg, nShadowDetection);
size_t globalsize[] = {(size_t)frame.cols, (size_t)frame.rows, 1};
return kernel_apply.run(2, globalsize, NULL, true);
}
bool BackgroundSubtractorMOG2Impl::ocl_getBackgroundImage(OutputArray _backgroundImage) const
{
_backgroundImage.create(frameSize, frameType);
UMat dst = _backgroundImage.getUMat();
int idxArg = 0;
idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::PtrReadOnly(u_bgmodelUsedModes));
idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::PtrReadOnly(u_weight));
idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::PtrReadOnly(u_mean));
idxArg = kernel_getBg.set(idxArg, ocl::KernelArg::WriteOnly(dst));
kernel_getBg.set(idxArg, backgroundRatio);
size_t globalsize[2] = {(size_t)u_bgmodelUsedModes.cols, (size_t)u_bgmodelUsedModes.rows};
return kernel_getBg.run(2, globalsize, NULL, false);
}
void BackgroundSubtractorMOG2Impl::create_ocl_apply_kernel()
{
int nchannels = CV_MAT_CN(frameType);
bool isFloat = CV_MAKETYPE(CV_32F,nchannels) == frameType;
String opts = format("-D CN=%d -D FL=%d -D NMIXTURES=%d%s", nchannels, isFloat, nmixtures, bShadowDetection ? " -D SHADOW_DETECT" : "");
kernel_apply.create("mog2_kernel", ocl::video::bgfg_mog2_oclsrc, opts);
}
#endif
void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
{
CV_INSTRUMENT_REGION();
#ifdef HAVE_OPENCL
if (opencl_ON)
{
CV_OCL_RUN(_fgmask.isUMat(), ocl_apply(_image, _fgmask, learningRate))
opencl_ON = false;
nframes = 0;
}
#endif
bool needToInitialize = nframes == 0 || learningRate >= 1 || _image.size() != frameSize || _image.type() != frameType;
if( needToInitialize )
initialize(_image.size(), _image.type());
Mat image = _image.getMat();
_fgmask.create( image.size(), CV_8U );
Mat fgmask = _fgmask.getMat();
++nframes;
learningRate = learningRate >= 0 && nframes > 1 ? learningRate : 1./std::min( 2*nframes, history );
CV_Assert(learningRate >= 0);
parallel_for_(Range(0, image.rows),
MOG2Invoker(image, fgmask,
bgmodel.ptr<GMM>(),
(float*)(bgmodel.ptr() + sizeof(GMM)*nmixtures*image.rows*image.cols),
bgmodelUsedModes.ptr(), nmixtures, (float)learningRate,
(float)varThreshold,
backgroundRatio, varThresholdGen,
fVarInit, fVarMin, fVarMax, float(-learningRate*fCT), fTau,
bShadowDetection, nShadowDetection),
image.total()/(double)(1 << 16));
}
template <typename T, int CN>
void BackgroundSubtractorMOG2Impl::getBackgroundImage_intern(OutputArray backgroundImage) const
{
CV_INSTRUMENT_REGION();
Mat meanBackground(frameSize, frameType, Scalar::all(0));
int firstGaussianIdx = 0;
const GMM* gmm = bgmodel.ptr<GMM>();
const float* mean = reinterpret_cast<const float*>(gmm + frameSize.width*frameSize.height*nmixtures);
Vec<float,CN> meanVal(0.f);
for(int row=0; row<meanBackground.rows; row++)
{
for(int col=0; col<meanBackground.cols; col++)
{
int nmodes = bgmodelUsedModes.at<uchar>(row, col);
float totalWeight = 0.f;
for(int gaussianIdx = firstGaussianIdx; gaussianIdx < firstGaussianIdx + nmodes; gaussianIdx++)
{
GMM gaussian = gmm[gaussianIdx];
size_t meanPosition = gaussianIdx*CN;
for(int chn = 0; chn < CN; chn++)
{
meanVal(chn) += gaussian.weight * mean[meanPosition + chn];
}
totalWeight += gaussian.weight;
if(totalWeight > backgroundRatio)
break;
}
float invWeight = 0.f;
if (std::abs(totalWeight) > FLT_EPSILON) {
invWeight = 1.f/totalWeight;
}
meanBackground.at<Vec<T,CN> >(row, col) = Vec<T,CN>(meanVal * invWeight);
meanVal = 0.f;
firstGaussianIdx += nmixtures;
}
}
meanBackground.copyTo(backgroundImage);
}
void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
{
CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_32FC1 || frameType == CV_32FC3);
#ifdef HAVE_OPENCL
if (opencl_ON)
{
CV_OCL_RUN(opencl_ON, ocl_getBackgroundImage(backgroundImage))
opencl_ON = false;
}
#endif
switch(frameType)
{
case CV_8UC1:
getBackgroundImage_intern<uchar,1>(backgroundImage);
break;
case CV_8UC3:
getBackgroundImage_intern<uchar,3>(backgroundImage);
break;
case CV_32FC1:
getBackgroundImage_intern<float,1>(backgroundImage);
break;
case CV_32FC3:
getBackgroundImage_intern<float,3>(backgroundImage);
break;
}
}
Ptr<BackgroundSubtractorMOG2> createBackgroundSubtractorMOG2(int _history, double _varThreshold,
bool _bShadowDetection)
{
return makePtr<BackgroundSubtractorMOG2Impl>(_history, (float)_varThreshold, _bShadowDetection);
}
}
/* End of file. */

View File

@@ -0,0 +1,220 @@
/*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, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, 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"
int cv::meanShift( InputArray _probImage, Rect& window, TermCriteria criteria )
{
CV_INSTRUMENT_REGION();
Size size;
int cn;
Mat mat;
UMat umat;
bool isUMat = _probImage.isUMat();
if (isUMat)
umat = _probImage.getUMat(), cn = umat.channels(), size = umat.size();
else
mat = _probImage.getMat(), cn = mat.channels(), size = mat.size();
Rect cur_rect = window;
CV_Assert( cn == 1 );
if( window.height <= 0 || window.width <= 0 )
CV_Error( Error::StsBadArg, "Input window has non-positive sizes" );
window = window & Rect(0, 0, size.width, size.height);
double eps = (criteria.type & TermCriteria::EPS) ? std::max(criteria.epsilon, 0.) : 1.;
eps = cvRound(eps*eps);
int i, niters = (criteria.type & TermCriteria::MAX_ITER) ? std::max(criteria.maxCount, 1) : 100;
for( i = 0; i < niters; i++ )
{
cur_rect = cur_rect & Rect(0, 0, size.width, size.height);
if( cur_rect == Rect() )
{
cur_rect.x = size.width/2;
cur_rect.y = size.height/2;
}
cur_rect.width = std::max(cur_rect.width, 1);
cur_rect.height = std::max(cur_rect.height, 1);
Moments m = isUMat ? moments(umat(cur_rect)) : moments(mat(cur_rect));
// Calculating center of mass
if( fabs(m.m00) < DBL_EPSILON )
break;
int dx = cvRound( m.m10/m.m00 - window.width*0.5 );
int dy = cvRound( m.m01/m.m00 - window.height*0.5 );
int nx = std::min(std::max(cur_rect.x + dx, 0), size.width - cur_rect.width);
int ny = std::min(std::max(cur_rect.y + dy, 0), size.height - cur_rect.height);
dx = nx - cur_rect.x;
dy = ny - cur_rect.y;
cur_rect.x = nx;
cur_rect.y = ny;
// Check for coverage centers mass & window
if( dx*dx + dy*dy < eps )
break;
}
window = cur_rect;
return i;
}
cv::RotatedRect cv::CamShift( InputArray _probImage, Rect& window,
TermCriteria criteria )
{
CV_INSTRUMENT_REGION();
const int TOLERANCE = 10;
Size size;
Mat mat;
UMat umat;
bool isUMat = _probImage.isUMat();
if (isUMat)
umat = _probImage.getUMat(), size = umat.size();
else
mat = _probImage.getMat(), size = mat.size();
meanShift( _probImage, window, criteria );
window.x -= TOLERANCE;
if( window.x < 0 )
window.x = 0;
window.y -= TOLERANCE;
if( window.y < 0 )
window.y = 0;
window.width += 2 * TOLERANCE;
if( window.x + window.width > size.width )
window.width = size.width - window.x;
window.height += 2 * TOLERANCE;
if( window.y + window.height > size.height )
window.height = size.height - window.y;
// Calculating moments in new center mass
Moments m = isUMat ? moments(umat(window)) : moments(mat(window));
double m00 = m.m00, m10 = m.m10, m01 = m.m01;
double mu11 = m.mu11, mu20 = m.mu20, mu02 = m.mu02;
if( fabs(m00) < DBL_EPSILON )
return RotatedRect();
double inv_m00 = 1. / m00;
int xc = cvRound( m10 * inv_m00 + window.x );
int yc = cvRound( m01 * inv_m00 + window.y );
double a = mu20 * inv_m00, b = mu11 * inv_m00, c = mu02 * inv_m00;
// Calculating width & height
double square = std::sqrt( 4 * b * b + (a - c) * (a - c) );
// Calculating orientation
double theta = atan2( 2 * b, a - c + square );
// Calculating width & length of figure
double cs = cos( theta );
double sn = sin( theta );
double rotate_a = cs * cs * mu20 + 2 * cs * sn * mu11 + sn * sn * mu02;
double rotate_c = sn * sn * mu20 - 2 * cs * sn * mu11 + cs * cs * mu02;
rotate_a = std::max(0.0, rotate_a); // avoid negative result due calculation numeric errors
rotate_c = std::max(0.0, rotate_c); // avoid negative result due calculation numeric errors
double length = std::sqrt( rotate_a * inv_m00 ) * 4;
double width = std::sqrt( rotate_c * inv_m00 ) * 4;
// In case, when tetta is 0 or 1.57... the Length & Width may be exchanged
if( length < width )
{
std::swap( length, width );
std::swap( cs, sn );
theta = CV_PI*0.5 - theta;
}
// Saving results
int _xc = cvRound( xc );
int _yc = cvRound( yc );
int t0 = cvRound( fabs( length * cs ));
int t1 = cvRound( fabs( width * sn ));
t0 = MAX( t0, t1 ) + 2;
window.width = MIN( t0, (size.width - _xc) * 2 );
t0 = cvRound( fabs( length * sn ));
t1 = cvRound( fabs( width * cs ));
t0 = MAX( t0, t1 ) + 2;
window.height = MIN( t0, (size.height - _yc) * 2 );
window.x = MAX( 0, _xc - window.width / 2 );
window.y = MAX( 0, _yc - window.height / 2 );
window.width = MIN( size.width - window.x, window.width );
window.height = MIN( size.height - window.y, window.height );
RotatedRect box;
box.size.height = (float)length;
box.size.width = (float)width;
box.angle = (float)((CV_PI*0.5+theta)*180./CV_PI);
while(box.angle < 0)
box.angle += 360;
while(box.angle >= 360)
box.angle -= 360;
if(box.angle >= 180)
box.angle -= 180;
box.center = Point2f( window.x + window.width*0.5f, window.y + window.height*0.5f);
return box;
}
/* End of file. */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,618 @@
/*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"
/****************************************************************************************\
* Image Alignment (ECC algorithm) *
\****************************************************************************************/
using namespace cv;
static void image_jacobian_homo_ECC(const Mat& src1, const Mat& src2,
const Mat& src3, const Mat& src4,
const Mat& src5, Mat& dst)
{
CV_Assert(src1.size() == src2.size());
CV_Assert(src1.size() == src3.size());
CV_Assert(src1.size() == src4.size());
CV_Assert( src1.rows == dst.rows);
CV_Assert(dst.cols == (src1.cols*8));
CV_Assert(dst.type() == CV_32FC1);
CV_Assert(src5.isContinuous());
const float* hptr = src5.ptr<float>(0);
const float h0_ = hptr[0];
const float h1_ = hptr[3];
const float h2_ = hptr[6];
const float h3_ = hptr[1];
const float h4_ = hptr[4];
const float h5_ = hptr[7];
const float h6_ = hptr[2];
const float h7_ = hptr[5];
const int w = src1.cols;
//create denominator for all points as a block
Mat den_ = src3*h2_ + src4*h5_ + 1.0;//check the time of this! otherwise use addWeighted
//create projected points
Mat hatX_ = -src3*h0_ - src4*h3_ - h6_;
divide(hatX_, den_, hatX_);
Mat hatY_ = -src3*h1_ - src4*h4_ - h7_;
divide(hatY_, den_, hatY_);
//instead of dividing each block with den,
//just pre-divide the block of gradients (it's more efficient)
Mat src1Divided_;
Mat src2Divided_;
divide(src1, den_, src1Divided_);
divide(src2, den_, src2Divided_);
//compute Jacobian blocks (8 blocks)
dst.colRange(0, w) = src1Divided_.mul(src3);//1
dst.colRange(w,2*w) = src2Divided_.mul(src3);//2
Mat temp_ = (hatX_.mul(src1Divided_)+hatY_.mul(src2Divided_));
dst.colRange(2*w,3*w) = temp_.mul(src3);//3
hatX_.release();
hatY_.release();
dst.colRange(3*w, 4*w) = src1Divided_.mul(src4);//4
dst.colRange(4*w, 5*w) = src2Divided_.mul(src4);//5
dst.colRange(5*w, 6*w) = temp_.mul(src4);//6
src1Divided_.copyTo(dst.colRange(6*w, 7*w));//7
src2Divided_.copyTo(dst.colRange(7*w, 8*w));//8
}
static void image_jacobian_euclidean_ECC(const Mat& src1, const Mat& src2,
const Mat& src3, const Mat& src4,
const Mat& src5, Mat& dst)
{
CV_Assert( src1.size()==src2.size());
CV_Assert( src1.size()==src3.size());
CV_Assert( src1.size()==src4.size());
CV_Assert( src1.rows == dst.rows);
CV_Assert(dst.cols == (src1.cols*3));
CV_Assert(dst.type() == CV_32FC1);
CV_Assert(src5.isContinuous());
const float* hptr = src5.ptr<float>(0);
const float h0 = hptr[0];//cos(theta)
const float h1 = hptr[3];//sin(theta)
const int w = src1.cols;
//create -sin(theta)*X -cos(theta)*Y for all points as a block -> hatX
Mat hatX = -(src3*h1) - (src4*h0);
//create cos(theta)*X -sin(theta)*Y for all points as a block -> hatY
Mat hatY = (src3*h0) - (src4*h1);
//compute Jacobian blocks (3 blocks)
dst.colRange(0, w) = (src1.mul(hatX))+(src2.mul(hatY));//1
src1.copyTo(dst.colRange(w, 2*w));//2
src2.copyTo(dst.colRange(2*w, 3*w));//3
}
static void image_jacobian_affine_ECC(const Mat& src1, const Mat& src2,
const Mat& src3, const Mat& src4,
Mat& dst)
{
CV_Assert(src1.size() == src2.size());
CV_Assert(src1.size() == src3.size());
CV_Assert(src1.size() == src4.size());
CV_Assert(src1.rows == dst.rows);
CV_Assert(dst.cols == (6*src1.cols));
CV_Assert(dst.type() == CV_32FC1);
const int w = src1.cols;
//compute Jacobian blocks (6 blocks)
dst.colRange(0,w) = src1.mul(src3);//1
dst.colRange(w,2*w) = src2.mul(src3);//2
dst.colRange(2*w,3*w) = src1.mul(src4);//3
dst.colRange(3*w,4*w) = src2.mul(src4);//4
src1.copyTo(dst.colRange(4*w,5*w));//5
src2.copyTo(dst.colRange(5*w,6*w));//6
}
static void image_jacobian_translation_ECC(const Mat& src1, const Mat& src2, Mat& dst)
{
CV_Assert( src1.size()==src2.size());
CV_Assert( src1.rows == dst.rows);
CV_Assert(dst.cols == (src1.cols*2));
CV_Assert(dst.type() == CV_32FC1);
const int w = src1.cols;
//compute Jacobian blocks (2 blocks)
src1.copyTo(dst.colRange(0, w));
src2.copyTo(dst.colRange(w, 2*w));
}
static void project_onto_jacobian_ECC(const Mat& src1, const Mat& src2, Mat& dst)
{
/* this functions is used for two types of projections. If src1.cols ==src.cols
it does a blockwise multiplication (like in the outer product of vectors)
of the blocks in matrices src1 and src2 and dst
has size (number_of_blcks x number_of_blocks), otherwise dst is a vector of size
(number_of_blocks x 1) since src2 is "multiplied"(dot) with each block of src1.
The number_of_blocks is equal to the number of parameters we are lloking for
(i.e. rtanslation:2, euclidean: 3, affine: 6, homography: 8)
*/
CV_Assert(src1.rows == src2.rows);
CV_Assert((src1.cols % src2.cols) == 0);
int w;
float* dstPtr = dst.ptr<float>(0);
if (src1.cols !=src2.cols){//dst.cols==1
w = src2.cols;
for (int i=0; i<dst.rows; i++){
dstPtr[i] = (float) src2.dot(src1.colRange(i*w,(i+1)*w));
}
}
else {
CV_Assert(dst.cols == dst.rows); //dst is square (and symmetric)
w = src2.cols/dst.cols;
Mat mat;
for (int i=0; i<dst.rows; i++){
mat = Mat(src1.colRange(i*w, (i+1)*w));
dstPtr[i*(dst.rows+1)] = (float) pow(norm(mat),2); //diagonal elements
for (int j=i+1; j<dst.cols; j++){ //j starts from i+1
dstPtr[i*dst.cols+j] = (float) mat.dot(src2.colRange(j*w, (j+1)*w));
dstPtr[j*dst.cols+i] = dstPtr[i*dst.cols+j]; //due to symmetry
}
}
}
}
static void update_warping_matrix_ECC (Mat& map_matrix, const Mat& update, const int motionType)
{
CV_Assert (map_matrix.type() == CV_32FC1);
CV_Assert (update.type() == CV_32FC1);
CV_Assert (motionType == MOTION_TRANSLATION || motionType == MOTION_EUCLIDEAN ||
motionType == MOTION_AFFINE || motionType == MOTION_HOMOGRAPHY);
if (motionType == MOTION_HOMOGRAPHY)
CV_Assert (map_matrix.rows == 3 && update.rows == 8);
else if (motionType == MOTION_AFFINE)
CV_Assert(map_matrix.rows == 2 && update.rows == 6);
else if (motionType == MOTION_EUCLIDEAN)
CV_Assert (map_matrix.rows == 2 && update.rows == 3);
else
CV_Assert (map_matrix.rows == 2 && update.rows == 2);
CV_Assert (update.cols == 1);
CV_Assert( map_matrix.isContinuous());
CV_Assert( update.isContinuous() );
float* mapPtr = map_matrix.ptr<float>(0);
const float* updatePtr = update.ptr<float>(0);
if (motionType == MOTION_TRANSLATION){
mapPtr[2] += updatePtr[0];
mapPtr[5] += updatePtr[1];
}
if (motionType == MOTION_AFFINE) {
mapPtr[0] += updatePtr[0];
mapPtr[3] += updatePtr[1];
mapPtr[1] += updatePtr[2];
mapPtr[4] += updatePtr[3];
mapPtr[2] += updatePtr[4];
mapPtr[5] += updatePtr[5];
}
if (motionType == MOTION_HOMOGRAPHY) {
mapPtr[0] += updatePtr[0];
mapPtr[3] += updatePtr[1];
mapPtr[6] += updatePtr[2];
mapPtr[1] += updatePtr[3];
mapPtr[4] += updatePtr[4];
mapPtr[7] += updatePtr[5];
mapPtr[2] += updatePtr[6];
mapPtr[5] += updatePtr[7];
}
if (motionType == MOTION_EUCLIDEAN) {
double new_theta = updatePtr[0];
new_theta += asin(mapPtr[3]);
mapPtr[2] += updatePtr[1];
mapPtr[5] += updatePtr[2];
mapPtr[0] = mapPtr[4] = (float) cos(new_theta);
mapPtr[3] = (float) sin(new_theta);
mapPtr[1] = -mapPtr[3];
}
}
/** Function that computes enhanced corelation coefficient from Georgios et.al. 2008
* See https://github.com/opencv/opencv/issues/12432
*/
double cv::computeECC(InputArray templateImage, InputArray inputImage, InputArray inputMask)
{
CV_Assert(!templateImage.empty());
CV_Assert(!inputImage.empty());
if( ! (templateImage.type()==inputImage.type()))
CV_Error( Error::StsUnmatchedFormats, "Both input images must have the same data type" );
Scalar meanTemplate, sdTemplate;
int active_pixels = inputMask.empty() ? templateImage.size().area() : countNonZero(inputMask);
int type = templateImage.type();
meanStdDev(templateImage, meanTemplate, sdTemplate, inputMask);
Mat templateImage_zeromean = Mat::zeros(templateImage.size(), templateImage.type());
Mat templateMat = templateImage.getMat();
Mat inputMat = inputImage.getMat();
/*
* For unsigned ints, when the mean is computed and subtracted, any values less than the mean
* will be set to 0 (since there are no negatives values). This impacts the norm and dot product, which
* ultimately results in an incorrect ECC. To circumvent this problem, if unsigned ints are provided,
* we convert them to a signed ints with larger resolution for the subtraction step.
*/
if(type == CV_8U || type == CV_16U) {
int newType = type == CV_8U ? CV_16S : CV_32S;
Mat templateMatConverted, inputMatConverted;
templateMat.convertTo(templateMatConverted, newType);
cv::swap(templateMat, templateMatConverted);
inputMat.convertTo(inputMatConverted, newType);
cv::swap(inputMat, inputMatConverted);
}
subtract(templateMat, meanTemplate, templateImage_zeromean, inputMask);
double templateImagenorm = std::sqrt(active_pixels*sdTemplate.val[0]*sdTemplate.val[0]);
Scalar meanInput, sdInput;
Mat inputImage_zeromean = Mat::zeros(inputImage.size(), inputImage.type());
meanStdDev(inputImage, meanInput, sdInput, inputMask);
subtract(inputMat, meanInput, inputImage_zeromean, inputMask);
double inputImagenorm = std::sqrt(active_pixels*sdInput.val[0]*sdInput.val[0]);
return templateImage_zeromean.dot(inputImage_zeromean)/(templateImagenorm*inputImagenorm);
}
double cv::findTransformECC(InputArray templateImage,
InputArray inputImage,
InputOutputArray warpMatrix,
int motionType,
TermCriteria criteria,
InputArray inputMask,
int gaussFiltSize)
{
Mat src = templateImage.getMat();//template image
Mat dst = inputImage.getMat(); //input image (to be warped)
Mat map = warpMatrix.getMat(); //warp (transformation)
CV_Assert(!src.empty());
CV_Assert(!dst.empty());
// If the user passed an un-initialized warpMatrix, initialize to identity
if(map.empty()) {
int rowCount = 2;
if(motionType == MOTION_HOMOGRAPHY)
rowCount = 3;
warpMatrix.create(rowCount, 3, CV_32FC1);
map = warpMatrix.getMat();
map = Mat::eye(rowCount, 3, CV_32F);
}
if( ! (src.type()==dst.type()))
CV_Error( Error::StsUnmatchedFormats, "Both input images must have the same data type" );
//accept only 1-channel images
if( src.type() != CV_8UC1 && src.type()!= CV_32FC1)
CV_Error( Error::StsUnsupportedFormat, "Images must have 8uC1 or 32fC1 type");
if( map.type() != CV_32FC1)
CV_Error( Error::StsUnsupportedFormat, "warpMatrix must be single-channel floating-point matrix");
CV_Assert (map.cols == 3);
CV_Assert (map.rows == 2 || map.rows ==3);
CV_Assert (motionType == MOTION_AFFINE || motionType == MOTION_HOMOGRAPHY ||
motionType == MOTION_EUCLIDEAN || motionType == MOTION_TRANSLATION);
if (motionType == MOTION_HOMOGRAPHY){
CV_Assert (map.rows ==3);
}
CV_Assert (criteria.type & TermCriteria::COUNT || criteria.type & TermCriteria::EPS);
const int numberOfIterations = (criteria.type & TermCriteria::COUNT) ? criteria.maxCount : 200;
const double termination_eps = (criteria.type & TermCriteria::EPS) ? criteria.epsilon : -1;
int paramTemp = 6;//default: affine
switch (motionType){
case MOTION_TRANSLATION:
paramTemp = 2;
break;
case MOTION_EUCLIDEAN:
paramTemp = 3;
break;
case MOTION_HOMOGRAPHY:
paramTemp = 8;
break;
}
const int numberOfParameters = paramTemp;
const int ws = src.cols;
const int hs = src.rows;
const int wd = dst.cols;
const int hd = dst.rows;
Mat Xcoord = Mat(1, ws, CV_32F);
Mat Ycoord = Mat(hs, 1, CV_32F);
Mat Xgrid = Mat(hs, ws, CV_32F);
Mat Ygrid = Mat(hs, ws, CV_32F);
float* XcoPtr = Xcoord.ptr<float>(0);
float* YcoPtr = Ycoord.ptr<float>(0);
int j;
for (j=0; j<ws; j++)
XcoPtr[j] = (float) j;
for (j=0; j<hs; j++)
YcoPtr[j] = (float) j;
repeat(Xcoord, hs, 1, Xgrid);
repeat(Ycoord, 1, ws, Ygrid);
Xcoord.release();
Ycoord.release();
Mat templateZM = Mat(hs, ws, CV_32F);// to store the (smoothed)zero-mean version of template
Mat templateFloat = Mat(hs, ws, CV_32F);// to store the (smoothed) template
Mat imageFloat = Mat(hd, wd, CV_32F);// to store the (smoothed) input image
Mat imageWarped = Mat(hs, ws, CV_32F);// to store the warped zero-mean input image
Mat imageMask = Mat(hs, ws, CV_8U); // to store the final mask
Mat inputMaskMat = inputMask.getMat();
//to use it for mask warping
Mat preMask;
if(inputMask.empty())
preMask = Mat::ones(hd, wd, CV_8U);
else
threshold(inputMask, preMask, 0, 1, THRESH_BINARY);
//gaussian filtering is optional
src.convertTo(templateFloat, templateFloat.type());
GaussianBlur(templateFloat, templateFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
Mat preMaskFloat;
preMask.convertTo(preMaskFloat, CV_32F);
GaussianBlur(preMaskFloat, preMaskFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
// Change threshold.
preMaskFloat *= (0.5/0.95);
// Rounding conversion.
preMaskFloat.convertTo(preMask, preMask.type());
preMask.convertTo(preMaskFloat, preMaskFloat.type());
dst.convertTo(imageFloat, imageFloat.type());
GaussianBlur(imageFloat, imageFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
// needed matrices for gradients and warped gradients
Mat gradientX = Mat::zeros(hd, wd, CV_32FC1);
Mat gradientY = Mat::zeros(hd, wd, CV_32FC1);
Mat gradientXWarped = Mat(hs, ws, CV_32FC1);
Mat gradientYWarped = Mat(hs, ws, CV_32FC1);
// calculate first order image derivatives
Matx13f dx(-0.5f, 0.0f, 0.5f);
filter2D(imageFloat, gradientX, -1, dx);
filter2D(imageFloat, gradientY, -1, dx.t());
gradientX = gradientX.mul(preMaskFloat);
gradientY = gradientY.mul(preMaskFloat);
// matrices needed for solving linear equation system for maximizing ECC
Mat jacobian = Mat(hs, ws*numberOfParameters, CV_32F);
Mat hessian = Mat(numberOfParameters, numberOfParameters, CV_32F);
Mat hessianInv = Mat(numberOfParameters, numberOfParameters, CV_32F);
Mat imageProjection = Mat(numberOfParameters, 1, CV_32F);
Mat templateProjection = Mat(numberOfParameters, 1, CV_32F);
Mat imageProjectionHessian = Mat(numberOfParameters, 1, CV_32F);
Mat errorProjection = Mat(numberOfParameters, 1, CV_32F);
Mat deltaP = Mat(numberOfParameters, 1, CV_32F);//transformation parameter correction
Mat error = Mat(hs, ws, CV_32F);//error as 2D matrix
const int imageFlags = INTER_LINEAR + WARP_INVERSE_MAP;
const int maskFlags = INTER_NEAREST + WARP_INVERSE_MAP;
// iteratively update map_matrix
double rho = -1;
double last_rho = - termination_eps;
for (int i = 1; (i <= numberOfIterations) && (fabs(rho-last_rho)>= termination_eps); i++)
{
// warp-back portion of the inputImage and gradients to the coordinate space of the templateImage
if (motionType != MOTION_HOMOGRAPHY)
{
warpAffine(imageFloat, imageWarped, map, imageWarped.size(), imageFlags);
warpAffine(gradientX, gradientXWarped, map, gradientXWarped.size(), imageFlags);
warpAffine(gradientY, gradientYWarped, map, gradientYWarped.size(), imageFlags);
warpAffine(preMask, imageMask, map, imageMask.size(), maskFlags);
}
else
{
warpPerspective(imageFloat, imageWarped, map, imageWarped.size(), imageFlags);
warpPerspective(gradientX, gradientXWarped, map, gradientXWarped.size(), imageFlags);
warpPerspective(gradientY, gradientYWarped, map, gradientYWarped.size(), imageFlags);
warpPerspective(preMask, imageMask, map, imageMask.size(), maskFlags);
}
Scalar imgMean, imgStd, tmpMean, tmpStd;
meanStdDev(imageWarped, imgMean, imgStd, imageMask);
meanStdDev(templateFloat, tmpMean, tmpStd, imageMask);
subtract(imageWarped, imgMean, imageWarped, imageMask);//zero-mean input
templateZM = Mat::zeros(templateZM.rows, templateZM.cols, templateZM.type());
subtract(templateFloat, tmpMean, templateZM, imageMask);//zero-mean template
const double tmpNorm = std::sqrt(countNonZero(imageMask)*(tmpStd.val[0])*(tmpStd.val[0]));
const double imgNorm = std::sqrt(countNonZero(imageMask)*(imgStd.val[0])*(imgStd.val[0]));
// calculate jacobian of image wrt parameters
switch (motionType){
case MOTION_AFFINE:
image_jacobian_affine_ECC(gradientXWarped, gradientYWarped, Xgrid, Ygrid, jacobian);
break;
case MOTION_HOMOGRAPHY:
image_jacobian_homo_ECC(gradientXWarped, gradientYWarped, Xgrid, Ygrid, map, jacobian);
break;
case MOTION_TRANSLATION:
image_jacobian_translation_ECC(gradientXWarped, gradientYWarped, jacobian);
break;
case MOTION_EUCLIDEAN:
image_jacobian_euclidean_ECC(gradientXWarped, gradientYWarped, Xgrid, Ygrid, map, jacobian);
break;
}
// calculate Hessian and its inverse
project_onto_jacobian_ECC(jacobian, jacobian, hessian);
hessianInv = hessian.inv();
const double correlation = templateZM.dot(imageWarped);
// calculate enhanced correlation coefficient (ECC)->rho
last_rho = rho;
rho = correlation/(imgNorm*tmpNorm);
if (cvIsNaN(rho)) {
CV_Error(Error::StsNoConv, "NaN encountered.");
}
// project images into jacobian
project_onto_jacobian_ECC( jacobian, imageWarped, imageProjection);
project_onto_jacobian_ECC(jacobian, templateZM, templateProjection);
// calculate the parameter lambda to account for illumination variation
imageProjectionHessian = hessianInv*imageProjection;
const double lambda_n = (imgNorm*imgNorm) - imageProjection.dot(imageProjectionHessian);
const double lambda_d = correlation - templateProjection.dot(imageProjectionHessian);
if (lambda_d <= 0.0)
{
rho = -1;
CV_Error(Error::StsNoConv, "The algorithm stopped before its convergence. The correlation is going to be minimized. Images may be uncorrelated or non-overlapped");
}
const double lambda = (lambda_n/lambda_d);
// estimate the update step delta_p
error = lambda*templateZM - imageWarped;
project_onto_jacobian_ECC(jacobian, error, errorProjection);
deltaP = hessianInv * errorProjection;
// update warping matrix
update_warping_matrix_ECC( map, deltaP, motionType);
}
// return final correlation coefficient
return rho;
}
double cv::findTransformECC(InputArray templateImage, InputArray inputImage,
InputOutputArray warpMatrix, int motionType,
TermCriteria criteria,
InputArray inputMask)
{
// Use default value of 5 for gaussFiltSize to maintain backward compatibility.
return findTransformECC(templateImage, inputImage, warpMatrix, motionType, criteria, inputMask, 5);
}
/* End of file. */

View File

@@ -0,0 +1,134 @@
/*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"
namespace cv
{
KalmanFilter::KalmanFilter() {}
KalmanFilter::KalmanFilter(int dynamParams, int measureParams, int controlParams, int type)
{
init(dynamParams, measureParams, controlParams, type);
}
void KalmanFilter::init(int DP, int MP, int CP, int type)
{
CV_Assert( DP > 0 && MP > 0 );
CV_Assert( type == CV_32F || type == CV_64F );
CP = std::max(CP, 0);
statePre = Mat::zeros(DP, 1, type);
statePost = Mat::zeros(DP, 1, type);
transitionMatrix = Mat::eye(DP, DP, type);
processNoiseCov = Mat::eye(DP, DP, type);
measurementMatrix = Mat::zeros(MP, DP, type);
measurementNoiseCov = Mat::eye(MP, MP, type);
errorCovPre = Mat::zeros(DP, DP, type);
errorCovPost = Mat::zeros(DP, DP, type);
gain = Mat::zeros(DP, MP, type);
if( CP > 0 )
controlMatrix = Mat::zeros(DP, CP, type);
else
controlMatrix.release();
temp1.create(DP, DP, type);
temp2.create(MP, DP, type);
temp3.create(MP, MP, type);
temp4.create(MP, DP, type);
temp5.create(MP, 1, type);
}
const Mat& KalmanFilter::predict(const Mat& control)
{
CV_INSTRUMENT_REGION();
// update the state: x'(k) = A*x(k)
statePre = transitionMatrix*statePost;
if( !control.empty() )
// x'(k) = x'(k) + B*u(k)
statePre += controlMatrix*control;
// update error covariance matrices: temp1 = A*P(k)
temp1 = transitionMatrix*errorCovPost;
// P'(k) = temp1*At + Q
gemm(temp1, transitionMatrix, 1, processNoiseCov, 1, errorCovPre, GEMM_2_T);
// handle the case when there will be measurement before the next predict.
statePre.copyTo(statePost);
errorCovPre.copyTo(errorCovPost);
return statePre;
}
const Mat& KalmanFilter::correct(const Mat& measurement)
{
CV_INSTRUMENT_REGION();
// temp2 = H*P'(k)
temp2 = measurementMatrix * errorCovPre;
// temp3 = temp2*Ht + R
gemm(temp2, measurementMatrix, 1, measurementNoiseCov, 1, temp3, GEMM_2_T);
// temp4 = inv(temp3)*temp2 = Kt(k)
solve(temp3, temp2, temp4, DECOMP_SVD);
// K(k)
gain = temp4.t();
// temp5 = z(k) - H*x'(k)
temp5 = measurement - measurementMatrix*statePre;
// x(k) = x'(k) + K(k)*temp5
statePost = statePre + gain*temp5;
// P(k) = P'(k) - K(k)*temp2
errorCovPost = errorCovPre - gain*temp2;
return statePost;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
#pragma once
namespace cv
{
namespace detail
{
typedef short deriv_type;
struct ScharrDerivInvoker : ParallelLoopBody
{
ScharrDerivInvoker(const Mat& _src, const Mat& _dst)
: src(_src), dst(_dst)
{ }
void operator()(const Range& range) const CV_OVERRIDE;
const Mat& src;
const Mat& dst;
};
struct LKTrackerInvoker : ParallelLoopBody
{
LKTrackerInvoker( const Mat& _prevImg, const Mat& _prevDeriv, const Mat& _nextImg,
const Point2f* _prevPts, Point2f* _nextPts,
uchar* _status, float* _err,
Size _winSize, TermCriteria _criteria,
int _level, int _maxLevel, int _flags, float _minEigThreshold );
void operator()(const Range& range) const CV_OVERRIDE;
const Mat* prevImg;
const Mat* nextImg;
const Mat* prevDeriv;
const Point2f* prevPts;
Point2f* nextPts;
uchar* status;
float* err;
Size winSize;
TermCriteria criteria;
int level;
int maxLevel;
int flags;
float minEigThreshold;
};
}// namespace detail
}// namespace cv

View File

@@ -0,0 +1,248 @@
/*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) 2018 Ya-Chiu Wu, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Ya-Chiu Wu, yacwu@cs.nctu.edu.tw
//
// 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*/
#if CN==1
#define T_MEAN float
#define F_ZERO (0.0f)
#define frameToMean(a, b) (b) = *(a);
#define meanToFrame(a, b) *b = convert_uchar_sat(a);
#else
#define T_MEAN float4
#define F_ZERO (0.0f, 0.0f, 0.0f, 0.0f)
#define meanToFrame(a, b)\
b[0] = convert_uchar_sat(a.x); \
b[1] = convert_uchar_sat(a.y); \
b[2] = convert_uchar_sat(a.z);
#define frameToMean(a, b)\
b.x = a[0]; \
b.y = a[1]; \
b.z = a[2]; \
b.w = 0.0f;
#endif
__kernel void knn_kernel(__global const uchar* frame, int frame_step, int frame_offset, int frame_row, int frame_col,
__global const uchar* nNextLongUpdate,
__global const uchar* nNextMidUpdate,
__global const uchar* nNextShortUpdate,
__global uchar* aModelIndexLong,
__global uchar* aModelIndexMid,
__global uchar* aModelIndexShort,
__global uchar* flag,
__global uchar* sample,
__global uchar* fgmask, int fgmask_step, int fgmask_offset,
int nLongCounter, int nMidCounter, int nShortCounter,
float c_Tb, int c_nkNN, float c_tau
#ifdef SHADOW_DETECT
, uchar c_shadowVal
#endif
)
{
int x = get_global_id(0);
int y = get_global_id(1);
if( x < frame_col && y < frame_row)
{
__global const uchar* _frame = (frame + mad24(y, frame_step, mad24(x, CN, frame_offset)));
T_MEAN pix;
frameToMean(_frame, pix);
uchar foreground = 255; // 0 - the pixel classified as background
int Pbf = 0;
int Pb = 0;
uchar include = 0;
int pt_idx = mad24(y, frame_col, x);
int idx_step = frame_row * frame_col;
__global T_MEAN* _sample = (__global T_MEAN*)(sample);
for (uchar n = 0; n < (NSAMPLES) * 3 ; ++n)
{
int n_idx = mad24(n, idx_step, pt_idx);
T_MEAN c_mean = _sample[n_idx];
uchar c_flag = flag[n_idx];
T_MEAN diff = c_mean - pix;
float dist2 = dot(diff, diff);
if (dist2 < c_Tb)
{
Pbf++;
if (c_flag)
{
Pb++;
if (Pb >= c_nkNN)
{
include = 1;
foreground = 0;
break;
}
}
}
}
if (Pbf >= c_nkNN)
{
include = 1;
}
#ifdef SHADOW_DETECT
if (foreground)
{
int Ps = 0;
for (uchar n = 0; n < (NSAMPLES) * 3 ; ++n)
{
int n_idx = mad24(n, idx_step, pt_idx);
uchar c_flag = flag[n_idx];
if (c_flag)
{
T_MEAN c_mean = _sample[n_idx];
float numerator = dot(pix, c_mean);
float denominator = dot(c_mean, c_mean);
if (denominator == 0)
break;
if (numerator <= denominator && numerator >= c_tau * denominator)
{
float a = numerator / denominator;
T_MEAN dD = mad(a, c_mean, -pix);
if (dot(dD, dD) < c_Tb * a * a)
{
Ps++;
if (Ps >= c_nkNN)
{
foreground = c_shadowVal;
break;
}
}
}
}
}
}
#endif
__global uchar* _fgmask = fgmask + mad24(y, fgmask_step, x + fgmask_offset);
*_fgmask = (uchar)foreground;
__global const uchar* _nNextLongUpdate = nNextLongUpdate + pt_idx;
__global const uchar* _nNextMidUpdate = nNextMidUpdate + pt_idx;
__global const uchar* _nNextShortUpdate = nNextShortUpdate + pt_idx;
__global uchar* _aModelIndexLong = aModelIndexLong + pt_idx;
__global uchar* _aModelIndexMid = aModelIndexMid + pt_idx;
__global uchar* _aModelIndexShort = aModelIndexShort + pt_idx;
uchar nextLongUpdate = _nNextLongUpdate[0];
uchar nextMidUpdate = _nNextMidUpdate[0];
uchar nextShortUpdate = _nNextShortUpdate[0];
uchar modelIndexLong = _aModelIndexLong[0];
uchar modelIndexMid = _aModelIndexMid[0];
uchar modelIndexShort = _aModelIndexShort[0];
int offsetLong = mad24(mad24(2, (NSAMPLES), modelIndexLong), idx_step, pt_idx);
int offsetMid = mad24((NSAMPLES)+modelIndexMid, idx_step, pt_idx);
int offsetShort = mad24(modelIndexShort, idx_step, pt_idx);
if (nextLongUpdate == nLongCounter)
{
_sample[offsetLong] = _sample[offsetMid];
flag[offsetLong] = flag[offsetMid];
_aModelIndexLong[0] = (modelIndexLong >= ((NSAMPLES)-1)) ? 0 : (modelIndexLong + 1);
}
if (nextMidUpdate == nMidCounter)
{
_sample[offsetMid] = _sample[offsetShort];
flag[offsetMid] = flag[offsetShort];
_aModelIndexMid[0] = (modelIndexMid >= ((NSAMPLES)-1)) ? 0 : (modelIndexMid + 1);
}
if (nextShortUpdate == nShortCounter)
{
_sample[offsetShort] = pix;
flag[offsetShort] = include;
_aModelIndexShort[0] = (modelIndexShort >= ((NSAMPLES)-1)) ? 0 : (modelIndexShort + 1);
}
}
}
__kernel void getBackgroundImage2_kernel(__global const uchar* flag,
__global const uchar* sample,
__global uchar* dst, int dst_step, int dst_offset, int dst_row, int dst_col)
{
int x = get_global_id(0);
int y = get_global_id(1);
if(x < dst_col && y < dst_row)
{
int pt_idx = mad24(y, dst_col, x);
T_MEAN meanVal = (T_MEAN)F_ZERO;
__global T_MEAN* _sample = (__global T_MEAN*)(sample);
int idx_step = dst_row * dst_col;
for (uchar n = 0; n < (NSAMPLES) * 3 ; ++n)
{
int n_idx = mad24(n, idx_step, pt_idx);
uchar c_flag = flag[n_idx];
if(c_flag)
{
meanVal = _sample[n_idx];
break;
}
}
__global uchar* _dst = dst + mad24(y, dst_step, mad24(x, CN, dst_offset));
meanToFrame(meanVal, _dst);
}
}

View File

@@ -0,0 +1,282 @@
#if CN==1
#define T_MEAN float
#define F_ZERO (0.0f)
#define cnMode 1
#define frameToMean(a, b) (b) = *(a);
#if FL==0
#define meanToFrame(a, b) *b = convert_uchar_sat(a);
#else
#define meanToFrame(a, b) *b = (float)a;
#endif
#else
#define T_MEAN float4
#define F_ZERO (0.0f, 0.0f, 0.0f, 0.0f)
#define cnMode 4
#if FL == 0
#define meanToFrame(a, b)\
b[0] = convert_uchar_sat(a.x); \
b[1] = convert_uchar_sat(a.y); \
b[2] = convert_uchar_sat(a.z);
#else
#define meanToFrame(a, b)\
b[0] = a.x; \
b[1] = a.y; \
b[2] = a.z;
#endif
#define frameToMean(a, b)\
b.x = a[0]; \
b.y = a[1]; \
b.z = a[2]; \
b.w = 0.0f;
#endif
__kernel void mog2_kernel(__global const uchar* frame, int frame_step, int frame_offset, int frame_row, int frame_col, //uchar || uchar3
__global uchar* modesUsed, //uchar
__global uchar* weight, //float
__global uchar* mean, //T_MEAN=float || float4
__global uchar* variance, //float
__global uchar* fgmask, int fgmask_step, int fgmask_offset, //uchar
float alphaT, float alpha1, float prune,
float c_Tb, float c_TB, float c_Tg, float c_varMin, //constants
float c_varMax, float c_varInit, float c_tau
#ifdef SHADOW_DETECT
, uchar c_shadowVal
#endif
)
{
int x = get_global_id(0);
int y = get_global_id(1);
if( x < frame_col && y < frame_row)
{
#if FL==0
__global const uchar* _frame = (frame + mad24(y, frame_step, mad24(x, CN, frame_offset)));
#else
__global const float* _frame = ((__global const float*)( frame + mad24(y, frame_step, frame_offset)) + mad24(x, CN, 0));
#endif
T_MEAN pix;
frameToMean(_frame, pix);
uchar foreground = 255; // 0 - the pixel classified as background
bool fitsPDF = false; //if it remains zero a new GMM mode will be added
int pt_idx = mad24(y, frame_col, x);
int idx_step = frame_row * frame_col;
__global uchar* _modesUsed = modesUsed + pt_idx;
uchar nmodes = _modesUsed[0];
float totalWeight = 0.0f;
__global float* _weight = (__global float*)(weight);
__global float* _variance = (__global float*)(variance);
__global T_MEAN* _mean = (__global T_MEAN*)(mean);
uchar mode = 0;
for (; mode < nmodes; ++mode)
{
int mode_idx = mad24(mode, idx_step, pt_idx);
float c_weight = mad(alpha1, _weight[mode_idx], prune);
float c_var = _variance[mode_idx];
T_MEAN c_mean = _mean[mode_idx];
T_MEAN diff = c_mean - pix;
float dist2 = dot(diff, diff);
if (totalWeight < c_TB && dist2 < c_Tb * c_var)
foreground = 0;
if (dist2 < c_Tg * c_var)
{
fitsPDF = true;
c_weight += alphaT;
float k = alphaT / c_weight;
T_MEAN mean_new = mad((T_MEAN)-k, diff, c_mean);
float variance_new = clamp(mad(k, (dist2 - c_var), c_var), c_varMin, c_varMax);
for (int i = mode; i > 0; --i)
{
int prev_idx = mode_idx - idx_step;
if (c_weight < _weight[prev_idx])
break;
_weight[mode_idx] = _weight[prev_idx];
_variance[mode_idx] = _variance[prev_idx];
_mean[mode_idx] = _mean[prev_idx];
mode_idx = prev_idx;
}
_mean[mode_idx] = mean_new;
_variance[mode_idx] = variance_new;
_weight[mode_idx] = c_weight; //update weight by the calculated value
totalWeight += c_weight;
mode ++;
break;
}
if (c_weight < -prune)
c_weight = 0.0f;
_weight[mode_idx] = c_weight; //update weight by the calculated value
totalWeight += c_weight;
}
for (; mode < nmodes; ++mode)
{
int mode_idx = mad24(mode, idx_step, pt_idx);
float c_weight = mad(alpha1, _weight[mode_idx], prune);
if (c_weight < -prune)
{
c_weight = 0.0f;
nmodes = mode;
break;
}
_weight[mode_idx] = c_weight; //update weight by the calculated value
totalWeight += c_weight;
}
if (0.f < totalWeight)
{
totalWeight = 1.f / totalWeight;
for (int mode = 0; mode < nmodes; ++mode)
_weight[mad24(mode, idx_step, pt_idx)] *= totalWeight;
}
if (!fitsPDF)
{
uchar mode = nmodes == (NMIXTURES) ? (NMIXTURES) - 1 : nmodes++;
int mode_idx = mad24(mode, idx_step, pt_idx);
if (nmodes == 1)
_weight[mode_idx] = 1.f;
else
{
_weight[mode_idx] = alphaT;
for (int i = pt_idx; i < mode_idx; i += idx_step)
_weight[i] *= alpha1;
}
for (int i = nmodes - 1; i > 0; --i)
{
int prev_idx = mode_idx - idx_step;
if (alphaT < _weight[prev_idx])
break;
_weight[mode_idx] = _weight[prev_idx];
_variance[mode_idx] = _variance[prev_idx];
_mean[mode_idx] = _mean[prev_idx];
mode_idx = prev_idx;
}
_mean[mode_idx] = pix;
_variance[mode_idx] = c_varInit;
}
_modesUsed[0] = nmodes;
#ifdef SHADOW_DETECT
if (foreground)
{
float tWeight = 0.0f;
for (uchar mode = 0; mode < nmodes; ++mode)
{
int mode_idx = mad24(mode, idx_step, pt_idx);
T_MEAN c_mean = _mean[mode_idx];
float numerator = dot(pix, c_mean);
float denominator = dot(c_mean, c_mean);
if (denominator == 0)
break;
if (numerator <= denominator && numerator >= c_tau * denominator)
{
float a = numerator / denominator;
T_MEAN dD = mad(a, c_mean, -pix);
if (dot(dD, dD) < c_Tb * _variance[mode_idx] * a * a)
{
foreground = c_shadowVal;
break;
}
}
tWeight += _weight[mode_idx];
if (tWeight > c_TB)
break;
}
}
#endif
__global uchar* _fgmask = fgmask + mad24(y, fgmask_step, x + fgmask_offset);
*_fgmask = (uchar)foreground;
}
}
__kernel void getBackgroundImage2_kernel(__global const uchar* modesUsed,
__global const uchar* weight,
__global const uchar* mean,
__global uchar* dst, int dst_step, int dst_offset, int dst_row, int dst_col,
float c_TB)
{
int x = get_global_id(0);
int y = get_global_id(1);
if(x < dst_col && y < dst_row)
{
int pt_idx = mad24(y, dst_col, x);
__global const uchar* _modesUsed = modesUsed + pt_idx;
uchar nmodes = _modesUsed[0];
T_MEAN meanVal = (T_MEAN)F_ZERO;
float totalWeight = 0.0f;
__global const float* _weight = (__global const float*)weight;
__global const T_MEAN* _mean = (__global const T_MEAN*)(mean);
int idx_step = dst_row * dst_col;
for (uchar mode = 0; mode < nmodes; ++mode)
{
int mode_idx = mad24(mode, idx_step, pt_idx);
float c_weight = _weight[mode_idx];
T_MEAN c_mean = _mean[mode_idx];
meanVal = mad(c_weight, c_mean, meanVal);
totalWeight += c_weight;
if (totalWeight > c_TB)
break;
}
if (0.f < totalWeight)
meanVal = meanVal / totalWeight;
else
meanVal = (T_MEAN)(0.f);
#if FL==0
__global uchar* _dst = dst + mad24(y, dst_step, mad24(x, CN, dst_offset));
meanToFrame(meanVal, _dst);
#else
__global float* _dst = ((__global float*)( dst + mad24(y, dst_step, dst_offset)) + mad24(x, CN, 0));
meanToFrame(meanVal, _dst);
#endif
}
}

View File

@@ -0,0 +1,540 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//#define CV_USE_SUBGROUPS
#define EPS 0.001f
#define INF 1E+10F
//#define DIS_BORDER_SIZE xxx
//#define DIS_PATCH_SIZE xxx
//#define DIS_PATCH_STRIDE xxx
#define DIS_PATCH_SIZE_HALF (DIS_PATCH_SIZE / 2)
#ifndef DIS_BORDER_SIZE
__kernel void dis_precomputeStructureTensor_hor(__global const short *I0x,
__global const short *I0y,
int w, int h, int ws,
__global float *I0xx_aux_ptr,
__global float *I0yy_aux_ptr,
__global float *I0xy_aux_ptr,
__global float *I0x_aux_ptr,
__global float *I0y_aux_ptr)
{
int i = get_global_id(0);
if (i >= h) return;
const __global short *x_row = I0x + i * w;
const __global short *y_row = I0y + i * w;
float sum_xx = 0.0f, sum_yy = 0.0f, sum_xy = 0.0f, sum_x = 0.0f, sum_y = 0.0f;
float8 x_vec = convert_float8(vload8(0, x_row));
float8 y_vec = convert_float8(vload8(0, y_row));
sum_xx = dot(x_vec.lo, x_vec.lo) + dot(x_vec.hi, x_vec.hi);
sum_yy = dot(y_vec.lo, y_vec.lo) + dot(y_vec.hi, y_vec.hi);
sum_xy = dot(x_vec.lo, y_vec.lo) + dot(x_vec.hi, y_vec.hi);
sum_x = dot(x_vec.lo, 1.0f) + dot(x_vec.hi, 1.0f);
sum_y = dot(y_vec.lo, 1.0f) + dot(y_vec.hi, 1.0f);
I0xx_aux_ptr[i * ws] = sum_xx;
I0yy_aux_ptr[i * ws] = sum_yy;
I0xy_aux_ptr[i * ws] = sum_xy;
I0x_aux_ptr[i * ws] = sum_x;
I0y_aux_ptr[i * ws] = sum_y;
int js = 1;
for (int j = DIS_PATCH_SIZE; j < w; j++)
{
short x_val1 = x_row[j];
short x_val2 = x_row[j - DIS_PATCH_SIZE];
short y_val1 = y_row[j];
short y_val2 = y_row[j - DIS_PATCH_SIZE];
sum_xx += (x_val1 * x_val1 - x_val2 * x_val2);
sum_yy += (y_val1 * y_val1 - y_val2 * y_val2);
sum_xy += (x_val1 * y_val1 - x_val2 * y_val2);
sum_x += (x_val1 - x_val2);
sum_y += (y_val1 - y_val2);
if ((j - DIS_PATCH_SIZE + 1) % DIS_PATCH_STRIDE == 0)
{
int index = i * ws + js;
I0xx_aux_ptr[index] = sum_xx;
I0yy_aux_ptr[index] = sum_yy;
I0xy_aux_ptr[index] = sum_xy;
I0x_aux_ptr[index] = sum_x;
I0y_aux_ptr[index] = sum_y;
js++;
}
}
}
__kernel void dis_precomputeStructureTensor_ver(__global const float *I0xx_aux_ptr,
__global const float *I0yy_aux_ptr,
__global const float *I0xy_aux_ptr,
__global const float *I0x_aux_ptr,
__global const float *I0y_aux_ptr,
int w, int h, int ws,
__global float *I0xx_ptr,
__global float *I0yy_ptr,
__global float *I0xy_ptr,
__global float *I0x_ptr,
__global float *I0y_ptr)
{
int j = get_global_id(0);
if (j >= ws) return;
float sum_xx, sum_yy, sum_xy, sum_x, sum_y;
sum_xx = sum_yy = sum_xy = sum_x = sum_y = 0.0f;
for (int i = 0; i < DIS_PATCH_SIZE; i++)
{
sum_xx += I0xx_aux_ptr[i * ws + j];
sum_yy += I0yy_aux_ptr[i * ws + j];
sum_xy += I0xy_aux_ptr[i * ws + j];
sum_x += I0x_aux_ptr[i * ws + j];
sum_y += I0y_aux_ptr[i * ws + j];
}
I0xx_ptr[j] = sum_xx;
I0yy_ptr[j] = sum_yy;
I0xy_ptr[j] = sum_xy;
I0x_ptr[j] = sum_x;
I0y_ptr[j] = sum_y;
int is = 1;
for (int i = DIS_PATCH_SIZE; i < h; i++)
{
sum_xx += (I0xx_aux_ptr[i * ws + j] - I0xx_aux_ptr[(i - DIS_PATCH_SIZE) * ws + j]);
sum_yy += (I0yy_aux_ptr[i * ws + j] - I0yy_aux_ptr[(i - DIS_PATCH_SIZE) * ws + j]);
sum_xy += (I0xy_aux_ptr[i * ws + j] - I0xy_aux_ptr[(i - DIS_PATCH_SIZE) * ws + j]);
sum_x += (I0x_aux_ptr[i * ws + j] - I0x_aux_ptr[(i - DIS_PATCH_SIZE) * ws + j]);
sum_y += (I0y_aux_ptr[i * ws + j] - I0y_aux_ptr[(i - DIS_PATCH_SIZE) * ws + j]);
if ((i - DIS_PATCH_SIZE + 1) % DIS_PATCH_STRIDE == 0)
{
I0xx_ptr[is * ws + j] = sum_xx;
I0yy_ptr[is * ws + j] = sum_yy;
I0xy_ptr[is * ws + j] = sum_xy;
I0x_ptr[is * ws + j] = sum_x;
I0y_ptr[is * ws + j] = sum_y;
is++;
}
}
}
__kernel void dis_densification(__global const float2 *S_ptr,
__global const uchar *i0, __global const uchar *i1,
int w, int h, int ws,
__global float2 *U_ptr)
{
int x = get_global_id(0);
int y = get_global_id(1);
int i, j;
if (x >= w || y >= h) return;
int start_is, end_is;
int start_js, end_js;
end_is = min(y / DIS_PATCH_STRIDE, (h - DIS_PATCH_SIZE) / DIS_PATCH_STRIDE);
start_is = max(0, y - DIS_PATCH_SIZE + DIS_PATCH_STRIDE) / DIS_PATCH_STRIDE;
start_is = min(start_is, end_is);
end_js = min(x / DIS_PATCH_STRIDE, (w - DIS_PATCH_SIZE) / DIS_PATCH_STRIDE);
start_js = max(0, x - DIS_PATCH_SIZE + DIS_PATCH_STRIDE) / DIS_PATCH_STRIDE;
start_js = min(start_js, end_js);
float sum_coef = 0.0f;
float2 sum_U = (float2)(0.0f, 0.0f);
int i_l, i_u;
int j_l, j_u;
float i_m, j_m, diff;
i = y;
j = x;
/* Iterate through all the patches that overlap the current location (i,j) */
for (int is = start_is; is <= end_is; is++)
for (int js = start_js; js <= end_js; js++)
{
float2 s_val = S_ptr[is * ws + js];
uchar2 i1_vec1, i1_vec2;
j_m = min(max(j + s_val.x, 0.0f), w - 1.0f - EPS);
i_m = min(max(i + s_val.y, 0.0f), h - 1.0f - EPS);
j_l = (int)j_m;
j_u = j_l + 1;
i_l = (int)i_m;
i_u = i_l + 1;
i1_vec1 = vload2(0, i1 + i_u * w + j_l);
i1_vec2 = vload2(0, i1 + i_l * w + j_l);
diff = (j_m - j_l) * (i_m - i_l) * i1_vec1.y +
(j_u - j_m) * (i_m - i_l) * i1_vec1.x +
(j_m - j_l) * (i_u - i_m) * i1_vec2.y +
(j_u - j_m) * (i_u - i_m) * i1_vec2.x - i0[i * w + j];
float coef = 1.0f / max(1.0f, fabs(diff));
sum_U += coef * s_val;
sum_coef += coef;
}
float inv_sum_coef = 1.0 / sum_coef;
U_ptr[i * w + j] = sum_U * inv_sum_coef;
}
#else // DIS_BORDER_SIZE
#define INIT_BILINEAR_WEIGHTS(Ux, Uy) \
i_I1 = clamp(i + Uy + DIS_BORDER_SIZE, i_lower_limit, i_upper_limit); \
j_I1 = clamp(j + Ux + DIS_BORDER_SIZE, j_lower_limit, j_upper_limit); \
{ \
float di = i_I1 - floor(i_I1); \
float dj = j_I1 - floor(j_I1); \
w11 = di * dj; \
w10 = di * (1 - dj); \
w01 = (1 - di) * dj; \
w00 = (1 - di) * (1 - dj); \
}
float computeSSDMeanNorm(const __global uchar *I0_ptr, const __global uchar *I1_ptr,
int I0_stride, int I1_stride,
float w00, float w01, float w10, float w11, int i
#ifndef CV_USE_SUBGROUPS
, __local float2 *smem /*[8]*/
#endif
)
{
float sum_diff = 0.0f, sum_diff_sq = 0.0f;
int n = DIS_PATCH_SIZE * DIS_PATCH_SIZE;
uchar8 I1_vec1, I1_vec2, I0_vec;
uchar I1_val1, I1_val2;
I0_vec = vload8(0, I0_ptr + i * I0_stride);
I1_vec1 = vload8(0, I1_ptr + i * I1_stride);
I1_vec2 = vload8(0, I1_ptr + (i + 1) * I1_stride);
I1_val1 = I1_ptr[i * I1_stride + 8];
I1_val2 = I1_ptr[(i + 1) * I1_stride + 8];
float8 vec = w00 * convert_float8(I1_vec1) + w01 * convert_float8((uchar8)(I1_vec1.s123, I1_vec1.s4567, I1_val1)) +
w10 * convert_float8(I1_vec2) + w11 * convert_float8((uchar8)(I1_vec2.s123, I1_vec2.s4567, I1_val2)) -
convert_float8(I0_vec);
sum_diff = (dot(vec.lo, 1.0) + dot(vec.hi, 1.0));
sum_diff_sq = (dot(vec.lo, vec.lo) + dot(vec.hi, vec.hi));
#ifdef CV_USE_SUBGROUPS
sum_diff = sub_group_reduce_add(sum_diff);
sum_diff_sq = sub_group_reduce_add(sum_diff_sq);
#else
barrier(CLK_LOCAL_MEM_FENCE);
smem[i] = (float2)(sum_diff, sum_diff_sq);
barrier(CLK_LOCAL_MEM_FENCE);
if (i < 4)
smem[i] += smem[i + 4];
barrier(CLK_LOCAL_MEM_FENCE);
if (i < 2)
smem[i] += smem[i + 2];
barrier(CLK_LOCAL_MEM_FENCE);
if (i == 0)
smem[0] += smem[1];
barrier(CLK_LOCAL_MEM_FENCE);
float2 reduce_add_result = smem[0];
sum_diff = reduce_add_result.x;
sum_diff_sq = reduce_add_result.y;
#endif
return sum_diff_sq - sum_diff * sum_diff / n;
}
__attribute__((reqd_work_group_size(8, 1, 1)))
__kernel void dis_patch_inverse_search_fwd_1(__global const float2 *U_ptr,
__global const uchar *I0_ptr, __global const uchar *I1_ptr,
int w, int h, int ws, int hs,
__global float2 *S_ptr)
{
int id = get_global_id(0);
int is = get_group_id(0);
int i = is * DIS_PATCH_STRIDE;
int j = 0;
int w_ext = w + 2 * DIS_BORDER_SIZE;
float i_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
float i_upper_limit = DIS_BORDER_SIZE + h - 1.0f;
float j_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
float j_upper_limit = DIS_BORDER_SIZE + w - 1.0f;
float2 prev_U = U_ptr[(i + DIS_PATCH_SIZE_HALF) * w + j + DIS_PATCH_SIZE_HALF];
S_ptr[is * ws] = prev_U;
j += DIS_PATCH_STRIDE;
#ifdef CV_USE_SUBGROUPS
int sid = get_sub_group_local_id();
#define EXTRA_ARGS_computeSSDMeanNorm sid
#else
__local float2 smem[8];
int sid = get_local_id(0);
#define EXTRA_ARGS_computeSSDMeanNorm sid, smem
#endif
for (int js = 1; js < ws; js++, j += DIS_PATCH_STRIDE)
{
float2 U = U_ptr[(i + DIS_PATCH_SIZE_HALF) * w + j + DIS_PATCH_SIZE_HALF];
float i_I1, j_I1, w00, w01, w10, w11;
INIT_BILINEAR_WEIGHTS(U.x, U.y);
float min_SSD = computeSSDMeanNorm(
I0_ptr + i * w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1,
w, w_ext, w00, w01, w10, w11, EXTRA_ARGS_computeSSDMeanNorm);
INIT_BILINEAR_WEIGHTS(prev_U.x, prev_U.y);
float cur_SSD = computeSSDMeanNorm(
I0_ptr + i * w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1,
w, w_ext, w00, w01, w10, w11, EXTRA_ARGS_computeSSDMeanNorm);
prev_U = (cur_SSD < min_SSD) ? prev_U : U;
S_ptr[is * ws + js] = prev_U;
}
#undef EXTRA_ARGS_computeSSDMeanNorm
}
#endif // DIS_BORDER_SIZE
float4 processPatchMeanNorm(const __global uchar *I0_ptr, const __global uchar *I1_ptr,
const __global short *I0x_ptr, const __global short *I0y_ptr,
int I0_stride, int I1_stride, float w00, float w01, float w10,
float w11, float x_grad_sum, float y_grad_sum)
{
const float inv_n = 1.0f / (float)(DIS_PATCH_SIZE * DIS_PATCH_SIZE);
float sum_diff = 0.0, sum_diff_sq = 0.0;
float sum_I0x_mul = 0.0, sum_I0y_mul = 0.0;
uchar8 I1_vec1;
uchar8 I1_vec2 = vload8(0, I1_ptr);
uchar I1_val1;
uchar I1_val2 = I1_ptr[DIS_PATCH_SIZE];
for (int i = 0; i < 8; i++)
{
uchar8 I0_vec = vload8(0, I0_ptr + i * I0_stride);
I1_vec1 = I1_vec2;
I1_vec2 = vload8(0, I1_ptr + (i + 1) * I1_stride);
I1_val1 = I1_val2;
I1_val2 = I1_ptr[(i + 1) * I1_stride + DIS_PATCH_SIZE];
float8 vec = w00 * convert_float8(I1_vec1) + w01 * convert_float8((uchar8)(I1_vec1.s123, I1_vec1.s4567, I1_val1)) +
w10 * convert_float8(I1_vec2) + w11 * convert_float8((uchar8)(I1_vec2.s123, I1_vec2.s4567, I1_val2)) -
convert_float8(I0_vec);
sum_diff += (dot(vec.lo, 1.0) + dot(vec.hi, 1.0));
sum_diff_sq += (dot(vec.lo, vec.lo) + dot(vec.hi, vec.hi));
short8 I0x_vec = vload8(0, I0x_ptr + i * I0_stride);
short8 I0y_vec = vload8(0, I0y_ptr + i * I0_stride);
sum_I0x_mul += dot(vec.lo, convert_float4(I0x_vec.lo));
sum_I0x_mul += dot(vec.hi, convert_float4(I0x_vec.hi));
sum_I0y_mul += dot(vec.lo, convert_float4(I0y_vec.lo));
sum_I0y_mul += dot(vec.hi, convert_float4(I0y_vec.hi));
}
float dst_dUx = sum_I0x_mul - sum_diff * x_grad_sum * inv_n;
float dst_dUy = sum_I0y_mul - sum_diff * y_grad_sum * inv_n;
float SSD = sum_diff_sq - sum_diff * sum_diff * inv_n;
return (float4)(SSD, dst_dUx, dst_dUy, 0);
}
#ifdef DIS_BORDER_SIZE
__kernel void dis_patch_inverse_search_fwd_2(__global const float2 *U_ptr,
__global const uchar *I0_ptr, __global const uchar *I1_ptr,
__global const short *I0x_ptr, __global const short *I0y_ptr,
__global const float *xx_ptr, __global const float *yy_ptr,
__global const float *xy_ptr,
__global const float *x_ptr, __global const float *y_ptr,
int w, int h, int ws, int hs, int num_inner_iter,
__global float2 *S_ptr)
{
int js = get_global_id(0);
int is = get_global_id(1);
int i = is * DIS_PATCH_STRIDE;
int j = js * DIS_PATCH_STRIDE;
const int psz = DIS_PATCH_SIZE;
int w_ext = w + 2 * DIS_BORDER_SIZE;
int index = is * ws + js;
if (js >= ws || is >= hs) return;
float2 U0 = S_ptr[index];
float2 cur_U = U0;
float cur_xx = xx_ptr[index];
float cur_yy = yy_ptr[index];
float cur_xy = xy_ptr[index];
float detH = cur_xx * cur_yy - cur_xy * cur_xy;
float inv_detH = (fabs(detH) < EPS) ? 1.0 / EPS : 1.0 / detH;
float invH11 = cur_yy * inv_detH;
float invH12 = -cur_xy * inv_detH;
float invH22 = cur_xx * inv_detH;
float prev_SSD = INF;
float x_grad_sum = x_ptr[index];
float y_grad_sum = y_ptr[index];
const float i_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
const float i_upper_limit = DIS_BORDER_SIZE + h - 1.0f;
const float j_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
const float j_upper_limit = DIS_BORDER_SIZE + w - 1.0f;
for (int t = 0; t < num_inner_iter; t++)
{
float i_I1, j_I1, w00, w01, w10, w11;
INIT_BILINEAR_WEIGHTS(cur_U.x, cur_U.y);
float4 res = processPatchMeanNorm(
I0_ptr + i * w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1,
I0x_ptr + i * w + j, I0y_ptr + i * w + j,
w, w_ext, w00, w01, w10, w11,
x_grad_sum, y_grad_sum);
float SSD = res.x;
float dUx = res.y;
float dUy = res.z;
float dx = invH11 * dUx + invH12 * dUy;
float dy = invH12 * dUx + invH22 * dUy;
cur_U -= (float2)(dx, dy);
if (SSD >= prev_SSD)
break;
prev_SSD = SSD;
}
float2 vec = cur_U - U0;
S_ptr[index] = (dot(vec, vec) <= (float)(DIS_PATCH_SIZE * DIS_PATCH_SIZE)) ? cur_U : U0;
}
__attribute__((reqd_work_group_size(8, 1, 1)))
__kernel void dis_patch_inverse_search_bwd_1(__global const uchar *I0_ptr, __global const uchar *I1_ptr,
int w, int h, int ws, int hs,
__global float2 *S_ptr)
{
int id = get_global_id(0);
int is = get_group_id(0);
is = (hs - 1 - is);
int i = is * DIS_PATCH_STRIDE;
int j = (ws - 2) * DIS_PATCH_STRIDE;
const int w_ext = w + 2 * DIS_BORDER_SIZE;
const float i_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
const float i_upper_limit = DIS_BORDER_SIZE + h - 1.0f;
const float j_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
const float j_upper_limit = DIS_BORDER_SIZE + w - 1.0f;
#ifdef CV_USE_SUBGROUPS
int sid = get_sub_group_local_id();
#define EXTRA_ARGS_computeSSDMeanNorm sid
#else
__local float2 smem[8];
int sid = get_local_id(0);
#define EXTRA_ARGS_computeSSDMeanNorm sid, smem
#endif
for (int js = (ws - 2); js > -1; js--, j -= DIS_PATCH_STRIDE)
{
float2 U0 = S_ptr[is * ws + js];
float2 U1 = S_ptr[is * ws + js + 1];
float i_I1, j_I1, w00, w01, w10, w11;
INIT_BILINEAR_WEIGHTS(U0.x, U0.y);
float min_SSD = computeSSDMeanNorm(
I0_ptr + i * w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1,
w, w_ext, w00, w01, w10, w11, EXTRA_ARGS_computeSSDMeanNorm);
INIT_BILINEAR_WEIGHTS(U1.x, U1.y);
float cur_SSD = computeSSDMeanNorm(
I0_ptr + i * w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1,
w, w_ext, w00, w01, w10, w11, EXTRA_ARGS_computeSSDMeanNorm);
S_ptr[is * ws + js] = (cur_SSD < min_SSD) ? U1 : U0;
}
#undef EXTRA_ARGS_computeSSDMeanNorm
}
__kernel void dis_patch_inverse_search_bwd_2(__global const uchar *I0_ptr, __global const uchar *I1_ptr,
__global const short *I0x_ptr, __global const short *I0y_ptr,
__global const float *xx_ptr, __global const float *yy_ptr,
__global const float *xy_ptr,
__global const float *x_ptr, __global const float *y_ptr,
int w, int h, int ws, int hs, int num_inner_iter,
__global float2 *S_ptr)
{
int js = get_global_id(0);
int is = get_global_id(1);
if (js >= ws || is >= hs) return;
js = (ws - 1 - js);
is = (hs - 1 - is);
int j = js * DIS_PATCH_STRIDE;
int i = is * DIS_PATCH_STRIDE;
int w_ext = w + 2 * DIS_BORDER_SIZE;
int index = is * ws + js;
float2 U0 = S_ptr[index];
float2 cur_U = U0;
float cur_xx = xx_ptr[index];
float cur_yy = yy_ptr[index];
float cur_xy = xy_ptr[index];
float detH = cur_xx * cur_yy - cur_xy * cur_xy;
float inv_detH = (fabs(detH) < EPS) ? 1.0 / EPS : 1.0 / detH;
float invH11 = cur_yy * inv_detH;
float invH12 = -cur_xy * inv_detH;
float invH22 = cur_xx * inv_detH;
float prev_SSD = INF;
float x_grad_sum = x_ptr[index];
float y_grad_sum = y_ptr[index];
const float i_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
const float i_upper_limit = DIS_BORDER_SIZE + h - 1.0f;
const float j_lower_limit = DIS_BORDER_SIZE - DIS_PATCH_SIZE + 1.0f;
const float j_upper_limit = DIS_BORDER_SIZE + w - 1.0f;
for (int t = 0; t < num_inner_iter; t++)
{
float i_I1, j_I1, w00, w01, w10, w11;
INIT_BILINEAR_WEIGHTS(cur_U.x, cur_U.y);
float4 res = processPatchMeanNorm(
I0_ptr + i * w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1,
I0x_ptr + i * w + j, I0y_ptr + i * w + j,
w, w_ext, w00, w01, w10, w11,
x_grad_sum, y_grad_sum);
float SSD = res.x;
float dUx = res.y;
float dUy = res.z;
float dx = invH11 * dUx + invH12 * dUy;
float dy = invH12 * dUx + invH22 * dUy;
cur_U -= (float2)(dx, dy);
if (SSD >= prev_SSD)
break;
prev_SSD = SSD;
}
float2 vec = cur_U - U0;
S_ptr[index] = ((dot(vec, vec)) <= (float)(DIS_PATCH_SIZE * DIS_PATCH_SIZE)) ? cur_U : U0;
}
#endif // DIS_BORDER_SIZE

View File

@@ -0,0 +1,429 @@
/*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) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Sen Liu, swjtuls1987@126.com
//
// 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*/
#define tx (int)get_local_id(0)
#define ty get_local_id(1)
#define bx get_group_id(0)
#define bdx (int)get_local_size(0)
#define BORDER_SIZE 5
#define MAX_KSIZE_HALF 100
#ifndef polyN
#define polyN 5
#endif
#if USE_DOUBLE
#ifdef cl_amd_fp64
#pragma OPENCL EXTENSION cl_amd_fp64:enable
#elif defined (cl_khr_fp64)
#pragma OPENCL EXTENSION cl_khr_fp64:enable
#endif
#define TYPE double
#define VECTYPE double4
#else
#define TYPE float
#define VECTYPE float4
#endif
__kernel void polynomialExpansion(__global __const float * src, int srcStep,
__global float * dst, int dstStep,
const int rows, const int cols,
__global __const float * c_g,
__global __const float * c_xg,
__global __const float * c_xxg,
__local float * smem,
const VECTYPE ig)
{
const int y = get_global_id(1);
const int x = bx * (bdx - 2*polyN) + tx - polyN;
int xWarped;
__local float *row = smem + tx;
if (y < rows && y >= 0)
{
xWarped = min(max(x, 0), cols - 1);
row[0] = src[mad24(y, srcStep, xWarped)] * c_g[0];
row[bdx] = 0.f;
row[2*bdx] = 0.f;
#pragma unroll
for (int k = 1; k <= polyN; ++k)
{
float t0 = src[mad24(max(y - k, 0), srcStep, xWarped)];
float t1 = src[mad24(min(y + k, rows - 1), srcStep, xWarped)];
row[0] += c_g[k] * (t0 + t1);
row[bdx] += c_xg[k] * (t1 - t0);
row[2*bdx] += c_xxg[k] * (t0 + t1);
}
}
barrier(CLK_LOCAL_MEM_FENCE);
if (y < rows && y >= 0 && tx >= polyN && tx + polyN < bdx && x < cols)
{
TYPE b1 = c_g[0] * row[0];
TYPE b3 = c_g[0] * row[bdx];
TYPE b5 = c_g[0] * row[2*bdx];
TYPE b2 = 0, b4 = 0, b6 = 0;
#pragma unroll
for (int k = 1; k <= polyN; ++k)
{
b1 += (row[k] + row[-k]) * c_g[k];
b4 += (row[k] + row[-k]) * c_xxg[k];
b2 += (row[k] - row[-k]) * c_xg[k];
b3 += (row[k + bdx] + row[-k + bdx]) * c_g[k];
b6 += (row[k + bdx] - row[-k + bdx]) * c_xg[k];
b5 += (row[k + 2*bdx] + row[-k + 2*bdx]) * c_g[k];
}
dst[mad24(y, dstStep, xWarped)] = (float)(b3*ig.s0);
dst[mad24(rows + y, dstStep, xWarped)] = (float)(b2*ig.s0);
dst[mad24(2*rows + y, dstStep, xWarped)] = (float)(b1*ig.s1 + b5*ig.s2);
dst[mad24(3*rows + y, dstStep, xWarped)] = (float)(b1*ig.s1 + b4*ig.s2);
dst[mad24(4*rows + y, dstStep, xWarped)] = (float)(b6*ig.s3);
}
}
inline int idx_row_low(const int y, const int last_row)
{
return abs(y) % (last_row + 1);
}
inline int idx_row_high(const int y, const int last_row)
{
return abs(last_row - abs(last_row - y)) % (last_row + 1);
}
inline int idx_col_low(const int x, const int last_col)
{
return abs(x) % (last_col + 1);
}
inline int idx_col_high(const int x, const int last_col)
{
return abs(last_col - abs(last_col - x)) % (last_col + 1);
}
inline int idx_col(const int x, const int last_col)
{
return idx_col_low(idx_col_high(x, last_col), last_col);
}
__kernel void gaussianBlur(__global const float * src, int srcStep,
__global float * dst, int dstStep, const int rows, const int cols,
__global const float * c_gKer, const int ksizeHalf,
__local float * smem)
{
const int y = get_global_id(1);
const int x = get_global_id(0);
__local float *row = smem + ty * (bdx + 2*ksizeHalf);
if (y < rows)
{
// Vertical pass
for (int i = tx; i < bdx + 2*ksizeHalf; i += bdx)
{
int xExt = (int)(bx * bdx) + i - ksizeHalf;
xExt = idx_col(xExt, cols - 1);
row[i] = src[mad24(y, srcStep, xExt)] * c_gKer[0];
for (int j = 1; j <= ksizeHalf; ++j)
row[i] += (src[mad24(idx_row_low(y - j, rows - 1), srcStep, xExt)]
+ src[mad24(idx_row_high(y + j, rows - 1), srcStep, xExt)]) * c_gKer[j];
}
}
barrier(CLK_LOCAL_MEM_FENCE);
if (y < rows && y >= 0 && x < cols && x >= 0)
{
// Horizontal pass
row += tx + ksizeHalf;
float res = row[0] * c_gKer[0];
for (int i = 1; i <= ksizeHalf; ++i)
res += (row[-i] + row[i]) * c_gKer[i];
dst[mad24(y, dstStep, x)] = res;
}
}
__kernel void gaussianBlur5(__global const float * src, int srcStep,
__global float * dst, int dstStep,
const int rows, const int cols,
__global const float * c_gKer, const int ksizeHalf,
__local float * smem)
{
const int y = get_global_id(1);
const int x = get_global_id(0);
const int smw = bdx + 2*ksizeHalf; // shared memory "cols"
__local volatile float *row = smem + 5 * ty * smw;
if (y < rows)
{
// Vertical pass
for (int i = tx; i < bdx + 2*ksizeHalf; i += bdx)
{
int xExt = (int)(bx * bdx) + i - ksizeHalf;
xExt = idx_col(xExt, cols - 1);
#pragma unroll
for (int k = 0; k < 5; ++k)
row[k*smw + i] = src[mad24(k*rows + y, srcStep, xExt)] * c_gKer[0];
for (int j = 1; j <= ksizeHalf; ++j)
#pragma unroll
for (int k = 0; k < 5; ++k)
row[k*smw + i] +=
(src[mad24(k*rows + idx_row_low(y - j, rows - 1), srcStep, xExt)] +
src[mad24(k*rows + idx_row_high(y + j, rows - 1), srcStep, xExt)]) * c_gKer[j];
}
}
barrier(CLK_LOCAL_MEM_FENCE);
if (y < rows && y >= 0 && x < cols && x >= 0)
{
// Horizontal pass
row += tx + ksizeHalf;
float res[5];
#pragma unroll
for (int k = 0; k < 5; ++k)
res[k] = row[k*smw] * c_gKer[0];
for (int i = 1; i <= ksizeHalf; ++i)
#pragma unroll
for (int k = 0; k < 5; ++k)
res[k] += (row[k*smw - i] + row[k*smw + i]) * c_gKer[i];
#pragma unroll
for (int k = 0; k < 5; ++k)
dst[mad24(k*rows + y, dstStep, x)] = res[k];
}
}
__constant float c_border[BORDER_SIZE + 1] = { 0.14f, 0.14f, 0.4472f, 0.4472f, 0.4472f, 1.f };
__kernel void updateMatrices(__global const float * flowx, int xStep,
__global const float * flowy, int yStep,
const int rows, const int cols,
__global const float * R0, int R0Step,
__global const float * R1, int R1Step,
__global float * M, int mStep)
{
const int y = get_global_id(1);
const int x = get_global_id(0);
if (y < rows && y >= 0 && x < cols && x >= 0)
{
float dx = flowx[mad24(y, xStep, x)];
float dy = flowy[mad24(y, yStep, x)];
float fx = x + dx;
float fy = y + dy;
int x1 = convert_int(floor(fx));
int y1 = convert_int(floor(fy));
fx -= x1;
fy -= y1;
float r2, r3, r4, r5, r6;
if (x1 >= 0 && y1 >= 0 && x1 < cols - 1 && y1 < rows - 1)
{
float a00 = (1.f - fx) * (1.f - fy);
float a01 = fx * (1.f - fy);
float a10 = (1.f - fx) * fy;
float a11 = fx * fy;
r2 = a00 * R1[mad24(y1, R1Step, x1)] +
a01 * R1[mad24(y1, R1Step, x1 + 1)] +
a10 * R1[mad24(y1 + 1, R1Step, x1)] +
a11 * R1[mad24(y1 + 1, R1Step, x1 + 1)];
r3 = a00 * R1[mad24(rows + y1, R1Step, x1)] +
a01 * R1[mad24(rows + y1, R1Step, x1 + 1)] +
a10 * R1[mad24(rows + y1 + 1, R1Step, x1)] +
a11 * R1[mad24(rows + y1 + 1, R1Step, x1 + 1)];
r4 = a00 * R1[mad24(2*rows + y1, R1Step, x1)] +
a01 * R1[mad24(2*rows + y1, R1Step, x1 + 1)] +
a10 * R1[mad24(2*rows + y1 + 1, R1Step, x1)] +
a11 * R1[mad24(2*rows + y1 + 1, R1Step, x1 + 1)];
r5 = a00 * R1[mad24(3*rows + y1, R1Step, x1)] +
a01 * R1[mad24(3*rows + y1, R1Step, x1 + 1)] +
a10 * R1[mad24(3*rows + y1 + 1, R1Step, x1)] +
a11 * R1[mad24(3*rows + y1 + 1, R1Step, x1 + 1)];
r6 = a00 * R1[mad24(4*rows + y1, R1Step, x1)] +
a01 * R1[mad24(4*rows + y1, R1Step, x1 + 1)] +
a10 * R1[mad24(4*rows + y1 + 1, R1Step, x1)] +
a11 * R1[mad24(4*rows + y1 + 1, R1Step, x1 + 1)];
r4 = (R0[mad24(2*rows + y, R0Step, x)] + r4) * 0.5f;
r5 = (R0[mad24(3*rows + y, R0Step, x)] + r5) * 0.5f;
r6 = (R0[mad24(4*rows + y, R0Step, x)] + r6) * 0.25f;
}
else
{
r2 = r3 = 0.f;
r4 = R0[mad24(2*rows + y, R0Step, x)];
r5 = R0[mad24(3*rows + y, R0Step, x)];
r6 = R0[mad24(4*rows + y, R0Step, x)] * 0.5f;
}
r2 = (R0[mad24(y, R0Step, x)] - r2) * 0.5f;
r3 = (R0[mad24(rows + y, R0Step, x)] - r3) * 0.5f;
r2 += r4*dy + r6*dx;
r3 += r6*dy + r5*dx;
float scale =
c_border[min(x, BORDER_SIZE)] *
c_border[min(y, BORDER_SIZE)] *
c_border[min(cols - x - 1, BORDER_SIZE)] *
c_border[min(rows - y - 1, BORDER_SIZE)];
r2 *= scale;
r3 *= scale;
r4 *= scale;
r5 *= scale;
r6 *= scale;
M[mad24(y, mStep, x)] = r4*r4 + r6*r6;
M[mad24(rows + y, mStep, x)] = (r4 + r5)*r6;
M[mad24(2*rows + y, mStep, x)] = r5*r5 + r6*r6;
M[mad24(3*rows + y, mStep, x)] = r4*r2 + r6*r3;
M[mad24(4*rows + y, mStep, x)] = r6*r2 + r5*r3;
}
}
__kernel void boxFilter5(__global const float * src, int srcStep,
__global float * dst, int dstStep,
const int rows, const int cols,
const int ksizeHalf,
__local float * smem)
{
const int y = get_global_id(1);
const int x = get_global_id(0);
const float boxAreaInv = 1.f / ((1 + 2*ksizeHalf) * (1 + 2*ksizeHalf));
const int smw = bdx + 2*ksizeHalf; // shared memory "width"
__local float *row = smem + 5 * ty * smw;
if (y < rows)
{
// Vertical pass
for (int i = tx; i < bdx + 2*ksizeHalf; i += bdx)
{
int xExt = (int)(bx * bdx) + i - ksizeHalf;
xExt = min(max(xExt, 0), cols - 1);
#pragma unroll
for (int k = 0; k < 5; ++k)
row[k*smw + i] = src[mad24(k*rows + y, srcStep, xExt)];
for (int j = 1; j <= ksizeHalf; ++j)
#pragma unroll
for (int k = 0; k < 5; ++k)
row[k*smw + i] +=
src[mad24(k*rows + max(y - j, 0), srcStep, xExt)] +
src[mad24(k*rows + min(y + j, rows - 1), srcStep, xExt)];
}
}
barrier(CLK_LOCAL_MEM_FENCE);
if (y < rows && y >= 0 && x < cols && x >= 0)
{
// Horizontal pass
row += tx + ksizeHalf;
float res[5];
#pragma unroll
for (int k = 0; k < 5; ++k)
res[k] = row[k*smw];
for (int i = 1; i <= ksizeHalf; ++i)
#pragma unroll
for (int k = 0; k < 5; ++k)
res[k] += row[k*smw - i] + row[k*smw + i];
#pragma unroll
for (int k = 0; k < 5; ++k)
dst[mad24(k*rows + y, dstStep, x)] = res[k] * boxAreaInv;
}
}
__kernel void updateFlow(__global const float * M, int mStep,
__global float * flowx, int xStep,
__global float * flowy, int yStep,
const int rows, const int cols)
{
const int y = get_global_id(1);
const int x = get_global_id(0);
if (y < rows && y >= 0 && x < cols && x >= 0)
{
float g11 = M[mad24(y, mStep, x)];
float g12 = M[mad24(rows + y, mStep, x)];
float g22 = M[mad24(2*rows + y, mStep, x)];
float h1 = M[mad24(3*rows + y, mStep, x)];
float h2 = M[mad24(4*rows + y, mStep, x)];
float detInv = 1.f / (g11*g22 - g12*g12 + 1e-3f);
flowx[mad24(y, xStep, x)] = (g11*h2 - g12*h1) * detInv;
flowy[mad24(y, yStep, x)] = (g22*h1 - g12*h2) * detInv;
}
}

View File

@@ -0,0 +1,558 @@
/*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) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Dachuan Zhao, dachuan@multicorewareinc.com
// Yao Wang, bitwangyaoyao@gmail.com
// Xiaopeng Fu, fuxiaopeng2222@163.com
//
// 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*/
#define GRIDSIZE 3
#define LSx 8
#define LSy 8
// define local memory sizes
#define LM_W (LSx*GRIDSIZE+2)
#define LM_H (LSy*GRIDSIZE+2)
#define BUFFER (LSx*LSy)
#define BUFFER2 BUFFER>>1
#ifdef CPU
inline void reduce3(float val1, float val2, float val3, __local float* smem1, __local float* smem2, __local float* smem3, int tid)
{
smem1[tid] = val1;
smem2[tid] = val2;
smem3[tid] = val3;
barrier(CLK_LOCAL_MEM_FENCE);
for(int i = BUFFER2; i > 0; i >>= 1)
{
if(tid < i)
{
smem1[tid] += smem1[tid + i];
smem2[tid] += smem2[tid + i];
smem3[tid] += smem3[tid + i];
}
barrier(CLK_LOCAL_MEM_FENCE);
}
}
inline void reduce2(float val1, float val2, __local float* smem1, __local float* smem2, int tid)
{
smem1[tid] = val1;
smem2[tid] = val2;
barrier(CLK_LOCAL_MEM_FENCE);
for(int i = BUFFER2; i > 0; i >>= 1)
{
if(tid < i)
{
smem1[tid] += smem1[tid + i];
smem2[tid] += smem2[tid + i];
}
barrier(CLK_LOCAL_MEM_FENCE);
}
}
inline void reduce1(float val1, __local float* smem1, int tid)
{
smem1[tid] = val1;
barrier(CLK_LOCAL_MEM_FENCE);
for(int i = BUFFER2; i > 0; i >>= 1)
{
if(tid < i)
{
smem1[tid] += smem1[tid + i];
}
barrier(CLK_LOCAL_MEM_FENCE);
}
}
#else
inline void reduce3(float val1, float val2, float val3,
__local float* smem1, __local float* smem2, __local float* smem3, int tid)
{
smem1[tid] = val1;
smem2[tid] = val2;
smem3[tid] = val3;
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 32)
{
smem1[tid] += smem1[tid + 32];
smem2[tid] += smem2[tid + 32];
smem3[tid] += smem3[tid + 32];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 16)
{
smem1[tid] += smem1[tid + 16];
smem2[tid] += smem2[tid + 16];
smem3[tid] += smem3[tid + 16];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 8)
{
smem1[tid] += smem1[tid + 8];
smem2[tid] += smem2[tid + 8];
smem3[tid] += smem3[tid + 8];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 4)
{
smem1[tid] += smem1[tid + 4];
smem2[tid] += smem2[tid + 4];
smem3[tid] += smem3[tid + 4];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid == 0)
{
smem1[0] = (smem1[0] + smem1[1]) + (smem1[2] + smem1[3]);
smem2[0] = (smem2[0] + smem2[1]) + (smem2[2] + smem2[3]);
smem3[0] = (smem3[0] + smem3[1]) + (smem3[2] + smem3[3]);
}
barrier(CLK_LOCAL_MEM_FENCE);
}
inline void reduce2(float val1, float val2, __local float* smem1, __local float* smem2, int tid)
{
smem1[tid] = val1;
smem2[tid] = val2;
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 32)
{
smem1[tid] += smem1[tid + 32];
smem2[tid] += smem2[tid + 32];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 16)
{
smem1[tid] += smem1[tid + 16];
smem2[tid] += smem2[tid + 16];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 8)
{
smem1[tid] += smem1[tid + 8];
smem2[tid] += smem2[tid + 8];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 4)
{
smem1[tid] += smem1[tid + 4];
smem2[tid] += smem2[tid + 4];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid == 0)
{
smem1[0] = (smem1[0] + smem1[1]) + (smem1[2] + smem1[3]);
smem2[0] = (smem2[0] + smem2[1]) + (smem2[2] + smem2[3]);
}
barrier(CLK_LOCAL_MEM_FENCE);
}
inline void reduce1(float val1, __local float* smem1, int tid)
{
smem1[tid] = val1;
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 32)
{
smem1[tid] += smem1[tid + 32];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 16)
{
smem1[tid] += smem1[tid + 16];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 8)
{
smem1[tid] += smem1[tid + 8];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid < 4)
{
smem1[tid] += smem1[tid + 4];
}
barrier(CLK_LOCAL_MEM_FENCE);
if (tid == 0)
{
smem1[0] = (smem1[0] + smem1[1]) + (smem1[2] + smem1[3]);
}
barrier(CLK_LOCAL_MEM_FENCE);
}
#endif
#define SCALE (1.0f / (1 << 20))
#define THRESHOLD 0.01f
// Image read mode
__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR;
// macro to get pixel value from local memory
#define VAL(_y,_x,_yy,_xx) (IPatchLocal[mad24(((_y) + (_yy)), LM_W, ((_x) + (_xx)))])
inline void SetPatch(local float* IPatchLocal, int TileY, int TileX,
float* Pch, float* Dx, float* Dy,
float* A11, float* A12, float* A22, float w)
{
int xid=get_local_id(0);
int yid=get_local_id(1);
int xBase = mad24(TileX, LSx, (xid + 1));
int yBase = mad24(TileY, LSy, (yid + 1));
*Pch = VAL(yBase,xBase,0,0);
*Dx = mad((VAL(yBase,xBase,-1,1) + VAL(yBase,xBase,+1,1) - VAL(yBase,xBase,-1,-1) - VAL(yBase,xBase,+1,-1)), 3.0f, (VAL(yBase,xBase,0,1) - VAL(yBase,xBase,0,-1)) * 10.0f) * w;
*Dy = mad((VAL(yBase,xBase,1,-1) + VAL(yBase,xBase,1,+1) - VAL(yBase,xBase,-1,-1) - VAL(yBase,xBase,-1,+1)), 3.0f, (VAL(yBase,xBase,1,0) - VAL(yBase,xBase,-1,0)) * 10.0f) * w;
*A11 = mad(*Dx, *Dx, *A11);
*A12 = mad(*Dx, *Dy, *A12);
*A22 = mad(*Dy, *Dy, *A22);
}
#undef VAL
inline void GetPatch(image2d_t J, float x, float y,
float* Pch, float* Dx, float* Dy,
float* b1, float* b2)
{
float diff = read_imagef(J, sampler, (float2)(x,y)).x-*Pch;
*b1 = mad(diff, *Dx, *b1);
*b2 = mad(diff, *Dy, *b2);
}
inline void GetError(image2d_t J, const float x, const float y, const float* Pch, float* errval, float w)
{
float diff = ((((read_imagef(J, sampler, (float2)(x,y)).x * 16384) + 256) / 512) - (((*Pch * 16384) + 256) /512)) * w;
*errval += fabs(diff);
}
//macro to read pixel value into local memory.
#define READI(_y,_x) IPatchLocal[mad24(mad24((_y), LSy, yid), LM_W, mad24((_x), LSx, xid))] = read_imagef(I, sampler, (float2)(mad((float)(_x), (float)LSx, Point.x + xid - 0.5f), mad((float)(_y), (float)LSy, Point.y + yid - 0.5f))).x;
void ReadPatchIToLocalMem(image2d_t I, float2 Point, local float* IPatchLocal)
{
int xid=get_local_id(0);
int yid=get_local_id(1);
//read (3*LSx)*(3*LSy) window. each macro call read LSx*LSy pixels block
READI(0,0);READI(0,1);READI(0,2);
READI(1,0);READI(1,1);READI(1,2);
READI(2,0);READI(2,1);READI(2,2);
if(xid<2)
{// read last 2 columns border. each macro call reads 2*LSy pixels block
READI(0,3);
READI(1,3);
READI(2,3);
}
if(yid<2)
{// read last 2 row. each macro call reads LSx*2 pixels block
READI(3,0);READI(3,1);READI(3,2);
}
if(yid<2 && xid<2)
{// read right bottom 2x2 corner. one macro call reads 2*2 pixels block
READI(3,3);
}
barrier(CLK_LOCAL_MEM_FENCE);
}
#undef READI
__attribute__((reqd_work_group_size(LSx, LSy, 1)))
__kernel void lkSparse(image2d_t I, image2d_t J,
__global const float2* prevPts, __global float2* nextPts, __global uchar* status, __global float* err,
const int level, const int rows, const int cols, int PATCH_X, int PATCH_Y, int c_winSize_x, int c_winSize_y, int c_iters, char calcErr)
{
__local float smem1[BUFFER];
__local float smem2[BUFFER];
__local float smem3[BUFFER];
int xid=get_local_id(0);
int yid=get_local_id(1);
int gid=get_group_id(0);
int xsize=get_local_size(0);
int ysize=get_local_size(1);
int k;
#ifdef CPU
float wx0 = 1.0f;
float wy0 = 1.0f;
int xBase = mad24(xsize, 2, xid);
int yBase = mad24(ysize, 2, yid);
float wx1 = (xBase < c_winSize_x) ? 1 : 0;
float wy1 = (yBase < c_winSize_y) ? 1 : 0;
#else
#if WSX == 1
float wx0 = 1.0f;
int xBase = mad24(xsize, 2, xid);
float wx1 = (xBase < c_winSize_x) ? 1 : 0;
#else
int xBase = mad24(xsize, 1, xid);
float wx0 = (xBase < c_winSize_x) ? 1 : 0;
float wx1 = 0.0f;
#endif
#if WSY == 1
float wy0 = 1.0f;
int yBase = mad24(ysize, 2, yid);
float wy1 = (yBase < c_winSize_y) ? 1 : 0;
#else
int yBase = mad24(ysize, 1, yid);
float wy0 = (yBase < c_winSize_y) ? 1 : 0;
float wy1 = 0.0f;
#endif
#endif
float2 c_halfWin = (float2)((c_winSize_x - 1)>>1, (c_winSize_y - 1)>>1);
const int tid = mad24(yid, xsize, xid);
float2 prevPt = prevPts[gid] / (float2)(1 << level);
if (prevPt.x < 0 || prevPt.x >= cols || prevPt.y < 0 || prevPt.y >= rows)
{
if (tid == 0 && level == 0)
{
status[gid] = 0;
}
return;
}
prevPt -= c_halfWin;
// extract the patch from the first image, compute covariation matrix of derivatives
float A11 = 0;
float A12 = 0;
float A22 = 0;
float I_patch[GRIDSIZE][GRIDSIZE];
float dIdx_patch[GRIDSIZE][GRIDSIZE];
float dIdy_patch[GRIDSIZE][GRIDSIZE];
// local memory to read image with border to calc sobels
local float IPatchLocal[LM_W*LM_H];
ReadPatchIToLocalMem(I,prevPt,IPatchLocal);
{
SetPatch(IPatchLocal, 0, 0,
&I_patch[0][0], &dIdx_patch[0][0], &dIdy_patch[0][0],
&A11, &A12, &A22,1);
SetPatch(IPatchLocal, 0, 1,
&I_patch[0][1], &dIdx_patch[0][1], &dIdy_patch[0][1],
&A11, &A12, &A22,wx0);
SetPatch(IPatchLocal, 0, 2,
&I_patch[0][2], &dIdx_patch[0][2], &dIdy_patch[0][2],
&A11, &A12, &A22,wx1);
}
{
SetPatch(IPatchLocal, 1, 0,
&I_patch[1][0], &dIdx_patch[1][0], &dIdy_patch[1][0],
&A11, &A12, &A22,wy0);
SetPatch(IPatchLocal, 1,1,
&I_patch[1][1], &dIdx_patch[1][1], &dIdy_patch[1][1],
&A11, &A12, &A22,wx0*wy0);
SetPatch(IPatchLocal, 1,2,
&I_patch[1][2], &dIdx_patch[1][2], &dIdy_patch[1][2],
&A11, &A12, &A22,wx1*wy0);
}
{
SetPatch(IPatchLocal, 2,0,
&I_patch[2][0], &dIdx_patch[2][0], &dIdy_patch[2][0],
&A11, &A12, &A22,wy1);
SetPatch(IPatchLocal, 2,1,
&I_patch[2][1], &dIdx_patch[2][1], &dIdy_patch[2][1],
&A11, &A12, &A22,wx0*wy1);
SetPatch(IPatchLocal, 2,2,
&I_patch[2][2], &dIdx_patch[2][2], &dIdy_patch[2][2],
&A11, &A12, &A22,wx1*wy1);
}
reduce3(A11, A12, A22, smem1, smem2, smem3, tid);
A11 = smem1[0];
A12 = smem2[0];
A22 = smem3[0];
barrier(CLK_LOCAL_MEM_FENCE);
float D = mad(A11, A22, - A12 * A12);
if (D < 1.192092896e-07f)
{
if (tid == 0 && level == 0)
status[gid] = 0;
return;
}
A11 /= D;
A12 /= D;
A22 /= D;
prevPt = mad(nextPts[gid], 2.0f, - c_halfWin);
float2 offset0 = (float2)(xid + 0.5f, yid + 0.5f);
float2 offset1 = (float2)(xsize, ysize);
float2 loc0 = prevPt + offset0;
float2 loc1 = loc0 + offset1;
float2 loc2 = loc1 + offset1;
for (k = 0; k < c_iters; ++k)
{
if (prevPt.x < -c_halfWin.x || prevPt.x >= cols || prevPt.y < -c_halfWin.y || prevPt.y >= rows)
{
if (tid == 0 && level == 0)
status[gid] = 0;
break;
}
float b1 = 0;
float b2 = 0;
{
GetPatch(J, loc0.x, loc0.y,
&I_patch[0][0], &dIdx_patch[0][0], &dIdy_patch[0][0],
&b1, &b2);
GetPatch(J, loc1.x, loc0.y,
&I_patch[0][1], &dIdx_patch[0][1], &dIdy_patch[0][1],
&b1, &b2);
GetPatch(J, loc2.x, loc0.y,
&I_patch[0][2], &dIdx_patch[0][2], &dIdy_patch[0][2],
&b1, &b2);
}
{
GetPatch(J, loc0.x, loc1.y,
&I_patch[1][0], &dIdx_patch[1][0], &dIdy_patch[1][0],
&b1, &b2);
GetPatch(J, loc1.x, loc1.y,
&I_patch[1][1], &dIdx_patch[1][1], &dIdy_patch[1][1],
&b1, &b2);
GetPatch(J, loc2.x, loc1.y,
&I_patch[1][2], &dIdx_patch[1][2], &dIdy_patch[1][2],
&b1, &b2);
}
{
GetPatch(J, loc0.x, loc2.y,
&I_patch[2][0], &dIdx_patch[2][0], &dIdy_patch[2][0],
&b1, &b2);
GetPatch(J, loc1.x, loc2.y,
&I_patch[2][1], &dIdx_patch[2][1], &dIdy_patch[2][1],
&b1, &b2);
GetPatch(J, loc2.x, loc2.y,
&I_patch[2][2], &dIdx_patch[2][2], &dIdy_patch[2][2],
&b1, &b2);
}
reduce2(b1, b2, smem1, smem2, tid);
b1 = smem1[0];
b2 = smem2[0];
barrier(CLK_LOCAL_MEM_FENCE);
float2 delta;
delta.x = mad(A12, b2, - A22 * b1) * 32.0f;
delta.y = mad(A12, b1, - A11 * b2) * 32.0f;
prevPt += delta;
loc0 += delta;
loc1 += delta;
loc2 += delta;
if (fabs(delta.x) < THRESHOLD && fabs(delta.y) < THRESHOLD)
break;
}
D = 0.0f;
if (calcErr)
{
{
GetError(J, loc0.x, loc0.y, &I_patch[0][0], &D, 1);
GetError(J, loc1.x, loc0.y, &I_patch[0][1], &D, wx0);
}
{
GetError(J, loc0.x, loc1.y, &I_patch[1][0], &D, wy0);
GetError(J, loc1.x, loc1.y, &I_patch[1][1], &D, wx0*wy0);
}
if(xBase < c_winSize_x)
{
GetError(J, loc2.x, loc0.y, &I_patch[0][2], &D, wx1);
GetError(J, loc2.x, loc1.y, &I_patch[1][2], &D, wx1*wy0);
}
if(yBase < c_winSize_y)
{
GetError(J, loc0.x, loc2.y, &I_patch[2][0], &D, wy1);
GetError(J, loc1.x, loc2.y, &I_patch[2][1], &D, wx0*wy1);
if(xBase < c_winSize_x)
GetError(J, loc2.x, loc2.y, &I_patch[2][2], &D, wx1*wy1);
}
reduce1(D, smem1, tid);
}
if (tid == 0)
{
prevPt += c_halfWin;
nextPts[gid] = prevPt;
if (calcErr)
err[gid] = smem1[0] / (float)(32 * c_winSize_x * c_winSize_y);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#include<iostream>
#include<fstream>
namespace cv {
const float FLOW_TAG_FLOAT = 202021.25f;
const char *FLOW_TAG_STRING = "PIEH";
CV_EXPORTS_W Mat readOpticalFlow( const String& path )
{
Mat_<Point2f> flow;
std::ifstream file(path.c_str(), std::ios_base::binary);
if ( !file.good() )
return std::move(flow); // no file - return empty matrix
float tag;
file.read((char*) &tag, sizeof(float));
if ( tag != FLOW_TAG_FLOAT )
return std::move(flow);
int width, height;
file.read((char*) &width, 4);
file.read((char*) &height, 4);
flow.create(height, width);
for ( int i = 0; i < flow.rows; ++i )
{
for ( int j = 0; j < flow.cols; ++j )
{
Point2f u;
file.read((char*) &u.x, sizeof(float));
file.read((char*) &u.y, sizeof(float));
if ( !file.good() )
{
flow.release();
return std::move(flow);
}
flow(i, j) = u;
}
}
file.close();
return std::move(flow);
}
CV_EXPORTS_W bool writeOpticalFlow( const String& path, InputArray flow )
{
const int nChannels = 2;
Mat input = flow.getMat();
if ( input.channels() != nChannels || input.depth() != CV_32F || path.length() == 0 )
return false;
std::ofstream file(path.c_str(), std::ofstream::binary);
if ( !file.good() )
return false;
int nRows, nCols;
nRows = (int) input.size().height;
nCols = (int) input.size().width;
const int headerSize = 12;
char header[headerSize];
memcpy(header, FLOW_TAG_STRING, 4);
// size of ints is known - has been asserted in the current function
memcpy(header + 4, reinterpret_cast<const char*>(&nCols), sizeof(nCols));
memcpy(header + 8, reinterpret_cast<const char*>(&nRows), sizeof(nRows));
file.write(header, headerSize);
if ( !file.good() )
return false;
int row;
char* p;
for ( row = 0; row < nRows; row++ )
{
p = input.ptr<char>(row);
file.write(p, nCols * nChannels * sizeof(float));
if ( !file.good() )
return false;
}
file.close();
return true;
}
}

View File

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

View File

@@ -0,0 +1,25 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerFeature::~TrackerFeature()
{
// nothing
}
void TrackerFeature::compute(const std::vector<Mat>& images, Mat& response)
{
if (images.empty())
return;
computeImpl(images, response);
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,121 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
#include "tracking_feature.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
inline namespace internal {
class TrackerFeatureHAAR : public TrackerFeature
{
public:
struct Params
{
Params();
int numFeatures; //!< # of rects
Size rectSize; //!< rect size
bool isIntegral; //!< true if input images are integral, false otherwise
};
TrackerFeatureHAAR(const TrackerFeatureHAAR::Params& parameters = TrackerFeatureHAAR::Params());
virtual ~TrackerFeatureHAAR() CV_OVERRIDE {}
protected:
bool computeImpl(const std::vector<Mat>& images, Mat& response) CV_OVERRIDE;
private:
Params params;
Ptr<CvHaarEvaluator> featureEvaluator;
};
/**
* Parameters
*/
TrackerFeatureHAAR::Params::Params()
{
numFeatures = 250;
rectSize = Size(100, 100);
isIntegral = false;
}
TrackerFeatureHAAR::TrackerFeatureHAAR(const TrackerFeatureHAAR::Params& parameters)
: params(parameters)
{
CvHaarFeatureParams haarParams;
haarParams.numFeatures = params.numFeatures;
haarParams.isIntegral = params.isIntegral;
featureEvaluator = makePtr<CvHaarEvaluator>();
featureEvaluator->init(&haarParams, 1, params.rectSize);
}
class Parallel_compute : public cv::ParallelLoopBody
{
private:
Ptr<CvHaarEvaluator> featureEvaluator;
std::vector<Mat> images;
Mat response;
//std::vector<CvHaarEvaluator::FeatureHaar> features;
public:
Parallel_compute(Ptr<CvHaarEvaluator>& fe, const std::vector<Mat>& img, Mat& resp)
: featureEvaluator(fe)
, images(img)
, response(resp)
{
//features = featureEvaluator->getFeatures();
}
virtual void operator()(const cv::Range& r) const CV_OVERRIDE
{
for (int jf = r.start; jf != r.end; ++jf)
{
int cols = images[jf].cols;
int rows = images[jf].rows;
for (int j = 0; j < featureEvaluator->getNumFeatures(); j++)
{
float res = 0;
featureEvaluator->getFeatures()[j].eval(images[jf], Rect(0, 0, cols, rows), &res);
(Mat_<float>(response))(j, jf) = res;
}
}
}
};
bool TrackerFeatureHAAR::computeImpl(const std::vector<Mat>& images, Mat& response)
{
if (images.empty())
{
return false;
}
int numFeatures = featureEvaluator->getNumFeatures();
response = Mat_<float>(Size((int)images.size(), numFeatures));
std::vector<CvHaarEvaluator::FeatureHaar> f = featureEvaluator->getFeatures();
//for each sample compute #n_feature -> put each feature (n Rect) in response
parallel_for_(Range(0, (int)images.size()), Parallel_compute(featureEvaluator, images, response));
/*for ( size_t i = 0; i < images.size(); i++ )
{
int c = images[i].cols;
int r = images[i].rows;
for ( int j = 0; j < numFeatures; j++ )
{
float res = 0;
featureEvaluator->getFeatures( j ).eval( images[i], Rect( 0, 0, c, r ), &res );
( Mat_<float>( response ) )( j, i ) = res;
}
}*/
return true;
}
}}}} // namespace cv::detail::tracking::internal

View File

@@ -0,0 +1,60 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerFeatureSet::TrackerFeatureSet()
{
blockAddTrackerFeature = false;
}
TrackerFeatureSet::~TrackerFeatureSet()
{
// nothing
}
void TrackerFeatureSet::extraction(const std::vector<Mat>& images)
{
blockAddTrackerFeature = true;
clearResponses();
responses.resize(features.size());
for (size_t i = 0; i < features.size(); i++)
{
CV_DbgAssert(features[i]);
features[i]->compute(images, responses[i]);
}
}
bool TrackerFeatureSet::addTrackerFeature(const Ptr<TrackerFeature>& feature)
{
CV_Assert(!blockAddTrackerFeature);
CV_Assert(feature);
features.push_back(feature);
return true;
}
const std::vector<Ptr<TrackerFeature>>& TrackerFeatureSet::getTrackerFeatures() const
{
return features;
}
const std::vector<Mat>& TrackerFeatureSet::getResponses() const
{
return responses;
}
void TrackerFeatureSet::clearResponses()
{
responses.clear();
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,85 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "tracker_mil_model.hpp"
/**
* TrackerMILModel
*/
namespace cv {
inline namespace tracking {
namespace impl {
TrackerMILModel::TrackerMILModel(const Rect& boundingBox)
{
currentSample.clear();
mode = MODE_POSITIVE;
width = boundingBox.width;
height = boundingBox.height;
Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState> initState = Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState>(
new TrackerStateEstimatorMILBoosting::TrackerMILTargetState(Point2f((float)boundingBox.x, (float)boundingBox.y), boundingBox.width, boundingBox.height,
true, Mat()));
trajectory.push_back(initState);
}
void TrackerMILModel::responseToConfidenceMap(const std::vector<Mat>& responses, ConfidenceMap& confidenceMap)
{
if (currentSample.empty())
{
CV_Error(-1, "The samples in Model estimation are empty");
}
for (size_t i = 0; i < responses.size(); i++)
{
//for each column (one sample) there are #num_feature
//get informations from currentSample
for (int j = 0; j < responses.at(i).cols; j++)
{
Size currentSize;
Point currentOfs;
currentSample.at(j).locateROI(currentSize, currentOfs);
bool foreground = false;
if (mode == MODE_POSITIVE || mode == MODE_ESTIMATON)
{
foreground = true;
}
else if (mode == MODE_NEGATIVE)
{
foreground = false;
}
//get the column of the HAAR responses
Mat singleResponse = responses.at(i).col(j);
//create the state
Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState> currentState = Ptr<TrackerStateEstimatorMILBoosting::TrackerMILTargetState>(
new TrackerStateEstimatorMILBoosting::TrackerMILTargetState(currentOfs, width, height, foreground, singleResponse));
confidenceMap.push_back(std::make_pair(currentState, 0.0f));
}
}
}
void TrackerMILModel::modelEstimationImpl(const std::vector<Mat>& responses)
{
responseToConfidenceMap(responses, currentConfidenceMap);
}
void TrackerMILModel::modelUpdateImpl()
{
}
void TrackerMILModel::setMode(int trainingMode, const std::vector<Mat>& samples)
{
currentSample.clear();
currentSample = samples;
mode = trainingMode;
}
}}} // namespace cv::tracking::impl

View File

@@ -0,0 +1,67 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef __OPENCV_TRACKER_MIL_MODEL_HPP__
#define __OPENCV_TRACKER_MIL_MODEL_HPP__
#include "opencv2/video/detail/tracking.detail.hpp"
#include "tracker_mil_state.hpp"
namespace cv {
inline namespace tracking {
namespace impl {
using namespace cv::detail::tracking;
/**
* \brief Implementation of TrackerModel for MIL algorithm
*/
class TrackerMILModel : public detail::TrackerModel
{
public:
enum
{
MODE_POSITIVE = 1, // mode for positive features
MODE_NEGATIVE = 2, // mode for negative features
MODE_ESTIMATON = 3 // mode for estimation step
};
/**
* \brief Constructor
* \param boundingBox The first boundingBox
*/
TrackerMILModel(const Rect& boundingBox);
/**
* \brief Destructor
*/
~TrackerMILModel() {};
/**
* \brief Set the mode
*/
void setMode(int trainingMode, const std::vector<Mat>& samples);
/**
* \brief Create the ConfidenceMap from a list of responses
* \param responses The list of the responses
* \param confidenceMap The output
*/
void responseToConfidenceMap(const std::vector<Mat>& responses, ConfidenceMap& confidenceMap);
protected:
void modelEstimationImpl(const std::vector<Mat>& responses) CV_OVERRIDE;
void modelUpdateImpl() CV_OVERRIDE;
private:
int mode;
std::vector<Mat> currentSample;
int width; //initial width of the boundingBox
int height; //initial height of the boundingBox
};
}}} // namespace cv::tracking::impl
#endif

View File

@@ -0,0 +1,159 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
#include "tracker_mil_state.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
/**
* TrackerStateEstimatorMILBoosting::TrackerMILTargetState
*/
TrackerStateEstimatorMILBoosting::TrackerMILTargetState::TrackerMILTargetState(const Point2f& position, int width, int height, bool foreground,
const Mat& features)
{
setTargetPosition(position);
setTargetWidth(width);
setTargetHeight(height);
setTargetFg(foreground);
setFeatures(features);
}
void TrackerStateEstimatorMILBoosting::TrackerMILTargetState::setTargetFg(bool foreground)
{
isTarget = foreground;
}
void TrackerStateEstimatorMILBoosting::TrackerMILTargetState::setFeatures(const Mat& features)
{
targetFeatures = features;
}
bool TrackerStateEstimatorMILBoosting::TrackerMILTargetState::isTargetFg() const
{
return isTarget;
}
Mat TrackerStateEstimatorMILBoosting::TrackerMILTargetState::getFeatures() const
{
return targetFeatures;
}
TrackerStateEstimatorMILBoosting::TrackerStateEstimatorMILBoosting(int nFeatures)
{
className = "BOOSTING";
trained = false;
numFeatures = nFeatures;
}
TrackerStateEstimatorMILBoosting::~TrackerStateEstimatorMILBoosting()
{
}
void TrackerStateEstimatorMILBoosting::setCurrentConfidenceMap(ConfidenceMap& confidenceMap)
{
currentConfidenceMap.clear();
currentConfidenceMap = confidenceMap;
}
uint TrackerStateEstimatorMILBoosting::max_idx(const std::vector<float>& v)
{
const float* findPtr = &(*std::max_element(v.begin(), v.end()));
const float* beginPtr = &(*v.begin());
return (uint)(findPtr - beginPtr);
}
Ptr<TrackerTargetState> TrackerStateEstimatorMILBoosting::estimateImpl(const std::vector<ConfidenceMap>& /*confidenceMaps*/)
{
//run ClfMilBoost classify in order to compute next location
if (currentConfidenceMap.empty())
return Ptr<TrackerTargetState>();
Mat positiveStates;
Mat negativeStates;
prepareData(currentConfidenceMap, positiveStates, negativeStates);
std::vector<float> prob = boostMILModel.classify(positiveStates);
int bestind = max_idx(prob);
//float resp = prob[bestind];
return currentConfidenceMap.at(bestind).first;
}
void TrackerStateEstimatorMILBoosting::prepareData(const ConfidenceMap& confidenceMap, Mat& positive, Mat& negative)
{
int posCounter = 0;
int negCounter = 0;
for (size_t i = 0; i < confidenceMap.size(); i++)
{
Ptr<TrackerMILTargetState> currentTargetState = confidenceMap.at(i).first.staticCast<TrackerMILTargetState>();
CV_DbgAssert(currentTargetState);
if (currentTargetState->isTargetFg())
posCounter++;
else
negCounter++;
}
positive.create(posCounter, numFeatures, CV_32FC1);
negative.create(negCounter, numFeatures, CV_32FC1);
//TODO change with mat fast access
//initialize trainData (positive and negative)
int pc = 0;
int nc = 0;
for (size_t i = 0; i < confidenceMap.size(); i++)
{
Ptr<TrackerMILTargetState> currentTargetState = confidenceMap.at(i).first.staticCast<TrackerMILTargetState>();
Mat stateFeatures = currentTargetState->getFeatures();
if (currentTargetState->isTargetFg())
{
for (int j = 0; j < stateFeatures.rows; j++)
{
//fill the positive trainData with the value of the feature j for sample i
positive.at<float>(pc, j) = stateFeatures.at<float>(j, 0);
}
pc++;
}
else
{
for (int j = 0; j < stateFeatures.rows; j++)
{
//fill the negative trainData with the value of the feature j for sample i
negative.at<float>(nc, j) = stateFeatures.at<float>(j, 0);
}
nc++;
}
}
}
void TrackerStateEstimatorMILBoosting::updateImpl(std::vector<ConfidenceMap>& confidenceMaps)
{
if (!trained)
{
//this is the first time that the classifier is built
//init MIL
boostMILModel.init();
trained = true;
}
ConfidenceMap lastConfidenceMap = confidenceMaps.back();
Mat positiveStates;
Mat negativeStates;
prepareData(lastConfidenceMap, positiveStates, negativeStates);
//update MIL
boostMILModel.update(positiveStates, negativeStates);
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,87 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_VIDEO_DETAIL_TRACKING_MIL_STATE_HPP
#define OPENCV_VIDEO_DETAIL_TRACKING_MIL_STATE_HPP
#include "opencv2/video/detail/tracking.detail.hpp"
#include "tracking_online_mil.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
/** @brief TrackerStateEstimator based on Boosting
*/
class CV_EXPORTS TrackerStateEstimatorMILBoosting : public TrackerStateEstimator
{
public:
/**
* Implementation of the target state for TrackerStateEstimatorMILBoosting
*/
class TrackerMILTargetState : public TrackerTargetState
{
public:
/**
* \brief Constructor
* \param position Top left corner of the bounding box
* \param width Width of the bounding box
* \param height Height of the bounding box
* \param foreground label for target or background
* \param features features extracted
*/
TrackerMILTargetState(const Point2f& position, int width, int height, bool foreground, const Mat& features);
~TrackerMILTargetState() {};
/** @brief Set label: true for target foreground, false for background
@param foreground Label for background/foreground
*/
void setTargetFg(bool foreground);
/** @brief Set the features extracted from TrackerFeatureSet
@param features The features extracted
*/
void setFeatures(const Mat& features);
/** @brief Get the label. Return true for target foreground, false for background
*/
bool isTargetFg() const;
/** @brief Get the features extracted
*/
Mat getFeatures() const;
private:
bool isTarget;
Mat targetFeatures;
};
/** @brief Constructor
@param nFeatures Number of features for each sample
*/
TrackerStateEstimatorMILBoosting(int nFeatures = 250);
~TrackerStateEstimatorMILBoosting();
/** @brief Set the current confidenceMap
@param confidenceMap The current :cConfidenceMap
*/
void setCurrentConfidenceMap(ConfidenceMap& confidenceMap);
protected:
Ptr<TrackerTargetState> estimateImpl(const std::vector<ConfidenceMap>& confidenceMaps) CV_OVERRIDE;
void updateImpl(std::vector<ConfidenceMap>& confidenceMaps) CV_OVERRIDE;
private:
uint max_idx(const std::vector<float>& v);
void prepareData(const ConfidenceMap& confidenceMap, Mat& positive, Mat& negative);
ClfMilBoost boostMILModel;
bool trained;
int numFeatures;
ConfidenceMap currentConfidenceMap;
};
}}} // namespace cv::detail::tracking
#endif

View File

@@ -0,0 +1,132 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerModel::TrackerModel()
{
stateEstimator = Ptr<TrackerStateEstimator>();
maxCMLength = 10;
}
TrackerModel::~TrackerModel()
{
// nothing
}
bool TrackerModel::setTrackerStateEstimator(Ptr<TrackerStateEstimator> trackerStateEstimator)
{
if (stateEstimator.get())
{
return false;
}
stateEstimator = trackerStateEstimator;
return true;
}
Ptr<TrackerStateEstimator> TrackerModel::getTrackerStateEstimator() const
{
return stateEstimator;
}
void TrackerModel::modelEstimation(const std::vector<Mat>& responses)
{
modelEstimationImpl(responses);
}
void TrackerModel::clearCurrentConfidenceMap()
{
currentConfidenceMap.clear();
}
void TrackerModel::modelUpdate()
{
modelUpdateImpl();
if (maxCMLength != -1 && (int)confidenceMaps.size() >= maxCMLength - 1)
{
int l = maxCMLength / 2;
confidenceMaps.erase(confidenceMaps.begin(), confidenceMaps.begin() + l);
}
if (maxCMLength != -1 && (int)trajectory.size() >= maxCMLength - 1)
{
int l = maxCMLength / 2;
trajectory.erase(trajectory.begin(), trajectory.begin() + l);
}
confidenceMaps.push_back(currentConfidenceMap);
stateEstimator->update(confidenceMaps);
clearCurrentConfidenceMap();
}
bool TrackerModel::runStateEstimator()
{
if (!stateEstimator)
{
CV_Error(-1, "Tracker state estimator is not setted");
}
Ptr<TrackerTargetState> targetState = stateEstimator->estimate(confidenceMaps);
if (!targetState)
return false;
setLastTargetState(targetState);
return true;
}
void TrackerModel::setLastTargetState(const Ptr<TrackerTargetState>& lastTargetState)
{
trajectory.push_back(lastTargetState);
}
Ptr<TrackerTargetState> TrackerModel::getLastTargetState() const
{
return trajectory.back();
}
const std::vector<ConfidenceMap>& TrackerModel::getConfidenceMaps() const
{
return confidenceMaps;
}
const ConfidenceMap& TrackerModel::getLastConfidenceMap() const
{
return confidenceMaps.back();
}
Point2f TrackerTargetState::getTargetPosition() const
{
return targetPosition;
}
void TrackerTargetState::setTargetPosition(const Point2f& position)
{
targetPosition = position;
}
int TrackerTargetState::getTargetWidth() const
{
return targetWidth;
}
void TrackerTargetState::setTargetWidth(int width)
{
targetWidth = width;
}
int TrackerTargetState::getTargetHeight() const
{
return targetHeight;
}
void TrackerTargetState::setTargetHeight(int height)
{
targetHeight = height;
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,68 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerSampler::TrackerSampler()
{
blockAddTrackerSampler = false;
}
TrackerSampler::~TrackerSampler()
{
// nothing
}
void TrackerSampler::sampling(const Mat& image, Rect boundingBox)
{
clearSamples();
for (size_t i = 0; i < samplers.size(); i++)
{
CV_DbgAssert(samplers[i]);
std::vector<Mat> current_samples;
samplers[i]->sampling(image, boundingBox, current_samples);
//push in samples all current_samples
for (size_t j = 0; j < current_samples.size(); j++)
{
std::vector<Mat>::iterator it = samples.end();
samples.insert(it, current_samples.at(j));
}
}
blockAddTrackerSampler = true;
}
bool TrackerSampler::addTrackerSamplerAlgorithm(const Ptr<TrackerSamplerAlgorithm>& sampler)
{
CV_Assert(!blockAddTrackerSampler);
CV_Assert(sampler);
samplers.push_back(sampler);
return true;
}
const std::vector<Ptr<TrackerSamplerAlgorithm>>& TrackerSampler::getSamplers() const
{
return samplers;
}
const std::vector<Mat>& TrackerSampler::getSamples() const
{
return samples;
}
void TrackerSampler::clearSamples()
{
samples.clear();
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,124 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerSamplerAlgorithm::~TrackerSamplerAlgorithm()
{
// nothing
}
TrackerSamplerCSC::Params::Params()
{
initInRad = 3;
initMaxNegNum = 65;
searchWinSize = 25;
trackInPosRad = 4;
trackMaxNegNum = 65;
trackMaxPosNum = 100000;
}
TrackerSamplerCSC::TrackerSamplerCSC(const TrackerSamplerCSC::Params& parameters)
: params(parameters)
{
mode = MODE_INIT_POS;
rng = theRNG();
}
TrackerSamplerCSC::~TrackerSamplerCSC()
{
// nothing
}
bool TrackerSamplerCSC::sampling(const Mat& image, const Rect& boundingBox, std::vector<Mat>& sample)
{
CV_Assert(!image.empty());
float inrad = 0;
float outrad = 0;
int maxnum = 0;
switch (mode)
{
case MODE_INIT_POS:
inrad = params.initInRad;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad);
break;
case MODE_INIT_NEG:
inrad = 2.0f * params.searchWinSize;
outrad = 1.5f * params.initInRad;
maxnum = params.initMaxNegNum;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad, outrad, maxnum);
break;
case MODE_TRACK_POS:
inrad = params.trackInPosRad;
outrad = 0;
maxnum = params.trackMaxPosNum;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad, outrad, maxnum);
break;
case MODE_TRACK_NEG:
inrad = 1.5f * params.searchWinSize;
outrad = params.trackInPosRad + 5;
maxnum = params.trackMaxNegNum;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad, outrad, maxnum);
break;
case MODE_DETECT:
inrad = params.searchWinSize;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad);
break;
default:
inrad = params.initInRad;
sample = sampleImage(image, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height, inrad);
break;
}
return false;
}
void TrackerSamplerCSC::setMode(int samplingMode)
{
mode = samplingMode;
}
std::vector<Mat> TrackerSamplerCSC::sampleImage(const Mat& img, int x, int y, int w, int h, float inrad, float outrad, int maxnum)
{
int rowsz = img.rows - h - 1;
int colsz = img.cols - w - 1;
float inradsq = inrad * inrad;
float outradsq = outrad * outrad;
int dist;
uint minrow = max(0, (int)y - (int)inrad);
uint maxrow = min((int)rowsz - 1, (int)y + (int)inrad);
uint mincol = max(0, (int)x - (int)inrad);
uint maxcol = min((int)colsz - 1, (int)x + (int)inrad);
//fprintf(stderr,"inrad=%f minrow=%d maxrow=%d mincol=%d maxcol=%d\n",inrad,minrow,maxrow,mincol,maxcol);
std::vector<Mat> samples;
samples.resize((maxrow - minrow + 1) * (maxcol - mincol + 1));
int i = 0;
float prob = ((float)(maxnum)) / samples.size();
for (int r = minrow; r <= int(maxrow); r++)
for (int c = mincol; c <= int(maxcol); c++)
{
dist = (y - r) * (y - r) + (x - c) * (x - c);
if (float(rng.uniform(0.f, 1.f)) < prob && dist < inradsq && dist >= outradsq)
{
samples[i] = img(Rect(c, r, w, h));
i++;
}
}
samples.resize(min(i, maxnum));
return samples;
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,37 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
TrackerStateEstimator::~TrackerStateEstimator()
{
}
Ptr<TrackerTargetState> TrackerStateEstimator::estimate(const std::vector<ConfidenceMap>& confidenceMaps)
{
if (confidenceMaps.empty())
return Ptr<TrackerTargetState>();
return estimateImpl(confidenceMaps);
}
void TrackerStateEstimator::update(std::vector<ConfidenceMap>& confidenceMaps)
{
if (confidenceMaps.empty())
return;
return updateImpl(confidenceMaps);
}
String TrackerStateEstimator::getClassName() const
{
return className;
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,582 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "opencv2/video/detail/tracking.detail.hpp"
#include "tracking_feature.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
/*
* TODO This implementation is based on apps/traincascade/
* TODO Changed CvHaarEvaluator based on ADABOOSTING implementation (Grabner et al.)
*/
CvParams::CvParams()
{
// nothing
}
//---------------------------- FeatureParams --------------------------------------
CvFeatureParams::CvFeatureParams()
: maxCatCount(0)
, featSize(1)
, numFeatures(1)
{
// nothing
}
//------------------------------------- FeatureEvaluator ---------------------------------------
void CvFeatureEvaluator::init(const CvFeatureParams* _featureParams, int _maxSampleCount, Size _winSize)
{
CV_Assert(_featureParams);
CV_Assert(_maxSampleCount > 0);
featureParams = (CvFeatureParams*)_featureParams;
winSize = _winSize;
numFeatures = _featureParams->numFeatures;
cls.create((int)_maxSampleCount, 1, CV_32FC1);
generateFeatures();
}
void CvFeatureEvaluator::setImage(const Mat& img, uchar clsLabel, int idx)
{
winSize.width = img.cols;
winSize.height = img.rows;
//CV_Assert( img.cols == winSize.width );
//CV_Assert( img.rows == winSize.height );
CV_Assert(idx < cls.rows);
cls.ptr<float>(idx)[0] = clsLabel;
}
CvHaarFeatureParams::CvHaarFeatureParams()
{
isIntegral = false;
}
//--------------------- HaarFeatureEvaluator ----------------
void CvHaarEvaluator::init(const CvFeatureParams* _featureParams, int /*_maxSampleCount*/, Size _winSize)
{
CV_Assert(_featureParams);
int cols = (_winSize.width + 1) * (_winSize.height + 1);
sum.create((int)1, cols, CV_32SC1);
isIntegral = ((CvHaarFeatureParams*)_featureParams)->isIntegral;
CvFeatureEvaluator::init(_featureParams, 1, _winSize);
}
void CvHaarEvaluator::setImage(const Mat& img, uchar /*clsLabel*/, int /*idx*/)
{
CV_DbgAssert(!sum.empty());
winSize.width = img.cols;
winSize.height = img.rows;
CvFeatureEvaluator::setImage(img, 1, 0);
if (!isIntegral)
{
std::vector<Mat_<float>> ii_imgs;
compute_integral(img, ii_imgs);
_ii_img = ii_imgs[0];
}
else
{
_ii_img = img;
}
}
void CvHaarEvaluator::generateFeatures()
{
generateFeatures(featureParams->numFeatures);
}
void CvHaarEvaluator::generateFeatures(int nFeatures)
{
for (int i = 0; i < nFeatures; i++)
{
CvHaarEvaluator::FeatureHaar feature(Size(winSize.width, winSize.height));
features.push_back(feature);
}
}
#define INITSIGMA(numAreas) (static_cast<float>(sqrt(256.0f * 256.0f / 12.0f * (numAreas))));
CvHaarEvaluator::FeatureHaar::FeatureHaar(Size patchSize)
{
try
{
generateRandomFeature(patchSize);
}
catch (...)
{
// FIXIT
throw;
}
}
void CvHaarEvaluator::FeatureHaar::generateRandomFeature(Size patchSize)
{
cv::Point2i position;
Size baseDim;
Size sizeFactor;
int area;
CV_Assert(!patchSize.empty());
//Size minSize = Size( 3, 3 );
int minArea = 9;
bool valid = false;
while (!valid)
{
//choose position and scale
position.y = rand() % (patchSize.height);
position.x = rand() % (patchSize.width);
baseDim.width = (int)((1 - sqrt(1 - (float)rand() * (float)(1.0 / RAND_MAX))) * patchSize.width);
baseDim.height = (int)((1 - sqrt(1 - (float)rand() * (float)(1.0 / RAND_MAX))) * patchSize.height);
//select types
//float probType[11] = {0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0909f, 0.0950f};
float probType[11] = { 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
float prob = (float)rand() * (float)(1.0 / RAND_MAX);
if (prob < probType[0])
{
//check if feature is valid
sizeFactor.height = 2;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 1;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 2;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 2;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2])
{
//check if feature is valid
sizeFactor.height = 4;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 3;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = 2 * baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + 3 * baseDim.height;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 4;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 3;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = 2 * baseDim.width;
m_areas[2].y = position.y;
m_areas[2].x = position.x + 3 * baseDim.width;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4])
{
//check if feature is valid
sizeFactor.height = 2;
sizeFactor.width = 2;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 5;
m_numAreas = 4;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_weights[2] = -1;
m_weights[3] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + baseDim.height;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_areas[3].y = position.y + baseDim.height;
m_areas[3].x = position.x + baseDim.width;
m_areas[3].height = baseDim.height;
m_areas[3].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 6;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -9;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = 3 * baseDim.height;
m_areas[0].width = 3 * baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = -8 * 128;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 7;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + baseDim.height * 2;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 8;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y;
m_areas[2].x = position.x + 2 * baseDim.width;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob < probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7] + probType[8])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 9;
m_numAreas = 2;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -2;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = 3 * baseDim.height;
m_areas[0].width = 3 * baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_initMean = 0;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob
< probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7] + probType[8] + probType[9])
{
//check if feature is valid
sizeFactor.height = 3;
sizeFactor.width = 1;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 10;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x;
m_areas[1].y = position.y + baseDim.height;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y + baseDim.height * 2;
m_areas[2].x = position.x;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 128;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else if (prob
< probType[0] + probType[1] + probType[2] + probType[3] + probType[4] + probType[5] + probType[6] + probType[7] + probType[8] + probType[9]
+ probType[10])
{
//check if feature is valid
sizeFactor.height = 1;
sizeFactor.width = 3;
if (position.y + baseDim.height * sizeFactor.height >= patchSize.height || position.x + baseDim.width * sizeFactor.width >= patchSize.width)
continue;
area = baseDim.height * sizeFactor.height * baseDim.width * sizeFactor.width;
if (area < minArea)
continue;
m_type = 11;
m_numAreas = 3;
m_weights.resize(m_numAreas);
m_weights[0] = 1;
m_weights[1] = -1;
m_weights[2] = 1;
m_areas.resize(m_numAreas);
m_areas[0].x = position.x;
m_areas[0].y = position.y;
m_areas[0].height = baseDim.height;
m_areas[0].width = baseDim.width;
m_areas[1].x = position.x + baseDim.width;
m_areas[1].y = position.y;
m_areas[1].height = baseDim.height;
m_areas[1].width = baseDim.width;
m_areas[2].y = position.y;
m_areas[2].x = position.x + 2 * baseDim.width;
m_areas[2].height = baseDim.height;
m_areas[2].width = baseDim.width;
m_initMean = 128;
m_initSigma = INITSIGMA(m_numAreas);
valid = true;
}
else
CV_Error(Error::StsAssert, "");
}
m_initSize = patchSize;
m_curSize = m_initSize;
m_scaleFactorWidth = m_scaleFactorHeight = 1.0f;
m_scaleAreas.resize(m_numAreas);
m_scaleWeights.resize(m_numAreas);
for (int curArea = 0; curArea < m_numAreas; curArea++)
{
m_scaleAreas[curArea] = m_areas[curArea];
m_scaleWeights[curArea] = (float)m_weights[curArea] / (float)(m_areas[curArea].width * m_areas[curArea].height);
}
}
bool CvHaarEvaluator::FeatureHaar::eval(const Mat& image, Rect /*ROI*/, float* result) const
{
*result = 0.0f;
for (int curArea = 0; curArea < m_numAreas; curArea++)
{
*result += (float)getSum(image, Rect(m_areas[curArea].x, m_areas[curArea].y, m_areas[curArea].width, m_areas[curArea].height))
* m_scaleWeights[curArea];
}
/*
if( image->getUseVariance() )
{
float variance = (float) image->getVariance( ROI );
*result /= variance;
}
*/
return true;
}
float CvHaarEvaluator::FeatureHaar::getSum(const Mat& image, Rect imageROI) const
{
// left upper Origin
int OriginX = imageROI.x;
int OriginY = imageROI.y;
// Check and fix width and height
int Width = imageROI.width;
int Height = imageROI.height;
if (OriginX + Width >= image.cols - 1)
Width = (image.cols - 1) - OriginX;
if (OriginY + Height >= image.rows - 1)
Height = (image.rows - 1) - OriginY;
float value = 0;
int depth = image.depth();
if (depth == CV_8U || depth == CV_32S)
value = static_cast<float>(image.at<int>(OriginY + Height, OriginX + Width) + image.at<int>(OriginY, OriginX) - image.at<int>(OriginY, OriginX + Width)
- image.at<int>(OriginY + Height, OriginX));
else if (depth == CV_64F)
value = static_cast<float>(image.at<double>(OriginY + Height, OriginX + Width) + image.at<double>(OriginY, OriginX)
- image.at<double>(OriginY, OriginX + Width) - image.at<double>(OriginY + Height, OriginX));
else if (depth == CV_32F)
value = static_cast<float>(image.at<float>(OriginY + Height, OriginX + Width) + image.at<float>(OriginY, OriginX) - image.at<float>(OriginY, OriginX + Width)
- image.at<float>(OriginY + Height, OriginX));
return value;
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,168 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_VIDEO_DETAIL_TRACKING_FEATURE_HPP
#define OPENCV_VIDEO_DETAIL_TRACKING_FEATURE_HPP
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
/*
* TODO This implementation is based on apps/traincascade/
* TODO Changed CvHaarEvaluator based on ADABOOSTING implementation (Grabner et al.)
*/
namespace cv {
namespace detail {
inline namespace tracking {
//! @addtogroup tracking_detail
//! @{
inline namespace feature {
class CvParams
{
public:
CvParams();
virtual ~CvParams()
{
}
};
class CvFeatureParams : public CvParams
{
public:
enum FeatureType
{
HAAR = 0,
LBP = 1,
HOG = 2
};
CvFeatureParams();
static Ptr<CvFeatureParams> create(CvFeatureParams::FeatureType featureType);
int maxCatCount; // 0 in case of numerical features
int featSize; // 1 in case of simple features (HAAR, LBP) and N_BINS(9)*N_CELLS(4) in case of Dalal's HOG features
int numFeatures;
};
class CvFeatureEvaluator
{
public:
virtual ~CvFeatureEvaluator()
{
}
virtual void init(const CvFeatureParams* _featureParams, int _maxSampleCount, Size _winSize);
virtual void setImage(const Mat& img, uchar clsLabel, int idx);
static Ptr<CvFeatureEvaluator> create(CvFeatureParams::FeatureType type);
int getNumFeatures() const
{
return numFeatures;
}
int getMaxCatCount() const
{
return featureParams->maxCatCount;
}
int getFeatureSize() const
{
return featureParams->featSize;
}
const Mat& getCls() const
{
return cls;
}
float getCls(int si) const
{
return cls.at<float>(si, 0);
}
protected:
virtual void generateFeatures() = 0;
int npos, nneg;
int numFeatures;
Size winSize;
CvFeatureParams* featureParams;
Mat cls;
};
class CvHaarFeatureParams : public CvFeatureParams
{
public:
CvHaarFeatureParams();
bool isIntegral;
};
class CvHaarEvaluator : public CvFeatureEvaluator
{
public:
class FeatureHaar
{
public:
FeatureHaar(Size patchSize);
bool eval(const Mat& image, Rect ROI, float* result) const;
inline int getNumAreas() const { return m_numAreas; }
inline const std::vector<float>& getWeights() const { return m_weights; }
inline const std::vector<Rect>& getAreas() const { return m_areas; }
private:
int m_type;
int m_numAreas;
std::vector<float> m_weights;
float m_initMean;
float m_initSigma;
void generateRandomFeature(Size imageSize);
float getSum(const Mat& image, Rect imgROI) const;
std::vector<Rect> m_areas; // areas within the patch over which to compute the feature
cv::Size m_initSize; // size of the patch used during training
cv::Size m_curSize; // size of the patches currently under investigation
float m_scaleFactorHeight; // scaling factor in vertical direction
float m_scaleFactorWidth; // scaling factor in horizontal direction
std::vector<Rect> m_scaleAreas; // areas after scaling
std::vector<float> m_scaleWeights; // weights after scaling
};
virtual void init(const CvFeatureParams* _featureParams, int _maxSampleCount, Size _winSize) CV_OVERRIDE;
virtual void setImage(const Mat& img, uchar clsLabel = 0, int idx = 1) CV_OVERRIDE;
inline const std::vector<CvHaarEvaluator::FeatureHaar>& getFeatures() const { return features; }
inline CvHaarEvaluator::FeatureHaar& getFeatures(int idx)
{
return features[idx];
}
inline void setWinSize(Size patchSize) { winSize = patchSize; }
inline Size getWinSize() const { return winSize; }
virtual void generateFeatures() CV_OVERRIDE;
/**
* \brief Overload the original generateFeatures in order to limit the number of the features
* @param numFeatures Number of the features
*/
virtual void generateFeatures(int numFeatures);
protected:
bool isIntegral;
/* TODO Added from MIL implementation */
Mat _ii_img;
void compute_integral(const cv::Mat& img, std::vector<cv::Mat_<float>>& ii_imgs)
{
Mat ii_img;
integral(img, ii_img, CV_32F);
split(ii_img, ii_imgs);
}
std::vector<FeatureHaar> features;
Mat sum; /* sum images (each row represents image) */
};
} // namespace feature
//! @}
}}} // namespace cv::detail::tracking
#endif

View File

@@ -0,0 +1,356 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../../precomp.hpp"
#include "tracking_online_mil.hpp"
namespace cv {
namespace detail {
inline namespace tracking {
#define sign(s) ((s > 0) ? 1 : ((s < 0) ? -1 : 0))
template <class T>
class SortableElementRev
{
public:
T _val;
int _ind;
SortableElementRev()
: _val(), _ind(0)
{
}
SortableElementRev(T val, int ind)
{
_val = val;
_ind = ind;
}
bool operator<(SortableElementRev<T>& b)
{
return (_val < b._val);
};
};
static bool CompareSortableElementRev(const SortableElementRev<float>& i, const SortableElementRev<float>& j)
{
return i._val < j._val;
}
template <class T>
void sort_order_des(std::vector<T>& v, std::vector<int>& order)
{
uint n = (uint)v.size();
std::vector<SortableElementRev<T>> v2;
v2.resize(n);
order.clear();
order.resize(n);
for (uint i = 0; i < n; i++)
{
v2[i]._ind = i;
v2[i]._val = v[i];
}
//std::sort( v2.begin(), v2.end() );
std::sort(v2.begin(), v2.end(), CompareSortableElementRev);
for (uint i = 0; i < n; i++)
{
order[i] = v2[i]._ind;
v[i] = v2[i]._val;
}
};
//implementations for strong classifier
ClfMilBoost::Params::Params()
{
_numSel = 50;
_numFeat = 250;
_lRate = 0.85f;
}
ClfMilBoost::ClfMilBoost()
: _numsamples(0)
, _counter(0)
{
_myParams = ClfMilBoost::Params();
_numsamples = 0;
}
ClfMilBoost::~ClfMilBoost()
{
_selectors.clear();
for (size_t i = 0; i < _weakclf.size(); i++)
delete _weakclf.at(i);
}
void ClfMilBoost::init(const ClfMilBoost::Params& parameters)
{
_myParams = parameters;
_numsamples = 0;
//_ftrs = Ftr::generate( _myParams->_ftrParams, _myParams->_numFeat );
// if( params->_storeFtrHistory )
// Ftr::toViz( _ftrs, "haarftrs" );
_weakclf.resize(_myParams._numFeat);
for (int k = 0; k < _myParams._numFeat; k++)
{
_weakclf[k] = new ClfOnlineStump(k);
_weakclf[k]->_lRate = _myParams._lRate;
}
_counter = 0;
}
void ClfMilBoost::update(const Mat& posx, const Mat& negx)
{
int numneg = negx.rows;
int numpos = posx.rows;
// compute ftrs
//if( !posx.ftrsComputed() )
// Ftr::compute( posx, _ftrs );
//if( !negx.ftrsComputed() )
// Ftr::compute( negx, _ftrs );
// initialize H
static std::vector<float> Hpos, Hneg;
Hpos.clear();
Hneg.clear();
Hpos.resize(posx.rows, 0.0f), Hneg.resize(negx.rows, 0.0f);
_selectors.clear();
std::vector<float> posw(posx.rows), negw(negx.rows);
std::vector<std::vector<float>> pospred(_weakclf.size()), negpred(_weakclf.size());
// train all weak classifiers without weights
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int m = 0; m < _myParams._numFeat; m++)
{
_weakclf[m]->update(posx, negx);
pospred[m] = _weakclf[m]->classifySetF(posx);
negpred[m] = _weakclf[m]->classifySetF(negx);
}
// pick the best features
for (int s = 0; s < _myParams._numSel; s++)
{
// compute errors/likl for all weak clfs
std::vector<float> poslikl(_weakclf.size(), 1.0f), neglikl(_weakclf.size()), likl(_weakclf.size());
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int w = 0; w < (int)_weakclf.size(); w++)
{
float lll = 1.0f;
for (int j = 0; j < numpos; j++)
lll *= (1 - sigmoid(Hpos[j] + pospred[w][j]));
poslikl[w] = (float)-log(1 - lll + 1e-5);
lll = 0.0f;
for (int j = 0; j < numneg; j++)
lll += (float)-log(1e-5f + 1 - sigmoid(Hneg[j] + negpred[w][j]));
neglikl[w] = lll;
likl[w] = poslikl[w] / numpos + neglikl[w] / numneg;
}
// pick best weak clf
std::vector<int> order;
sort_order_des(likl, order);
// find best weakclf that isn't already included
for (uint k = 0; k < order.size(); k++)
if (std::count(_selectors.begin(), _selectors.end(), order[k]) == 0)
{
_selectors.push_back(order[k]);
break;
}
// update H = H + h_m
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int k = 0; k < posx.rows; k++)
Hpos[k] += pospred[_selectors[s]][k];
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int k = 0; k < negx.rows; k++)
Hneg[k] += negpred[_selectors[s]][k];
}
//if( _myParams->_storeFtrHistory )
//for ( uint j = 0; j < _selectors.size(); j++ )
// _ftrHist( _selectors[j], _counter ) = 1.0f / ( j + 1 );
_counter++;
/* */
return;
}
std::vector<float> ClfMilBoost::classify(const Mat& x, bool logR)
{
int numsamples = x.rows;
std::vector<float> res(numsamples);
std::vector<float> tr;
for (uint w = 0; w < _selectors.size(); w++)
{
tr = _weakclf[_selectors[w]]->classifySetF(x);
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int j = 0; j < numsamples; j++)
{
res[j] += tr[j];
}
}
// return probabilities or log odds ratio
if (!logR)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int j = 0; j < (int)res.size(); j++)
{
res[j] = sigmoid(res[j]);
}
}
return res;
}
//implementations for weak classifier
ClfOnlineStump::ClfOnlineStump()
: _mu0(0), _mu1(0), _sig0(0), _sig1(0)
, _q(0)
, _s(0)
, _log_n1(0), _log_n0(0)
, _e1(0), _e0(0)
, _lRate(0)
{
_trained = false;
_ind = -1;
init();
}
ClfOnlineStump::ClfOnlineStump(int ind)
: _mu0(0), _mu1(0), _sig0(0), _sig1(0)
, _q(0)
, _s(0)
, _log_n1(0), _log_n0(0)
, _e1(0), _e0(0)
, _lRate(0)
{
_trained = false;
_ind = ind;
init();
}
void ClfOnlineStump::init()
{
_mu0 = 0;
_mu1 = 0;
_sig0 = 1;
_sig1 = 1;
_lRate = 0.85f;
_trained = false;
}
void ClfOnlineStump::update(const Mat& posx, const Mat& negx, const Mat_<float>& /*posw*/, const Mat_<float>& /*negw*/)
{
//std::cout << " ClfOnlineStump::update" << _ind << std::endl;
float posmu = 0.0, negmu = 0.0;
if (posx.cols > 0)
posmu = float(mean(posx.col(_ind))[0]);
if (negx.cols > 0)
negmu = float(mean(negx.col(_ind))[0]);
if (_trained)
{
if (posx.cols > 0)
{
_mu1 = (_lRate * _mu1 + (1 - _lRate) * posmu);
cv::Mat diff = posx.col(_ind) - _mu1;
_sig1 = _lRate * _sig1 + (1 - _lRate) * float(mean(diff.mul(diff))[0]);
}
if (negx.cols > 0)
{
_mu0 = (_lRate * _mu0 + (1 - _lRate) * negmu);
cv::Mat diff = negx.col(_ind) - _mu0;
_sig0 = _lRate * _sig0 + (1 - _lRate) * float(mean(diff.mul(diff))[0]);
}
_q = (_mu1 - _mu0) / 2;
_s = sign(_mu1 - _mu0);
_log_n0 = std::log(float(1.0f / pow(_sig0, 0.5f)));
_log_n1 = std::log(float(1.0f / pow(_sig1, 0.5f)));
//_e1 = -1.0f/(2.0f*_sig1+1e-99f);
//_e0 = -1.0f/(2.0f*_sig0+1e-99f);
_e1 = -1.0f / (2.0f * _sig1 + std::numeric_limits<float>::min());
_e0 = -1.0f / (2.0f * _sig0 + std::numeric_limits<float>::min());
}
else
{
_trained = true;
if (posx.cols > 0)
{
_mu1 = posmu;
cv::Scalar scal_mean, scal_std_dev;
cv::meanStdDev(posx.col(_ind), scal_mean, scal_std_dev);
_sig1 = float(scal_std_dev[0]) * float(scal_std_dev[0]) + 1e-9f;
}
if (negx.cols > 0)
{
_mu0 = negmu;
cv::Scalar scal_mean, scal_std_dev;
cv::meanStdDev(negx.col(_ind), scal_mean, scal_std_dev);
_sig0 = float(scal_std_dev[0]) * float(scal_std_dev[0]) + 1e-9f;
}
_q = (_mu1 - _mu0) / 2;
_s = sign(_mu1 - _mu0);
_log_n0 = std::log(float(1.0f / pow(_sig0, 0.5f)));
_log_n1 = std::log(float(1.0f / pow(_sig1, 0.5f)));
//_e1 = -1.0f/(2.0f*_sig1+1e-99f);
//_e0 = -1.0f/(2.0f*_sig0+1e-99f);
_e1 = -1.0f / (2.0f * _sig1 + std::numeric_limits<float>::min());
_e0 = -1.0f / (2.0f * _sig0 + std::numeric_limits<float>::min());
}
}
bool ClfOnlineStump::classify(const Mat& x, int i)
{
float xx = x.at<float>(i, _ind);
double log_p0 = (xx - _mu0) * (xx - _mu0) * _e0 + _log_n0;
double log_p1 = (xx - _mu1) * (xx - _mu1) * _e1 + _log_n1;
return log_p1 > log_p0;
}
float ClfOnlineStump::classifyF(const Mat& x, int i)
{
float xx = x.at<float>(i, _ind);
double log_p0 = (xx - _mu0) * (xx - _mu0) * _e0 + _log_n0;
double log_p1 = (xx - _mu1) * (xx - _mu1) * _e1 + _log_n1;
return float(log_p1 - log_p0);
}
inline std::vector<float> ClfOnlineStump::classifySetF(const Mat& x)
{
std::vector<float> res(x.rows);
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int k = 0; k < (int)res.size(); k++)
{
res[k] = classifyF(x, k);
}
return res;
}
}}} // namespace cv::detail::tracking

View File

@@ -0,0 +1,79 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_VIDEO_DETAIL_TRACKING_ONLINE_MIL_HPP
#define OPENCV_VIDEO_DETAIL_TRACKING_ONLINE_MIL_HPP
#include <limits>
namespace cv {
namespace detail {
inline namespace tracking {
//! @addtogroup tracking_detail
//! @{
//TODO based on the original implementation
//http://vision.ucsd.edu/~bbabenko/project_miltrack.shtml
class ClfOnlineStump;
class CV_EXPORTS ClfMilBoost
{
public:
struct CV_EXPORTS Params
{
Params();
int _numSel;
int _numFeat;
float _lRate;
};
ClfMilBoost();
~ClfMilBoost();
void init(const ClfMilBoost::Params& parameters = ClfMilBoost::Params());
void update(const Mat& posx, const Mat& negx);
std::vector<float> classify(const Mat& x, bool logR = true);
inline float sigmoid(float x)
{
return 1.0f / (1.0f + exp(-x));
}
private:
uint _numsamples;
ClfMilBoost::Params _myParams;
std::vector<int> _selectors;
std::vector<ClfOnlineStump*> _weakclf;
uint _counter;
};
class ClfOnlineStump
{
public:
float _mu0, _mu1, _sig0, _sig1;
float _q;
int _s;
float _log_n1, _log_n0;
float _e1, _e0;
float _lRate;
ClfOnlineStump();
ClfOnlineStump(int ind);
void init();
void update(const Mat& posx, const Mat& negx, const cv::Mat_<float>& posw = cv::Mat_<float>(), const cv::Mat_<float>& negw = cv::Mat_<float>());
bool classify(const Mat& x, int i);
float classifyF(const Mat& x, int i);
std::vector<float> classifySetF(const Mat& x);
private:
bool _trained;
int _ind;
};
//! @}
}}} // namespace cv::detail::tracking
#endif

View File

@@ -0,0 +1,19 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
namespace cv {
Tracker::Tracker()
{
// nothing
}
Tracker::~Tracker()
{
// nothing
}
} // namespace cv

View File

@@ -0,0 +1,440 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
#ifdef HAVE_OPENCV_DNN
#include "opencv2/dnn.hpp"
#endif
namespace cv {
TrackerDaSiamRPN::TrackerDaSiamRPN()
{
// nothing
}
TrackerDaSiamRPN::~TrackerDaSiamRPN()
{
// nothing
}
TrackerDaSiamRPN::Params::Params()
{
model = "dasiamrpn_model.onnx";
kernel_cls1 = "dasiamrpn_kernel_cls1.onnx";
kernel_r1 = "dasiamrpn_kernel_r1.onnx";
#ifdef HAVE_OPENCV_DNN
backend = dnn::DNN_BACKEND_DEFAULT;
target = dnn::DNN_TARGET_CPU;
#else
backend = -1; // invalid value
target = -1; // invalid value
#endif
}
#ifdef HAVE_OPENCV_DNN
template <typename T> static
T sizeCal(const T& w, const T& h)
{
T pad = (w + h) * T(0.5);
T sz2 = (w + pad) * (h + pad);
return sqrt(sz2);
}
template <>
Mat sizeCal(const Mat& w, const Mat& h)
{
Mat pad = (w + h) * 0.5;
Mat sz2 = (w + pad).mul((h + pad));
cv::sqrt(sz2, sz2);
return sz2;
}
class TrackerDaSiamRPNImpl : public TrackerDaSiamRPN
{
public:
TrackerDaSiamRPNImpl(const TrackerDaSiamRPN::Params& parameters)
: params(parameters)
{
siamRPN = dnn::readNet(params.model);
siamKernelCL1 = dnn::readNet(params.kernel_cls1);
siamKernelR1 = dnn::readNet(params.kernel_r1);
CV_Assert(!siamRPN.empty());
CV_Assert(!siamKernelCL1.empty());
CV_Assert(!siamKernelR1.empty());
siamRPN.setPreferableBackend(params.backend);
siamRPN.setPreferableTarget(params.target);
siamKernelR1.setPreferableBackend(params.backend);
siamKernelR1.setPreferableTarget(params.target);
siamKernelCL1.setPreferableBackend(params.backend);
siamKernelCL1.setPreferableTarget(params.target);
}
void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
bool update(InputArray image, Rect& boundingBox) CV_OVERRIDE;
float getTrackingScore() CV_OVERRIDE;
TrackerDaSiamRPN::Params params;
protected:
dnn::Net siamRPN, siamKernelR1, siamKernelCL1;
Rect boundingBox_;
Mat image_;
struct trackerConfig
{
float windowInfluence = 0.43f;
float lr = 0.4f;
int scale = 8;
bool swapRB = false;
int totalStride = 8;
float penaltyK = 0.055f;
int exemplarSize = 127;
int instanceSize = 271;
float contextAmount = 0.5f;
std::vector<float> ratios = { 0.33f, 0.5f, 1.0f, 2.0f, 3.0f };
int anchorNum = int(ratios.size());
Mat anchors;
Mat windows;
Scalar avgChans;
Size imgSize = { 0, 0 };
Rect2f targetBox = { 0, 0, 0, 0 };
int scoreSize = (instanceSize - exemplarSize) / totalStride + 1;
float tracking_score;
void update_scoreSize()
{
scoreSize = int((instanceSize - exemplarSize) / totalStride + 1);
}
};
trackerConfig trackState;
void softmax(const Mat& src, Mat& dst);
void elementMax(Mat& src);
Mat generateHanningWindow();
Mat generateAnchors();
Mat getSubwindow(Mat& img, const Rect2f& targetBox, float originalSize, Scalar avgChans);
void trackerInit(Mat img);
void trackerEval(Mat img);
};
void TrackerDaSiamRPNImpl::init(InputArray image, const Rect& boundingBox)
{
image_ = image.getMat().clone();
trackState.update_scoreSize();
trackState.targetBox = Rect2f(
float(boundingBox.x) + float(boundingBox.width) * 0.5f, // FIXIT don't use center in Rect structures, it is confusing
float(boundingBox.y) + float(boundingBox.height) * 0.5f,
float(boundingBox.width),
float(boundingBox.height)
);
trackerInit(image_);
}
void TrackerDaSiamRPNImpl::trackerInit(Mat img)
{
Rect2f targetBox = trackState.targetBox;
Mat anchors = generateAnchors();
trackState.anchors = anchors;
Mat windows = generateHanningWindow();
trackState.windows = windows;
trackState.imgSize = img.size();
trackState.avgChans = mean(img);
float wc = targetBox.width + trackState.contextAmount * (targetBox.width + targetBox.height);
float hc = targetBox.height + trackState.contextAmount * (targetBox.width + targetBox.height);
float sz = (float)cvRound(sqrt(wc * hc));
Mat zCrop = getSubwindow(img, targetBox, sz, trackState.avgChans);
Mat blob;
dnn::blobFromImage(zCrop, blob, 1.0, Size(trackState.exemplarSize, trackState.exemplarSize), Scalar(), trackState.swapRB, false, CV_32F);
siamRPN.setInput(blob);
Mat out1;
siamRPN.forward(out1, "63");
siamKernelCL1.setInput(out1);
siamKernelR1.setInput(out1);
Mat cls1 = siamKernelCL1.forward();
Mat r1 = siamKernelR1.forward();
std::vector<int> r1_shape = { 20, 256, 4, 4 }, cls1_shape = { 10, 256, 4, 4 };
siamRPN.setParam(siamRPN.getLayerId("65"), 0, r1.reshape(0, r1_shape));
siamRPN.setParam(siamRPN.getLayerId("68"), 0, cls1.reshape(0, cls1_shape));
}
bool TrackerDaSiamRPNImpl::update(InputArray image, Rect& boundingBox)
{
image_ = image.getMat().clone();
trackerEval(image_);
boundingBox = {
int(trackState.targetBox.x - int(trackState.targetBox.width / 2)),
int(trackState.targetBox.y - int(trackState.targetBox.height / 2)),
int(trackState.targetBox.width),
int(trackState.targetBox.height)
};
return true;
}
void TrackerDaSiamRPNImpl::trackerEval(Mat img)
{
Rect2f targetBox = trackState.targetBox;
float wc = targetBox.height + trackState.contextAmount * (targetBox.width + targetBox.height);
float hc = targetBox.width + trackState.contextAmount * (targetBox.width + targetBox.height);
float sz = sqrt(wc * hc);
float scaleZ = trackState.exemplarSize / sz;
float searchSize = float((trackState.instanceSize - trackState.exemplarSize) / 2);
float pad = searchSize / scaleZ;
float sx = sz + 2 * pad;
Mat xCrop = getSubwindow(img, targetBox, (float)cvRound(sx), trackState.avgChans);
Mat blob;
std::vector<Mat> outs;
std::vector<String> outNames;
Mat delta, score;
Mat sc, rc, penalty, pscore;
dnn::blobFromImage(xCrop, blob, 1.0, Size(trackState.instanceSize, trackState.instanceSize), Scalar(), trackState.swapRB, false, CV_32F);
siamRPN.setInput(blob);
outNames = siamRPN.getUnconnectedOutLayersNames();
siamRPN.forward(outs, outNames);
delta = outs[0];
score = outs[1];
score = score.reshape(0, { 2, trackState.anchorNum, trackState.scoreSize, trackState.scoreSize });
delta = delta.reshape(0, { 4, trackState.anchorNum, trackState.scoreSize, trackState.scoreSize });
softmax(score, score);
targetBox.width *= scaleZ;
targetBox.height *= scaleZ;
score = score.row(1);
score = score.reshape(0, { 5, 19, 19 });
// Post processing
delta.row(0) = delta.row(0).mul(trackState.anchors.row(2)) + trackState.anchors.row(0);
delta.row(1) = delta.row(1).mul(trackState.anchors.row(3)) + trackState.anchors.row(1);
exp(delta.row(2), delta.row(2));
delta.row(2) = delta.row(2).mul(trackState.anchors.row(2));
exp(delta.row(3), delta.row(3));
delta.row(3) = delta.row(3).mul(trackState.anchors.row(3));
sc = sizeCal(delta.row(2), delta.row(3)) / sizeCal(targetBox.width, targetBox.height);
elementMax(sc);
rc = delta.row(2).mul(1 / delta.row(3));
rc = (targetBox.width / targetBox.height) / rc;
elementMax(rc);
// Calculating the penalty
exp(((rc.mul(sc) - 1.) * trackState.penaltyK * (-1.0)), penalty);
penalty = penalty.reshape(0, { trackState.anchorNum, trackState.scoreSize, trackState.scoreSize });
pscore = penalty.mul(score);
pscore = pscore * (1.0 - trackState.windowInfluence) + trackState.windows * trackState.windowInfluence;
int bestID[2] = { 0, 0 };
// Find the index of best score.
minMaxIdx(pscore.reshape(0, { trackState.anchorNum * trackState.scoreSize * trackState.scoreSize, 1 }), 0, 0, 0, bestID);
delta = delta.reshape(0, { 4, trackState.anchorNum * trackState.scoreSize * trackState.scoreSize });
penalty = penalty.reshape(0, { trackState.anchorNum * trackState.scoreSize * trackState.scoreSize, 1 });
score = score.reshape(0, { trackState.anchorNum * trackState.scoreSize * trackState.scoreSize, 1 });
int index[2] = { 0, bestID[0] };
Rect2f resBox = { 0, 0, 0, 0 };
resBox.x = delta.at<float>(index) / scaleZ;
index[0] = 1;
resBox.y = delta.at<float>(index) / scaleZ;
index[0] = 2;
resBox.width = delta.at<float>(index) / scaleZ;
index[0] = 3;
resBox.height = delta.at<float>(index) / scaleZ;
float lr = penalty.at<float>(bestID) * score.at<float>(bestID) * trackState.lr;
resBox.x = resBox.x + targetBox.x;
resBox.y = resBox.y + targetBox.y;
targetBox.width /= scaleZ;
targetBox.height /= scaleZ;
resBox.width = targetBox.width * (1 - lr) + resBox.width * lr;
resBox.height = targetBox.height * (1 - lr) + resBox.height * lr;
resBox.x = float(fmax(0., fmin(float(trackState.imgSize.width), resBox.x)));
resBox.y = float(fmax(0., fmin(float(trackState.imgSize.height), resBox.y)));
resBox.width = float(fmax(10., fmin(float(trackState.imgSize.width), resBox.width)));
resBox.height = float(fmax(10., fmin(float(trackState.imgSize.height), resBox.height)));
trackState.targetBox = resBox;
trackState.tracking_score = score.at<float>(bestID);
}
float TrackerDaSiamRPNImpl::getTrackingScore()
{
return trackState.tracking_score;
}
void TrackerDaSiamRPNImpl::softmax(const Mat& src, Mat& dst)
{
Mat maxVal;
cv::max(src.row(1), src.row(0), maxVal);
src.row(1) -= maxVal;
src.row(0) -= maxVal;
exp(src, dst);
Mat sumVal = dst.row(0) + dst.row(1);
dst.row(0) = dst.row(0) / sumVal;
dst.row(1) = dst.row(1) / sumVal;
}
void TrackerDaSiamRPNImpl::elementMax(Mat& src)
{
int* p = src.size.p;
int index[4] = { 0, 0, 0, 0 };
for (int n = 0; n < *p; n++)
{
for (int k = 0; k < *(p + 1); k++)
{
for (int i = 0; i < *(p + 2); i++)
{
for (int j = 0; j < *(p + 3); j++)
{
index[0] = n, index[1] = k, index[2] = i, index[3] = j;
float& v = src.at<float>(index);
v = fmax(v, 1.0f / v);
}
}
}
}
}
Mat TrackerDaSiamRPNImpl::generateHanningWindow()
{
Mat baseWindows, HanningWindows;
createHanningWindow(baseWindows, Size(trackState.scoreSize, trackState.scoreSize), CV_32F);
baseWindows = baseWindows.reshape(0, { 1, trackState.scoreSize, trackState.scoreSize });
HanningWindows = baseWindows.clone();
for (int i = 1; i < trackState.anchorNum; i++)
{
HanningWindows.push_back(baseWindows);
}
return HanningWindows;
}
Mat TrackerDaSiamRPNImpl::generateAnchors()
{
int totalStride = trackState.totalStride, scales = trackState.scale, scoreSize = trackState.scoreSize;
std::vector<float> ratios = trackState.ratios;
std::vector<Rect2f> baseAnchors;
int anchorNum = int(ratios.size());
int size = totalStride * totalStride;
float ori = -(float(scoreSize / 2)) * float(totalStride);
for (auto i = 0; i < anchorNum; i++)
{
int ws = int(sqrt(size / ratios[i]));
int hs = int(ws * ratios[i]);
float wws = float(ws) * scales;
float hhs = float(hs) * scales;
Rect2f anchor = { 0, 0, wws, hhs };
baseAnchors.push_back(anchor);
}
int anchorIndex[4] = { 0, 0, 0, 0 };
const int sizes[4] = { 4, (int)ratios.size(), scoreSize, scoreSize };
Mat anchors(4, sizes, CV_32F);
for (auto i = 0; i < scoreSize; i++)
{
for (auto j = 0; j < scoreSize; j++)
{
for (auto k = 0; k < anchorNum; k++)
{
anchorIndex[0] = 1, anchorIndex[1] = k, anchorIndex[2] = i, anchorIndex[3] = j;
anchors.at<float>(anchorIndex) = ori + totalStride * i;
anchorIndex[0] = 0;
anchors.at<float>(anchorIndex) = ori + totalStride * j;
anchorIndex[0] = 2;
anchors.at<float>(anchorIndex) = baseAnchors[k].width;
anchorIndex[0] = 3;
anchors.at<float>(anchorIndex) = baseAnchors[k].height;
}
}
}
return anchors;
}
Mat TrackerDaSiamRPNImpl::getSubwindow(Mat& img, const Rect2f& targetBox, float originalSize, Scalar avgChans)
{
Mat zCrop, dst;
Size imgSize = img.size();
float c = (originalSize + 1) / 2;
float xMin = (float)cvRound(targetBox.x - c);
float xMax = xMin + originalSize - 1;
float yMin = (float)cvRound(targetBox.y - c);
float yMax = yMin + originalSize - 1;
int leftPad = (int)(fmax(0., -xMin));
int topPad = (int)(fmax(0., -yMin));
int rightPad = (int)(fmax(0., xMax - imgSize.width + 1));
int bottomPad = (int)(fmax(0., yMax - imgSize.height + 1));
xMin = xMin + leftPad;
xMax = xMax + leftPad;
yMax = yMax + topPad;
yMin = yMin + topPad;
if (topPad == 0 && bottomPad == 0 && leftPad == 0 && rightPad == 0)
{
img(Rect(int(xMin), int(yMin), int(xMax - xMin + 1), int(yMax - yMin + 1))).copyTo(zCrop);
}
else
{
copyMakeBorder(img, dst, topPad, bottomPad, leftPad, rightPad, BORDER_CONSTANT, avgChans);
dst(Rect(int(xMin), int(yMin), int(xMax - xMin + 1), int(yMax - yMin + 1))).copyTo(zCrop);
}
return zCrop;
}
Ptr<TrackerDaSiamRPN> TrackerDaSiamRPN::create(const TrackerDaSiamRPN::Params& parameters)
{
return makePtr<TrackerDaSiamRPNImpl>(parameters);
}
#else // OPENCV_HAVE_DNN
Ptr<TrackerDaSiamRPN> TrackerDaSiamRPN::create(const TrackerDaSiamRPN::Params& parameters)
{
(void)(parameters);
CV_Error(cv::Error::StsNotImplemented, "to use GOTURN, the tracking module needs to be built with opencv_dnn !");
}
#endif // OPENCV_HAVE_DNN
}

View File

@@ -0,0 +1,140 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
#ifdef HAVE_OPENCV_DNN
#include "opencv2/dnn.hpp"
#endif
namespace cv {
TrackerGOTURN::TrackerGOTURN()
{
// nothing
}
TrackerGOTURN::~TrackerGOTURN()
{
// nothing
}
TrackerGOTURN::Params::Params()
{
modelTxt = "goturn.prototxt";
modelBin = "goturn.caffemodel";
}
#ifdef HAVE_OPENCV_DNN
class TrackerGOTURNImpl : public TrackerGOTURN
{
public:
TrackerGOTURNImpl(const TrackerGOTURN::Params& parameters)
: params(parameters)
{
// Load GOTURN architecture from *.prototxt and pretrained weights from *.caffemodel
net = dnn::readNetFromCaffe(params.modelTxt, params.modelBin);
CV_Assert(!net.empty());
}
void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
bool update(InputArray image, Rect& boundingBox) CV_OVERRIDE;
void setBoudingBox(Rect boundingBox)
{
if (image_.empty())
CV_Error(Error::StsInternal, "Set image first");
boundingBox_ = boundingBox & Rect(Point(0, 0), image_.size());
}
TrackerGOTURN::Params params;
dnn::Net net;
Rect boundingBox_;
Mat image_;
};
void TrackerGOTURNImpl::init(InputArray image, const Rect& boundingBox)
{
image_ = image.getMat().clone();
setBoudingBox(boundingBox);
}
bool TrackerGOTURNImpl::update(InputArray image, Rect& boundingBox)
{
int INPUT_SIZE = 227;
//Using prevFrame & prevBB from model and curFrame GOTURN calculating curBB
InputArray curFrame = image;
Mat prevFrame = image_;
Rect2d prevBB = boundingBox_;
Rect curBB;
float padTargetPatch = 2.0;
Rect2f searchPatchRect, targetPatchRect;
Point2f currCenter, prevCenter;
Mat prevFramePadded, curFramePadded;
Mat searchPatch, targetPatch;
prevCenter.x = (float)(prevBB.x + prevBB.width / 2);
prevCenter.y = (float)(prevBB.y + prevBB.height / 2);
targetPatchRect.width = (float)(prevBB.width * padTargetPatch);
targetPatchRect.height = (float)(prevBB.height * padTargetPatch);
targetPatchRect.x = (float)(prevCenter.x - prevBB.width * padTargetPatch / 2.0 + targetPatchRect.width);
targetPatchRect.y = (float)(prevCenter.y - prevBB.height * padTargetPatch / 2.0 + targetPatchRect.height);
targetPatchRect.width = std::min(targetPatchRect.width, (float)prevFrame.cols);
targetPatchRect.height = std::min(targetPatchRect.height, (float)prevFrame.rows);
targetPatchRect.x = std::max(-prevFrame.cols * 0.5f, std::min(targetPatchRect.x, prevFrame.cols * 1.5f));
targetPatchRect.y = std::max(-prevFrame.rows * 0.5f, std::min(targetPatchRect.y, prevFrame.rows * 1.5f));
copyMakeBorder(prevFrame, prevFramePadded, (int)targetPatchRect.height, (int)targetPatchRect.height, (int)targetPatchRect.width, (int)targetPatchRect.width, BORDER_REPLICATE);
targetPatch = prevFramePadded(targetPatchRect).clone();
copyMakeBorder(curFrame, curFramePadded, (int)targetPatchRect.height, (int)targetPatchRect.height, (int)targetPatchRect.width, (int)targetPatchRect.width, BORDER_REPLICATE);
searchPatch = curFramePadded(targetPatchRect).clone();
// Preprocess
// Resize
resize(targetPatch, targetPatch, Size(INPUT_SIZE, INPUT_SIZE), 0, 0, INTER_LINEAR_EXACT);
resize(searchPatch, searchPatch, Size(INPUT_SIZE, INPUT_SIZE), 0, 0, INTER_LINEAR_EXACT);
// Convert to Float type and subtract mean
Mat targetBlob = dnn::blobFromImage(targetPatch, 1.0f, Size(), Scalar::all(128), false);
Mat searchBlob = dnn::blobFromImage(searchPatch, 1.0f, Size(), Scalar::all(128), false);
net.setInput(targetBlob, "data1");
net.setInput(searchBlob, "data2");
Mat resMat = net.forward("scale").reshape(1, 1);
curBB.x = cvRound(targetPatchRect.x + (resMat.at<float>(0) * targetPatchRect.width / INPUT_SIZE) - targetPatchRect.width);
curBB.y = cvRound(targetPatchRect.y + (resMat.at<float>(1) * targetPatchRect.height / INPUT_SIZE) - targetPatchRect.height);
curBB.width = cvRound((resMat.at<float>(2) - resMat.at<float>(0)) * targetPatchRect.width / INPUT_SIZE);
curBB.height = cvRound((resMat.at<float>(3) - resMat.at<float>(1)) * targetPatchRect.height / INPUT_SIZE);
// Predicted BB
boundingBox = curBB & Rect(Point(0, 0), image_.size());
// Set new model image and BB from current frame
image_ = image.getMat().clone();
setBoudingBox(curBB);
return true;
}
Ptr<TrackerGOTURN> TrackerGOTURN::create(const TrackerGOTURN::Params& parameters)
{
return makePtr<TrackerGOTURNImpl>(parameters);
}
#else // OPENCV_HAVE_DNN
Ptr<TrackerGOTURN> TrackerGOTURN::create(const TrackerGOTURN::Params& parameters)
{
(void)(parameters);
CV_Error(cv::Error::StsNotImplemented, "to use GOTURN, the tracking module needs to be built with opencv_dnn !");
}
#endif // OPENCV_HAVE_DNN
} // namespace cv

View File

@@ -0,0 +1,227 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "../precomp.hpp"
#include "detail/tracker_mil_model.hpp"
#include "detail/tracker_feature_haar.impl.hpp"
namespace cv {
inline namespace tracking {
namespace impl {
using cv::detail::tracking::internal::TrackerFeatureHAAR;
class TrackerMILImpl CV_FINAL : public TrackerMIL
{
public:
TrackerMILImpl(const TrackerMIL::Params& parameters);
virtual void init(InputArray image, const Rect& boundingBox) CV_OVERRIDE;
virtual bool update(InputArray image, Rect& boundingBox) CV_OVERRIDE;
void compute_integral(const Mat& img, Mat& ii_img);
TrackerMIL::Params params;
Ptr<TrackerMILModel> model;
Ptr<TrackerSampler> sampler;
Ptr<TrackerFeatureSet> featureSet;
};
TrackerMILImpl::TrackerMILImpl(const TrackerMIL::Params& parameters)
: params(parameters)
{
// nothing
}
void TrackerMILImpl::compute_integral(const Mat& img, Mat& ii_img)
{
Mat ii;
std::vector<Mat> ii_imgs;
integral(img, ii, CV_32F); // FIXIT split first
split(ii, ii_imgs);
ii_img = ii_imgs[0];
}
void TrackerMILImpl::init(InputArray image, const Rect& boundingBox)
{
sampler = makePtr<TrackerSampler>();
featureSet = makePtr<TrackerFeatureSet>();
Mat intImage;
compute_integral(image.getMat(), intImage);
TrackerSamplerCSC::Params CSCparameters;
CSCparameters.initInRad = params.samplerInitInRadius;
CSCparameters.searchWinSize = params.samplerSearchWinSize;
CSCparameters.initMaxNegNum = params.samplerInitMaxNegNum;
CSCparameters.trackInPosRad = params.samplerTrackInRadius;
CSCparameters.trackMaxPosNum = params.samplerTrackMaxPosNum;
CSCparameters.trackMaxNegNum = params.samplerTrackMaxNegNum;
Ptr<TrackerSamplerAlgorithm> CSCSampler = makePtr<TrackerSamplerCSC>(CSCparameters);
CV_Assert(sampler->addTrackerSamplerAlgorithm(CSCSampler));
//or add CSC sampler with default parameters
//sampler->addTrackerSamplerAlgorithm( "CSC" );
//Positive sampling
CSCSampler.staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_POS);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> posSamples = sampler->getSamples();
//Negative sampling
CSCSampler.staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_NEG);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> negSamples = sampler->getSamples();
CV_Assert(!posSamples.empty());
CV_Assert(!negSamples.empty());
//compute HAAR features
TrackerFeatureHAAR::Params HAARparameters;
HAARparameters.numFeatures = params.featureSetNumFeatures;
HAARparameters.rectSize = Size((int)boundingBox.width, (int)boundingBox.height);
HAARparameters.isIntegral = true;
Ptr<TrackerFeature> trackerFeature = makePtr<TrackerFeatureHAAR>(HAARparameters);
featureSet->addTrackerFeature(trackerFeature);
featureSet->extraction(posSamples);
const std::vector<Mat> posResponse = featureSet->getResponses();
featureSet->extraction(negSamples);
const std::vector<Mat> negResponse = featureSet->getResponses();
model = makePtr<TrackerMILModel>(boundingBox);
Ptr<TrackerStateEstimatorMILBoosting> stateEstimator = makePtr<TrackerStateEstimatorMILBoosting>(params.featureSetNumFeatures);
model->setTrackerStateEstimator(stateEstimator);
//Run model estimation and update
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_POSITIVE, posSamples);
model->modelEstimation(posResponse);
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_NEGATIVE, negSamples);
model->modelEstimation(negResponse);
model->modelUpdate();
}
bool TrackerMILImpl::update(InputArray image, Rect& boundingBox)
{
Mat intImage;
compute_integral(image.getMat(), intImage);
//get the last location [AAM] X(k-1)
Ptr<TrackerTargetState> lastLocation = model->getLastTargetState();
Rect lastBoundingBox((int)lastLocation->getTargetPosition().x, (int)lastLocation->getTargetPosition().y, lastLocation->getTargetWidth(),
lastLocation->getTargetHeight());
//sampling new frame based on last location
auto& samplers = sampler->getSamplers();
CV_Assert(!samplers.empty());
CV_Assert(samplers[0]);
samplers[0].staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_DETECT);
sampler->sampling(intImage, lastBoundingBox);
std::vector<Mat> detectSamples = sampler->getSamples();
if (detectSamples.empty())
return false;
/*//TODO debug samples
Mat f;
image.copyTo(f);
for( size_t i = 0; i < detectSamples.size(); i=i+10 )
{
Size sz;
Point off;
detectSamples.at(i).locateROI(sz, off);
rectangle(f, Rect(off.x,off.y,detectSamples.at(i).cols,detectSamples.at(i).rows), Scalar(255,0,0), 1);
}*/
//extract features from new samples
featureSet->extraction(detectSamples);
std::vector<Mat> response = featureSet->getResponses();
//predict new location
ConfidenceMap cmap;
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_ESTIMATON, detectSamples);
model.staticCast<TrackerMILModel>()->responseToConfidenceMap(response, cmap);
model->getTrackerStateEstimator().staticCast<TrackerStateEstimatorMILBoosting>()->setCurrentConfidenceMap(cmap);
if (!model->runStateEstimator())
{
return false;
}
Ptr<TrackerTargetState> currentState = model->getLastTargetState();
boundingBox = Rect((int)currentState->getTargetPosition().x, (int)currentState->getTargetPosition().y, currentState->getTargetWidth(),
currentState->getTargetHeight());
/*//TODO debug
rectangle(f, lastBoundingBox, Scalar(0,255,0), 1);
rectangle(f, boundingBox, Scalar(0,0,255), 1);
imshow("f", f);
//waitKey( 0 );*/
//sampling new frame based on new location
//Positive sampling
samplers[0].staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_POS);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> posSamples = sampler->getSamples();
//Negative sampling
samplers[0].staticCast<TrackerSamplerCSC>()->setMode(TrackerSamplerCSC::MODE_INIT_NEG);
sampler->sampling(intImage, boundingBox);
std::vector<Mat> negSamples = sampler->getSamples();
if (posSamples.empty() || negSamples.empty())
return false;
//extract features
featureSet->extraction(posSamples);
std::vector<Mat> posResponse = featureSet->getResponses();
featureSet->extraction(negSamples);
std::vector<Mat> negResponse = featureSet->getResponses();
//model estimate
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_POSITIVE, posSamples);
model->modelEstimation(posResponse);
model.staticCast<TrackerMILModel>()->setMode(TrackerMILModel::MODE_NEGATIVE, negSamples);
model->modelEstimation(negResponse);
//model update
model->modelUpdate();
return true;
}
}} // namespace tracking::impl
TrackerMIL::Params::Params()
{
samplerInitInRadius = 3;
samplerSearchWinSize = 25;
samplerInitMaxNegNum = 65;
samplerTrackInRadius = 4;
samplerTrackMaxPosNum = 100000;
samplerTrackMaxNegNum = 65;
featureSetNumFeatures = 250;
}
TrackerMIL::TrackerMIL()
{
// nothing
}
TrackerMIL::~TrackerMIL()
{
// nothing
}
Ptr<TrackerMIL> TrackerMIL::create(const TrackerMIL::Params& parameters)
{
return makePtr<tracking::impl::TrackerMILImpl>(parameters);
}
} // namespace cv

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,145 @@
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
//////////////////////////Mog2_Update///////////////////////////////////
namespace
{
IMPLEMENT_PARAM_CLASS(UseGray, bool)
IMPLEMENT_PARAM_CLASS(DetectShadow, bool)
IMPLEMENT_PARAM_CLASS(UseFloat, bool)
}
PARAM_TEST_CASE(Mog2_Update, UseGray, DetectShadow,UseFloat)
{
bool useGray;
bool detectShadow;
bool useFloat;
virtual void SetUp()
{
useGray = GET_PARAM(0);
detectShadow = GET_PARAM(1);
useFloat = GET_PARAM(2);
}
};
OCL_TEST_P(Mog2_Update, Accuracy)
{
string inputFile = string(TS::ptr()->get_data_path()) + "video/768x576.avi";
VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
Ptr<BackgroundSubtractorMOG2> mog2_cpu = createBackgroundSubtractorMOG2();
Ptr<BackgroundSubtractorMOG2> mog2_ocl = createBackgroundSubtractorMOG2();
mog2_cpu->setDetectShadows(detectShadow);
mog2_ocl->setDetectShadows(detectShadow);
Mat frame, foreground;
UMat u_foreground;
for (int i = 0; i < 10; ++i)
{
cap >> frame;
ASSERT_FALSE(frame.empty());
if (useGray)
{
Mat temp;
cvtColor(frame, temp, COLOR_BGR2GRAY);
swap(temp, frame);
}
if(useFloat)
{
Mat temp;
frame.convertTo(temp,CV_32F);
swap(temp,frame);
}
OCL_OFF(mog2_cpu->apply(frame, foreground));
OCL_ON (mog2_ocl->apply(frame, u_foreground));
if (detectShadow)
EXPECT_MAT_SIMILAR(foreground, u_foreground, 15e-3);
else
EXPECT_MAT_NEAR(foreground, u_foreground, 0);
}
}
//////////////////////////Mog2_getBackgroundImage///////////////////////////////////
PARAM_TEST_CASE(Mog2_getBackgroundImage, DetectShadow, UseFloat)
{
bool detectShadow;
bool useFloat;
virtual void SetUp()
{
detectShadow = GET_PARAM(0);
useFloat = GET_PARAM(1);
}
};
OCL_TEST_P(Mog2_getBackgroundImage, Accuracy)
{
string inputFile = string(TS::ptr()->get_data_path()) + "video/768x576.avi";
VideoCapture cap(inputFile);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
Ptr<BackgroundSubtractorMOG2> mog2_cpu = createBackgroundSubtractorMOG2();
Ptr<BackgroundSubtractorMOG2> mog2_ocl = createBackgroundSubtractorMOG2();
mog2_cpu->setDetectShadows(detectShadow);
mog2_ocl->setDetectShadows(detectShadow);
Mat frame, foreground;
UMat u_foreground;
for (int i = 0; i < 10; ++i)
{
cap >> frame;
ASSERT_FALSE(frame.empty());
if(useFloat)
{
Mat temp;
frame.convertTo(temp,CV_32F);
swap(temp,frame);
}
OCL_OFF(mog2_cpu->apply(frame, foreground));
OCL_ON (mog2_ocl->apply(frame, u_foreground));
}
Mat background;
OCL_OFF(mog2_cpu->getBackgroundImage(background));
UMat u_background;
OCL_ON (mog2_ocl->getBackgroundImage(u_background));
EXPECT_MAT_NEAR(background, u_background, 1.0);
}
///////////////////////////////////////////////////////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_Update, Combine(
Values(UseGray(true),UseGray(false)),
Values(DetectShadow(true), DetectShadow(false)),
Values(UseFloat(false),UseFloat(true)))
);
OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_getBackgroundImage, Combine(
Values(DetectShadow(true), DetectShadow(false)),
Values(UseFloat(false),UseFloat(true)))
);
}}// namespace opencv_test::ocl
#endif

View File

@@ -0,0 +1,85 @@
/*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 "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test { namespace {
CV_ENUM(DIS_TestPresets, DISOpticalFlow::PRESET_ULTRAFAST, DISOpticalFlow::PRESET_FAST, DISOpticalFlow::PRESET_MEDIUM);
typedef ocl::TSTestWithParam<DIS_TestPresets> OCL_DenseOpticalFlow_DIS;
OCL_TEST_P(OCL_DenseOpticalFlow_DIS, Mat)
{
int preset = (int)GetParam();
Mat frame1, frame2, GT;
frame1 = imread(TS::ptr()->get_data_path() + "optflow/RubberWhale1.png");
frame2 = imread(TS::ptr()->get_data_path() + "optflow/RubberWhale2.png");
CV_Assert(!frame1.empty() && !frame2.empty());
cvtColor(frame1, frame1, COLOR_BGR2GRAY);
cvtColor(frame2, frame2, COLOR_BGR2GRAY);
{
Mat flow;
UMat ocl_flow;
Ptr<DenseOpticalFlow> algo = DISOpticalFlow::create(preset);
OCL_OFF(algo->calc(frame1, frame2, flow));
OCL_ON(algo->calc(frame1, frame2, ocl_flow));
ASSERT_EQ(flow.rows, ocl_flow.rows);
ASSERT_EQ(flow.cols, ocl_flow.cols);
EXPECT_MAT_SIMILAR(flow, ocl_flow, 6e-3);
}
}
OCL_INSTANTIATE_TEST_CASE_P(Video, OCL_DenseOpticalFlow_DIS,
DIS_TestPresets::all());
}} // namespace
#endif // HAVE_OPENCL

View File

@@ -0,0 +1,120 @@
/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Copyright (C) 2010-2012, Multicoreware, 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 "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
/////////////////////////////////////////////////////////////////////////////////////////////////
// FarnebackOpticalFlow
namespace
{
IMPLEMENT_PARAM_CLASS(PyrScale, double)
IMPLEMENT_PARAM_CLASS(PolyN, int)
CV_FLAGS(FarnebackOptFlowFlags, 0, OPTFLOW_FARNEBACK_GAUSSIAN)
IMPLEMENT_PARAM_CLASS(UseInitFlow, bool)
}
PARAM_TEST_CASE(FarnebackOpticalFlow, PyrScale, PolyN, FarnebackOptFlowFlags, UseInitFlow)
{
int numLevels;
int winSize;
int numIters;
double pyrScale;
int polyN;
int flags;
bool useInitFlow;
virtual void SetUp()
{
numLevels = 5;
winSize = 13;
numIters = 10;
pyrScale = GET_PARAM(0);
polyN = GET_PARAM(1);
flags = GET_PARAM(2);
useInitFlow = GET_PARAM(3);
}
};
OCL_TEST_P(FarnebackOpticalFlow, Mat)
{
cv::Mat frame0 = readImage("optflow/RubberWhale1.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame0.empty());
cv::Mat frame1 = readImage("optflow/RubberWhale2.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame1.empty());
double polySigma = polyN <= 5 ? 1.1 : 1.5;
cv::Mat flow; cv::UMat uflow;
if (useInitFlow)
{
OCL_ON(cv::calcOpticalFlowFarneback(frame0, frame1, uflow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
uflow.copyTo(flow);
flags |= cv::OPTFLOW_USE_INITIAL_FLOW;
}
OCL_OFF(cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
OCL_ON(cv::calcOpticalFlowFarneback(frame0, frame1, uflow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
EXPECT_MAT_SIMILAR(flow, uflow, 0.1);
}
OCL_INSTANTIATE_TEST_CASE_P(Video, FarnebackOpticalFlow,
Combine(
Values(PyrScale(0.3), PyrScale(0.5), PyrScale(0.8)),
Values(PolyN(5), PolyN(7)),
Values(FarnebackOptFlowFlags(0), FarnebackOptFlowFlags(cv::OPTFLOW_FARNEBACK_GAUSSIAN)),
Values(UseInitFlow(false), UseInitFlow(true))
)
);
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL

View File

@@ -0,0 +1,161 @@
/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Copyright (C) 2010-2012, Multicoreware, 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 "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test { namespace ocl {
/////////////////////////////////////////////////////////////////////////////////////////////////
// PyrLKOpticalFlow
PARAM_TEST_CASE(PyrLKOpticalFlow, int, int)
{
Size winSize;
int maxLevel;
TermCriteria criteria;
int flags;
double minEigThreshold;
virtual void SetUp()
{
winSize = Size(GET_PARAM(0), GET_PARAM(0));
maxLevel = GET_PARAM(1);
criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01);
flags = 0;
minEigThreshold = 1e-4f;
}
};
OCL_TEST_P(PyrLKOpticalFlow, Mat)
{
static const int npoints = 1000;
static const float eps = 0.03f;
static const float erreps = 0.1f;
cv::Mat frame0 = readImage("optflow/RubberWhale1.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame0.empty());
UMat umatFrame0; frame0.copyTo(umatFrame0);
cv::Mat frame1 = readImage("optflow/RubberWhale2.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(frame1.empty());
UMat umatFrame1; frame1.copyTo(umatFrame1);
// SKIP unstable tests
#ifdef __linux__
if (cvtest::skipUnstableTests && ocl::useOpenCL())
{
if (ocl::Device::getDefault().isIntel())
throw cvtest::SkipTestException("Skip unstable test");
}
#endif
std::vector<cv::Point2f> pts;
cv::goodFeaturesToTrack(frame0, pts, npoints, 0.01, 0.0);
std::vector<cv::Point2f> cpuNextPts;
std::vector<unsigned char> cpuStatusCPU;
std::vector<float> cpuErr;
OCL_OFF(cv::calcOpticalFlowPyrLK(frame0, frame1, pts, cpuNextPts, cpuStatusCPU, cpuErr, winSize, maxLevel, criteria, flags, minEigThreshold));
UMat umatNextPts, umatStatus, umatErr;
OCL_ON(cv::calcOpticalFlowPyrLK(umatFrame0, umatFrame1, pts, umatNextPts, umatStatus, umatErr, winSize, maxLevel, criteria, flags, minEigThreshold));
std::vector<cv::Point2f> nextPts; umatNextPts.reshape(2, 1).copyTo(nextPts);
std::vector<unsigned char> status; umatStatus.reshape(1, 1).copyTo(status);
std::vector<float> err; umatErr.reshape(1, 1).copyTo(err);
ASSERT_EQ(cpuNextPts.size(), nextPts.size());
ASSERT_EQ(cpuStatusCPU.size(), status.size());
size_t mistmatch = 0;
size_t errmatch = 0;
for (size_t i = 0; i < nextPts.size(); ++i)
{
if (status[i] != cpuStatusCPU[i])
{
++mistmatch;
continue;
}
if (status[i])
{
cv::Point2i a = nextPts[i];
cv::Point2i b = cpuNextPts[i];
bool eq = std::abs(a.x - b.x) < 1 && std::abs(a.y - b.y) < 1;
float errdiff = 0.0f;
if (!eq || errdiff > 1e-1)
{
++mistmatch;
continue;
}
eq = std::abs(cpuErr[i] - err[i]) <= (0.01 * std::max(1.0f, cpuErr[i]));
if(!eq)
++errmatch;
}
}
double bad_ratio = static_cast<double>(mistmatch) / (nextPts.size());
double err_ratio = static_cast<double>(errmatch) / (nextPts.size());
ASSERT_LE(bad_ratio, eps);
ASSERT_LE(err_ratio, erreps);
}
OCL_INSTANTIATE_TEST_CASE_P(Video, PyrLKOpticalFlow,
Combine(
Values(11, 15, 21, 25),
Values(3, 5)
)
);
}} // namespace
#endif // HAVE_OPENCL

View File

@@ -0,0 +1,175 @@
/*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 "test_precomp.hpp"
namespace opencv_test { namespace {
static string getDataDir() { return TS::ptr()->get_data_path(); }
static string getRubberWhaleFrame1() { return getDataDir() + "optflow/RubberWhale1.png"; }
static string getRubberWhaleFrame2() { return getDataDir() + "optflow/RubberWhale2.png"; }
static string getRubberWhaleGroundTruth() { return getDataDir() + "optflow/RubberWhale.flo"; }
static bool isFlowCorrect(float u) { return !cvIsNaN(u) && (fabs(u) < 1e9); }
static float calcRMSE(Mat flow1, Mat flow2)
{
float sum = 0;
int counter = 0;
const int rows = flow1.rows;
const int cols = flow1.cols;
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
Vec2f flow1_at_point = flow1.at<Vec2f>(y, x);
Vec2f flow2_at_point = flow2.at<Vec2f>(y, x);
float u1 = flow1_at_point[0];
float v1 = flow1_at_point[1];
float u2 = flow2_at_point[0];
float v2 = flow2_at_point[1];
if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2))
{
sum += (u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2);
counter++;
}
}
}
return (float)sqrt(sum / (1e-9 + counter));
}
bool readRubberWhale(Mat &dst_frame_1, Mat &dst_frame_2, Mat &dst_GT)
{
const string frame1_path = getRubberWhaleFrame1();
const string frame2_path = getRubberWhaleFrame2();
const string gt_flow_path = getRubberWhaleGroundTruth();
dst_frame_1 = imread(frame1_path);
dst_frame_2 = imread(frame2_path);
dst_GT = readOpticalFlow(gt_flow_path);
if (dst_frame_1.empty() || dst_frame_2.empty() || dst_GT.empty())
return false;
else
return true;
}
TEST(DenseOpticalFlow_DIS, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
int presets[] = {DISOpticalFlow::PRESET_ULTRAFAST, DISOpticalFlow::PRESET_FAST, DISOpticalFlow::PRESET_MEDIUM};
float target_RMSE[] = {0.86f, 0.74f, 0.49f};
cvtColor(frame1, frame1, COLOR_BGR2GRAY);
cvtColor(frame2, frame2, COLOR_BGR2GRAY);
Ptr<DenseOpticalFlow> algo;
// iterate over presets:
for (int i = 0; i < 3; i++)
{
Mat flow;
algo = DISOpticalFlow::create(presets[i]);
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), target_RMSE[i]);
}
}
TEST(DenseOpticalFlow_DIS, InvalidImgSize_CoarsestLevelLessThanZero)
{
cv::Ptr<cv::DISOpticalFlow> of = cv::DISOpticalFlow::create();
const int mat_size = 10;
cv::Mat x(mat_size, mat_size, CV_8UC1, 42);
cv::Mat y(mat_size, mat_size, CV_8UC1, 42);
cv::Mat flow;
ASSERT_THROW(of->calc(x, y, flow), cv::Exception);
}
// make sure that autoSelectPatchSizeAndScales() works properly.
TEST(DenseOpticalFlow_DIS, InvalidImgSize_CoarsestLevelLessThanFinestLevel)
{
cv::Ptr<cv::DISOpticalFlow> of = cv::DISOpticalFlow::create();
const int mat_size = 80;
cv::Mat x(mat_size, mat_size, CV_8UC1, 42);
cv::Mat y(mat_size, mat_size, CV_8UC1, 42);
cv::Mat flow;
of->calc(x, y, flow);
ASSERT_EQ(flow.rows, mat_size);
ASSERT_EQ(flow.cols, mat_size);
}
TEST(DenseOpticalFlow_VariationalRefinement, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
float target_RMSE = 0.86f;
cvtColor(frame1, frame1, COLOR_BGR2GRAY);
cvtColor(frame2, frame2, COLOR_BGR2GRAY);
Ptr<VariationalRefinement> var_ref;
var_ref = VariationalRefinement::create();
var_ref->setAlpha(20.0f);
var_ref->setDelta(5.0f);
var_ref->setGamma(10.0f);
var_ref->setSorIterations(25);
var_ref->setFixedPointIterations(25);
Mat flow(frame1.size(), CV_32FC2);
flow.setTo(0.0f);
var_ref->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
}
}} // namespace

View File

@@ -0,0 +1,160 @@
/*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 "test_precomp.hpp"
namespace opencv_test { namespace {
typedef tuple<Size> OFParams;
typedef TestWithParam<OFParams> DenseOpticalFlow_DIS;
typedef TestWithParam<OFParams> DenseOpticalFlow_VariationalRefinement;
TEST_P(DenseOpticalFlow_DIS, MultithreadReproducibility)
{
double MAX_DIF = 0.01;
double MAX_MEAN_DIF = 0.001;
int loopsCount = 2;
RNG rng(0);
OFParams params = GetParam();
Size size = get<0>(params);
int nThreads = cv::getNumThreads();
if (nThreads == 1)
throw SkipTestException("Single thread environment");
for (int iter = 0; iter <= loopsCount; iter++)
{
Mat frame1(size, CV_8U);
randu(frame1, 0, 255);
Mat frame2(size, CV_8U);
randu(frame2, 0, 255);
Ptr<DISOpticalFlow> algo = DISOpticalFlow::create();
int psz = rng.uniform(4, 16);
int pstr = rng.uniform(1, psz - 1);
int grad_iter = rng.uniform(1, 64);
int var_iter = rng.uniform(0, 10);
bool use_mean_normalization = !!rng.uniform(0, 2);
bool use_spatial_propagation = !!rng.uniform(0, 2);
algo->setFinestScale(0);
algo->setPatchSize(psz);
algo->setPatchStride(pstr);
algo->setGradientDescentIterations(grad_iter);
algo->setVariationalRefinementIterations(var_iter);
algo->setUseMeanNormalization(use_mean_normalization);
algo->setUseSpatialPropagation(use_spatial_propagation);
cv::setNumThreads(nThreads);
Mat resMultiThread;
algo->calc(frame1, frame2, resMultiThread);
cv::setNumThreads(1);
Mat resSingleThread;
algo->calc(frame1, frame2, resSingleThread);
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF);
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_L1), MAX_MEAN_DIF * frame1.total());
// resulting flow should be within the frame bounds:
double min_val, max_val;
minMaxLoc(resMultiThread, &min_val, &max_val);
EXPECT_LE(abs(min_val), sqrt( static_cast<double>(size.height * size.height + size.width * size.width)) );
EXPECT_LE(abs(max_val), sqrt( static_cast<double>(size.height * size.height + size.width * size.width)) );
}
}
INSTANTIATE_TEST_CASE_P(FullSet, DenseOpticalFlow_DIS, Values(szODD, szQVGA));
TEST_P(DenseOpticalFlow_VariationalRefinement, MultithreadReproducibility)
{
double MAX_DIF = 0.01;
double MAX_MEAN_DIF = 0.001;
float input_flow_rad = 5.0;
int loopsCount = 2;
RNG rng(0);
OFParams params = GetParam();
Size size = get<0>(params);
int nThreads = cv::getNumThreads();
if (nThreads == 1)
throw SkipTestException("Single thread environment");
for (int iter = 0; iter <= loopsCount; iter++)
{
Mat frame1(size, CV_8U);
randu(frame1, 0, 255);
Mat frame2(size, CV_8U);
randu(frame2, 0, 255);
Mat flow(size, CV_32FC2);
randu(flow, -input_flow_rad, input_flow_rad);
Ptr<VariationalRefinement> var = VariationalRefinement::create();
var->setAlpha(rng.uniform(1.0f, 100.0f));
var->setGamma(rng.uniform(0.1f, 10.0f));
var->setDelta(rng.uniform(0.1f, 10.0f));
var->setSorIterations(rng.uniform(1, 20));
var->setFixedPointIterations(rng.uniform(1, 20));
var->setOmega(rng.uniform(1.01f, 1.99f));
cv::setNumThreads(nThreads);
Mat resMultiThread;
flow.copyTo(resMultiThread);
var->calc(frame1, frame2, resMultiThread);
cv::setNumThreads(1);
Mat resSingleThread;
flow.copyTo(resSingleThread);
var->calc(frame1, frame2, resSingleThread);
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF);
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_L1), MAX_MEAN_DIF * frame1.total());
// resulting flow should be within the frame bounds:
double min_val, max_val;
minMaxLoc(resMultiThread, &min_val, &max_val);
EXPECT_LE(abs(min_val), sqrt( static_cast<double>(size.height * size.height + size.width * size.width)) );
EXPECT_LE(abs(max_val), sqrt( static_cast<double>(size.height * size.height + size.width * size.width)) );
}
}
INSTANTIATE_TEST_CASE_P(FullSet, DenseOpticalFlow_VariationalRefinement, Values(szODD, szQVGA));
}} // namespace

View File

@@ -0,0 +1,249 @@
/*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 "test_precomp.hpp"
#include "opencv2/imgproc/imgproc_c.h"
namespace opencv_test { namespace {
class CV_AccumBaseTest : public cvtest::ArrayTest
{
public:
CV_AccumBaseTest();
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
double get_success_error_level( int test_case_idx, int i, int j );
double alpha;
};
CV_AccumBaseTest::CV_AccumBaseTest()
{
test_array[INPUT].push_back(NULL);
test_array[INPUT_OUTPUT].push_back(NULL);
test_array[REF_INPUT_OUTPUT].push_back(NULL);
test_array[MASK].push_back(NULL);
optional_mask = true;
element_wise_relative_error = false;
} // ctor
void CV_AccumBaseTest::get_test_array_types_and_sizes( int test_case_idx,
vector<vector<Size> >& sizes, vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
int depth = cvtest::randInt(rng) % 4, cn = cvtest::randInt(rng) & 1 ? 3 : 1;
int accdepth = (int)(cvtest::randInt(rng) % 2 + 1);
int i, input_count = (int)test_array[INPUT].size();
cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_32F : CV_64F;
accdepth = accdepth == 1 ? CV_32F : CV_64F;
accdepth = MAX(accdepth, depth);
for( i = 0; i < input_count; i++ )
types[INPUT][i] = CV_MAKETYPE(depth,cn);
types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(accdepth,cn);
alpha = cvtest::randReal(rng);
}
double CV_AccumBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
{
return test_mat[INPUT_OUTPUT][0].depth() < CV_64F ||
test_mat[INPUT][0].depth() == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000;
}
/// acc
class CV_AccTest : public CV_AccumBaseTest
{
public:
CV_AccTest() { }
protected:
void run_func();
void prepare_to_validation( int );
};
void CV_AccTest::run_func(void)
{
cvAcc( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
}
void CV_AccTest::prepare_to_validation( int )
{
const Mat& src = test_mat[INPUT][0];
Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
Mat temp;
cvtest::add( src, 1, dst, 1, cvScalarAll(0.), temp, dst.type() );
cvtest::copy( temp, dst, mask );
}
/// square acc
class CV_SquareAccTest : public CV_AccumBaseTest
{
public:
CV_SquareAccTest();
protected:
void run_func();
void prepare_to_validation( int );
};
CV_SquareAccTest::CV_SquareAccTest()
{
}
void CV_SquareAccTest::run_func()
{
cvSquareAcc( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
}
void CV_SquareAccTest::prepare_to_validation( int )
{
const Mat& src = test_mat[INPUT][0];
Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
Mat temp;
cvtest::convert( src, temp, dst.type() );
cvtest::multiply( temp, temp, temp, 1 );
cvtest::add( temp, 1, dst, 1, cvScalarAll(0.), temp, dst.depth() );
cvtest::copy( temp, dst, mask );
}
/// multiply acc
class CV_MultiplyAccTest : public CV_AccumBaseTest
{
public:
CV_MultiplyAccTest();
protected:
void run_func();
void prepare_to_validation( int );
};
CV_MultiplyAccTest::CV_MultiplyAccTest()
{
test_array[INPUT].push_back(NULL);
}
void CV_MultiplyAccTest::run_func()
{
cvMultiplyAcc( test_array[INPUT][0], test_array[INPUT][1],
test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
}
void CV_MultiplyAccTest::prepare_to_validation( int )
{
const Mat& src1 = test_mat[INPUT][0];
const Mat& src2 = test_mat[INPUT][1];
Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
Mat temp1, temp2;
cvtest::convert( src1, temp1, dst.type() );
cvtest::convert( src2, temp2, dst.type() );
cvtest::multiply( temp1, temp2, temp1, 1 );
cvtest::add( temp1, 1, dst, 1, cvScalarAll(0.), temp1, dst.depth() );
cvtest::copy( temp1, dst, mask );
}
/// running average
class CV_RunningAvgTest : public CV_AccumBaseTest
{
public:
CV_RunningAvgTest();
protected:
void run_func();
void prepare_to_validation( int );
};
CV_RunningAvgTest::CV_RunningAvgTest()
{
}
void CV_RunningAvgTest::run_func()
{
cvRunningAvg( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
alpha, test_array[MASK][0] );
}
void CV_RunningAvgTest::prepare_to_validation( int )
{
const Mat& src = test_mat[INPUT][0];
Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
Mat temp;
const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
double a[1], b[1];
int accdepth = test_mat[INPUT_OUTPUT][0].depth();
CvMat A = cvMat(1,1,accdepth,a), B = cvMat(1,1,accdepth,b);
cvSetReal1D( &A, 0, alpha);
cvSetReal1D( &B, 0, 1 - cvGetReal1D(&A, 0));
cvtest::convert( src, temp, dst.type() );
cvtest::add( src, cvGetReal1D(&A, 0), dst, cvGetReal1D(&B, 0), cvScalarAll(0.), temp, temp.depth() );
cvtest::copy( temp, dst, mask );
}
TEST(Video_Acc, accuracy) { CV_AccTest test; test.safe_run(); }
TEST(Video_AccSquared, accuracy) { CV_SquareAccTest test; test.safe_run(); }
TEST(Video_AccProduct, accuracy) { CV_MultiplyAccTest test; test.safe_run(); }
TEST(Video_RunningAvg, accuracy) { CV_RunningAvgTest test; test.safe_run(); }
}} // namespace

View File

@@ -0,0 +1,466 @@
/*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 "test_precomp.hpp"
#include "opencv2/video/tracking.hpp"
namespace opencv_test { namespace {
using namespace cv;
class CV_TrackBaseTest : public cvtest::BaseTest
{
public:
CV_TrackBaseTest();
virtual ~CV_TrackBaseTest();
void clear();
protected:
int read_params( const cv::FileStorage& fs );
void run_func(void);
int prepare_test_case( int test_case_idx );
int validate_test_results( int test_case_idx );
void generate_object();
int min_log_size, max_log_size;
Mat img;
RotatedRect box0;
Size img_size;
TermCriteria criteria;
int img_type;
};
CV_TrackBaseTest::CV_TrackBaseTest()
{
img = 0;
test_case_count = 100;
min_log_size = 5;
max_log_size = 8;
}
CV_TrackBaseTest::~CV_TrackBaseTest()
{
clear();
}
void CV_TrackBaseTest::clear()
{
img.release();
cvtest::BaseTest::clear();
}
int CV_TrackBaseTest::read_params( const cv::FileStorage& fs )
{
int code = cvtest::BaseTest::read_params( fs );
if( code < 0 )
return code;
read( find_param( fs, "test_case_count" ), test_case_count, test_case_count );
read( find_param( fs, "min_log_size" ), min_log_size, min_log_size );
read( find_param( fs, "max_log_size" ), max_log_size, max_log_size );
min_log_size = cvtest::clipInt( min_log_size, 1, 10 );
max_log_size = cvtest::clipInt( max_log_size, 1, 10 );
if( min_log_size > max_log_size )
{
std::swap( min_log_size, max_log_size );
}
return 0;
}
void CV_TrackBaseTest::generate_object()
{
int x, y;
double cx = box0.center.x;
double cy = box0.center.y;
double width = box0.size.width*0.5;
double height = box0.size.height*0.5;
double angle = box0.angle*CV_PI/180.;
double a = sin(angle), b = -cos(angle);
double inv_ww = 1./(width*width), inv_hh = 1./(height*height);
img = Mat::zeros( img_size.height, img_size.width, img_type );
// use the straightforward algorithm: for every pixel check if it is inside the ellipse
for( y = 0; y < img_size.height; y++ )
{
uchar* ptr = img.ptr(y);
float* fl = (float*)ptr;
double x_ = (y - cy)*b, y_ = (y - cy)*a;
for( x = 0; x < img_size.width; x++ )
{
double x1 = (x - cx)*a - x_;
double y1 = (x - cx)*b + y_;
if( x1*x1*inv_hh + y1*y1*inv_ww <= 1. )
{
if( img_type == CV_8U )
ptr[x] = (uchar)1;
else
fl[x] = (float)1.f;
}
}
}
}
int CV_TrackBaseTest::prepare_test_case( int test_case_idx )
{
RNG& rng = ts->get_rng();
cvtest::BaseTest::prepare_test_case( test_case_idx );
float m;
clear();
box0.size.width = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
box0.size.height = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
box0.angle = (float)(cvtest::randReal(rng)*180.);
if( box0.size.width > box0.size.height )
{
std::swap( box0.size.width, box0.size.height );
}
m = MAX( box0.size.width, box0.size.height );
img_size.width = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
img_size.height = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
img_type = cvtest::randInt(rng) % 2 ? CV_32F : CV_8U;
img_type = CV_8U;
box0.center.x = (float)(img_size.width*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.width - m));
box0.center.y = (float)(img_size.height*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.height - m));
criteria = TermCriteria( TermCriteria::EPS + TermCriteria::MAX_ITER, 10, 0.1 );
generate_object();
return 1;
}
void CV_TrackBaseTest::run_func(void)
{
}
int CV_TrackBaseTest::validate_test_results( int /*test_case_idx*/ )
{
return 0;
}
///////////////////////// CamShift //////////////////////////////
class CV_CamShiftTest : public CV_TrackBaseTest
{
public:
CV_CamShiftTest();
protected:
void run_func(void);
int prepare_test_case( int test_case_idx );
int validate_test_results( int test_case_idx );
void generate_object();
RotatedRect box;
Rect init_rect;
int area0;
};
CV_CamShiftTest::CV_CamShiftTest()
{
}
int CV_CamShiftTest::prepare_test_case( int test_case_idx )
{
RNG& rng = ts->get_rng();
double m;
int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
int i, area;
if( code <= 0 )
return code;
area0 = countNonZero(img);
for(i = 0; i < 100; i++)
{
m = MAX(box0.size.width,box0.size.height)*0.8;
init_rect.x = cvFloor(box0.center.x - m*(0.45 + cvtest::randReal(rng)*0.2));
init_rect.y = cvFloor(box0.center.y - m*(0.45 + cvtest::randReal(rng)*0.2));
init_rect.width = cvCeil(box0.center.x + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.x);
init_rect.height = cvCeil(box0.center.y + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.y);
if( init_rect.x < 0 || init_rect.y < 0 ||
init_rect.x + init_rect.width >= img_size.width ||
init_rect.y + init_rect.height >= img_size.height )
continue;
Mat temp = img(init_rect);
area = countNonZero( temp );
if( area >= 0.1*area0 )
break;
}
return i < 100 ? code : 0;
}
void CV_CamShiftTest::run_func(void)
{
box = CamShift( img, init_rect, criteria );
}
int CV_CamShiftTest::validate_test_results( int /*test_case_idx*/ )
{
int code = cvtest::TS::OK;
double m = MAX(box0.size.width, box0.size.height);
double diff_angle;
if( cvIsNaN(box.size.width) || cvIsInf(box.size.width) || box.size.width <= 0 ||
cvIsNaN(box.size.height) || cvIsInf(box.size.height) || box.size.height <= 0 ||
cvIsNaN(box.center.x) || cvIsInf(box.center.x) ||
cvIsNaN(box.center.y) || cvIsInf(box.center.y) ||
cvIsNaN(box.angle) || cvIsInf(box.angle) || box.angle < -180 || box.angle > 180 )
{
ts->printf( cvtest::TS::LOG, "Invalid CvBox2D or CvConnectedComp was returned by cvCamShift\n" );
code = cvtest::TS::FAIL_INVALID_OUTPUT;
goto _exit_;
}
box.angle = (float)(180 - box.angle);
if( fabs(box.size.width - box0.size.width) > box0.size.width*0.2 ||
fabs(box.size.height - box0.size.height) > box0.size.height*0.3 )
{
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D size (=%.1f x %.1f, should be %.1f x %.1f)\n",
box.size.width, box.size.height, box0.size.width, box0.size.height );
code = cvtest::TS::FAIL_BAD_ACCURACY;
goto _exit_;
}
if( fabs(box.center.x - box0.center.x) > m*0.1 ||
fabs(box.center.y - box0.center.y) > m*0.1 )
{
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
box.center.x, box.center.y, box0.center.x, box0.center.y );
code = cvtest::TS::FAIL_BAD_ACCURACY;
goto _exit_;
}
if( box.angle < 0 )
box.angle += 180;
diff_angle = fabs(box0.angle - box.angle);
diff_angle = MIN( diff_angle, fabs(box0.angle - box.angle + 180));
if( fabs(diff_angle) > 30 && box0.size.height > box0.size.width*1.2 )
{
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D angle (=%1.f, should be %1.f)\n",
box.angle, box0.angle );
code = cvtest::TS::FAIL_BAD_ACCURACY;
goto _exit_;
}
_exit_:
if( code < 0 )
{
#if 0 //defined _DEBUG && defined _WIN32
IplImage* dst = cvCreateImage( img_size, 8, 3 );
cvNamedWindow( "test", 1 );
cvCmpS( img, 0, img, CV_CMP_GT );
cvCvtColor( img, dst, CV_GRAY2BGR );
cvRectangle( dst, cvPoint(init_rect.x, init_rect.y),
cvPoint(init_rect.x + init_rect.width, init_rect.y + init_rect.height),
CV_RGB(255,0,0), 3, 8, 0 );
cvEllipseBox( dst, box, CV_RGB(0,255,0), 3, 8, 0 );
cvShowImage( "test", dst );
cvReleaseImage( &dst );
cvWaitKey();
#endif
ts->set_failed_test_info( code );
}
return code;
}
///////////////////////// MeanShift //////////////////////////////
class CV_MeanShiftTest : public CV_TrackBaseTest
{
public:
CV_MeanShiftTest();
protected:
void run_func(void);
int prepare_test_case( int test_case_idx );
int validate_test_results( int test_case_idx );
void generate_object();
Rect init_rect, rect;
int area0, area;
};
CV_MeanShiftTest::CV_MeanShiftTest()
{
}
int CV_MeanShiftTest::prepare_test_case( int test_case_idx )
{
RNG& rng = ts->get_rng();
double m;
int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
int i;
if( code <= 0 )
return code;
area0 = countNonZero(img);
for(i = 0; i < 100; i++)
{
m = (box0.size.width + box0.size.height)*0.5;
init_rect.x = cvFloor(box0.center.x - m*(0.4 + cvtest::randReal(rng)*0.2));
init_rect.y = cvFloor(box0.center.y - m*(0.4 + cvtest::randReal(rng)*0.2));
init_rect.width = cvCeil(box0.center.x + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.x);
init_rect.height = cvCeil(box0.center.y + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.y);
if( init_rect.x < 0 || init_rect.y < 0 ||
init_rect.x + init_rect.width >= img_size.width ||
init_rect.y + init_rect.height >= img_size.height )
continue;
Mat temp = img(init_rect);
area = countNonZero( temp );
if( area >= 0.5*area0 )
break;
}
return i < 100 ? code : 0;
}
void CV_MeanShiftTest::run_func(void)
{
rect = init_rect;
meanShift( img, rect, criteria );
}
int CV_MeanShiftTest::validate_test_results( int /*test_case_idx*/ )
{
int code = cvtest::TS::OK;
Point2f c;
double m = MAX(box0.size.width, box0.size.height), delta;
c.x = (float)(rect.x + rect.width*0.5);
c.y = (float)(rect.y + rect.height*0.5);
if( fabs(c.x - box0.center.x) > m*0.1 ||
fabs(c.y - box0.center.y) > m*0.1 )
{
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
c.x, c.y, box0.center.x, box0.center.y );
code = cvtest::TS::FAIL_BAD_ACCURACY;
goto _exit_;
}
delta = m*0.7;
if( rect.x < box0.center.x - delta ||
rect.y < box0.center.y - delta ||
rect.x + rect.width > box0.center.x + delta ||
rect.y + rect.height > box0.center.y + delta )
{
ts->printf( cvtest::TS::LOG,
"Incorrect CvConnectedComp ((%d,%d,%d,%d) is not within (%.1f,%.1f,%.1f,%.1f))\n",
rect.x, rect.y, rect.x + rect.width, rect.y + rect.height,
box0.center.x - delta, box0.center.y - delta, box0.center.x + delta, box0.center.y + delta );
code = cvtest::TS::FAIL_BAD_ACCURACY;
}
_exit_:
if( code < 0 )
{
#if 0// defined _DEBUG && defined _WIN32
IplImage* dst = cvCreateImage( img_size, 8, 3 );
cvNamedWindow( "test", 1 );
cvCmpS( img, 0, img, CV_CMP_GT );
cvCvtColor( img, dst, CV_GRAY2BGR );
cvRectangle( dst, cvPoint(init_rect.x, init_rect.y),
cvPoint(init_rect.x + init_rect.width, init_rect.y + init_rect.height),
CV_RGB(255,0,0), 3, 8, 0 );
cvRectangle( dst, cvPoint(comp.rect.x, comp.rect.y),
cvPoint(comp.rect.x + comp.rect.width, comp.rect.y + comp.rect.height),
CV_RGB(0,255,0), 3, 8, 0 );
cvShowImage( "test", dst );
cvReleaseImage( &dst );
cvWaitKey();
#endif
ts->set_failed_test_info( code );
}
return code;
}
TEST(Video_CAMShift, accuracy) { CV_CamShiftTest test; test.safe_run(); }
TEST(Video_MeanShift, accuracy) { CV_MeanShiftTest test; test.safe_run(); }
}} // namespace
/* End of file. */

View File

@@ -0,0 +1,522 @@
/*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"
namespace opencv_test { namespace {
class CV_ECC_BaseTest : public cvtest::BaseTest
{
public:
CV_ECC_BaseTest();
protected:
double computeRMS(const Mat& mat1, const Mat& mat2);
bool isMapCorrect(const Mat& mat);
double MAX_RMS_ECC;//upper bound for RMS error
int ntests;//number of tests per motion type
int ECC_iterations;//number of iterations for ECC
double ECC_epsilon; //we choose a negative value, so that
// ECC_iterations are always executed
};
CV_ECC_BaseTest::CV_ECC_BaseTest()
{
MAX_RMS_ECC=0.1;
ntests = 3;
ECC_iterations = 50;
ECC_epsilon = -1; //-> negative value means that ECC_Iterations will be executed
}
bool CV_ECC_BaseTest::isMapCorrect(const Mat& map)
{
bool tr = true;
float mapVal;
for(int i =0; i<map.rows; i++)
for(int j=0; j<map.cols; j++){
mapVal = map.at<float>(i, j);
tr = tr & (!cvIsNaN(mapVal) && (fabs(mapVal) < 1e9));
}
return tr;
}
double CV_ECC_BaseTest::computeRMS(const Mat& mat1, const Mat& mat2){
CV_Assert(mat1.rows == mat2.rows);
CV_Assert(mat1.cols == mat2.cols);
Mat errorMat;
subtract(mat1, mat2, errorMat);
return sqrt(errorMat.dot(errorMat)/(mat1.rows*mat1.cols));
}
class CV_ECC_Test_Translation : public CV_ECC_BaseTest
{
public:
CV_ECC_Test_Translation();
protected:
void run(int);
bool testTranslation(int);
};
CV_ECC_Test_Translation::CV_ECC_Test_Translation(){}
bool CV_ECC_Test_Translation::testTranslation(int from)
{
Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0);
if (img.empty())
{
ts->printf( ts->LOG, "test image can not be read");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return false;
}
Mat testImg;
resize(img, testImg, Size(216, 216), 0, 0, INTER_LINEAR_EXACT);
cv::RNG rng = ts->get_rng();
int progress=0;
for (int k=from; k<ntests; k++){
ts->update_context( this, k, true );
progress = update_progress(progress, k, ntests, 0);
Mat translationGround = (Mat_<float>(2,3) << 1, 0, (rng.uniform(10.f, 20.f)),
0, 1, (rng.uniform(10.f, 20.f)));
Mat warpedImage;
warpAffine(testImg, warpedImage, translationGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
Mat mapTranslation = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0);
findTransformECC(warpedImage, testImg, mapTranslation, 0,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon));
if (!isMapCorrect(mapTranslation)){
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return false;
}
if (computeRMS(mapTranslation, translationGround)>MAX_RMS_ECC){
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( ts->LOG, "RMS = %f",
computeRMS(mapTranslation, translationGround));
return false;
}
}
return true;
}
void CV_ECC_Test_Translation::run(int from)
{
if (!testTranslation(from))
return;
ts->set_failed_test_info(cvtest::TS::OK);
}
class CV_ECC_Test_Euclidean : public CV_ECC_BaseTest
{
public:
CV_ECC_Test_Euclidean();
protected:
void run(int);
bool testEuclidean(int);
};
CV_ECC_Test_Euclidean::CV_ECC_Test_Euclidean() { }
bool CV_ECC_Test_Euclidean::testEuclidean(int from)
{
Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0);
if (img.empty())
{
ts->printf( ts->LOG, "test image can not be read");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return false;
}
Mat testImg;
resize(img, testImg, Size(216, 216), 0, 0, INTER_LINEAR_EXACT);
cv::RNG rng = ts->get_rng();
int progress = 0;
for (int k=from; k<ntests; k++){
ts->update_context( this, k, true );
progress = update_progress(progress, k, ntests, 0);
double angle = CV_PI/30 + CV_PI*rng.uniform((double)-2.f, (double)2.f)/180;
Mat euclideanGround = (Mat_<float>(2,3) << cos(angle), -sin(angle), (rng.uniform(10.f, 20.f)),
sin(angle), cos(angle), (rng.uniform(10.f, 20.f)));
Mat warpedImage;
warpAffine(testImg, warpedImage, euclideanGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
Mat mapEuclidean = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0);
findTransformECC(warpedImage, testImg, mapEuclidean, 1,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon));
if (!isMapCorrect(mapEuclidean)){
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return false;
}
if (computeRMS(mapEuclidean, euclideanGround)>MAX_RMS_ECC){
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( ts->LOG, "RMS = %f",
computeRMS(mapEuclidean, euclideanGround));
return false;
}
}
return true;
}
void CV_ECC_Test_Euclidean::run(int from)
{
if (!testEuclidean(from))
return;
ts->set_failed_test_info(cvtest::TS::OK);
}
class CV_ECC_Test_Affine : public CV_ECC_BaseTest
{
public:
CV_ECC_Test_Affine();
protected:
void run(int);
bool testAffine(int);
};
CV_ECC_Test_Affine::CV_ECC_Test_Affine(){}
bool CV_ECC_Test_Affine::testAffine(int from)
{
Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0);
if (img.empty())
{
ts->printf( ts->LOG, "test image can not be read");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return false;
}
Mat testImg;
resize(img, testImg, Size(216, 216), 0, 0, INTER_LINEAR_EXACT);
cv::RNG rng = ts->get_rng();
int progress = 0;
for (int k=from; k<ntests; k++){
ts->update_context( this, k, true );
progress = update_progress(progress, k, ntests, 0);
Mat affineGround = (Mat_<float>(2,3) << (1-rng.uniform(-0.05f, 0.05f)),
(rng.uniform(-0.03f, 0.03f)), (rng.uniform(10.f, 20.f)),
(rng.uniform(-0.03f, 0.03f)), (1-rng.uniform(-0.05f, 0.05f)),
(rng.uniform(10.f, 20.f)));
Mat warpedImage;
warpAffine(testImg, warpedImage, affineGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
Mat mapAffine = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0);
findTransformECC(warpedImage, testImg, mapAffine, 2,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon));
if (!isMapCorrect(mapAffine)){
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return false;
}
if (computeRMS(mapAffine, affineGround)>MAX_RMS_ECC){
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( ts->LOG, "RMS = %f",
computeRMS(mapAffine, affineGround));
return false;
}
}
return true;
}
void CV_ECC_Test_Affine::run(int from)
{
if (!testAffine(from))
return;
ts->set_failed_test_info(cvtest::TS::OK);
}
class CV_ECC_Test_Homography : public CV_ECC_BaseTest
{
public:
CV_ECC_Test_Homography();
protected:
void run(int);
bool testHomography(int);
};
CV_ECC_Test_Homography::CV_ECC_Test_Homography(){}
bool CV_ECC_Test_Homography::testHomography(int from)
{
Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0);
if (img.empty())
{
ts->printf( ts->LOG, "test image can not be read");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return false;
}
Mat testImg;
resize(img, testImg, Size(216, 216), 0, 0, INTER_LINEAR_EXACT);
cv::RNG rng = ts->get_rng();
int progress = 0;
for (int k=from; k<ntests; k++){
ts->update_context( this, k, true );
progress = update_progress(progress, k, ntests, 0);
Mat homoGround = (Mat_<float>(3,3) << (1-rng.uniform(-0.05f, 0.05f)),
(rng.uniform(-0.03f, 0.03f)), (rng.uniform(10.f, 20.f)),
(rng.uniform(-0.03f, 0.03f)), (1-rng.uniform(-0.05f, 0.05f)),(rng.uniform(10.f, 20.f)),
(rng.uniform(0.0001f, 0.0003f)), (rng.uniform(0.0001f, 0.0003f)), 1.f);
Mat warpedImage;
warpPerspective(testImg, warpedImage, homoGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
Mat mapHomography = Mat::eye(3, 3, CV_32F);
findTransformECC(warpedImage, testImg, mapHomography, 3,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon));
if (!isMapCorrect(mapHomography)){
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return false;
}
if (computeRMS(mapHomography, homoGround)>MAX_RMS_ECC){
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( ts->LOG, "RMS = %f",
computeRMS(mapHomography, homoGround));
return false;
}
}
return true;
}
void CV_ECC_Test_Homography::run(int from)
{
if (!testHomography(from))
return;
ts->set_failed_test_info(cvtest::TS::OK);
}
class CV_ECC_Test_Mask : public CV_ECC_BaseTest
{
public:
CV_ECC_Test_Mask();
protected:
void run(int);
bool testMask(int);
};
CV_ECC_Test_Mask::CV_ECC_Test_Mask(){}
bool CV_ECC_Test_Mask::testMask(int from)
{
Mat img = imread( string(ts->get_data_path()) + "shared/fruits.png", 0);
if (img.empty())
{
ts->printf( ts->LOG, "test image can not be read");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return false;
}
Mat scaledImage;
resize(img, scaledImage, Size(216, 216), 0, 0, INTER_LINEAR_EXACT );
Mat_<float> testImg;
scaledImage.convertTo(testImg, testImg.type());
cv::RNG rng = ts->get_rng();
int progress=0;
for (int k=from; k<ntests; k++){
ts->update_context( this, k, true );
progress = update_progress(progress, k, ntests, 0);
Mat translationGround = (Mat_<float>(2,3) << 1, 0, (rng.uniform(10.f, 20.f)),
0, 1, (rng.uniform(10.f, 20.f)));
Mat warpedImage;
warpAffine(testImg, warpedImage, translationGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
Mat mapTranslation = (Mat_<float>(2,3) << 1, 0, 0, 0, 1, 0);
Mat_<unsigned char> mask = Mat_<unsigned char>::ones(testImg.rows, testImg.cols);
for (int i=testImg.rows*2/3; i<testImg.rows; i++) {
for (int j=testImg.cols*2/3; j<testImg.cols; j++) {
testImg(i, j) = 0;
mask(i, j) = 0;
}
}
findTransformECC(warpedImage, testImg, mapTranslation, 0,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon), mask);
if (!isMapCorrect(mapTranslation)){
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return false;
}
if (computeRMS(mapTranslation, translationGround)>MAX_RMS_ECC){
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( ts->LOG, "RMS = %f",
computeRMS(mapTranslation, translationGround));
return false;
}
// Test with non-default gaussian blur.
findTransformECC(warpedImage, testImg, mapTranslation, 0,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon), mask, 1);
if (!isMapCorrect(mapTranslation)){
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return false;
}
if (computeRMS(mapTranslation, translationGround)>MAX_RMS_ECC){
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( ts->LOG, "RMS = %f",
computeRMS(mapTranslation, translationGround));
return false;
}
}
return true;
}
void CV_ECC_Test_Mask::run(int from)
{
if (!testMask(from))
return;
ts->set_failed_test_info(cvtest::TS::OK);
}
TEST(Video_ECC_Test_Compute, accuracy)
{
Mat testImg = (Mat_<float>(3, 3) << 1, 0, 0, 1, 0, 0, 1, 0, 0);
Mat warpedImage = (Mat_<float>(3, 3) << 0, 1, 0, 0, 1, 0, 0, 1, 0);
Mat_<unsigned char> mask = Mat_<unsigned char>::ones(testImg.rows, testImg.cols);
double ecc = computeECC(warpedImage, testImg, mask);
EXPECT_NEAR(ecc, -0.5f, 1e-5f);
}
TEST(Video_ECC_Test_Compute, bug_14657)
{
/*
* Simple test case - a 2 x 2 matrix with 10, 10, 10, 6. When the mean (36 / 4 = 9) is subtracted,
* it results in 1, 1, 1, 0 for the unsigned int case - compare to 1, 1, 1, -3 in the signed case.
* For this reason, when the same matrix was provided as the input and the template, we didn't get 1 as expected.
*/
Mat img = (Mat_<uint8_t>(2, 2) << 10, 10, 10, 6);
EXPECT_NEAR(computeECC(img, img), 1.0f, 1e-5f);
}
TEST(Video_ECC_Translation, accuracy) { CV_ECC_Test_Translation test; test.safe_run();}
TEST(Video_ECC_Euclidean, accuracy) { CV_ECC_Test_Euclidean test; test.safe_run(); }
TEST(Video_ECC_Affine, accuracy) { CV_ECC_Test_Affine test; test.safe_run(); }
TEST(Video_ECC_Homography, accuracy) { CV_ECC_Test_Homography test; test.safe_run(); }
TEST(Video_ECC_Mask, accuracy) { CV_ECC_Test_Mask test; test.safe_run(); }
}} // namespace

View File

@@ -0,0 +1,184 @@
/*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"
// this is test for a deprecated function. let's ignore deprecated warnings in this file
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning( disable : 4996)
#endif
namespace opencv_test { namespace {
class CV_RigidTransform_Test : public cvtest::BaseTest
{
public:
CV_RigidTransform_Test();
~CV_RigidTransform_Test();
protected:
void run(int);
bool testNPoints(int);
bool testImage();
};
CV_RigidTransform_Test::CV_RigidTransform_Test()
{
}
CV_RigidTransform_Test::~CV_RigidTransform_Test() {}
struct WrapAff2D
{
const double *F;
WrapAff2D(const Mat& aff) : F(aff.ptr<double>()) {}
Point2f operator()(const Point2f& p)
{
return Point2f( (float)(p.x * F[0] + p.y * F[1] + F[2]),
(float)(p.x * F[3] + p.y * F[4] + F[5]) );
}
};
bool CV_RigidTransform_Test::testNPoints(int from)
{
cv::RNG rng = ts->get_rng();
int progress = 0;
int k, ntests = 10000;
for( k = from; k < ntests; k++ )
{
ts->update_context( this, k, true );
progress = update_progress(progress, k, ntests, 0);
Mat aff(2, 3, CV_64F);
rng.fill(aff, RNG::UNIFORM, Scalar(-2), Scalar(2));
int n = (unsigned)rng % 100 + 10;
Mat fpts(1, n, CV_32FC2);
Mat tpts(1, n, CV_32FC2);
rng.fill(fpts, RNG::UNIFORM, Scalar(0,0), Scalar(10,10));
std::transform(fpts.ptr<Point2f>(), fpts.ptr<Point2f>() + n, tpts.ptr<Point2f>(), WrapAff2D(aff));
Mat noise(1, n, CV_32FC2);
rng.fill(noise, RNG::NORMAL, Scalar::all(0), Scalar::all(0.001*(n<=7 ? 0 : n <= 30 ? 1 : 10)));
tpts += noise;
Mat aff_est = estimateRigidTransform(fpts, tpts, true);
double thres = 0.1*cvtest::norm(aff, NORM_L2);
double d = cvtest::norm(aff_est, aff, NORM_L2);
if (d > thres)
{
double dB=0, nB=0;
if (n <= 4)
{
Mat A = fpts.reshape(1, 3);
Mat B = A - repeat(A.row(0), 3, 1), Bt = B.t();
B = Bt*B;
dB = cv::determinant(B);
nB = cvtest::norm(B, NORM_L2);
if( fabs(dB) < 0.01*nB )
continue;
}
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( cvtest::TS::LOG, "Threshold = %f, norm of difference = %f", thres, d );
return false;
}
}
return true;
}
bool CV_RigidTransform_Test::testImage()
{
Mat img;
Mat testImg = imread( string(ts->get_data_path()) + "shared/graffiti.png", 1);
if (testImg.empty())
{
ts->printf( ts->LOG, "test image can not be read");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return false;
}
pyrDown(testImg, img);
Mat aff = cv::getRotationMatrix2D(Point(img.cols/2, img.rows/2), 1, 0.99);
aff.ptr<double>()[2]+=3;
aff.ptr<double>()[5]+=3;
Mat rotated;
warpAffine(img, rotated, aff, img.size());
Mat aff_est = estimateRigidTransform(img, rotated, true);
const double thres = 0.033;
if (cvtest::norm(aff_est, aff, NORM_INF) > thres)
{
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
ts->printf( cvtest::TS::LOG, "Threshold = %f, norm of difference = %f", thres,
cvtest::norm(aff_est, aff, NORM_INF) );
return false;
}
return true;
}
void CV_RigidTransform_Test::run( int start_from )
{
cvtest::DefaultRngAuto dra;
if (!testNPoints(start_from))
return;
if (!testImage())
return;
ts->set_failed_test_info(cvtest::TS::OK);
}
TEST(Video_RigidFlow, accuracy) { CV_RigidTransform_Test test; test.safe_run(); }
}} // namespace

View File

@@ -0,0 +1,113 @@
/*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 "test_precomp.hpp"
#include "opencv2/video/tracking.hpp"
namespace opencv_test { namespace {
class CV_KalmanTest : public cvtest::BaseTest
{
public:
CV_KalmanTest();
protected:
void run(int);
};
CV_KalmanTest::CV_KalmanTest()
{
}
void CV_KalmanTest::run( int )
{
int code = cvtest::TS::OK;
const int Dim = 7;
const int Steps = 100;
const double max_init = 1;
const double max_noise = 0.1;
const double EPSILON = 1.000;
RNG& rng = ts->get_rng();
int i, j;
cv::Mat Sample(Dim,1,CV_32F);
cv::Mat Temp(Dim,1,CV_32F);
cv::KalmanFilter Kalm(Dim, Dim);
Kalm.transitionMatrix = cv::Mat::eye(Dim, Dim, CV_32F);
Kalm.measurementMatrix = cv::Mat::eye(Dim, Dim, CV_32F);
Kalm.processNoiseCov = cv::Mat::eye(Dim, Dim, CV_32F);
Kalm.errorCovPre = cv::Mat::eye(Dim, Dim, CV_32F);
Kalm.errorCovPost = cv::Mat::eye(Dim, Dim, CV_32F);
Kalm.measurementNoiseCov = cv::Mat::zeros(Dim, Dim, CV_32F);
Kalm.statePre = cv::Mat::zeros(Dim, 1, CV_32F);
Kalm.statePost = cv::Mat::zeros(Dim, 1, CV_32F);
cvtest::randUni(rng, Sample, Scalar::all(-max_init), Scalar::all(max_init));
Kalm.correct(Sample);
for(i = 0; i<Steps; i++)
{
Kalm.predict();
const Mat& Dyn = Kalm.transitionMatrix;
for(j = 0; j<Dim; j++)
{
float t = 0;
for(int k=0; k<Dim; k++)
{
t += Dyn.at<float>(j,k)*Sample.at<float>(k);
}
Temp.at<float>(j) = (float)(t+(cvtest::randReal(rng)*2-1)*max_noise);
}
Temp.copyTo(Sample);
Kalm.correct(Temp);
}
Mat _state_post = Kalm.statePost;
code = cvtest::cmpEps2( ts, Sample, _state_post, EPSILON, false, "The final estimated state" );
if( code < 0 )
ts->set_failed_test_info( code );
}
TEST(Video_Kalman, accuracy) { CV_KalmanTest test; test.safe_run(); }
}} // namespace
/* End of file. */

View File

@@ -0,0 +1,25 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#if defined(HAVE_HPX)
#include <hpx/hpx_main.hpp>
#endif
static
void initTests()
{
const char* extraTestDataPath =
#ifdef WINRT
NULL;
#else
getenv("OPENCV_DNN_TEST_DATA_PATH");
#endif
if (extraTestDataPath)
cvtest::addDataSearchPath(extraTestDataPath);
cvtest::addDataSearchSubDirectory(""); // override "cv" prefix below to access without "../dnn" hacks
}
CV_TEST_MAIN("cv", initTests())

View File

@@ -0,0 +1,257 @@
/*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 "test_precomp.hpp"
namespace opencv_test { namespace {
/* ///////////////////// pyrlk_test ///////////////////////// */
class CV_OptFlowPyrLKTest : public cvtest::BaseTest
{
public:
CV_OptFlowPyrLKTest();
protected:
void run(int);
};
CV_OptFlowPyrLKTest::CV_OptFlowPyrLKTest() {}
void CV_OptFlowPyrLKTest::run( int )
{
int code = cvtest::TS::OK;
const double success_error_level = 0.3;
const int bad_points_max = 8;
/* test parameters */
double max_err = 0., sum_err = 0;
int pt_cmpd = 0;
int pt_exceed = 0;
int merr_i = 0, merr_j = 0, merr_k = 0, merr_nan = 0;
char filename[1000];
cv::Point2f *v = 0, *v2 = 0;
cv::Mat _u, _v, _v2;
cv::Mat imgI, imgJ;
int n = 0, i = 0;
for(;;)
{
sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "lk_prev.dat" );
{
FileStorage fs(filename, FileStorage::READ);
fs["points"] >> _u;
if( _u.empty() )
{
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
break;
}
}
sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "lk_next.dat" );
{
FileStorage fs(filename, FileStorage::READ);
fs["points"] >> _v;
if( _v.empty() )
{
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
break;
}
}
if( _u.cols != 2 || _u.type() != CV_32F ||
_v.cols != 2 || _v.type() != CV_32F ||
_v.rows != _u.rows )
{
ts->printf( cvtest::TS::LOG, "the loaded matrices of points are not valid\n" );
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
break;
}
/* read first image */
sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "rock_1.bmp" );
imgI = cv::imread( filename, cv::IMREAD_UNCHANGED );
if( imgI.empty() )
{
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
break;
}
/* read second image */
sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "rock_2.bmp" );
imgJ = cv::imread( filename, cv::IMREAD_UNCHANGED );
if( imgJ.empty() )
{
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
break;
}
n = _u.rows;
std::vector<uchar> status(n, (uchar)0);
/* calculate flow */
calcOpticalFlowPyrLK(imgI, imgJ, _u, _v2, status, cv::noArray(), Size( 41, 41 ), 4,
TermCriteria( TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0.01f ), 0 );
v = (cv::Point2f*)_v.ptr();
v2 = (cv::Point2f*)_v2.ptr();
/* compare results */
for( i = 0; i < n; i++ )
{
if( status[i] != 0 )
{
double err;
if( cvIsNaN(v[i].x) || cvIsNaN(v[i].y) )
{
merr_j++;
continue;
}
if( cvIsNaN(v2[i].x) || cvIsNaN(v2[i].y) )
{
merr_nan++;
continue;
}
err = fabs(v2[i].x - v[i].x) + fabs(v2[i].y - v[i].y);
if( err > max_err )
{
max_err = err;
merr_i = i;
}
pt_exceed += err > success_error_level;
sum_err += err;
pt_cmpd++;
}
else
{
if( !cvIsNaN( v[i].x ))
{
merr_i = i;
merr_k++;
ts->printf( cvtest::TS::LOG, "The algorithm lost the point #%d\n", i );
code = cvtest::TS::FAIL_BAD_ACCURACY;
break;
}
}
}
if( i < n )
break;
if( pt_exceed > bad_points_max )
{
ts->printf( cvtest::TS::LOG,
"The number of poorly tracked points is too big (>=%d)\n", pt_exceed );
code = cvtest::TS::FAIL_BAD_ACCURACY;
break;
}
if( max_err > 1 )
{
ts->printf( cvtest::TS::LOG, "Maximum tracking error is too big (=%g) at %d\n", max_err, merr_i );
code = cvtest::TS::FAIL_BAD_ACCURACY;
break;
}
if( merr_nan > 0 )
{
ts->printf( cvtest::TS::LOG, "NAN tracking result with status != 0 (%d times)\n", merr_nan );
code = cvtest::TS::FAIL_BAD_ACCURACY;
}
break;
}
if( code < 0 )
ts->set_failed_test_info( code );
}
TEST(Video_OpticalFlowPyrLK, accuracy) { CV_OptFlowPyrLKTest test; test.safe_run(); }
TEST(Video_OpticalFlowPyrLK, submat)
{
// see bug #2075
std::string path = cvtest::TS::ptr()->get_data_path() + "../cv/shared/lena.png";
cv::Mat lenaImg = cv::imread(path);
ASSERT_FALSE(lenaImg.empty());
cv::Mat wholeImage;
cv::resize(lenaImg, wholeImage, cv::Size(1024, 1024), 0, 0, cv::INTER_LINEAR_EXACT);
cv::Mat img1 = wholeImage(cv::Rect(0, 0, 640, 360)).clone();
cv::Mat img2 = wholeImage(cv::Rect(40, 60, 640, 360));
std::vector<uchar> status;
std::vector<float> error;
std::vector<cv::Point2f> prev;
std::vector<cv::Point2f> next;
cv::RNG rng(123123);
for(int i = 0; i < 50; ++i)
{
int x = rng.uniform(0, 640);
int y = rng.uniform(0, 360);
prev.push_back(cv::Point2f((float)x, (float)y));
}
ASSERT_NO_THROW(cv::calcOpticalFlowPyrLK(img1, img2, prev, next, status, error));
}
}} // namespace

View File

@@ -0,0 +1,15 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include "opencv2/ts.hpp"
#include "opencv2/video.hpp"
#include <opencv2/ts/ts_perf.hpp>
namespace opencv_test {
using namespace perf;
}
#endif

View File

@@ -0,0 +1,129 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
//#define DEBUG_TEST
#ifdef DEBUG_TEST
#include <opencv2/highgui.hpp>
#endif
namespace opencv_test { namespace {
//using namespace cv::tracking;
#define TESTSET_NAMES testing::Values("david", "dudek", "faceocc2")
const string TRACKING_DIR = "tracking";
const string FOLDER_IMG = "data";
const string FOLDER_OMIT_INIT = "initOmit";
#include "test_trackers.impl.hpp"
//[TESTDATA]
PARAM_TEST_CASE(DistanceAndOverlap, string)
{
string dataset;
virtual void SetUp()
{
dataset = GET_PARAM(0);
}
};
TEST_P(DistanceAndOverlap, MIL)
{
TrackerTest<Tracker, Rect> test(TrackerMIL::create(), dataset, 30, .65f, NoTransform);
test.run();
}
TEST_P(DistanceAndOverlap, Shifted_Data_MIL)
{
TrackerTest<Tracker, Rect> test(TrackerMIL::create(), dataset, 30, .6f, CenterShiftLeft);
test.run();
}
/***************************************************************************************/
//Tests with scaled initial window
TEST_P(DistanceAndOverlap, Scaled_Data_MIL)
{
TrackerTest<Tracker, Rect> test(TrackerMIL::create(), dataset, 30, .7f, Scale_1_1);
test.run();
}
TEST_P(DistanceAndOverlap, GOTURN)
{
std::string model = cvtest::findDataFile("dnn/gsoc2016-goturn/goturn.prototxt");
std::string weights = cvtest::findDataFile("dnn/gsoc2016-goturn/goturn.caffemodel", false);
cv::TrackerGOTURN::Params params;
params.modelTxt = model;
params.modelBin = weights;
TrackerTest<Tracker, Rect> test(TrackerGOTURN::create(params), dataset, 35, .35f, NoTransform);
test.run();
}
INSTANTIATE_TEST_CASE_P(Tracking, DistanceAndOverlap, TESTSET_NAMES);
TEST(GOTURN, memory_usage)
{
cv::Rect roi(145, 70, 85, 85);
std::string model = cvtest::findDataFile("dnn/gsoc2016-goturn/goturn.prototxt");
std::string weights = cvtest::findDataFile("dnn/gsoc2016-goturn/goturn.caffemodel", false);
cv::TrackerGOTURN::Params params;
params.modelTxt = model;
params.modelBin = weights;
cv::Ptr<Tracker> tracker = TrackerGOTURN::create(params);
string inputVideo = cvtest::findDataFile("tracking/david/data/david.webm");
cv::VideoCapture video(inputVideo);
ASSERT_TRUE(video.isOpened()) << inputVideo;
cv::Mat frame;
video >> frame;
ASSERT_FALSE(frame.empty()) << inputVideo;
tracker->init(frame, roi);
string ground_truth_bb;
for (int nframes = 0; nframes < 15; ++nframes)
{
std::cout << "Frame: " << nframes << std::endl;
video >> frame;
bool res = tracker->update(frame, roi);
ASSERT_TRUE(res);
std::cout << "Predicted ROI: " << roi << std::endl;
}
}
TEST(DaSiamRPN, memory_usage)
{
cv::Rect roi(145, 70, 85, 85);
std::string model = cvtest::findDataFile("dnn/onnx/models/dasiamrpn_model.onnx", false);
std::string kernel_r1 = cvtest::findDataFile("dnn/onnx/models/dasiamrpn_kernel_r1.onnx", false);
std::string kernel_cls1 = cvtest::findDataFile("dnn/onnx/models/dasiamrpn_kernel_cls1.onnx", false);
cv::TrackerDaSiamRPN::Params params;
params.model = model;
params.kernel_r1 = kernel_r1;
params.kernel_cls1 = kernel_cls1;
cv::Ptr<Tracker> tracker = TrackerDaSiamRPN::create(params);
string inputVideo = cvtest::findDataFile("tracking/david/data/david.webm");
cv::VideoCapture video(inputVideo);
ASSERT_TRUE(video.isOpened()) << inputVideo;
cv::Mat frame;
video >> frame;
ASSERT_FALSE(frame.empty()) << inputVideo;
tracker->init(frame, roi);
string ground_truth_bb;
for (int nframes = 0; nframes < 15; ++nframes)
{
std::cout << "Frame: " << nframes << std::endl;
video >> frame;
bool res = tracker->update(frame, roi);
ASSERT_TRUE(res);
std::cout << "Predicted ROI: " << roi << std::endl;
}
}
}} // namespace opencv_test::

View File

@@ -0,0 +1,369 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* The Evaluation Methodologies are partially based on:
* ====================================================================================================================
* [OTB] Y. Wu, J. Lim, and M.-H. Yang, "Online object tracking: A benchmark," in Computer Vision and Pattern Recognition (CVPR), 2013
*
*/
enum BBTransformations
{
NoTransform = 0,
CenterShiftLeft = 1,
CenterShiftRight = 2,
CenterShiftUp = 3,
CenterShiftDown = 4,
CornerShiftTopLeft = 5,
CornerShiftTopRight = 6,
CornerShiftBottomLeft = 7,
CornerShiftBottomRight = 8,
Scale_0_8 = 9,
Scale_0_9 = 10,
Scale_1_1 = 11,
Scale_1_2 = 12
};
namespace {
std::vector<std::string> splitString(const std::string& s_, const std::string& delimiter)
{
std::string s = s_;
std::vector<string> token;
size_t pos = 0;
while ((pos = s.find(delimiter)) != std::string::npos)
{
token.push_back(s.substr(0, pos));
s.erase(0, pos + delimiter.length());
}
token.push_back(s);
return token;
}
float calcDistance(const Rect& a, const Rect& b)
{
Point2f p_a((float)(a.x + a.width / 2), (float)(a.y + a.height / 2));
Point2f p_b((float)(b.x + b.width / 2), (float)(b.y + b.height / 2));
Point2f diff = p_a - p_b;
return sqrt(diff.dot(diff));
}
float calcOverlap(const Rect& a, const Rect& b)
{
float rectIntersectionArea = (float)(a & b).area();
return rectIntersectionArea / (a.area() + b.area() - rectIntersectionArea);
}
} // namespace
template <typename Tracker, typename ROI_t = Rect2d>
class TrackerTest
{
public:
TrackerTest(const Ptr<Tracker>& tracker, const string& video, float distanceThreshold,
float overlapThreshold, int shift = NoTransform, int segmentIdx = 1, int numSegments = 10);
~TrackerTest() {}
void run();
protected:
void checkDataTest();
void distanceAndOverlapTest();
Ptr<Tracker> tracker;
string video;
std::vector<Rect> bbs;
int startFrame;
string suffix;
string prefix;
float overlapThreshold;
float distanceThreshold;
int segmentIdx;
int shift;
int numSegments;
int gtStartFrame;
int endFrame;
vector<int> validSequence;
private:
Rect applyShift(const Rect& bb);
};
template <typename Tracker, typename ROI_t>
TrackerTest<Tracker, ROI_t>::TrackerTest(const Ptr<Tracker>& _tracker, const string& _video, float _distanceThreshold,
float _overlapThreshold, int _shift, int _segmentIdx, int _numSegments)
: tracker(_tracker)
, video(_video)
, overlapThreshold(_overlapThreshold)
, distanceThreshold(_distanceThreshold)
, segmentIdx(_segmentIdx)
, shift(_shift)
, numSegments(_numSegments)
{
// nothing
}
template <typename Tracker, typename ROI_t>
Rect TrackerTest<Tracker, ROI_t>::applyShift(const Rect& bb_)
{
Rect bb = bb_;
Point center(bb.x + (bb.width / 2), bb.y + (bb.height / 2));
int xLimit = bb.x + bb.width - 1;
int yLimit = bb.y + bb.height - 1;
int h = 0;
int w = 0;
float ratio = 1.0;
switch (shift)
{
case CenterShiftLeft:
bb.x = bb.x - (int)ceil(0.1 * bb.width);
break;
case CenterShiftRight:
bb.x = bb.x + (int)ceil(0.1 * bb.width);
break;
case CenterShiftUp:
bb.y = bb.y - (int)ceil(0.1 * bb.height);
break;
case CenterShiftDown:
bb.y = bb.y + (int)ceil(0.1 * bb.height);
break;
case CornerShiftTopLeft:
bb.x = (int)cvRound(bb.x - 0.1 * bb.width);
bb.y = (int)cvRound(bb.y - 0.1 * bb.height);
bb.width = xLimit - bb.x + 1;
bb.height = yLimit - bb.y + 1;
break;
case CornerShiftTopRight:
xLimit = (int)cvRound(xLimit + 0.1 * bb.width);
bb.y = (int)cvRound(bb.y - 0.1 * bb.height);
bb.width = xLimit - bb.x + 1;
bb.height = yLimit - bb.y + 1;
break;
case CornerShiftBottomLeft:
bb.x = (int)cvRound(bb.x - 0.1 * bb.width);
yLimit = (int)cvRound(yLimit + 0.1 * bb.height);
bb.width = xLimit - bb.x + 1;
bb.height = yLimit - bb.y + 1;
break;
case CornerShiftBottomRight:
xLimit = (int)cvRound(xLimit + 0.1 * bb.width);
yLimit = (int)cvRound(yLimit + 0.1 * bb.height);
bb.width = xLimit - bb.x + 1;
bb.height = yLimit - bb.y + 1;
break;
case Scale_0_8:
ratio = 0.8f;
w = (int)(ratio * bb.width);
h = (int)(ratio * bb.height);
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
break;
case Scale_0_9:
ratio = 0.9f;
w = (int)(ratio * bb.width);
h = (int)(ratio * bb.height);
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
break;
case 11:
//scale 1.1
ratio = 1.1f;
w = (int)(ratio * bb.width);
h = (int)(ratio * bb.height);
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
break;
case 12:
//scale 1.2
ratio = 1.2f;
w = (int)(ratio * bb.width);
h = (int)(ratio * bb.height);
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
break;
default:
break;
}
return bb;
}
template <typename Tracker, typename ROI_t>
void TrackerTest<Tracker, ROI_t>::distanceAndOverlapTest()
{
bool initialized = false;
int fc = (startFrame - gtStartFrame);
bbs.at(fc) = applyShift(bbs.at(fc));
Rect currentBBi = bbs.at(fc);
ROI_t currentBB(currentBBi);
float sumDistance = 0;
float sumOverlap = 0;
string folder = cvtest::TS::ptr()->get_data_path() + "/" + TRACKING_DIR + "/" + video + "/" + FOLDER_IMG;
string videoPath = folder + "/" + video + ".webm";
VideoCapture c;
c.open(videoPath);
if (!c.isOpened())
throw SkipTestException("Can't open video file");
#if 0
c.set(CAP_PROP_POS_FRAMES, startFrame);
#else
if (startFrame)
std::cout << "startFrame = " << startFrame << std::endl;
for (int i = 0; i < startFrame; i++)
{
Mat dummy_frame;
c >> dummy_frame;
ASSERT_FALSE(dummy_frame.empty()) << i << ": " << videoPath;
}
#endif
for (int frameCounter = startFrame; frameCounter < endFrame; frameCounter++)
{
Mat frame;
c >> frame;
ASSERT_FALSE(frame.empty()) << "frameCounter=" << frameCounter << " video=" << videoPath;
if (!initialized)
{
tracker->init(frame, currentBB);
std::cout << "frame size = " << frame.size() << std::endl;
initialized = true;
}
else if (initialized)
{
if (frameCounter >= (int)bbs.size())
break;
tracker->update(frame, currentBB);
}
float curDistance = calcDistance(currentBB, bbs.at(fc));
float curOverlap = calcOverlap(currentBB, bbs.at(fc));
#ifdef DEBUG_TEST
Mat result;
repeat(frame, 1, 2, result);
rectangle(result, currentBB, Scalar(0, 255, 0), 1);
Rect roi2(frame.cols, 0, frame.cols, frame.rows);
rectangle(result(roi2), bbs.at(fc), Scalar(0, 0, 255), 1);
imshow("result", result);
waitKey(1);
#endif
sumDistance += curDistance;
sumOverlap += curOverlap;
fc++;
}
float meanDistance = sumDistance / (endFrame - startFrame);
float meanOverlap = sumOverlap / (endFrame - startFrame);
EXPECT_LE(meanDistance, distanceThreshold);
EXPECT_GE(meanOverlap, overlapThreshold);
}
template <typename Tracker, typename ROI_t>
void TrackerTest<Tracker, ROI_t>::checkDataTest()
{
FileStorage fs;
fs.open(cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/" + video + ".yml", FileStorage::READ);
fs["start"] >> startFrame;
fs["prefix"] >> prefix;
fs["suffix"] >> suffix;
fs.release();
string gtFile = cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/gt.txt";
std::ifstream gt;
//open the ground truth
gt.open(gtFile.c_str());
ASSERT_TRUE(gt.is_open()) << gtFile;
string line;
int bbCounter = 0;
while (getline(gt, line))
{
bbCounter++;
}
gt.close();
int seqLength = bbCounter;
for (int i = startFrame; i < seqLength; i++)
{
validSequence.push_back(i);
}
//exclude from the images sequence, the frames where the target is occluded or out of view
string omitFile = cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/" + FOLDER_OMIT_INIT + "/" + video + ".txt";
std::ifstream omit;
omit.open(omitFile.c_str());
if (omit.is_open())
{
string omitLine;
while (getline(omit, omitLine))
{
vector<string> tokens = splitString(omitLine, " ");
int s_start = atoi(tokens.at(0).c_str());
int s_end = atoi(tokens.at(1).c_str());
for (int k = s_start; k <= s_end; k++)
{
std::vector<int>::iterator position = std::find(validSequence.begin(), validSequence.end(), k);
if (position != validSequence.end())
validSequence.erase(position);
}
}
}
omit.close();
gtStartFrame = startFrame;
//compute the start and the and for each segment
int numFrame = (int)(validSequence.size() / numSegments);
startFrame += (segmentIdx - 1) * numFrame;
endFrame = startFrame + numFrame;
std::ifstream gt2;
//open the ground truth
gt2.open(gtFile.c_str());
ASSERT_TRUE(gt2.is_open()) << gtFile;
string line2;
int bbCounter2 = 0;
while (getline(gt2, line2))
{
vector<string> tokens = splitString(line2, ",");
Rect bb(atoi(tokens.at(0).c_str()), atoi(tokens.at(1).c_str()), atoi(tokens.at(2).c_str()), atoi(tokens.at(3).c_str()));
ASSERT_EQ((size_t)4, tokens.size()) << "Incorrect ground truth file " << gtFile;
bbs.push_back(bb);
bbCounter2++;
}
gt2.close();
if (segmentIdx == numSegments)
endFrame = (int)bbs.size();
}
template <typename Tracker, typename ROI_t>
void TrackerTest<Tracker, ROI_t>::run()
{
srand(1); // FIXIT remove that, ensure that there is no "rand()" in implementation
ASSERT_TRUE(tracker);
checkDataTest();
//check for failure
if (::testing::Test::HasFatalFailure())
return;
distanceAndOverlapTest();
}