mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 20:50:25 +08:00
Merge pull request #13084 from vpisarev:shuffle_optflow_algos
* moved DIS optical flow from opencv_contrib to opencv, moved TVL1 from opencv to opencv_contrib * fixed compile warning * TVL1 optical flow example moved to opencv_contrib
This commit is contained in:
parent
841741aa52
commit
96bf26611e
@ -397,6 +397,29 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** @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:
|
||||
@ -433,131 +456,6 @@ public:
|
||||
OutputArray err = cv::noArray()) = 0;
|
||||
};
|
||||
|
||||
/** @brief "Dual TV L1" Optical Flow Algorithm.
|
||||
|
||||
The class implements the "Dual TV L1" optical flow algorithm described in @cite Zach2007 and
|
||||
@cite Javier2012 .
|
||||
Here are important members of the class that control the algorithm, which you can set after
|
||||
constructing the class instance:
|
||||
|
||||
- member double tau
|
||||
Time step of the numerical scheme.
|
||||
|
||||
- member double lambda
|
||||
Weight parameter for the data term, attachment parameter. This is the most relevant
|
||||
parameter, which determines the smoothness of the output. The smaller this parameter is,
|
||||
the smoother the solutions we obtain. It depends on the range of motions of the images, so
|
||||
its value should be adapted to each image sequence.
|
||||
|
||||
- member double theta
|
||||
Weight parameter for (u - v)\^2, tightness parameter. It serves as a link between the
|
||||
attachment and the regularization terms. In theory, it should have a small value in order
|
||||
to maintain both parts in correspondence. The method is stable for a large range of values
|
||||
of this parameter.
|
||||
|
||||
- member int nscales
|
||||
Number of scales used to create the pyramid of images.
|
||||
|
||||
- member int warps
|
||||
Number of warpings per scale. Represents the number of times that I1(x+u0) and grad(
|
||||
I1(x+u0) ) are computed per scale. This is a parameter that assures the stability of the
|
||||
method. It also affects the running time, so it is a compromise between speed and
|
||||
accuracy.
|
||||
|
||||
- member double epsilon
|
||||
Stopping criterion threshold used in the numerical scheme, which is a trade-off between
|
||||
precision and running time. A small value will yield more accurate solutions at the
|
||||
expense of a slower convergence.
|
||||
|
||||
- member int iterations
|
||||
Stopping criterion iterations number used in the numerical scheme.
|
||||
|
||||
C. Zach, T. Pock and H. Bischof, "A Duality Based Approach for Realtime TV-L1 Optical Flow".
|
||||
Javier Sanchez, Enric Meinhardt-Llopis and Gabriele Facciolo. "TV-L1 Optical Flow Estimation".
|
||||
*/
|
||||
class CV_EXPORTS_W DualTVL1OpticalFlow : public DenseOpticalFlow
|
||||
{
|
||||
public:
|
||||
//! @brief Time step of the numerical scheme
|
||||
/** @see setTau */
|
||||
CV_WRAP virtual double getTau() const = 0;
|
||||
/** @copybrief getTau @see getTau */
|
||||
CV_WRAP virtual void setTau(double val) = 0;
|
||||
//! @brief Weight parameter for the data term, attachment parameter
|
||||
/** @see setLambda */
|
||||
CV_WRAP virtual double getLambda() const = 0;
|
||||
/** @copybrief getLambda @see getLambda */
|
||||
CV_WRAP virtual void setLambda(double val) = 0;
|
||||
//! @brief Weight parameter for (u - v)^2, tightness parameter
|
||||
/** @see setTheta */
|
||||
CV_WRAP virtual double getTheta() const = 0;
|
||||
/** @copybrief getTheta @see getTheta */
|
||||
CV_WRAP virtual void setTheta(double val) = 0;
|
||||
//! @brief coefficient for additional illumination variation term
|
||||
/** @see setGamma */
|
||||
CV_WRAP virtual double getGamma() const = 0;
|
||||
/** @copybrief getGamma @see getGamma */
|
||||
CV_WRAP virtual void setGamma(double val) = 0;
|
||||
//! @brief Number of scales used to create the pyramid of images
|
||||
/** @see setScalesNumber */
|
||||
CV_WRAP virtual int getScalesNumber() const = 0;
|
||||
/** @copybrief getScalesNumber @see getScalesNumber */
|
||||
CV_WRAP virtual void setScalesNumber(int val) = 0;
|
||||
//! @brief Number of warpings per scale
|
||||
/** @see setWarpingsNumber */
|
||||
CV_WRAP virtual int getWarpingsNumber() const = 0;
|
||||
/** @copybrief getWarpingsNumber @see getWarpingsNumber */
|
||||
CV_WRAP virtual void setWarpingsNumber(int val) = 0;
|
||||
//! @brief Stopping criterion threshold used in the numerical scheme, which is a trade-off between precision and running time
|
||||
/** @see setEpsilon */
|
||||
CV_WRAP virtual double getEpsilon() const = 0;
|
||||
/** @copybrief getEpsilon @see getEpsilon */
|
||||
CV_WRAP virtual void setEpsilon(double val) = 0;
|
||||
//! @brief Inner iterations (between outlier filtering) used in the numerical scheme
|
||||
/** @see setInnerIterations */
|
||||
CV_WRAP virtual int getInnerIterations() const = 0;
|
||||
/** @copybrief getInnerIterations @see getInnerIterations */
|
||||
CV_WRAP virtual void setInnerIterations(int val) = 0;
|
||||
//! @brief Outer iterations (number of inner loops) used in the numerical scheme
|
||||
/** @see setOuterIterations */
|
||||
CV_WRAP virtual int getOuterIterations() const = 0;
|
||||
/** @copybrief getOuterIterations @see getOuterIterations */
|
||||
CV_WRAP virtual void setOuterIterations(int val) = 0;
|
||||
//! @brief Use initial flow
|
||||
/** @see setUseInitialFlow */
|
||||
CV_WRAP virtual bool getUseInitialFlow() const = 0;
|
||||
/** @copybrief getUseInitialFlow @see getUseInitialFlow */
|
||||
CV_WRAP virtual void setUseInitialFlow(bool val) = 0;
|
||||
//! @brief Step between scales (<1)
|
||||
/** @see setScaleStep */
|
||||
CV_WRAP virtual double getScaleStep() const = 0;
|
||||
/** @copybrief getScaleStep @see getScaleStep */
|
||||
CV_WRAP virtual void setScaleStep(double val) = 0;
|
||||
//! @brief Median filter kernel size (1 = no filter) (3 or 5)
|
||||
/** @see setMedianFiltering */
|
||||
CV_WRAP virtual int getMedianFiltering() const = 0;
|
||||
/** @copybrief getMedianFiltering @see getMedianFiltering */
|
||||
CV_WRAP virtual void setMedianFiltering(int val) = 0;
|
||||
|
||||
/** @brief Creates instance of cv::DualTVL1OpticalFlow*/
|
||||
CV_WRAP static Ptr<DualTVL1OpticalFlow> create(
|
||||
double tau = 0.25,
|
||||
double lambda = 0.15,
|
||||
double theta = 0.3,
|
||||
int nscales = 5,
|
||||
int warps = 5,
|
||||
double epsilon = 0.01,
|
||||
int innnerIterations = 30,
|
||||
int outerIterations = 10,
|
||||
double scaleStep = 0.8,
|
||||
double gamma = 0.0,
|
||||
int medianFiltering = 5,
|
||||
bool useInitialFlow = false);
|
||||
};
|
||||
|
||||
/** @brief Creates instance of cv::DenseOpticalFlow
|
||||
*/
|
||||
CV_EXPORTS_W Ptr<DualTVL1OpticalFlow> createOptFlow_DualTVL1();
|
||||
|
||||
/** @brief Class computing a dense optical flow using the Gunnar Farneback's algorithm.
|
||||
*/
|
||||
@ -599,6 +497,166 @@ public:
|
||||
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.
|
||||
|
||||
|
72
modules/video/perf/opencl/perf_dis_optflow.cpp
Normal file
72
modules/video/perf/opencl/perf_dis_optflow.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
// 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);
|
||||
|
||||
OCL_TEST_CYCLE_N(10)
|
||||
{
|
||||
algo->calc(frame1, frame2, flow);
|
||||
}
|
||||
|
||||
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
|
@ -1,111 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 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 {
|
||||
|
||||
///////////// OpticalFlow Dual TVL1 ////////////////////////
|
||||
typedef tuple< tuple<int, double>, bool> OpticalFlowDualTVL1Params;
|
||||
typedef TestBaseWithParam<OpticalFlowDualTVL1Params> OpticalFlowDualTVL1Fixture;
|
||||
|
||||
OCL_PERF_TEST_P(OpticalFlowDualTVL1Fixture, OpticalFlowDualTVL1,
|
||||
::testing::Combine(
|
||||
::testing::Values(make_tuple<int, double>(-1, 0.3),
|
||||
make_tuple<int, double>(3, 0.5)),
|
||||
::testing::Bool()
|
||||
)
|
||||
)
|
||||
{
|
||||
Mat frame0 = imread(getDataPath("cv/optflow/RubberWhale1.png"), cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame0.empty()) << "can't load RubberWhale1.png";
|
||||
|
||||
Mat frame1 = imread(getDataPath("cv/optflow/RubberWhale2.png"), cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame1.empty()) << "can't load RubberWhale2.png";
|
||||
|
||||
const Size srcSize = frame0.size();
|
||||
|
||||
const OpticalFlowDualTVL1Params params = GetParam();
|
||||
const tuple<int, double> filteringScale = get<0>(params);
|
||||
const int medianFiltering = get<0>(filteringScale);
|
||||
const double scaleStep = get<1>(filteringScale);
|
||||
const bool useInitFlow = get<1>(params);
|
||||
double eps = 0.9;
|
||||
|
||||
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);
|
||||
|
||||
//create algorithm
|
||||
cv::Ptr<cv::DualTVL1OpticalFlow> alg = cv::createOptFlow_DualTVL1();
|
||||
|
||||
//set parameters
|
||||
alg->setScaleStep(scaleStep);
|
||||
alg->setMedianFiltering(medianFiltering);
|
||||
|
||||
if (useInitFlow)
|
||||
{
|
||||
//calculate initial flow as result of optical flow
|
||||
alg->calc(uFrame0, uFrame1, uFlow);
|
||||
}
|
||||
|
||||
//set flag to use initial flow
|
||||
alg->setUseInitialFlow(useInitFlow);
|
||||
OCL_TEST_CYCLE()
|
||||
alg->calc(uFrame0, uFrame1, uFlow);
|
||||
|
||||
SANITY_CHECK(uFlow, eps, ERROR_RELATIVE);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace opencv_test::ocl
|
||||
|
||||
#endif // HAVE_OPENCL
|
66
modules/video/perf/perf_disflow.cpp
Normal file
66
modules/video/perf/perf_disflow.cpp
Normal 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
|
@ -6,5 +6,11 @@
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include <opencv2/video.hpp>
|
||||
#include "opencv2/ts/ts_perf.hpp"
|
||||
|
||||
namespace cvtest
|
||||
{
|
||||
using namespace perf;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,31 +0,0 @@
|
||||
#include "perf_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
using namespace perf;
|
||||
|
||||
typedef TestBaseWithParam< std::pair<string, string> > ImagePair;
|
||||
|
||||
std::pair<string, string> impair(const char* im1, const char* im2)
|
||||
{
|
||||
return std::make_pair(string(im1), string(im2));
|
||||
}
|
||||
|
||||
PERF_TEST_P(ImagePair, OpticalFlowDual_TVL1, testing::Values(impair("cv/optflow/RubberWhale1.png", "cv/optflow/RubberWhale2.png")))
|
||||
{
|
||||
declare.time(260);
|
||||
|
||||
Mat frame1 = imread(getDataPath(GetParam().first), IMREAD_GRAYSCALE);
|
||||
Mat frame2 = imread(getDataPath(GetParam().second), IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame1.empty());
|
||||
ASSERT_FALSE(frame2.empty());
|
||||
|
||||
Mat flow;
|
||||
|
||||
Ptr<DenseOpticalFlow> tvl1 = createOptFlow_DualTVL1();
|
||||
|
||||
TEST_CYCLE() tvl1->calc(frame1, frame2, flow);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
}} // namespace
|
40
modules/video/perf/perf_variational_refinement.cpp
Normal file
40
modules/video/perf/perf_variational_refinement.cpp
Normal 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
|
1500
modules/video/src/dis_flow.cpp
Normal file
1500
modules/video/src/dis_flow.cpp
Normal file
File diff suppressed because it is too large
Load Diff
521
modules/video/src/opencl/dis_flow.cl
Normal file
521
modules/video/src/opencl/dis_flow.cl
Normal file
@ -0,0 +1,521 @@
|
||||
// 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 EPS 0.001f
|
||||
#define INF 1E+10F
|
||||
|
||||
__kernel void dis_precomputeStructureTensor_hor(__global const short *I0x,
|
||||
__global const short *I0y,
|
||||
int patch_size, int patch_stride,
|
||||
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 = patch_size; j < w; j++)
|
||||
{
|
||||
short x_val1 = x_row[j];
|
||||
short x_val2 = x_row[j - patch_size];
|
||||
short y_val1 = y_row[j];
|
||||
short y_val2 = y_row[j - 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 - patch_size + 1) % 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 patch_size, int patch_stride,
|
||||
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 < 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 = patch_size; i < h; i++)
|
||||
{
|
||||
sum_xx += (I0xx_aux_ptr[i * ws + j] - I0xx_aux_ptr[(i - patch_size) * ws + j]);
|
||||
sum_yy += (I0yy_aux_ptr[i * ws + j] - I0yy_aux_ptr[(i - patch_size) * ws + j]);
|
||||
sum_xy += (I0xy_aux_ptr[i * ws + j] - I0xy_aux_ptr[(i - patch_size) * ws + j]);
|
||||
sum_x += (I0x_aux_ptr[i * ws + j] - I0x_aux_ptr[(i - patch_size) * ws + j]);
|
||||
sum_y += (I0y_aux_ptr[i * ws + j] - I0y_aux_ptr[(i - patch_size) * ws + j]);
|
||||
|
||||
if ((i - patch_size + 1) % 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 float *sx, __global const float *sy,
|
||||
__global const uchar *i0, __global const uchar *i1,
|
||||
int psz, int pstr,
|
||||
int w, int h, int ws,
|
||||
__global float *ux, __global float *uy)
|
||||
{
|
||||
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 / pstr, (h - psz) / pstr);
|
||||
start_is = max(0, y - psz + pstr) / pstr;
|
||||
start_is = min(start_is, end_is);
|
||||
|
||||
end_js = min(x / pstr, (w - psz) / pstr);
|
||||
start_js = max(0, x - psz + pstr) / pstr;
|
||||
start_js = min(start_js, end_js);
|
||||
|
||||
float coef, sum_coef = 0.0f;
|
||||
float sum_Ux = 0.0f;
|
||||
float sum_Uy = 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++)
|
||||
{
|
||||
float sx_val = sx[is * ws + js];
|
||||
float sy_val = sy[is * ws + js];
|
||||
uchar2 i1_vec1, i1_vec2;
|
||||
|
||||
j_m = min(max(j + sx_val, 0.0f), w - 1.0f - EPS);
|
||||
i_m = min(max(i + sy_val, 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];
|
||||
coef = 1 / max(1.0f, fabs(diff));
|
||||
sum_Ux += coef * sx_val;
|
||||
sum_Uy += coef * sy_val;
|
||||
sum_coef += coef;
|
||||
}
|
||||
|
||||
ux[i * w + j] = sum_Ux / sum_coef;
|
||||
uy[i * w + j] = sum_Uy / sum_coef;
|
||||
}
|
||||
|
||||
#define INIT_BILINEAR_WEIGHTS(Ux, Uy) \
|
||||
i_I1 = min(max(i + Uy + bsz, i_lower_limit), i_upper_limit); \
|
||||
j_I1 = min(max(j + Ux + bsz, j_lower_limit), j_upper_limit); \
|
||||
\
|
||||
w11 = (i_I1 - floor(i_I1)) * (j_I1 - floor(j_I1)); \
|
||||
w10 = (i_I1 - floor(i_I1)) * (floor(j_I1) + 1 - j_I1); \
|
||||
w01 = (floor(i_I1) + 1 - i_I1) * (j_I1 - floor(j_I1)); \
|
||||
w00 = (floor(i_I1) + 1 - i_I1) * (floor(j_I1) + 1 - j_I1);
|
||||
|
||||
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 patch_sz, int i)
|
||||
{
|
||||
float sum_diff = 0.0f, sum_diff_sq = 0.0f;
|
||||
int n = patch_sz * patch_sz;
|
||||
|
||||
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));
|
||||
|
||||
sum_diff = sub_group_reduce_add(sum_diff);
|
||||
sum_diff_sq = sub_group_reduce_add(sum_diff_sq);
|
||||
|
||||
return sum_diff_sq - sum_diff * sum_diff / n;
|
||||
}
|
||||
|
||||
__kernel void dis_patch_inverse_search_fwd_1(__global const float *Ux_ptr, __global const float *Uy_ptr,
|
||||
__global const uchar *I0_ptr, __global const uchar *I1_ptr,
|
||||
int border_size, int patch_size, int patch_stride,
|
||||
int w, int h, int ws, int hs, int pyr_level,
|
||||
__global float *Sx_ptr, __global float *Sy_ptr)
|
||||
{
|
||||
int id = get_global_id(0);
|
||||
int is = id / 8;
|
||||
if (id >= (hs * 8)) return;
|
||||
|
||||
int i = is * patch_stride;
|
||||
int j = 0;
|
||||
int psz = patch_size;
|
||||
int psz2 = psz / 2;
|
||||
int w_ext = w + 2 * border_size;
|
||||
int bsz = border_size;
|
||||
|
||||
float i_lower_limit = bsz - psz + 1.0f;
|
||||
float i_upper_limit = bsz + h - 1.0f;
|
||||
float j_lower_limit = bsz - psz + 1.0f;
|
||||
float j_upper_limit = bsz + w - 1.0f;
|
||||
float i_I1, j_I1, w00, w01, w10, w11;
|
||||
|
||||
float prev_Ux = Ux_ptr[(i + psz2) * w + j + psz2];
|
||||
float prev_Uy = Uy_ptr[(i + psz2) * w + j + psz2];
|
||||
Sx_ptr[is * ws] = prev_Ux;
|
||||
Sy_ptr[is * ws] = prev_Uy;
|
||||
j += patch_stride;
|
||||
|
||||
int sid = get_sub_group_local_id();
|
||||
for (int js = 1; js < ws; js++, j += patch_stride)
|
||||
{
|
||||
float min_SSD, cur_SSD;
|
||||
float Ux = Ux_ptr[(i + psz2) * w + j + psz2];
|
||||
float Uy = Uy_ptr[(i + psz2) * w + j + psz2];
|
||||
|
||||
INIT_BILINEAR_WEIGHTS(Ux, Uy);
|
||||
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, psz, sid);
|
||||
|
||||
INIT_BILINEAR_WEIGHTS(prev_Ux, prev_Uy);
|
||||
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, psz, sid);
|
||||
if (cur_SSD < min_SSD)
|
||||
{
|
||||
Ux = prev_Ux;
|
||||
Uy = prev_Uy;
|
||||
}
|
||||
|
||||
prev_Ux = Ux;
|
||||
prev_Uy = Uy;
|
||||
Sx_ptr[is * ws + js] = Ux;
|
||||
Sy_ptr[is * ws + js] = Uy;
|
||||
}
|
||||
}
|
||||
|
||||
float3 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, int patch_sz, float x_grad_sum, float y_grad_sum)
|
||||
{
|
||||
float sum_diff = 0.0, sum_diff_sq = 0.0;
|
||||
float sum_I0x_mul = 0.0, sum_I0y_mul = 0.0;
|
||||
int n = patch_sz * patch_sz;
|
||||
uchar8 I1_vec1, I1_vec2;
|
||||
uchar I1_val1, I1_val2;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uchar8 I0_vec = vload8(0, I0_ptr + i * I0_stride);
|
||||
|
||||
I1_vec1 = (i == 0) ? vload8(0, I1_ptr + i * I1_stride) : I1_vec2;
|
||||
I1_vec2 = vload8(0, I1_ptr + (i + 1) * I1_stride);
|
||||
I1_val1 = (i == 0) ? I1_ptr[i * I1_stride + patch_sz] : I1_val2;
|
||||
I1_val2 = I1_ptr[(i + 1) * I1_stride + patch_sz];
|
||||
|
||||
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 / n;
|
||||
float dst_dUy = sum_I0y_mul - sum_diff * y_grad_sum / n;
|
||||
float SSD = sum_diff_sq - sum_diff * sum_diff / n;
|
||||
|
||||
return (float3)(SSD, dst_dUx, dst_dUy);
|
||||
}
|
||||
|
||||
__kernel void dis_patch_inverse_search_fwd_2(__global const float *Ux_ptr, __global const float *Uy_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 border_size, int patch_size, int patch_stride,
|
||||
int w, int h, int ws, int hs, int num_inner_iter, int pyr_level,
|
||||
__global float *Sx_ptr, __global float *Sy_ptr)
|
||||
{
|
||||
int js = get_global_id(0);
|
||||
int is = get_global_id(1);
|
||||
int i = is * patch_stride;
|
||||
int j = js * patch_stride;
|
||||
int psz = patch_size;
|
||||
int psz2 = psz / 2;
|
||||
int w_ext = w + 2 * border_size;
|
||||
int bsz = border_size;
|
||||
int index = is * ws + js;
|
||||
|
||||
if (js >= ws || is >= hs) return;
|
||||
|
||||
float Ux = Sx_ptr[index];
|
||||
float Uy = Sy_ptr[index];
|
||||
float cur_Ux = Ux;
|
||||
float cur_Uy = Uy;
|
||||
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;
|
||||
|
||||
if (fabs(detH) < EPS) detH = EPS;
|
||||
|
||||
float invH11 = cur_yy / detH;
|
||||
float invH12 = -cur_xy / detH;
|
||||
float invH22 = cur_xx / detH;
|
||||
float prev_SSD = INF, SSD;
|
||||
float x_grad_sum = x_ptr[index];
|
||||
float y_grad_sum = y_ptr[index];
|
||||
|
||||
float i_lower_limit = bsz - psz + 1.0f;
|
||||
float i_upper_limit = bsz + h - 1.0f;
|
||||
float j_lower_limit = bsz - psz + 1.0f;
|
||||
float j_upper_limit = bsz + w - 1.0f;
|
||||
float dUx, dUy, i_I1, j_I1, w00, w01, w10, w11, dx, dy;
|
||||
float3 res;
|
||||
|
||||
for (int t = 0; t < num_inner_iter; t++)
|
||||
{
|
||||
INIT_BILINEAR_WEIGHTS(cur_Ux, cur_Uy);
|
||||
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, psz,
|
||||
x_grad_sum, y_grad_sum);
|
||||
|
||||
SSD = res.x;
|
||||
dUx = res.y;
|
||||
dUy = res.z;
|
||||
dx = invH11 * dUx + invH12 * dUy;
|
||||
dy = invH12 * dUx + invH22 * dUy;
|
||||
|
||||
cur_Ux -= dx;
|
||||
cur_Uy -= dy;
|
||||
|
||||
if (SSD >= prev_SSD)
|
||||
break;
|
||||
prev_SSD = SSD;
|
||||
}
|
||||
|
||||
float2 vec = (float2)(cur_Ux - Ux, cur_Uy - Uy);
|
||||
if (dot(vec, vec) <= (float)(psz * psz))
|
||||
{
|
||||
Sx_ptr[index] = cur_Ux;
|
||||
Sy_ptr[index] = cur_Uy;
|
||||
}
|
||||
}
|
||||
|
||||
__kernel void dis_patch_inverse_search_bwd_1(__global const uchar *I0_ptr, __global const uchar *I1_ptr,
|
||||
int border_size, int patch_size, int patch_stride,
|
||||
int w, int h, int ws, int hs, int pyr_level,
|
||||
__global float *Sx_ptr, __global float *Sy_ptr)
|
||||
{
|
||||
int id = get_global_id(0);
|
||||
int is = id / 8;
|
||||
if (id >= (hs * 8)) return;
|
||||
|
||||
is = (hs - 1 - is);
|
||||
int i = is * patch_stride;
|
||||
int j = (ws - 2) * patch_stride;
|
||||
int psz = patch_size;
|
||||
int psz2 = psz / 2;
|
||||
int w_ext = w + 2 * border_size;
|
||||
int bsz = border_size;
|
||||
|
||||
float i_lower_limit = bsz - psz + 1.0f;
|
||||
float i_upper_limit = bsz + h - 1.0f;
|
||||
float j_lower_limit = bsz - psz + 1.0f;
|
||||
float j_upper_limit = bsz + w - 1.0f;
|
||||
float i_I1, j_I1, w00, w01, w10, w11;
|
||||
|
||||
int sid = get_sub_group_local_id();
|
||||
for (int js = (ws - 2); js > -1; js--, j -= patch_stride)
|
||||
{
|
||||
float min_SSD, cur_SSD;
|
||||
float2 Ux = vload2(0, Sx_ptr + is * ws + js);
|
||||
float2 Uy = vload2(0, Sy_ptr + is * ws + js);
|
||||
|
||||
INIT_BILINEAR_WEIGHTS(Ux.x, Uy.x);
|
||||
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, psz, sid);
|
||||
|
||||
INIT_BILINEAR_WEIGHTS(Ux.y, Uy.y);
|
||||
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, psz, sid);
|
||||
if (cur_SSD < min_SSD)
|
||||
{
|
||||
Sx_ptr[is * ws + js] = Ux.y;
|
||||
Sy_ptr[is * ws + js] = Uy.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__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 border_size, int patch_size, int patch_stride,
|
||||
int w, int h, int ws, int hs, int num_inner_iter,
|
||||
__global float *Sx_ptr, __global float *Sy_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 * patch_stride;
|
||||
int i = is * patch_stride;
|
||||
int psz = patch_size;
|
||||
int psz2 = psz / 2;
|
||||
int w_ext = w + 2 * border_size;
|
||||
int bsz = border_size;
|
||||
int index = is * ws + js;
|
||||
|
||||
float Ux = Sx_ptr[index];
|
||||
float Uy = Sy_ptr[index];
|
||||
float cur_Ux = Ux;
|
||||
float cur_Uy = Uy;
|
||||
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;
|
||||
|
||||
if (fabs(detH) < EPS) detH = EPS;
|
||||
|
||||
float invH11 = cur_yy / detH;
|
||||
float invH12 = -cur_xy / detH;
|
||||
float invH22 = cur_xx / detH;
|
||||
float prev_SSD = INF, SSD;
|
||||
float x_grad_sum = x_ptr[index];
|
||||
float y_grad_sum = y_ptr[index];
|
||||
|
||||
float i_lower_limit = bsz - psz + 1.0f;
|
||||
float i_upper_limit = bsz + h - 1.0f;
|
||||
float j_lower_limit = bsz - psz + 1.0f;
|
||||
float j_upper_limit = bsz + w - 1.0f;
|
||||
float dUx, dUy, i_I1, j_I1, w00, w01, w10, w11, dx, dy;
|
||||
float3 res;
|
||||
|
||||
for (int t = 0; t < num_inner_iter; t++)
|
||||
{
|
||||
INIT_BILINEAR_WEIGHTS(cur_Ux, cur_Uy);
|
||||
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, psz,
|
||||
x_grad_sum, y_grad_sum);
|
||||
|
||||
SSD = res.x;
|
||||
dUx = res.y;
|
||||
dUy = res.z;
|
||||
dx = invH11 * dUx + invH12 * dUy;
|
||||
dy = invH12 * dUx + invH22 * dUy;
|
||||
|
||||
cur_Ux -= dx;
|
||||
cur_Uy -= dy;
|
||||
|
||||
if (SSD >= prev_SSD)
|
||||
break;
|
||||
prev_SSD = SSD;
|
||||
}
|
||||
|
||||
float2 vec = (float2)(cur_Ux - Ux, cur_Uy - Uy);
|
||||
if ((dot(vec, vec)) <= (float)(psz * psz))
|
||||
{
|
||||
Sx_ptr[index] = cur_Ux;
|
||||
Sy_ptr[index] = cur_Uy;
|
||||
}
|
||||
}
|
@ -1,378 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 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
|
||||
// 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*/
|
||||
|
||||
__kernel void centeredGradientKernel(__global const float* src_ptr, int src_col, int src_row, int src_step,
|
||||
__global float* dx, __global float* dy, int d_step)
|
||||
{
|
||||
int x = get_global_id(0);
|
||||
int y = get_global_id(1);
|
||||
|
||||
if((x < src_col)&&(y < src_row))
|
||||
{
|
||||
int src_x1 = (x + 1) < (src_col -1)? (x + 1) : (src_col - 1);
|
||||
int src_x2 = (x - 1) > 0 ? (x -1) : 0;
|
||||
dx[y * d_step+ x] = 0.5f * (src_ptr[y * src_step + src_x1] - src_ptr[y * src_step+ src_x2]);
|
||||
|
||||
int src_y1 = (y+1) < (src_row - 1) ? (y + 1) : (src_row - 1);
|
||||
int src_y2 = (y - 1) > 0 ? (y - 1) : 0;
|
||||
dy[y * d_step+ x] = 0.5f * (src_ptr[src_y1 * src_step + x] - src_ptr[src_y2 * src_step+ x]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline float bicubicCoeff(float x_)
|
||||
{
|
||||
|
||||
float x = fabs(x_);
|
||||
if (x <= 1.0f)
|
||||
return x * x * (1.5f * x - 2.5f) + 1.0f;
|
||||
else if (x < 2.0f)
|
||||
return x * (x * (-0.5f * x + 2.5f) - 4.0f) + 2.0f;
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
__kernel void warpBackwardKernel(__global const float* I0, int I0_step, int I0_col, int I0_row,
|
||||
image2d_t tex_I1, image2d_t tex_I1x, image2d_t tex_I1y,
|
||||
__global const float* u1, int u1_step,
|
||||
__global const float* u2,
|
||||
__global float* I1w,
|
||||
__global float* I1wx, /*int I1wx_step,*/
|
||||
__global float* I1wy, /*int I1wy_step,*/
|
||||
__global float* grad, /*int grad_step,*/
|
||||
__global float* rho,
|
||||
int I1w_step,
|
||||
int u2_step,
|
||||
int u1_offset_x,
|
||||
int u1_offset_y,
|
||||
int u2_offset_x,
|
||||
int u2_offset_y)
|
||||
{
|
||||
int x = get_global_id(0);
|
||||
int y = get_global_id(1);
|
||||
|
||||
if(x < I0_col&&y < I0_row)
|
||||
{
|
||||
//float u1Val = u1(y, x);
|
||||
float u1Val = u1[(y + u1_offset_y) * u1_step + x + u1_offset_x];
|
||||
//float u2Val = u2(y, x);
|
||||
float u2Val = u2[(y + u2_offset_y) * u2_step + x + u2_offset_x];
|
||||
|
||||
float wx = x + u1Val;
|
||||
float wy = y + u2Val;
|
||||
|
||||
int xmin = ceil(wx - 2.0f);
|
||||
int xmax = floor(wx + 2.0f);
|
||||
|
||||
int ymin = ceil(wy - 2.0f);
|
||||
int ymax = floor(wy + 2.0f);
|
||||
|
||||
float sum = 0.0f;
|
||||
float sumx = 0.0f;
|
||||
float sumy = 0.0f;
|
||||
float wsum = 0.0f;
|
||||
sampler_t sampleri = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;
|
||||
for (int cy = ymin; cy <= ymax; ++cy)
|
||||
{
|
||||
for (int cx = xmin; cx <= xmax; ++cx)
|
||||
{
|
||||
float w = bicubicCoeff(wx - cx) * bicubicCoeff(wy - cy);
|
||||
//sum += w * tex2D(tex_I1 , cx, cy);
|
||||
int2 cood = (int2)(cx, cy);
|
||||
sum += w * read_imagef(tex_I1, sampleri, cood).x;
|
||||
//sumx += w * tex2D(tex_I1x, cx, cy);
|
||||
sumx += w * read_imagef(tex_I1x, sampleri, cood).x;
|
||||
//sumy += w * tex2D(tex_I1y, cx, cy);
|
||||
sumy += w * read_imagef(tex_I1y, sampleri, cood).x;
|
||||
wsum += w;
|
||||
}
|
||||
}
|
||||
float coeff = 1.0f / wsum;
|
||||
float I1wVal = sum * coeff;
|
||||
float I1wxVal = sumx * coeff;
|
||||
float I1wyVal = sumy * coeff;
|
||||
I1w[y * I1w_step + x] = I1wVal;
|
||||
I1wx[y * I1w_step + x] = I1wxVal;
|
||||
I1wy[y * I1w_step + x] = I1wyVal;
|
||||
float Ix2 = I1wxVal * I1wxVal;
|
||||
float Iy2 = I1wyVal * I1wyVal;
|
||||
|
||||
// store the |Grad(I1)|^2
|
||||
grad[y * I1w_step + x] = Ix2 + Iy2;
|
||||
|
||||
// compute the constant part of the rho function
|
||||
float I0Val = I0[y * I0_step + x];
|
||||
rho[y * I1w_step + x] = I1wVal - I1wxVal * u1Val - I1wyVal * u2Val - I0Val;
|
||||
}
|
||||
}
|
||||
|
||||
inline float readImage(__global const float *image, int x, int y, int rows, int cols, int elemCntPerRow)
|
||||
{
|
||||
int i0 = clamp(x, 0, cols - 1);
|
||||
int j0 = clamp(y, 0, rows - 1);
|
||||
|
||||
return image[j0 * elemCntPerRow + i0];
|
||||
}
|
||||
|
||||
__kernel void warpBackwardKernelNoImage2d(__global const float* I0, int I0_step, int I0_col, int I0_row,
|
||||
__global const float* tex_I1, __global const float* tex_I1x, __global const float* tex_I1y,
|
||||
__global const float* u1, int u1_step,
|
||||
__global const float* u2,
|
||||
__global float* I1w,
|
||||
__global float* I1wx, /*int I1wx_step,*/
|
||||
__global float* I1wy, /*int I1wy_step,*/
|
||||
__global float* grad, /*int grad_step,*/
|
||||
__global float* rho,
|
||||
int I1w_step,
|
||||
int u2_step,
|
||||
int I1_step,
|
||||
int I1x_step)
|
||||
{
|
||||
int x = get_global_id(0);
|
||||
int y = get_global_id(1);
|
||||
|
||||
if(x < I0_col&&y < I0_row)
|
||||
{
|
||||
//float u1Val = u1(y, x);
|
||||
float u1Val = u1[y * u1_step + x];
|
||||
//float u2Val = u2(y, x);
|
||||
float u2Val = u2[y * u2_step + x];
|
||||
|
||||
float wx = x + u1Val;
|
||||
float wy = y + u2Val;
|
||||
|
||||
int xmin = ceil(wx - 2.0f);
|
||||
int xmax = floor(wx + 2.0f);
|
||||
|
||||
int ymin = ceil(wy - 2.0f);
|
||||
int ymax = floor(wy + 2.0f);
|
||||
|
||||
float sum = 0.0f;
|
||||
float sumx = 0.0f;
|
||||
float sumy = 0.0f;
|
||||
float wsum = 0.0f;
|
||||
|
||||
for (int cy = ymin; cy <= ymax; ++cy)
|
||||
{
|
||||
for (int cx = xmin; cx <= xmax; ++cx)
|
||||
{
|
||||
float w = bicubicCoeff(wx - cx) * bicubicCoeff(wy - cy);
|
||||
|
||||
int2 cood = (int2)(cx, cy);
|
||||
sum += w * readImage(tex_I1, cood.x, cood.y, I0_col, I0_row, I1_step);
|
||||
sumx += w * readImage(tex_I1x, cood.x, cood.y, I0_col, I0_row, I1x_step);
|
||||
sumy += w * readImage(tex_I1y, cood.x, cood.y, I0_col, I0_row, I1x_step);
|
||||
wsum += w;
|
||||
}
|
||||
}
|
||||
|
||||
float coeff = 1.0f / wsum;
|
||||
|
||||
float I1wVal = sum * coeff;
|
||||
float I1wxVal = sumx * coeff;
|
||||
float I1wyVal = sumy * coeff;
|
||||
|
||||
I1w[y * I1w_step + x] = I1wVal;
|
||||
I1wx[y * I1w_step + x] = I1wxVal;
|
||||
I1wy[y * I1w_step + x] = I1wyVal;
|
||||
|
||||
float Ix2 = I1wxVal * I1wxVal;
|
||||
float Iy2 = I1wyVal * I1wyVal;
|
||||
|
||||
// store the |Grad(I1)|^2
|
||||
grad[y * I1w_step + x] = Ix2 + Iy2;
|
||||
|
||||
// compute the constant part of the rho function
|
||||
float I0Val = I0[y * I0_step + x];
|
||||
rho[y * I1w_step + x] = I1wVal - I1wxVal * u1Val - I1wyVal * u2Val - I0Val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
__kernel void estimateDualVariablesKernel(__global const float* u1, int u1_col, int u1_row, int u1_step,
|
||||
__global const float* u2,
|
||||
__global float* p11, int p11_step,
|
||||
__global float* p12,
|
||||
__global float* p21,
|
||||
__global float* p22,
|
||||
float taut,
|
||||
int u2_step,
|
||||
int u1_offset_x,
|
||||
int u1_offset_y,
|
||||
int u2_offset_x,
|
||||
int u2_offset_y)
|
||||
{
|
||||
int x = get_global_id(0);
|
||||
int y = get_global_id(1);
|
||||
|
||||
if(x < u1_col && y < u1_row)
|
||||
{
|
||||
int src_x1 = (x + 1) < (u1_col - 1) ? (x + 1) : (u1_col - 1);
|
||||
float u1x = u1[(y + u1_offset_y) * u1_step + src_x1 + u1_offset_x] - u1[(y + u1_offset_y) * u1_step + x + u1_offset_x];
|
||||
|
||||
int src_y1 = (y + 1) < (u1_row - 1) ? (y + 1) : (u1_row - 1);
|
||||
float u1y = u1[(src_y1 + u1_offset_y) * u1_step + x + u1_offset_x] - u1[(y + u1_offset_y) * u1_step + x + u1_offset_x];
|
||||
|
||||
int src_x2 = (x + 1) < (u1_col - 1) ? (x + 1) : (u1_col - 1);
|
||||
float u2x = u2[(y + u2_offset_y) * u2_step + src_x2 + u2_offset_x] - u2[(y + u2_offset_y) * u2_step + x + u2_offset_x];
|
||||
|
||||
int src_y2 = (y + 1) < (u1_row - 1) ? (y + 1) : (u1_row - 1);
|
||||
float u2y = u2[(src_y2 + u2_offset_y) * u2_step + x + u2_offset_x] - u2[(y + u2_offset_y) * u2_step + x + u2_offset_x];
|
||||
|
||||
float g1 = hypot(u1x, u1y);
|
||||
float g2 = hypot(u2x, u2y);
|
||||
|
||||
float ng1 = 1.0f + taut * g1;
|
||||
float ng2 = 1.0f + taut * g2;
|
||||
|
||||
p11[y * p11_step + x] = (p11[y * p11_step + x] + taut * u1x) / ng1;
|
||||
p12[y * p11_step + x] = (p12[y * p11_step + x] + taut * u1y) / ng1;
|
||||
p21[y * p11_step + x] = (p21[y * p11_step + x] + taut * u2x) / ng2;
|
||||
p22[y * p11_step + x] = (p22[y * p11_step + x] + taut * u2y) / ng2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline float divergence(__global const float* v1, __global const float* v2, int y, int x, int v1_step, int v2_step)
|
||||
{
|
||||
|
||||
if (x > 0 && y > 0)
|
||||
{
|
||||
float v1x = v1[y * v1_step + x] - v1[y * v1_step + x - 1];
|
||||
float v2y = v2[y * v2_step + x] - v2[(y - 1) * v2_step + x];
|
||||
return v1x + v2y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y > 0)
|
||||
return v1[y * v1_step + 0] + v2[y * v2_step + 0] - v2[(y - 1) * v2_step + 0];
|
||||
else
|
||||
{
|
||||
if (x > 0)
|
||||
return v1[0 * v1_step + x] - v1[0 * v1_step + x - 1] + v2[0 * v2_step + x];
|
||||
else
|
||||
return v1[0 * v1_step + 0] + v2[0 * v2_step + 0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__kernel void estimateUKernel(__global const float* I1wx, int I1wx_col, int I1wx_row, int I1wx_step,
|
||||
__global const float* I1wy, /*int I1wy_step,*/
|
||||
__global const float* grad, /*int grad_step,*/
|
||||
__global const float* rho_c, /*int rho_c_step,*/
|
||||
__global const float* p11, /*int p11_step,*/
|
||||
__global const float* p12, /*int p12_step,*/
|
||||
__global const float* p21, /*int p21_step,*/
|
||||
__global const float* p22, /*int p22_step,*/
|
||||
__global float* u1, int u1_step,
|
||||
__global float* u2,
|
||||
__global float* error, float l_t, float theta, int u2_step,
|
||||
int u1_offset_x,
|
||||
int u1_offset_y,
|
||||
int u2_offset_x,
|
||||
int u2_offset_y,
|
||||
char calc_error)
|
||||
{
|
||||
int x = get_global_id(0);
|
||||
int y = get_global_id(1);
|
||||
|
||||
if(x < I1wx_col && y < I1wx_row)
|
||||
{
|
||||
float I1wxVal = I1wx[y * I1wx_step + x];
|
||||
float I1wyVal = I1wy[y * I1wx_step + x];
|
||||
float gradVal = grad[y * I1wx_step + x];
|
||||
float u1OldVal = u1[(y + u1_offset_y) * u1_step + x + u1_offset_x];
|
||||
float u2OldVal = u2[(y + u2_offset_y) * u2_step + x + u2_offset_x];
|
||||
|
||||
float rho = rho_c[y * I1wx_step + x] + (I1wxVal * u1OldVal + I1wyVal * u2OldVal);
|
||||
|
||||
// estimate the values of the variable (v1, v2) (thresholding operator TH)
|
||||
|
||||
float d1 = 0.0f;
|
||||
float d2 = 0.0f;
|
||||
|
||||
if (rho < -l_t * gradVal)
|
||||
{
|
||||
d1 = l_t * I1wxVal;
|
||||
d2 = l_t * I1wyVal;
|
||||
}
|
||||
else if (rho > l_t * gradVal)
|
||||
{
|
||||
d1 = -l_t * I1wxVal;
|
||||
d2 = -l_t * I1wyVal;
|
||||
}
|
||||
else if (gradVal > 1.192092896e-07f)
|
||||
{
|
||||
float fi = -rho / gradVal;
|
||||
d1 = fi * I1wxVal;
|
||||
d2 = fi * I1wyVal;
|
||||
}
|
||||
|
||||
float v1 = u1OldVal + d1;
|
||||
float v2 = u2OldVal + d2;
|
||||
|
||||
// compute the divergence of the dual variable (p1, p2)
|
||||
|
||||
float div_p1 = divergence(p11, p12, y, x, I1wx_step, I1wx_step);
|
||||
float div_p2 = divergence(p21, p22, y, x, I1wx_step, I1wx_step);
|
||||
|
||||
// estimate the values of the optical flow (u1, u2)
|
||||
|
||||
float u1NewVal = v1 + theta * div_p1;
|
||||
float u2NewVal = v2 + theta * div_p2;
|
||||
|
||||
u1[(y + u1_offset_y) * u1_step + x + u1_offset_x] = u1NewVal;
|
||||
u2[(y + u2_offset_y) * u2_step + x + u2_offset_x] = u2NewVal;
|
||||
|
||||
if(calc_error)
|
||||
{
|
||||
float n1 = (u1OldVal - u1NewVal) * (u1OldVal - u1NewVal);
|
||||
float n2 = (u2OldVal - u2NewVal) * (u2OldVal - u2NewVal);
|
||||
error[y * I1wx_step + x] = n1 + n2;
|
||||
}
|
||||
}
|
||||
}
|
129
modules/video/src/optical_flow_io.cpp
Normal file
129
modules/video/src/optical_flow_io.cpp
Normal 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 flow; // no file - return empty matrix
|
||||
|
||||
float tag;
|
||||
file.read((char*) &tag, sizeof(float));
|
||||
if ( tag != FLOW_TAG_FLOAT )
|
||||
return 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 flow;
|
||||
}
|
||||
|
||||
flow(i, j) = u;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
return 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;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
1191
modules/video/src/variational_refinement.cpp
Normal file
1191
modules/video/src/variational_refinement.cpp
Normal file
File diff suppressed because it is too large
Load Diff
96
modules/video/test/ocl/test_dis.cpp
Normal file
96
modules/video/test/ocl/test_dis.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/*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 {
|
||||
|
||||
PARAM_TEST_CASE(OCL_DenseOpticalFlow_DIS, int)
|
||||
{
|
||||
int preset;
|
||||
|
||||
virtual void SetUp()
|
||||
{
|
||||
preset = GET_PARAM(0);
|
||||
}
|
||||
};
|
||||
|
||||
OCL_TEST_P(OCL_DenseOpticalFlow_DIS, Mat)
|
||||
{
|
||||
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);
|
||||
|
||||
Ptr<DenseOpticalFlow> algo;
|
||||
|
||||
// iterate over presets:
|
||||
for (int i = 0; i < cvtest::ocl::test_loop_times; i++)
|
||||
{
|
||||
Mat flow;
|
||||
UMat ocl_flow;
|
||||
|
||||
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,
|
||||
Values(DISOpticalFlow::PRESET_ULTRAFAST,
|
||||
DISOpticalFlow::PRESET_FAST,
|
||||
DISOpticalFlow::PRESET_MEDIUM));
|
||||
|
||||
}} // namespace
|
||||
|
||||
#endif // HAVE_OPENCL
|
@ -1,117 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 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 {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Optical_flow_tvl1
|
||||
namespace
|
||||
{
|
||||
IMPLEMENT_PARAM_CLASS(UseInitFlow, bool)
|
||||
IMPLEMENT_PARAM_CLASS(MedianFiltering, int)
|
||||
IMPLEMENT_PARAM_CLASS(ScaleStep, double)
|
||||
}
|
||||
|
||||
PARAM_TEST_CASE(OpticalFlowTVL1, UseInitFlow, MedianFiltering, ScaleStep)
|
||||
{
|
||||
bool useInitFlow;
|
||||
int medianFiltering;
|
||||
double scaleStep;
|
||||
virtual void SetUp()
|
||||
{
|
||||
useInitFlow = GET_PARAM(0);
|
||||
medianFiltering = GET_PARAM(1);
|
||||
scaleStep = GET_PARAM(2);
|
||||
}
|
||||
};
|
||||
|
||||
OCL_TEST_P(OpticalFlowTVL1, 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());
|
||||
|
||||
cv::Mat flow; cv::UMat uflow;
|
||||
|
||||
//create algorithm
|
||||
cv::Ptr<cv::DualTVL1OpticalFlow> alg = cv::createOptFlow_DualTVL1();
|
||||
|
||||
//set parameters
|
||||
alg->setScaleStep(scaleStep);
|
||||
alg->setMedianFiltering(medianFiltering);
|
||||
|
||||
//create initial flow as result of algorithm calculation
|
||||
if (useInitFlow)
|
||||
{
|
||||
OCL_ON(alg->calc(frame0, frame1, uflow));
|
||||
uflow.copyTo(flow);
|
||||
}
|
||||
|
||||
//set flag to use initial flow as it is ready to use
|
||||
alg->setUseInitialFlow(useInitFlow);
|
||||
|
||||
OCL_OFF(alg->calc(frame0, frame1, flow));
|
||||
OCL_ON(alg->calc(frame0, frame1, uflow));
|
||||
|
||||
EXPECT_MAT_SIMILAR(flow, uflow, 1e-2);
|
||||
}
|
||||
|
||||
OCL_INSTANTIATE_TEST_CASE_P(Video, OpticalFlowTVL1,
|
||||
Combine(
|
||||
Values(UseInitFlow(false), UseInitFlow(true)),
|
||||
Values(MedianFiltering(3), MedianFiltering(-1)),
|
||||
Values(ScaleStep(0.3),ScaleStep(0.5))
|
||||
)
|
||||
);
|
||||
|
||||
} } // namespace opencv_test::ocl
|
||||
|
||||
#endif // HAVE_OPENCL
|
147
modules/video/test/test_OF_accuracy.cpp
Normal file
147
modules/video/test/test_OF_accuracy.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*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_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
|
160
modules/video/test/test_OF_reproducibility.cpp
Normal file
160
modules/video/test/test_OF_reproducibility.cpp
Normal 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
|
@ -6,5 +6,10 @@
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/video.hpp"
|
||||
#include <opencv2/ts/ts_perf.hpp>
|
||||
|
||||
namespace opencv_test {
|
||||
using namespace perf;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,173 +0,0 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
//#define DUMP
|
||||
|
||||
// first four bytes, should be the same in little endian
|
||||
const float FLO_TAG_FLOAT = 202021.25f; // check for this when READING the file
|
||||
|
||||
#ifdef DUMP
|
||||
// binary file format for flow data specified here:
|
||||
// http://vision.middlebury.edu/flow/data/
|
||||
void writeOpticalFlowToFile(const Mat_<Point2f>& flow, const string& fileName)
|
||||
{
|
||||
const char FLO_TAG_STRING[] = "PIEH"; // use this when WRITING the file
|
||||
ofstream file(fileName.c_str(), ios_base::binary);
|
||||
|
||||
file << FLO_TAG_STRING;
|
||||
|
||||
file.write((const char*) &flow.cols, sizeof(int));
|
||||
file.write((const char*) &flow.rows, sizeof(int));
|
||||
|
||||
for (int i = 0; i < flow.rows; ++i)
|
||||
{
|
||||
for (int j = 0; j < flow.cols; ++j)
|
||||
{
|
||||
const Point2f u = flow(i, j);
|
||||
|
||||
file.write((const char*) &u.x, sizeof(float));
|
||||
file.write((const char*) &u.y, sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// binary file format for flow data specified here:
|
||||
// http://vision.middlebury.edu/flow/data/
|
||||
void readOpticalFlowFromFile(Mat_<Point2f>& flow, const string& fileName)
|
||||
{
|
||||
std::ifstream file(fileName.c_str(), std::ios_base::binary);
|
||||
|
||||
float tag;
|
||||
file.read((char*) &tag, sizeof(float));
|
||||
CV_Assert( tag == FLO_TAG_FLOAT );
|
||||
|
||||
Size size;
|
||||
|
||||
file.read((char*) &size.width, sizeof(int));
|
||||
file.read((char*) &size.height, sizeof(int));
|
||||
|
||||
flow.create(size);
|
||||
|
||||
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));
|
||||
|
||||
flow(i, j) = u;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
bool isFlowCorrect(Point2f u)
|
||||
{
|
||||
return !cvIsNaN(u.x) && !cvIsNaN(u.y) && (fabs(u.x) < 1e9) && (fabs(u.y) < 1e9);
|
||||
}
|
||||
|
||||
void check(const Mat_<Point2f>& gold, const Mat_<Point2f>& flow, double threshold = 0.1, double expectedAccuracy = 0.95)
|
||||
{
|
||||
threshold = threshold*threshold;
|
||||
|
||||
size_t gold_counter = 0;
|
||||
size_t valid_counter = 0;
|
||||
|
||||
for (int i = 0; i < gold.rows; ++i)
|
||||
{
|
||||
for (int j = 0; j < gold.cols; ++j)
|
||||
{
|
||||
const Point2f u1 = gold(i, j);
|
||||
const Point2f u2 = flow(i, j);
|
||||
|
||||
if (isFlowCorrect(u1))
|
||||
{
|
||||
gold_counter++;
|
||||
if (isFlowCorrect(u2))
|
||||
{
|
||||
const Point2f diff = u1 - u2;
|
||||
double err = diff.ddot(diff);
|
||||
if (err <= threshold)
|
||||
valid_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_GE(valid_counter, expectedAccuracy * gold_counter);
|
||||
}
|
||||
|
||||
TEST(Video_calcOpticalFlowDual_TVL1, Regression)
|
||||
{
|
||||
const string frame1_path = TS::ptr()->get_data_path() + "optflow/RubberWhale1.png";
|
||||
const string frame2_path = TS::ptr()->get_data_path() + "optflow/RubberWhale2.png";
|
||||
const string gold_flow_path = TS::ptr()->get_data_path() + "optflow/tvl1_flow.flo";
|
||||
|
||||
Mat frame1 = imread(frame1_path, IMREAD_GRAYSCALE);
|
||||
Mat frame2 = imread(frame2_path, IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame1.empty());
|
||||
ASSERT_FALSE(frame2.empty());
|
||||
|
||||
Mat_<Point2f> flow;
|
||||
Ptr<DualTVL1OpticalFlow> tvl1 = cv::DualTVL1OpticalFlow::create();
|
||||
|
||||
tvl1->calc(frame1, frame2, flow);
|
||||
|
||||
#ifdef DUMP
|
||||
writeOpticalFlowToFile(flow, gold_flow_path);
|
||||
#else
|
||||
Mat_<Point2f> gold;
|
||||
readOpticalFlowFromFile(gold, gold_flow_path);
|
||||
|
||||
ASSERT_EQ(gold.rows, flow.rows);
|
||||
ASSERT_EQ(gold.cols, flow.cols);
|
||||
|
||||
check(gold, flow);
|
||||
#endif
|
||||
}
|
||||
|
||||
}} // namespace
|
73
samples/cpp/dis_opticalflow.cpp
Normal file
73
samples/cpp/dis_opticalflow.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/video.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
static void help()
|
||||
{
|
||||
printf("Usage: dis_optflow <video_file>\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
VideoCapture cap;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cap.open(argv[1]);
|
||||
if(!cap.isOpened())
|
||||
{
|
||||
printf("ERROR: Cannot open file %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat prevgray, gray, rgb, frame;
|
||||
Mat flow, flow_uv[2];
|
||||
Mat mag, ang;
|
||||
Mat hsv_split[3], hsv;
|
||||
char ret;
|
||||
|
||||
namedWindow("flow", 1);
|
||||
namedWindow("orig", 1);
|
||||
|
||||
Ptr<DenseOpticalFlow> algorithm = DISOpticalFlow::create(DISOpticalFlow::PRESET_MEDIUM);
|
||||
|
||||
while(true)
|
||||
{
|
||||
cap >> frame;
|
||||
if (frame.empty())
|
||||
break;
|
||||
|
||||
cvtColor(frame, gray, COLOR_BGR2GRAY);
|
||||
|
||||
if (!prevgray.empty())
|
||||
{
|
||||
algorithm->calc(prevgray, gray, flow);
|
||||
split(flow, flow_uv);
|
||||
multiply(flow_uv[1], -1, flow_uv[1]);
|
||||
cartToPolar(flow_uv[0], flow_uv[1], mag, ang, true);
|
||||
normalize(mag, mag, 0, 1, NORM_MINMAX);
|
||||
hsv_split[0] = ang;
|
||||
hsv_split[1] = mag;
|
||||
hsv_split[2] = Mat::ones(ang.size(), ang.type());
|
||||
merge(hsv_split, 3, hsv);
|
||||
cvtColor(hsv, rgb, COLOR_HSV2BGR);
|
||||
imshow("flow", rgb);
|
||||
imshow("orig", frame);
|
||||
}
|
||||
|
||||
if ((ret = (char)waitKey(20)) > 0)
|
||||
break;
|
||||
std::swap(prevgray, gray);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include "opencv2/video.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
inline bool isFlowCorrect(Point2f u)
|
||||
{
|
||||
return !cvIsNaN(u.x) && !cvIsNaN(u.y) && fabs(u.x) < 1e9 && fabs(u.y) < 1e9;
|
||||
}
|
||||
|
||||
static Vec3b computeColor(float fx, float fy)
|
||||
{
|
||||
static bool first = true;
|
||||
|
||||
// relative lengths of color transitions:
|
||||
// these are chosen based on perceptual similarity
|
||||
// (e.g. one can distinguish more shades between red and yellow
|
||||
// than between yellow and green)
|
||||
const int RY = 15;
|
||||
const int YG = 6;
|
||||
const int GC = 4;
|
||||
const int CB = 11;
|
||||
const int BM = 13;
|
||||
const int MR = 6;
|
||||
const int NCOLS = RY + YG + GC + CB + BM + MR;
|
||||
static Vec3i colorWheel[NCOLS];
|
||||
|
||||
if (first)
|
||||
{
|
||||
int k = 0;
|
||||
|
||||
for (int i = 0; i < RY; ++i, ++k)
|
||||
colorWheel[k] = Vec3i(255, 255 * i / RY, 0);
|
||||
|
||||
for (int i = 0; i < YG; ++i, ++k)
|
||||
colorWheel[k] = Vec3i(255 - 255 * i / YG, 255, 0);
|
||||
|
||||
for (int i = 0; i < GC; ++i, ++k)
|
||||
colorWheel[k] = Vec3i(0, 255, 255 * i / GC);
|
||||
|
||||
for (int i = 0; i < CB; ++i, ++k)
|
||||
colorWheel[k] = Vec3i(0, 255 - 255 * i / CB, 255);
|
||||
|
||||
for (int i = 0; i < BM; ++i, ++k)
|
||||
colorWheel[k] = Vec3i(255 * i / BM, 0, 255);
|
||||
|
||||
for (int i = 0; i < MR; ++i, ++k)
|
||||
colorWheel[k] = Vec3i(255, 0, 255 - 255 * i / MR);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
const float rad = sqrt(fx * fx + fy * fy);
|
||||
const float a = atan2(-fy, -fx) / (float)CV_PI;
|
||||
|
||||
const float fk = (a + 1.0f) / 2.0f * (NCOLS - 1);
|
||||
const int k0 = static_cast<int>(fk);
|
||||
const int k1 = (k0 + 1) % NCOLS;
|
||||
const float f = fk - k0;
|
||||
|
||||
Vec3b pix;
|
||||
|
||||
for (int b = 0; b < 3; b++)
|
||||
{
|
||||
const float col0 = colorWheel[k0][b] / 255.f;
|
||||
const float col1 = colorWheel[k1][b] / 255.f;
|
||||
|
||||
float col = (1 - f) * col0 + f * col1;
|
||||
|
||||
if (rad <= 1)
|
||||
col = 1 - rad * (1 - col); // increase saturation with radius
|
||||
else
|
||||
col *= .75; // out of range
|
||||
|
||||
pix[2 - b] = static_cast<uchar>(255.f * col);
|
||||
}
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
static void drawOpticalFlow(const Mat_<Point2f>& flow, Mat& dst, float maxmotion = -1)
|
||||
{
|
||||
dst.create(flow.size(), CV_8UC3);
|
||||
dst.setTo(Scalar::all(0));
|
||||
|
||||
// determine motion range:
|
||||
float maxrad = maxmotion;
|
||||
|
||||
if (maxmotion <= 0)
|
||||
{
|
||||
maxrad = 1;
|
||||
for (int y = 0; y < flow.rows; ++y)
|
||||
{
|
||||
for (int x = 0; x < flow.cols; ++x)
|
||||
{
|
||||
Point2f u = flow(y, x);
|
||||
|
||||
if (!isFlowCorrect(u))
|
||||
continue;
|
||||
|
||||
maxrad = max(maxrad, sqrt(u.x * u.x + u.y * u.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < flow.rows; ++y)
|
||||
{
|
||||
for (int x = 0; x < flow.cols; ++x)
|
||||
{
|
||||
Point2f u = flow(y, x);
|
||||
|
||||
if (isFlowCorrect(u))
|
||||
dst.at<Vec3b>(y, x) = computeColor(u.x / maxrad, u.y / maxrad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// binary file format for flow data specified here:
|
||||
// http://vision.middlebury.edu/flow/data/
|
||||
static void writeOpticalFlowToFile(const Mat_<Point2f>& flow, const string& fileName)
|
||||
{
|
||||
static const char FLO_TAG_STRING[] = "PIEH";
|
||||
|
||||
ofstream file(fileName.c_str(), ios_base::binary);
|
||||
|
||||
file << FLO_TAG_STRING;
|
||||
|
||||
file.write((const char*) &flow.cols, sizeof(int));
|
||||
file.write((const char*) &flow.rows, sizeof(int));
|
||||
|
||||
for (int i = 0; i < flow.rows; ++i)
|
||||
{
|
||||
for (int j = 0; j < flow.cols; ++j)
|
||||
{
|
||||
const Point2f u = flow(i, j);
|
||||
|
||||
file.write((const char*) &u.x, sizeof(float));
|
||||
file.write((const char*) &u.y, sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
cv::CommandLineParser parser(argc, argv, "{help h || show help message}"
|
||||
"{ @frame0 | | frame 0}{ @frame1 | | frame 1}{ @output | | output flow}");
|
||||
if (parser.has("help"))
|
||||
{
|
||||
parser.printMessage();
|
||||
return 0;
|
||||
}
|
||||
string frame0_name = parser.get<string>("@frame0");
|
||||
string frame1_name = parser.get<string>("@frame1");
|
||||
string file = parser.get<string>("@output");
|
||||
if (frame0_name.empty() || frame1_name.empty() || file.empty())
|
||||
{
|
||||
cerr << "Usage : " << argv[0] << " [<frame0>] [<frame1>] [<output_flow>]" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat frame0 = imread(frame0_name, IMREAD_GRAYSCALE);
|
||||
Mat frame1 = imread(frame1_name, IMREAD_GRAYSCALE);
|
||||
|
||||
if (frame0.empty())
|
||||
{
|
||||
cerr << "Can't open image [" << parser.get<string>("frame0") << "]" << endl;
|
||||
return -1;
|
||||
}
|
||||
if (frame1.empty())
|
||||
{
|
||||
cerr << "Can't open image [" << parser.get<string>("frame1") << "]" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (frame1.size() != frame0.size())
|
||||
{
|
||||
cerr << "Images should be of equal sizes" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat_<Point2f> flow;
|
||||
Ptr<DualTVL1OpticalFlow> tvl1 = cv::DualTVL1OpticalFlow::create();
|
||||
|
||||
const double start = (double)getTickCount();
|
||||
tvl1->calc(frame0, frame1, flow);
|
||||
const double timeSec = (getTickCount() - start) / getTickFrequency();
|
||||
cout << "calcOpticalFlowDual_TVL1 : " << timeSec << " sec" << endl;
|
||||
|
||||
Mat out;
|
||||
drawOpticalFlow(flow, out);
|
||||
if (!file.empty())
|
||||
writeOpticalFlowToFile(flow, file);
|
||||
|
||||
imshow("Flow", out);
|
||||
waitKey();
|
||||
|
||||
return 0;
|
||||
}
|
114
samples/python/dis_opt_flow.py
Executable file
114
samples/python/dis_opt_flow.py
Executable file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
example to show optical flow estimation using DISOpticalFlow
|
||||
|
||||
USAGE: dis_opt_flow.py [<video_source>]
|
||||
|
||||
Keys:
|
||||
1 - toggle HSV flow visualization
|
||||
2 - toggle glitch
|
||||
3 - toggle spatial propagation of flow vectors
|
||||
4 - toggle temporal propagation of flow vectors
|
||||
ESC - exit
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import video
|
||||
|
||||
|
||||
def draw_flow(img, flow, step=16):
|
||||
h, w = img.shape[:2]
|
||||
y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2,-1).astype(int)
|
||||
fx, fy = flow[y,x].T
|
||||
lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
|
||||
lines = np.int32(lines + 0.5)
|
||||
vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
|
||||
cv.polylines(vis, lines, 0, (0, 255, 0))
|
||||
for (x1, y1), (x2, y2) in lines:
|
||||
cv.circle(vis, (x1, y1), 1, (0, 255, 0), -1)
|
||||
return vis
|
||||
|
||||
|
||||
def draw_hsv(flow):
|
||||
h, w = flow.shape[:2]
|
||||
fx, fy = flow[:,:,0], flow[:,:,1]
|
||||
ang = np.arctan2(fy, fx) + np.pi
|
||||
v = np.sqrt(fx*fx+fy*fy)
|
||||
hsv = np.zeros((h, w, 3), np.uint8)
|
||||
hsv[...,0] = ang*(180/np.pi/2)
|
||||
hsv[...,1] = 255
|
||||
hsv[...,2] = np.minimum(v*4, 255)
|
||||
bgr = cv.cvtColor(hsv, cv.COLOR_HSV2BGR)
|
||||
return bgr
|
||||
|
||||
|
||||
def warp_flow(img, flow):
|
||||
h, w = flow.shape[:2]
|
||||
flow = -flow
|
||||
flow[:,:,0] += np.arange(w)
|
||||
flow[:,:,1] += np.arange(h)[:,np.newaxis]
|
||||
res = cv.remap(img, flow, None, cv.INTER_LINEAR)
|
||||
return res
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
print(__doc__)
|
||||
try:
|
||||
fn = sys.argv[1]
|
||||
except IndexError:
|
||||
fn = 0
|
||||
|
||||
cam = video.create_capture(fn)
|
||||
ret, prev = cam.read()
|
||||
prevgray = cv.cvtColor(prev, cv.COLOR_BGR2GRAY)
|
||||
show_hsv = False
|
||||
show_glitch = False
|
||||
use_spatial_propagation = False
|
||||
use_temporal_propagation = True
|
||||
cur_glitch = prev.copy()
|
||||
inst = cv.DISOpticalFlow.create(cv.DISOPTICAL_FLOW_PRESET_MEDIUM)
|
||||
inst.setUseSpatialPropagation(use_spatial_propagation)
|
||||
|
||||
flow = None
|
||||
while True:
|
||||
ret, img = cam.read()
|
||||
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
|
||||
if flow is not None and use_temporal_propagation:
|
||||
#warp previous flow to get an initial approximation for the current flow:
|
||||
flow = inst.calc(prevgray, gray, warp_flow(flow,flow))
|
||||
else:
|
||||
flow = inst.calc(prevgray, gray, None)
|
||||
prevgray = gray
|
||||
|
||||
cv.imshow('flow', draw_flow(gray, flow))
|
||||
if show_hsv:
|
||||
cv.imshow('flow HSV', draw_hsv(flow))
|
||||
if show_glitch:
|
||||
cur_glitch = warp_flow(cur_glitch, flow)
|
||||
cv.imshow('glitch', cur_glitch)
|
||||
|
||||
ch = 0xFF & cv.waitKey(5)
|
||||
if ch == 27:
|
||||
break
|
||||
if ch == ord('1'):
|
||||
show_hsv = not show_hsv
|
||||
print('HSV flow visualization is', ['off', 'on'][show_hsv])
|
||||
if ch == ord('2'):
|
||||
show_glitch = not show_glitch
|
||||
if show_glitch:
|
||||
cur_glitch = img.copy()
|
||||
print('glitch is', ['off', 'on'][show_glitch])
|
||||
if ch == ord('3'):
|
||||
use_spatial_propagation = not use_spatial_propagation
|
||||
inst.setUseSpatialPropagation(use_spatial_propagation)
|
||||
print('spatial propagation is', ['off', 'on'][use_spatial_propagation])
|
||||
if ch == ord('4'):
|
||||
use_temporal_propagation = not use_temporal_propagation
|
||||
print('temporal propagation is', ['off', 'on'][use_temporal_propagation])
|
||||
cv.destroyAllWindows()
|
@ -50,7 +50,7 @@ int main(int argc, const char* argv[])
|
||||
const char* keys =
|
||||
"{ h help | | print help message }"
|
||||
"{ c camera | 0 | capture video from camera (device index starting from 0) }"
|
||||
"{ a algorithm | fb | algorithm (supported: 'fb', 'tvl')}"
|
||||
"{ a algorithm | fb | algorithm (supported: 'fb', 'dis')}"
|
||||
"{ m cpu | | run without OpenCL }"
|
||||
"{ v video | | use video as input }"
|
||||
"{ o original | | use original frame size (do not resize to 640x480)}"
|
||||
@ -84,11 +84,11 @@ int main(int argc, const char* argv[])
|
||||
return 2;
|
||||
}
|
||||
|
||||
cv::Ptr<cv::DenseOpticalFlow> alg;
|
||||
Ptr<DenseOpticalFlow> alg;
|
||||
if (algorithm == "fb")
|
||||
alg = cv::FarnebackOpticalFlow::create();
|
||||
else if (algorithm == "tvl")
|
||||
alg = cv::DualTVL1OpticalFlow::create();
|
||||
alg = FarnebackOpticalFlow::create();
|
||||
else if (algorithm == "dis")
|
||||
alg = DISOpticalFlow::create(DISOpticalFlow::PRESET_FAST);
|
||||
else
|
||||
{
|
||||
cout << "Invalid algorithm: " << algorithm << endl;
|
||||
|
Loading…
Reference in New Issue
Block a user