vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:11:13 +08:00
commit 12022378a3
3872 changed files with 2513409 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test { namespace {
PARAM_TEST_CASE(UpdateMotionHistory, bool)
{
double timestamp, duration;
bool use_roi;
TEST_DECLARE_INPUT_PARAMETER(silhouette);
TEST_DECLARE_OUTPUT_PARAMETER(mhi);
virtual void SetUp()
{
use_roi = GET_PARAM(0);
}
virtual void generateTestData()
{
Size roiSize = randomSize(1, MAX_VALUE);
Border silhouetteBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(silhouette, silhouette_roi, roiSize, silhouetteBorder, CV_8UC1, -11, 11);
Border mhiBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
randomSubMat(mhi, mhi_roi, roiSize, mhiBorder, CV_32FC1, 0, 1);
timestamp = randomDouble(0, 1);
duration = randomDouble(0, 1);
if (timestamp < duration)
std::swap(timestamp, duration);
UMAT_UPLOAD_INPUT_PARAMETER(silhouette);
UMAT_UPLOAD_OUTPUT_PARAMETER(mhi);
}
};
OCL_TEST_P(UpdateMotionHistory, Mat)
{
for (int j = 0; j < cvtest::ocl::test_loop_times; j++)
{
generateTestData();
OCL_OFF(cv::motempl::updateMotionHistory(silhouette_roi, mhi_roi, timestamp, duration));
OCL_ON(cv::motempl::updateMotionHistory(usilhouette_roi, umhi_roi, timestamp, duration));
OCL_EXPECT_MATS_NEAR(mhi, 0);
}
}
//////////////////////////////////////// Instantiation /////////////////////////////////////////
OCL_INSTANTIATE_TEST_CASE_P(Video, UpdateMotionHistory, Values(false, true));
}} // namespace
#endif // HAVE_OPENCL
@@ -0,0 +1,117 @@
/*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)
{
Mat frame0 = readImage("optflow/RubberWhale1.png", IMREAD_GRAYSCALE);
ASSERT_FALSE(frame0.empty());
Mat frame1 = readImage("optflow/RubberWhale2.png", IMREAD_GRAYSCALE);
ASSERT_FALSE(frame1.empty());
Mat flow; UMat uflow;
//create algorithm
Ptr<DualTVL1OpticalFlow> alg = 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(Contrib, 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
+353
View File
@@ -0,0 +1,353 @@
/*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 bool isFlowCorrect(double 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));
}
static float calcRMSE(vector<Point2f> prevPts, vector<Point2f> currPts, Mat flow)
{
vector<float> ee;
for (unsigned int n = 0; n < prevPts.size(); n++)
{
Point2f gtFlow = flow.at<Point2f>(prevPts[n]);
if (isFlowCorrect(gtFlow.x) && isFlowCorrect(gtFlow.y))
{
Point2f diffFlow = (currPts[n] - prevPts[n]) - gtFlow;
ee.push_back(sqrt(diffFlow.x * diffFlow.x + diffFlow.y * diffFlow.y));
}
}
return static_cast<float>(mean(ee).val[0]);
}
static float calcAvgEPE(vector< pair<Point2i, Point2i> > corr, Mat flow)
{
double sum = 0;
int counter = 0;
for (size_t i = 0; i < corr.size(); ++i)
{
Vec2f flow1_at_point = Point2f(corr[i].second - corr[i].first);
Vec2f flow2_at_point = flow.at<Vec2f>(corr[i].first.y, corr[i].first.x);
double u1 = (double)flow1_at_point[0];
double v1 = (double)flow1_at_point[1];
double u2 = (double)flow2_at_point[0];
double v2 = (double)flow2_at_point[1];
if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2))
{
sum += sqrt((u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2));
counter++;
}
}
return (float)(sum / counter);
}
bool readRubberWhale(Mat &dst_frame_1, Mat &dst_frame_2, Mat &dst_GT)
{
string frame1_path = getRubberWhaleFrame1();
string frame2_path = getRubberWhaleFrame2();
string gt_flow_path = getRubberWhaleGroundTruth();
// removing space may be an issue on windows machines
frame1_path.erase(std::remove_if(frame1_path.begin(), frame1_path.end(), isspace), frame1_path.end());
frame2_path.erase(std::remove_if(frame2_path.begin(), frame2_path.end(), isspace), frame2_path.end());
gt_flow_path.erase(std::remove_if(gt_flow_path.begin(), gt_flow_path.end(), isspace), gt_flow_path.end());
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_SimpleFlow, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
float target_RMSE = 0.37f;
Mat flow;
Ptr<DenseOpticalFlow> algo;
algo = createOptFlow_SimpleFlow();
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
}
TEST(DenseOpticalFlow_DeepFlow, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
float target_RMSE = 0.35f;
cvtColor(frame1, frame1, COLOR_BGR2GRAY);
cvtColor(frame2, frame2, COLOR_BGR2GRAY);
Mat flow;
Ptr<DenseOpticalFlow> algo;
algo = createOptFlow_DeepFlow();
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
}
TEST(SparseOpticalFlow, ReferenceAccuracy)
{
// with the following test each invoker class should be tested once
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
vector<Point2f> prevPts, currPts;
for (int r = 0; r < frame1.rows; r+=10)
{
for (int c = 0; c < frame1.cols; c+=10)
{
prevPts.push_back(Point2f(static_cast<float>(c), static_cast<float>(r)));
}
}
vector<uchar> status(prevPts.size());
vector<float> err(prevPts.size());
Ptr<SparseRLOFOpticalFlow> algo = SparseRLOFOpticalFlow::create();
algo->setForwardBackward(0.0f);
Ptr<RLOFOpticalFlowParameter> param = Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter);
param->supportRegionType = SR_CROSS;
param->useIlluminationModel = true;
param->solverType = ST_BILINEAR;
param->setUseMEstimator(true);
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.3f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.34f);
param->useIlluminationModel = false;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.27f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.27f);
param->setUseMEstimator(false);
param->useIlluminationModel = true;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.28f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.28f);
param->useIlluminationModel = false;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.80f);
param->solverType = ST_STANDART;
algo->setRLOFOpticalFlowParameter(param);
algo->calc(frame1, frame2, prevPts, currPts, status, err);
EXPECT_LE(calcRMSE(prevPts, currPts, GT), 0.28f);
}
TEST(DenseOpticalFlow_RLOF, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
Mat flow;
Ptr<DenseRLOFOpticalFlow> algo = DenseRLOFOpticalFlow::create();
Ptr<RLOFOpticalFlowParameter> param = Ptr<RLOFOpticalFlowParameter>(new RLOFOpticalFlowParameter);
param->setUseMEstimator(true);
param->supportRegionType = SR_CROSS;
param->solverType = ST_BILINEAR;
algo->setRLOFOpticalFlowParameter(param);
algo->setForwardBackward(1.0f);
algo->setGridStep(cv::Size(4, 4));
algo->setInterpolation(INTERP_EPIC);
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), 0.46f);
algo->setInterpolation(INTERP_GEO);
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), 0.55f);
}
TEST(DenseOpticalFlow_SparseToDenseFlow, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
float target_RMSE = 0.52f;
Mat flow;
Ptr<DenseOpticalFlow> algo;
algo = createOptFlow_SparseToDense();
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
}
TEST(DenseOpticalFlow_PCAFlow, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
const float target_RMSE = 0.55f;
Mat flow;
Ptr<DenseOpticalFlow> algo = createOptFlow_PCAFlow();
algo->calc(frame1, frame2, flow);
ASSERT_EQ(GT.rows, flow.rows);
ASSERT_EQ(GT.cols, flow.cols);
EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
}
TEST(DenseOpticalFlow_GlobalPatchColliderDCT, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
const Size sz = frame1.size() / 2;
frame1 = frame1(Rect(0, 0, sz.width, sz.height));
frame2 = frame2(Rect(0, 0, sz.width, sz.height));
GT = GT(Rect(0, 0, sz.width, sz.height));
vector<Mat> img1, img2, gt;
vector< pair<Point2i, Point2i> > corr;
img1.push_back(frame1);
img2.push_back(frame2);
gt.push_back(GT);
Ptr< GPCForest<5> > forest = GPCForest<5>::create();
forest->train(img1, img2, gt, GPCTrainingParams(8, 3, GPC_DESCRIPTOR_DCT, false));
forest->findCorrespondences(frame1, frame2, corr);
ASSERT_LE(7500U, corr.size());
ASSERT_LE(calcAvgEPE(corr, GT), 0.5f);
}
TEST(DenseOpticalFlow_GlobalPatchColliderWHT, ReferenceAccuracy)
{
Mat frame1, frame2, GT;
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
const Size sz = frame1.size() / 2;
frame1 = frame1(Rect(0, 0, sz.width, sz.height));
frame2 = frame2(Rect(0, 0, sz.width, sz.height));
GT = GT(Rect(0, 0, sz.width, sz.height));
vector<Mat> img1, img2, gt;
vector< pair<Point2i, Point2i> > corr;
img1.push_back(frame1);
img2.push_back(frame2);
gt.push_back(GT);
Ptr< GPCForest<5> > forest = GPCForest<5>::create();
forest->train(img1, img2, gt, GPCTrainingParams(8, 3, GPC_DESCRIPTOR_WHT, false));
forest->findCorrespondences(frame1, frame2, corr);
ASSERT_LE(7000U, corr.size());
ASSERT_LE(calcAvgEPE(corr, GT), 0.5f);
}
}} // namespace
+6
View File
@@ -0,0 +1,6 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
CV_TEST_MAIN("cv")
@@ -0,0 +1,501 @@
/*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 {
///////////////////// base MHI class ///////////////////////
class CV_MHIBaseTest : public cvtest::ArrayTest
{
public:
CV_MHIBaseTest();
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
int prepare_test_case( int test_case_idx );
double timestamp, duration, max_log_duration;
int mhi_i, mhi_ref_i;
double silh_ratio;
};
CV_MHIBaseTest::CV_MHIBaseTest()
{
timestamp = duration = 0;
max_log_duration = 9;
mhi_i = mhi_ref_i = -1;
silh_ratio = 0.25;
}
void CV_MHIBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
{
cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
if( i == INPUT && CV_MAT_DEPTH(type) == CV_8U )
{
low = Scalar::all(cvRound(-1./silh_ratio)+2.);
high = Scalar::all(2);
}
else if( i == mhi_i || i == mhi_ref_i )
{
low = Scalar::all(-exp(max_log_duration));
high = Scalar::all(0.);
}
}
void CV_MHIBaseTest::get_test_array_types_and_sizes( int test_case_idx,
vector<vector<Size> >& sizes, vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
types[INPUT][0] = CV_8UC1;
types[mhi_i][0] = types[mhi_ref_i][0] = CV_32FC1;
duration = exp(cvtest::randReal(rng)*max_log_duration);
timestamp = duration + cvtest::randReal(rng)*30.-10.;
}
int CV_MHIBaseTest::prepare_test_case( int test_case_idx )
{
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
if( code > 0 )
{
Mat& mat = test_mat[mhi_i][0];
mat += Scalar::all(duration);
cv::max(mat, 0, mat);
if( mhi_i != mhi_ref_i )
{
Mat& mat0 = test_mat[mhi_ref_i][0];
cvtest::copy( mat, mat0 );
}
}
return code;
}
///////////////////// update motion history ////////////////////////////
static void test_updateMHI( const Mat& silh, Mat& mhi, double timestamp, double duration )
{
int i, j;
float delbound = (float)(timestamp - duration);
for( i = 0; i < mhi.rows; i++ )
{
const uchar* silh_row = silh.ptr(i);
float* mhi_row = mhi.ptr<float>(i);
for( j = 0; j < mhi.cols; j++ )
{
if( silh_row[j] )
mhi_row[j] = (float)timestamp;
else if( mhi_row[j] < delbound )
mhi_row[j] = 0.f;
}
}
}
class CV_UpdateMHITest : public CV_MHIBaseTest
{
public:
CV_UpdateMHITest();
protected:
double get_success_error_level( int test_case_idx, int i, int j );
void run_func();
void prepare_to_validation( int );
};
CV_UpdateMHITest::CV_UpdateMHITest()
{
test_array[INPUT].push_back(NULL);
test_array[INPUT_OUTPUT].push_back(NULL);
test_array[REF_INPUT_OUTPUT].push_back(NULL);
mhi_i = INPUT_OUTPUT; mhi_ref_i = REF_INPUT_OUTPUT;
}
double CV_UpdateMHITest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
{
return 0;
}
void CV_UpdateMHITest::run_func()
{
cv::motempl::updateMotionHistory( test_mat[INPUT][0], test_mat[INPUT_OUTPUT][0], timestamp, duration);
}
void CV_UpdateMHITest::prepare_to_validation( int /*test_case_idx*/ )
{
//CvMat m0 = test_mat[REF_INPUT_OUTPUT][0];
test_updateMHI( test_mat[INPUT][0], test_mat[REF_INPUT_OUTPUT][0], timestamp, duration );
}
///////////////////// calc motion gradient ////////////////////////////
static void test_MHIGradient( const Mat& mhi, Mat& mask, Mat& orientation,
double delta1, double delta2, int aperture_size )
{
Point anchor( aperture_size/2, aperture_size/2 );
double limit = 1e-4*aperture_size*aperture_size;
Mat dx, dy, min_mhi, max_mhi;
Mat kernel = cvtest::calcSobelKernel2D( 1, 0, aperture_size );
cvtest::filter2D( mhi, dx, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
kernel = cvtest::calcSobelKernel2D( 0, 1, aperture_size );
cvtest::filter2D( mhi, dy, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
kernel = Mat::ones(aperture_size, aperture_size, CV_8U);
cvtest::erode(mhi, min_mhi, kernel, anchor, 0, BORDER_REPLICATE);
cvtest::dilate(mhi, max_mhi, kernel, anchor, 0, BORDER_REPLICATE);
if( delta1 > delta2 )
{
std::swap( delta1, delta2 );
}
for( int i = 0; i < mhi.rows; i++ )
{
uchar* mask_row = mask.ptr(i);
float* orient_row = orientation.ptr<float>(i);
const float* dx_row = dx.ptr<float>(i);
const float* dy_row = dy.ptr<float>(i);
const float* min_row = min_mhi.ptr<float>(i);
const float* max_row = max_mhi.ptr<float>(i);
for( int j = 0; j < mhi.cols; j++ )
{
double delta = max_row[j] - min_row[j];
double _dx = dx_row[j], _dy = dy_row[j];
if( delta1 <= delta && delta <= delta2 &&
(fabs(_dx) > limit || fabs(_dy) > limit) )
{
mask_row[j] = 1;
double angle = atan2( _dy, _dx ) * (180/CV_PI);
if( angle < 0 )
angle += 360.;
orient_row[j] = (float)angle;
}
else
{
mask_row[j] = 0;
orient_row[j] = 0.f;
}
}
}
}
class CV_MHIGradientTest : public CV_MHIBaseTest
{
public:
CV_MHIGradientTest();
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
double get_success_error_level( int test_case_idx, int i, int j );
void run_func();
void prepare_to_validation( int );
double delta1, delta2, delta_range_log;
int aperture_size;
};
CV_MHIGradientTest::CV_MHIGradientTest()
{
mhi_i = mhi_ref_i = INPUT;
test_array[INPUT].push_back(NULL);
test_array[OUTPUT].push_back(NULL);
test_array[OUTPUT].push_back(NULL);
test_array[REF_OUTPUT].push_back(NULL);
test_array[REF_OUTPUT].push_back(NULL);
delta1 = delta2 = 0;
aperture_size = 0;
delta_range_log = 4;
}
void CV_MHIGradientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8UC1;
types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32FC1;
delta1 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
delta2 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
aperture_size = (cvtest::randInt(rng)%3)*2+3;
//duration = exp(cvtest::randReal(rng)*max_log_duration);
//timestamp = duration + cvtest::randReal(rng)*30.-10.;
}
double CV_MHIGradientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
{
return j == 0 ? 0 : 2e-1;
}
void CV_MHIGradientTest::run_func()
{
cv::motempl::calcMotionGradient(test_mat[INPUT][0], test_mat[OUTPUT][0],
test_mat[OUTPUT][1], delta1, delta2, aperture_size );
//cvCalcMotionGradient( test_array[INPUT][0], test_array[OUTPUT][0],
// test_array[OUTPUT][1], delta1, delta2, aperture_size );
}
void CV_MHIGradientTest::prepare_to_validation( int /*test_case_idx*/ )
{
test_MHIGradient( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
test_mat[REF_OUTPUT][1], delta1, delta2, aperture_size );
test_mat[REF_OUTPUT][0] += Scalar::all(1);
test_mat[OUTPUT][0] += Scalar::all(1);
}
////////////////////// calc global orientation /////////////////////////
static double test_calcGlobalOrientation( const Mat& orient, const Mat& mask,
const Mat& mhi, double timestamp, double duration )
{
const int HIST_SIZE = 12;
int y, x;
int histogram[HIST_SIZE];
int max_bin = 0;
double base_orientation = 0, delta_orientation = 0, weight = 0;
double low_time, global_orientation;
memset( histogram, 0, sizeof( histogram ));
timestamp = 0;
for( y = 0; y < orient.rows; y++ )
{
const float* orient_data = orient.ptr<float>(y);
const uchar* mask_data = mask.ptr(y);
const float* mhi_data = mhi.ptr<float>(y);
for( x = 0; x < orient.cols; x++ )
if( mask_data[x] )
{
int bin = cvFloor( (orient_data[x]*HIST_SIZE)/360 );
histogram[bin < 0 ? 0 : bin >= HIST_SIZE ? HIST_SIZE-1 : bin]++;
if( mhi_data[x] > timestamp )
timestamp = mhi_data[x];
}
}
low_time = timestamp - duration;
for( x = 1; x < HIST_SIZE; x++ )
{
if( histogram[x] > histogram[max_bin] )
max_bin = x;
}
base_orientation = ((double)max_bin*360)/HIST_SIZE;
for( y = 0; y < orient.rows; y++ )
{
const float* orient_data = orient.ptr<float>(y);
const float* mhi_data = mhi.ptr<float>(y);
const uchar* mask_data = mask.ptr(y);
for( x = 0; x < orient.cols; x++ )
{
if( mask_data[x] && mhi_data[x] > low_time )
{
double diff = orient_data[x] - base_orientation;
double delta_weight = (((mhi_data[x] - low_time)/duration)*254 + 1)/255;
if( diff < -180 ) diff += 360;
if( diff > 180 ) diff -= 360;
if( delta_weight > 0 && fabs(diff) < 45 )
{
delta_orientation += diff*delta_weight;
weight += delta_weight;
}
}
}
}
if( weight == 0 )
global_orientation = base_orientation;
else
{
global_orientation = base_orientation + delta_orientation/weight;
if( global_orientation < 0 ) global_orientation += 360;
if( global_orientation > 360 ) global_orientation -= 360;
}
return global_orientation;
}
class CV_MHIGlobalOrientTest : public CV_MHIBaseTest
{
public:
CV_MHIGlobalOrientTest();
protected:
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
double get_success_error_level( int test_case_idx, int i, int j );
int validate_test_results( int test_case_idx );
void run_func();
double angle, min_angle, max_angle;
};
CV_MHIGlobalOrientTest::CV_MHIGlobalOrientTest()
{
mhi_i = mhi_ref_i = INPUT;
test_array[INPUT].push_back(NULL);
test_array[INPUT].push_back(NULL);
test_array[INPUT].push_back(NULL);
min_angle = max_angle = 0;
}
void CV_MHIGlobalOrientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
Size size = sizes[INPUT][0];
size.width = MAX( size.width, 16 );
size.height = MAX( size.height, 16 );
sizes[INPUT][0] = sizes[INPUT][1] = sizes[INPUT][2] = size;
types[INPUT][1] = CV_8UC1; // mask
types[INPUT][2] = CV_32FC1; // orientation
min_angle = cvtest::randReal(rng)*359.9;
max_angle = cvtest::randReal(rng)*359.9;
if( min_angle >= max_angle )
{
std::swap( min_angle, max_angle);
}
max_angle += 0.1;
duration = exp(cvtest::randReal(rng)*max_log_duration);
timestamp = duration + cvtest::randReal(rng)*30.-10.;
}
void CV_MHIGlobalOrientTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
{
CV_MHIBaseTest::get_minmax_bounds( i, j, type, low, high );
if( i == INPUT && j == 2 )
{
low = Scalar::all(min_angle);
high = Scalar::all(max_angle);
}
}
double CV_MHIGlobalOrientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
{
return 15;
}
void CV_MHIGlobalOrientTest::run_func()
{
//angle = cvCalcGlobalOrientation( test_array[INPUT][2], test_array[INPUT][1],
// test_array[INPUT][0], timestamp, duration );
angle = cv::motempl::calcGlobalOrientation(test_mat[INPUT][2], test_mat[INPUT][1],
test_mat[INPUT][0], timestamp, duration );
}
int CV_MHIGlobalOrientTest::validate_test_results( int test_case_idx )
{
//printf("%d. rows=%d, cols=%d, nzmask=%d\n", test_case_idx, test_mat[INPUT][1].rows, test_mat[INPUT][1].cols,
// cvCountNonZero(test_array[INPUT][1]));
double ref_angle = test_calcGlobalOrientation( test_mat[INPUT][2], test_mat[INPUT][1],
test_mat[INPUT][0], timestamp, duration );
double err_level = get_success_error_level( test_case_idx, 0, 0 );
int code = cvtest::TS::OK;
int nz = countNonZero( test_mat[INPUT][1] );
if( nz > 32 && !(min_angle - err_level <= angle &&
max_angle + err_level >= angle) &&
!(min_angle - err_level <= angle+360 &&
max_angle + err_level >= angle+360) )
{
ts->printf( cvtest::TS::LOG, "The angle=%g is outside (%g,%g) range\n",
angle, min_angle - err_level, max_angle + err_level );
code = cvtest::TS::FAIL_BAD_ACCURACY;
}
else if( fabs(angle - ref_angle) > err_level &&
fabs(360 - fabs(angle - ref_angle)) > err_level )
{
ts->printf( cvtest::TS::LOG, "The angle=%g differs too much from reference value=%g\n",
angle, ref_angle );
code = cvtest::TS::FAIL_BAD_ACCURACY;
}
if( code < 0 )
ts->set_failed_test_info( code );
return code;
}
TEST(Video_MHIUpdate, accuracy) { CV_UpdateMHITest test; test.safe_run(); }
TEST(Video_MHIGradient, accuracy) { CV_MHIGradientTest test; test.safe_run(); }
TEST(Video_MHIGlobalOrient, accuracy) { CV_MHIGlobalOrientTest test; test.safe_run(); }
}} // namespace
+15
View File
@@ -0,0 +1,15 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include "opencv2/ts.hpp"
#include "opencv2/optflow.hpp"
namespace opencv_test {
using namespace cv::optflow;
using namespace perf;
}
#endif
+173
View File
@@ -0,0 +1,173 @@
/*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(Contrib_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::optflow::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