vendor: OpenCV 5.0.0 snapshot at 40738fb16ceddb5fb3fea747585f7ce6abb0605b
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
#include "../test_precomp.hpp"
|
||||
#include "opencv2/ts/ocl_test.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
namespace opencv_test {
|
||||
namespace ocl {
|
||||
|
||||
//////////////////////////Mog2_Update///////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
IMPLEMENT_PARAM_CLASS(UseGray, bool)
|
||||
IMPLEMENT_PARAM_CLASS(DetectShadow, bool)
|
||||
IMPLEMENT_PARAM_CLASS(UseFloat, bool)
|
||||
}
|
||||
|
||||
PARAM_TEST_CASE(Mog2_Update, UseGray, DetectShadow,UseFloat)
|
||||
{
|
||||
bool useGray;
|
||||
bool detectShadow;
|
||||
bool useFloat;
|
||||
virtual void SetUp()
|
||||
{
|
||||
useGray = GET_PARAM(0);
|
||||
detectShadow = GET_PARAM(1);
|
||||
useFloat = GET_PARAM(2);
|
||||
}
|
||||
};
|
||||
|
||||
OCL_TEST_P(Mog2_Update, Accuracy)
|
||||
{
|
||||
string inputFile = string(TS::ptr()->get_data_path()) + "video/768x576.avi";
|
||||
VideoCapture cap(inputFile);
|
||||
if (!cap.isOpened())
|
||||
throw SkipTestException("Video file can not be opened");
|
||||
|
||||
Ptr<BackgroundSubtractorMOG2> mog2_cpu = createBackgroundSubtractorMOG2();
|
||||
Ptr<BackgroundSubtractorMOG2> mog2_ocl = createBackgroundSubtractorMOG2();
|
||||
|
||||
mog2_cpu->setDetectShadows(detectShadow);
|
||||
mog2_ocl->setDetectShadows(detectShadow);
|
||||
|
||||
Mat frame, foreground;
|
||||
UMat u_foreground;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
cap >> frame;
|
||||
ASSERT_FALSE(frame.empty());
|
||||
|
||||
if (useGray)
|
||||
{
|
||||
Mat temp;
|
||||
cvtColor(frame, temp, COLOR_BGR2GRAY);
|
||||
swap(temp, frame);
|
||||
}
|
||||
|
||||
if(useFloat)
|
||||
{
|
||||
Mat temp;
|
||||
frame.convertTo(temp,CV_32F);
|
||||
swap(temp,frame);
|
||||
}
|
||||
|
||||
OCL_OFF(mog2_cpu->apply(frame, foreground));
|
||||
OCL_ON (mog2_ocl->apply(frame, u_foreground));
|
||||
|
||||
if (detectShadow)
|
||||
EXPECT_MAT_SIMILAR(foreground, u_foreground, 15e-3);
|
||||
else
|
||||
EXPECT_MAT_NEAR(foreground, u_foreground, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////Mog2_getBackgroundImage///////////////////////////////////
|
||||
|
||||
PARAM_TEST_CASE(Mog2_getBackgroundImage, DetectShadow, UseFloat)
|
||||
{
|
||||
bool detectShadow;
|
||||
bool useFloat;
|
||||
virtual void SetUp()
|
||||
{
|
||||
detectShadow = GET_PARAM(0);
|
||||
useFloat = GET_PARAM(1);
|
||||
}
|
||||
};
|
||||
|
||||
OCL_TEST_P(Mog2_getBackgroundImage, Accuracy)
|
||||
{
|
||||
string inputFile = string(TS::ptr()->get_data_path()) + "video/768x576.avi";
|
||||
VideoCapture cap(inputFile);
|
||||
if (!cap.isOpened())
|
||||
throw SkipTestException("Video file can not be opened");
|
||||
|
||||
Ptr<BackgroundSubtractorMOG2> mog2_cpu = createBackgroundSubtractorMOG2();
|
||||
Ptr<BackgroundSubtractorMOG2> mog2_ocl = createBackgroundSubtractorMOG2();
|
||||
|
||||
mog2_cpu->setDetectShadows(detectShadow);
|
||||
mog2_ocl->setDetectShadows(detectShadow);
|
||||
|
||||
Mat frame, foreground;
|
||||
UMat u_foreground;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
cap >> frame;
|
||||
ASSERT_FALSE(frame.empty());
|
||||
|
||||
if(useFloat)
|
||||
{
|
||||
Mat temp;
|
||||
frame.convertTo(temp,CV_32F);
|
||||
swap(temp,frame);
|
||||
}
|
||||
|
||||
OCL_OFF(mog2_cpu->apply(frame, foreground));
|
||||
OCL_ON (mog2_ocl->apply(frame, u_foreground));
|
||||
}
|
||||
|
||||
Mat background;
|
||||
OCL_OFF(mog2_cpu->getBackgroundImage(background));
|
||||
|
||||
UMat u_background;
|
||||
OCL_ON (mog2_ocl->getBackgroundImage(u_background));
|
||||
|
||||
EXPECT_MAT_NEAR(background, u_background, 1.0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_Update, Combine(
|
||||
Values(UseGray(true),UseGray(false)),
|
||||
Values(DetectShadow(true), DetectShadow(false)),
|
||||
Values(UseFloat(false),UseFloat(true)))
|
||||
);
|
||||
|
||||
OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_getBackgroundImage, Combine(
|
||||
Values(DetectShadow(true), DetectShadow(false)),
|
||||
Values(UseFloat(false),UseFloat(true)))
|
||||
);
|
||||
|
||||
}}// namespace opencv_test::ocl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
#include "opencv2/ts/ocl_test.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
CV_ENUM(DIS_TestPresets, DISOpticalFlow::PRESET_ULTRAFAST, DISOpticalFlow::PRESET_FAST, DISOpticalFlow::PRESET_MEDIUM)
|
||||
|
||||
typedef ocl::TSTestWithParam<DIS_TestPresets> OCL_DenseOpticalFlow_DIS;
|
||||
|
||||
OCL_TEST_P(OCL_DenseOpticalFlow_DIS, Mat)
|
||||
{
|
||||
int preset = (int)GetParam();
|
||||
Mat frame1, frame2, GT;
|
||||
|
||||
frame1 = imread(TS::ptr()->get_data_path() + "optflow/RubberWhale1.png");
|
||||
frame2 = imread(TS::ptr()->get_data_path() + "optflow/RubberWhale2.png");
|
||||
|
||||
CV_Assert(!frame1.empty() && !frame2.empty());
|
||||
|
||||
cvtColor(frame1, frame1, COLOR_BGR2GRAY);
|
||||
cvtColor(frame2, frame2, COLOR_BGR2GRAY);
|
||||
|
||||
{
|
||||
Mat flow;
|
||||
UMat ocl_flow;
|
||||
|
||||
Ptr<DenseOpticalFlow> algo = DISOpticalFlow::create(preset);
|
||||
OCL_OFF(algo->calc(frame1, frame2, flow));
|
||||
OCL_ON(algo->calc(frame1, frame2, ocl_flow));
|
||||
ASSERT_EQ(flow.rows, ocl_flow.rows);
|
||||
ASSERT_EQ(flow.cols, ocl_flow.cols);
|
||||
|
||||
EXPECT_MAT_SIMILAR(flow, ocl_flow, 6e-3);
|
||||
}
|
||||
}
|
||||
|
||||
OCL_INSTANTIATE_TEST_CASE_P(Video, OCL_DenseOpticalFlow_DIS,
|
||||
DIS_TestPresets::all());
|
||||
|
||||
}} // namespace
|
||||
|
||||
#endif // HAVE_OPENCL
|
||||
@@ -0,0 +1,120 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
|
||||
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
|
||||
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
#include "opencv2/ts/ocl_test.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
|
||||
namespace opencv_test {
|
||||
namespace ocl {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FarnebackOpticalFlow
|
||||
namespace
|
||||
{
|
||||
IMPLEMENT_PARAM_CLASS(PyrScale, double)
|
||||
IMPLEMENT_PARAM_CLASS(PolyN, int)
|
||||
CV_FLAGS(FarnebackOptFlowFlags, 0, OPTFLOW_FARNEBACK_GAUSSIAN)
|
||||
IMPLEMENT_PARAM_CLASS(UseInitFlow, bool)
|
||||
}
|
||||
|
||||
PARAM_TEST_CASE(FarnebackOpticalFlow, PyrScale, PolyN, FarnebackOptFlowFlags, UseInitFlow)
|
||||
{
|
||||
int numLevels;
|
||||
int winSize;
|
||||
int numIters;
|
||||
double pyrScale;
|
||||
int polyN;
|
||||
int flags;
|
||||
bool useInitFlow;
|
||||
|
||||
virtual void SetUp()
|
||||
{
|
||||
numLevels = 5;
|
||||
winSize = 13;
|
||||
numIters = 10;
|
||||
pyrScale = GET_PARAM(0);
|
||||
polyN = GET_PARAM(1);
|
||||
flags = GET_PARAM(2);
|
||||
useInitFlow = GET_PARAM(3);
|
||||
}
|
||||
};
|
||||
|
||||
OCL_TEST_P(FarnebackOpticalFlow, Mat)
|
||||
{
|
||||
cv::Mat frame0 = readImage("optflow/RubberWhale1.png", cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame0.empty());
|
||||
|
||||
cv::Mat frame1 = readImage("optflow/RubberWhale2.png", cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame1.empty());
|
||||
|
||||
double polySigma = polyN <= 5 ? 1.1 : 1.5;
|
||||
|
||||
cv::Mat flow; cv::UMat uflow;
|
||||
if (useInitFlow)
|
||||
{
|
||||
OCL_ON(cv::calcOpticalFlowFarneback(frame0, frame1, uflow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
|
||||
uflow.copyTo(flow);
|
||||
flags |= cv::OPTFLOW_USE_INITIAL_FLOW;
|
||||
}
|
||||
OCL_OFF(cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
|
||||
OCL_ON(cv::calcOpticalFlowFarneback(frame0, frame1, uflow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags));
|
||||
|
||||
EXPECT_MAT_SIMILAR(flow, uflow, 0.1);
|
||||
}
|
||||
|
||||
|
||||
OCL_INSTANTIATE_TEST_CASE_P(Video, FarnebackOpticalFlow,
|
||||
Combine(
|
||||
Values(PyrScale(0.3), PyrScale(0.5), PyrScale(0.8)),
|
||||
Values(PolyN(5), PolyN(7)),
|
||||
Values(FarnebackOptFlowFlags(0), FarnebackOptFlowFlags(cv::OPTFLOW_FARNEBACK_GAUSSIAN)),
|
||||
Values(UseInitFlow(false), UseInitFlow(true))
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
} } // namespace opencv_test::ocl
|
||||
|
||||
#endif // HAVE_OPENCL
|
||||
@@ -0,0 +1,164 @@
|
||||
/*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_OPENCV_FEATURES
|
||||
#include "opencv2/features.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_OPENCL) && defined(HAVE_OPENCV_FEATURES)
|
||||
|
||||
namespace opencv_test { namespace ocl {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PyrLKOpticalFlow
|
||||
|
||||
PARAM_TEST_CASE(PyrLKOpticalFlow, int, int)
|
||||
{
|
||||
Size winSize;
|
||||
int maxLevel;
|
||||
TermCriteria criteria;
|
||||
int flags;
|
||||
double minEigThreshold;
|
||||
|
||||
virtual void SetUp()
|
||||
{
|
||||
winSize = Size(GET_PARAM(0), GET_PARAM(0));
|
||||
maxLevel = GET_PARAM(1);
|
||||
criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01);
|
||||
flags = 0;
|
||||
minEigThreshold = 1e-4f;
|
||||
}
|
||||
};
|
||||
|
||||
OCL_TEST_P(PyrLKOpticalFlow, Mat)
|
||||
{
|
||||
static const int npoints = 1000;
|
||||
static const float eps = 0.03f;
|
||||
static const float erreps = 0.1f;
|
||||
|
||||
cv::Mat frame0 = readImage("optflow/RubberWhale1.png", cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame0.empty());
|
||||
UMat umatFrame0; frame0.copyTo(umatFrame0);
|
||||
|
||||
cv::Mat frame1 = readImage("optflow/RubberWhale2.png", cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(frame1.empty());
|
||||
UMat umatFrame1; frame1.copyTo(umatFrame1);
|
||||
|
||||
// SKIP unstable tests
|
||||
#ifdef __linux__
|
||||
if (cvtest::skipUnstableTests && ocl::useOpenCL())
|
||||
{
|
||||
if (ocl::Device::getDefault().isIntel())
|
||||
throw cvtest::SkipTestException("Skip unstable test");
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<cv::Point2f> pts;
|
||||
cv::goodFeaturesToTrack(frame0, pts, npoints, 0.01, 0.0);
|
||||
|
||||
std::vector<cv::Point2f> cpuNextPts;
|
||||
std::vector<unsigned char> cpuStatusCPU;
|
||||
std::vector<float> cpuErr;
|
||||
OCL_OFF(cv::calcOpticalFlowPyrLK(frame0, frame1, pts, cpuNextPts, cpuStatusCPU, cpuErr, winSize, maxLevel, criteria, flags, minEigThreshold));
|
||||
|
||||
UMat umatNextPts, umatStatus, umatErr;
|
||||
OCL_ON(cv::calcOpticalFlowPyrLK(umatFrame0, umatFrame1, pts, umatNextPts, umatStatus, umatErr, winSize, maxLevel, criteria, flags, minEigThreshold));
|
||||
std::vector<cv::Point2f> nextPts; umatNextPts.reshape(2, 1).copyTo(nextPts);
|
||||
std::vector<unsigned char> status; umatStatus.reshape(1, 1).copyTo(status);
|
||||
std::vector<float> err; umatErr.reshape(1, 1).copyTo(err);
|
||||
|
||||
ASSERT_EQ(cpuNextPts.size(), nextPts.size());
|
||||
ASSERT_EQ(cpuStatusCPU.size(), status.size());
|
||||
|
||||
size_t mistmatch = 0;
|
||||
size_t errmatch = 0;
|
||||
|
||||
for (size_t i = 0; i < nextPts.size(); ++i)
|
||||
{
|
||||
if (status[i] != cpuStatusCPU[i])
|
||||
{
|
||||
++mistmatch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status[i])
|
||||
{
|
||||
cv::Point2i a = nextPts[i];
|
||||
cv::Point2i b = cpuNextPts[i];
|
||||
|
||||
bool eq = std::abs(a.x - b.x) < 1 && std::abs(a.y - b.y) < 1;
|
||||
float errdiff = 0.0f;
|
||||
|
||||
if (!eq || errdiff > 1e-1)
|
||||
{
|
||||
++mistmatch;
|
||||
continue;
|
||||
}
|
||||
|
||||
eq = std::abs(cpuErr[i] - err[i]) <= (0.01 * std::max(1.0f, cpuErr[i]));
|
||||
if(!eq)
|
||||
++errmatch;
|
||||
}
|
||||
}
|
||||
|
||||
double bad_ratio = static_cast<double>(mistmatch) / (nextPts.size());
|
||||
double err_ratio = static_cast<double>(errmatch) / (nextPts.size());
|
||||
|
||||
ASSERT_LE(bad_ratio, eps);
|
||||
ASSERT_LE(err_ratio, erreps);
|
||||
}
|
||||
|
||||
OCL_INSTANTIATE_TEST_CASE_P(Video, PyrLKOpticalFlow,
|
||||
Combine(
|
||||
Values(11, 15, 21, 25),
|
||||
Values(3, 5)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
}} // namespace
|
||||
#endif // HAVE_OPENCL
|
||||
@@ -0,0 +1,200 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
static string getDataDir() { return TS::ptr()->get_data_path(); }
|
||||
|
||||
static string getRubberWhaleFrame1() { return getDataDir() + "optflow/RubberWhale1.png"; }
|
||||
|
||||
static string getRubberWhaleFrame2() { return getDataDir() + "optflow/RubberWhale2.png"; }
|
||||
|
||||
static string getRubberWhaleGroundTruth() { return getDataDir() + "optflow/RubberWhale.flo"; }
|
||||
|
||||
static bool isFlowCorrect(float u) { return !cvIsNaN(u) && (fabs(u) < 1e9); }
|
||||
|
||||
static float calcRMSE(Mat flow1, Mat flow2)
|
||||
{
|
||||
float sum = 0;
|
||||
int counter = 0;
|
||||
const int rows = flow1.rows;
|
||||
const int cols = flow1.cols;
|
||||
|
||||
for (int y = 0; y < rows; ++y)
|
||||
{
|
||||
for (int x = 0; x < cols; ++x)
|
||||
{
|
||||
Vec2f flow1_at_point = flow1.at<Vec2f>(y, x);
|
||||
Vec2f flow2_at_point = flow2.at<Vec2f>(y, x);
|
||||
|
||||
float u1 = flow1_at_point[0];
|
||||
float v1 = flow1_at_point[1];
|
||||
float u2 = flow2_at_point[0];
|
||||
float v2 = flow2_at_point[1];
|
||||
|
||||
if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2))
|
||||
{
|
||||
sum += (u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (float)sqrt(sum / (1e-9 + counter));
|
||||
}
|
||||
|
||||
bool readRubberWhale(Mat &dst_frame_1, Mat &dst_frame_2, Mat &dst_GT)
|
||||
{
|
||||
const string frame1_path = getRubberWhaleFrame1();
|
||||
const string frame2_path = getRubberWhaleFrame2();
|
||||
const string gt_flow_path = getRubberWhaleGroundTruth();
|
||||
|
||||
dst_frame_1 = imread(frame1_path);
|
||||
dst_frame_2 = imread(frame2_path);
|
||||
dst_GT = readOpticalFlow(gt_flow_path);
|
||||
|
||||
if (dst_frame_1.empty() || dst_frame_2.empty() || dst_GT.empty())
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(DenseOpticalFlow_DIS, ReferenceAccuracy)
|
||||
{
|
||||
Mat frame1, frame2, GT;
|
||||
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
|
||||
int presets[] = {DISOpticalFlow::PRESET_ULTRAFAST, DISOpticalFlow::PRESET_FAST, DISOpticalFlow::PRESET_MEDIUM};
|
||||
float target_RMSE[] = {0.86f, 0.74f, 0.49f};
|
||||
cvtColor(frame1, frame1, COLOR_BGR2GRAY);
|
||||
cvtColor(frame2, frame2, COLOR_BGR2GRAY);
|
||||
|
||||
Ptr<DenseOpticalFlow> algo;
|
||||
|
||||
// iterate over presets:
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
Mat flow;
|
||||
algo = DISOpticalFlow::create(presets[i]);
|
||||
algo->calc(frame1, frame2, flow);
|
||||
ASSERT_EQ(GT.rows, flow.rows);
|
||||
ASSERT_EQ(GT.cols, flow.cols);
|
||||
EXPECT_LE(calcRMSE(GT, flow), target_RMSE[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DenseOpticalFlow_DIS, InvalidImgSize_CoarsestLevelLessThanZero)
|
||||
{
|
||||
cv::Ptr<cv::DISOpticalFlow> of = cv::DISOpticalFlow::create();
|
||||
const int mat_size = 10;
|
||||
|
||||
cv::Mat x(mat_size, mat_size, CV_8UC1, 42);
|
||||
cv::Mat y(mat_size, mat_size, CV_8UC1, 42);
|
||||
cv::Mat flow;
|
||||
|
||||
ASSERT_THROW(of->calc(x, y, flow), cv::Exception);
|
||||
}
|
||||
|
||||
// make sure that autoSelectPatchSizeAndScales() works properly.
|
||||
TEST(DenseOpticalFlow_DIS, InvalidImgSize_CoarsestLevelLessThanFinestLevel)
|
||||
{
|
||||
cv::Ptr<cv::DISOpticalFlow> of = cv::DISOpticalFlow::create();
|
||||
const int mat_size = 80;
|
||||
|
||||
cv::Mat x(mat_size, mat_size, CV_8UC1, 42);
|
||||
cv::Mat y(mat_size, mat_size, CV_8UC1, 42);
|
||||
cv::Mat flow;
|
||||
|
||||
of->calc(x, y, flow);
|
||||
|
||||
ASSERT_EQ(flow.rows, mat_size);
|
||||
ASSERT_EQ(flow.cols, mat_size);
|
||||
}
|
||||
|
||||
TEST(DenseOpticalFlow_VariationalRefinement, ReferenceAccuracy)
|
||||
{
|
||||
Mat frame1, frame2, GT;
|
||||
ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
|
||||
float target_RMSE = 0.86f;
|
||||
cvtColor(frame1, frame1, COLOR_BGR2GRAY);
|
||||
cvtColor(frame2, frame2, COLOR_BGR2GRAY);
|
||||
|
||||
Ptr<VariationalRefinement> var_ref;
|
||||
var_ref = VariationalRefinement::create();
|
||||
var_ref->setAlpha(20.0f);
|
||||
var_ref->setDelta(5.0f);
|
||||
var_ref->setGamma(10.0f);
|
||||
var_ref->setSorIterations(25);
|
||||
var_ref->setFixedPointIterations(25);
|
||||
Mat flow(frame1.size(), CV_32FC2);
|
||||
flow.setTo(0.0f);
|
||||
var_ref->calc(frame1, frame2, flow);
|
||||
ASSERT_EQ(GT.rows, flow.rows);
|
||||
ASSERT_EQ(GT.cols, flow.cols);
|
||||
EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
|
||||
}
|
||||
|
||||
TEST(DenseOpticalFlow_DIS, ManualCoarsestScale)
|
||||
{
|
||||
Mat prev = Mat::zeros(Size(320, 240), CV_8UC1);
|
||||
Mat next = Mat::zeros(Size(320, 240), CV_8UC1);
|
||||
randu(prev, 0, 255);
|
||||
randu(next, 0, 255);
|
||||
|
||||
Ptr<DISOpticalFlow> dis = DISOpticalFlow::create(DISOpticalFlow::PRESET_FAST);
|
||||
|
||||
EXPECT_EQ(dis->getCoarsestScale(), -1);
|
||||
|
||||
Mat flow;
|
||||
dis->calc(prev, next, flow);
|
||||
EXPECT_FALSE(flow.empty());
|
||||
int manual_scale = 3;
|
||||
dis->setCoarsestScale(manual_scale);
|
||||
EXPECT_EQ(dis->getCoarsestScale(), manual_scale);
|
||||
|
||||
dis->calc(prev, next, flow);
|
||||
EXPECT_FALSE(flow.empty());
|
||||
|
||||
dis->setCoarsestScale(-1);
|
||||
EXPECT_EQ(dis->getCoarsestScale(), -1);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -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
|
||||
@@ -0,0 +1,157 @@
|
||||
/*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 testing::TestWithParam<tuple<Size, int, int> > Video_Acc_Cn4;
|
||||
|
||||
TEST_P(Video_Acc_Cn4, accuracy)
|
||||
{
|
||||
const Size size = get<0>(GetParam());
|
||||
const int pattern = get<1>(GetParam());
|
||||
const int srcType = get<2>(GetParam());
|
||||
|
||||
RNG& rng = theRNG();
|
||||
|
||||
Mat src(size, srcType);
|
||||
Mat dst(size, CV_32FC4);
|
||||
Mat mask(size, CV_8UC1);
|
||||
|
||||
if (srcType == CV_8UC4)
|
||||
rng.fill(src, RNG::UNIFORM, Scalar::all(0), Scalar::all(256));
|
||||
else
|
||||
rng.fill(src, RNG::UNIFORM, Scalar::all(-10.0), Scalar::all(10.0));
|
||||
|
||||
rng.fill(dst, RNG::UNIFORM, Scalar::all(-1000.0), Scalar::all(1000.0));
|
||||
|
||||
for (int y = 0; y < mask.rows; ++y)
|
||||
{
|
||||
uchar* row = mask.ptr<uchar>(y);
|
||||
|
||||
for (int x = 0; x < mask.cols; ++x)
|
||||
{
|
||||
switch (pattern)
|
||||
{
|
||||
case 0:
|
||||
row[x] = 0;
|
||||
break;
|
||||
case 1:
|
||||
row[x] = 255;
|
||||
break;
|
||||
case 2:
|
||||
row[x] = ((x + y) % 2) ? 255 : 0;
|
||||
break;
|
||||
case 3:
|
||||
row[x] = ((x * 13 + y * 7) % 5) ? 255 : 0;
|
||||
break;
|
||||
default:
|
||||
row[x] = ((x * 17 + y * 11) % 3) ? 255 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mat dstRef = dst.clone();
|
||||
|
||||
if (srcType == CV_32FC4)
|
||||
{
|
||||
for (int y = 0; y < src.rows; ++y)
|
||||
{
|
||||
const Vec4f* srcRow = src.ptr<Vec4f>(y);
|
||||
Vec4f* dstRefRow = dstRef.ptr<Vec4f>(y);
|
||||
const uchar* maskRow = mask.ptr<uchar>(y);
|
||||
|
||||
for (int x = 0; x < src.cols; ++x)
|
||||
{
|
||||
if (maskRow[x])
|
||||
{
|
||||
for (int c = 0; c < 4; ++c)
|
||||
dstRefRow[x][c] += srcRow[x][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Assert(srcType == CV_8UC4);
|
||||
|
||||
for (int y = 0; y < src.rows; ++y)
|
||||
{
|
||||
const Vec4b* srcRow = src.ptr<Vec4b>(y);
|
||||
Vec4f* dstRefRow = dstRef.ptr<Vec4f>(y);
|
||||
const uchar* maskRow = mask.ptr<uchar>(y);
|
||||
|
||||
for (int x = 0; x < src.cols; ++x)
|
||||
{
|
||||
if (maskRow[x])
|
||||
{
|
||||
for (int c = 0; c < 4; ++c)
|
||||
dstRefRow[x][c] += static_cast<float>(srcRow[x][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::accumulate(src, dst, mask);
|
||||
|
||||
const double err = cv::norm(dst, dstRef, NORM_INF);
|
||||
|
||||
EXPECT_EQ(0.0, err)
|
||||
<< "size=" << size
|
||||
<< ", pattern=" << pattern
|
||||
<< ", srcType=" << srcType;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Accumulate,
|
||||
Video_Acc_Cn4,
|
||||
testing::Combine(
|
||||
testing::Values(Size(1, 1),
|
||||
Size(3, 5),
|
||||
Size(17, 7),
|
||||
Size(37, 19),
|
||||
Size(128, 16),
|
||||
Size(641, 37)),
|
||||
testing::Values(0, 1, 2, 3, 4),
|
||||
testing::Values(CV_32FC4, CV_8UC4)));
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,108 @@
|
||||
// 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"
|
||||
#include "opencv2/video/background_segm.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
using namespace cv;
|
||||
|
||||
///////////////////////// MOG2 //////////////////////////////
|
||||
TEST(BackgroundSubtractorMOG2, KnownForegroundMaskShadowsTrue)
|
||||
{
|
||||
Ptr<BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2(500, 16, true);
|
||||
|
||||
//Black Frame
|
||||
Mat input = Mat::zeros(480,640 , CV_8UC3);
|
||||
|
||||
//White Rectangle
|
||||
Mat knownFG = Mat::zeros(input.size(), CV_8U);
|
||||
|
||||
rectangle(knownFG, Rect(3,3,5,5), Scalar(255,255,255), -1);
|
||||
|
||||
Mat output;
|
||||
mog2->apply(input, knownFG, output);
|
||||
|
||||
for(int y = 3; y < 8; y++)
|
||||
{
|
||||
for (int x = 3; x < 8; x++){
|
||||
EXPECT_EQ(255,output.at<uchar>(y,x)) << "Expected foreground at (" << x << "," << y << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BackgroundSubtractorMOG2, KnownForegroundMaskShadowsFalse)
|
||||
{
|
||||
Ptr<BackgroundSubtractorMOG2> mog2 = createBackgroundSubtractorMOG2(500, 16, false);
|
||||
|
||||
//Black Frame
|
||||
Mat input = Mat::zeros(480,640 , CV_8UC3);
|
||||
|
||||
//White Rectangle
|
||||
Mat knownFG = Mat::zeros(input.size(), CV_8U);
|
||||
|
||||
rectangle(knownFG, Rect(3,3,5,5), Scalar(255,255,255), FILLED);
|
||||
|
||||
Mat output;
|
||||
mog2->apply(input, knownFG, output);
|
||||
|
||||
for(int y = 3; y < 8; y++)
|
||||
{
|
||||
for (int x = 3; x < 8; x++){
|
||||
EXPECT_EQ(255,output.at<uchar>(y,x)) << "Expected foreground at (" << x << "," << y << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////// KNN //////////////////////////////
|
||||
|
||||
TEST(BackgroundSubtractorKNN, KnownForegroundMaskShadowsTrue)
|
||||
{
|
||||
Ptr<BackgroundSubtractorKNN> knn = createBackgroundSubtractorKNN(500, 400.0, true);
|
||||
|
||||
//Black Frame
|
||||
Mat input = Mat::zeros(480,640 , CV_8UC3);
|
||||
|
||||
//White Rectangle
|
||||
Mat knownFG = Mat::zeros(input.size(), CV_8U);
|
||||
|
||||
rectangle(knownFG, Rect(3,3,5,5), Scalar(255,255,255), FILLED);
|
||||
|
||||
Mat output;
|
||||
knn->apply(input, knownFG, output);
|
||||
|
||||
for(int y = 3; y < 8; y++)
|
||||
{
|
||||
for (int x = 3; x < 8; x++){
|
||||
EXPECT_EQ(255,output.at<uchar>(y,x)) << "Expected foreground at (" << x << "," << y << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BackgroundSubtractorKNN, KnownForegroundMaskShadowsFalse)
|
||||
{
|
||||
Ptr<BackgroundSubtractorKNN> knn = createBackgroundSubtractorKNN(500, 400.0, false);
|
||||
|
||||
//Black Frame
|
||||
Mat input = Mat::zeros(480,640 , CV_8UC3);
|
||||
|
||||
//White Rectangle
|
||||
Mat knownFG = Mat::zeros(input.size(), CV_8U);
|
||||
|
||||
rectangle(knownFG, Rect(3,3,5,5), Scalar(255,255,255), FILLED);
|
||||
|
||||
Mat output;
|
||||
knn->apply(input, knownFG, output);
|
||||
|
||||
for(int y = 3; y < 8; y++)
|
||||
{
|
||||
for (int x = 3; x < 8; x++){
|
||||
EXPECT_EQ(255,output.at<uchar>(y,x)) << "Expected foreground at (" << x << "," << y << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
/* End of file. */
|
||||
@@ -0,0 +1,438 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
using namespace cv;
|
||||
|
||||
class CV_TrackBaseTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_TrackBaseTest();
|
||||
virtual ~CV_TrackBaseTest();
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
int read_params( const cv::FileStorage& fs );
|
||||
void run_func(void);
|
||||
int prepare_test_case( int test_case_idx );
|
||||
int validate_test_results( int test_case_idx );
|
||||
void generate_object();
|
||||
|
||||
int min_log_size, max_log_size;
|
||||
Mat img;
|
||||
RotatedRect box0;
|
||||
Size img_size;
|
||||
TermCriteria criteria;
|
||||
int img_type;
|
||||
};
|
||||
|
||||
|
||||
CV_TrackBaseTest::CV_TrackBaseTest()
|
||||
{
|
||||
img = 0;
|
||||
test_case_count = 100;
|
||||
min_log_size = 5;
|
||||
max_log_size = 8;
|
||||
}
|
||||
|
||||
|
||||
CV_TrackBaseTest::~CV_TrackBaseTest()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
void CV_TrackBaseTest::clear()
|
||||
{
|
||||
img.release();
|
||||
cvtest::BaseTest::clear();
|
||||
}
|
||||
|
||||
|
||||
int CV_TrackBaseTest::read_params( const cv::FileStorage& fs )
|
||||
{
|
||||
int code = cvtest::BaseTest::read_params( fs );
|
||||
if( code < 0 )
|
||||
return code;
|
||||
|
||||
read( find_param( fs, "test_case_count" ), test_case_count, test_case_count );
|
||||
read( find_param( fs, "min_log_size" ), min_log_size, min_log_size );
|
||||
read( find_param( fs, "max_log_size" ), max_log_size, max_log_size );
|
||||
|
||||
min_log_size = cvtest::clipInt( min_log_size, 1, 10 );
|
||||
max_log_size = cvtest::clipInt( max_log_size, 1, 10 );
|
||||
if( min_log_size > max_log_size )
|
||||
{
|
||||
std::swap( min_log_size, max_log_size );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CV_TrackBaseTest::generate_object()
|
||||
{
|
||||
int x, y;
|
||||
double cx = box0.center.x;
|
||||
double cy = box0.center.y;
|
||||
double width = box0.size.width*0.5;
|
||||
double height = box0.size.height*0.5;
|
||||
double angle = box0.angle*CV_PI/180.;
|
||||
double a = sin(angle), b = -cos(angle);
|
||||
double inv_ww = 1./(width*width), inv_hh = 1./(height*height);
|
||||
|
||||
img = Mat::zeros( img_size.height, img_size.width, img_type );
|
||||
|
||||
// use the straightforward algorithm: for every pixel check if it is inside the ellipse
|
||||
for( y = 0; y < img_size.height; y++ )
|
||||
{
|
||||
uchar* ptr = img.ptr(y);
|
||||
float* fl = (float*)ptr;
|
||||
double x_ = (y - cy)*b, y_ = (y - cy)*a;
|
||||
|
||||
for( x = 0; x < img_size.width; x++ )
|
||||
{
|
||||
double x1 = (x - cx)*a - x_;
|
||||
double y1 = (x - cx)*b + y_;
|
||||
|
||||
if( x1*x1*inv_hh + y1*y1*inv_ww <= 1. )
|
||||
{
|
||||
if( img_type == CV_8U )
|
||||
ptr[x] = (uchar)1;
|
||||
else
|
||||
fl[x] = (float)1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CV_TrackBaseTest::prepare_test_case( int test_case_idx )
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
cvtest::BaseTest::prepare_test_case( test_case_idx );
|
||||
float m;
|
||||
|
||||
clear();
|
||||
|
||||
box0.size.width = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
|
||||
box0.size.height = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
|
||||
box0.angle = (float)(cvtest::randReal(rng)*180.);
|
||||
|
||||
if( box0.size.width > box0.size.height )
|
||||
{
|
||||
std::swap( box0.size.width, box0.size.height );
|
||||
}
|
||||
|
||||
m = MAX( box0.size.width, box0.size.height );
|
||||
img_size.width = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
|
||||
img_size.height = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
|
||||
img_type = cvtest::randInt(rng) % 2 ? CV_32F : CV_8U;
|
||||
img_type = CV_8U;
|
||||
|
||||
box0.center.x = (float)(img_size.width*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.width - m));
|
||||
box0.center.y = (float)(img_size.height*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.height - m));
|
||||
|
||||
criteria = TermCriteria( TermCriteria::EPS + TermCriteria::MAX_ITER, 10, 0.1 );
|
||||
|
||||
generate_object();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void CV_TrackBaseTest::run_func(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int CV_TrackBaseTest::validate_test_results( int /*test_case_idx*/ )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////// CamShift //////////////////////////////
|
||||
|
||||
class CV_CamShiftTest : public CV_TrackBaseTest
|
||||
{
|
||||
public:
|
||||
CV_CamShiftTest();
|
||||
|
||||
protected:
|
||||
void run_func(void);
|
||||
int prepare_test_case( int test_case_idx );
|
||||
int validate_test_results( int test_case_idx );
|
||||
void generate_object();
|
||||
|
||||
RotatedRect box;
|
||||
Rect init_rect;
|
||||
int area0;
|
||||
};
|
||||
|
||||
|
||||
CV_CamShiftTest::CV_CamShiftTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int CV_CamShiftTest::prepare_test_case( int test_case_idx )
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
double m;
|
||||
int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
|
||||
int i, area;
|
||||
|
||||
if( code <= 0 )
|
||||
return code;
|
||||
|
||||
area0 = countNonZero(img);
|
||||
|
||||
for(i = 0; i < 100; i++)
|
||||
{
|
||||
m = MAX(box0.size.width,box0.size.height)*0.8;
|
||||
init_rect.x = cvFloor(box0.center.x - m*(0.45 + cvtest::randReal(rng)*0.2));
|
||||
init_rect.y = cvFloor(box0.center.y - m*(0.45 + cvtest::randReal(rng)*0.2));
|
||||
init_rect.width = cvCeil(box0.center.x + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.x);
|
||||
init_rect.height = cvCeil(box0.center.y + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.y);
|
||||
|
||||
if( init_rect.x < 0 || init_rect.y < 0 ||
|
||||
init_rect.x + init_rect.width >= img_size.width ||
|
||||
init_rect.y + init_rect.height >= img_size.height )
|
||||
continue;
|
||||
|
||||
Mat temp = img(init_rect);
|
||||
area = countNonZero( temp );
|
||||
|
||||
if( area >= 0.1*area0 )
|
||||
break;
|
||||
}
|
||||
|
||||
return i < 100 ? code : 0;
|
||||
}
|
||||
|
||||
|
||||
void CV_CamShiftTest::run_func(void)
|
||||
{
|
||||
box = CamShift( img, init_rect, criteria );
|
||||
}
|
||||
|
||||
|
||||
int CV_CamShiftTest::validate_test_results( int /*test_case_idx*/ )
|
||||
{
|
||||
int code = cvtest::TS::OK;
|
||||
|
||||
double m = MAX(box0.size.width, box0.size.height);
|
||||
double diff_angle;
|
||||
|
||||
if( cvIsNaN(box.size.width) || cvIsInf(box.size.width) || box.size.width <= 0 ||
|
||||
cvIsNaN(box.size.height) || cvIsInf(box.size.height) || box.size.height <= 0 ||
|
||||
cvIsNaN(box.center.x) || cvIsInf(box.center.x) ||
|
||||
cvIsNaN(box.center.y) || cvIsInf(box.center.y) ||
|
||||
cvIsNaN(box.angle) || cvIsInf(box.angle) || box.angle < -180 || box.angle > 180 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Invalid RotatedRect was returned by CamShift\n" );
|
||||
code = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
box.angle = (float)(180 - box.angle);
|
||||
|
||||
if( fabs(box.size.width - box0.size.width) > box0.size.width*0.2 ||
|
||||
fabs(box.size.height - box0.size.height) > box0.size.height*0.3 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D size (=%.1f x %.1f, should be %.1f x %.1f)\n",
|
||||
box.size.width, box.size.height, box0.size.width, box0.size.height );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
if( fabs(box.center.x - box0.center.x) > m*0.1 ||
|
||||
fabs(box.center.y - box0.center.y) > m*0.1 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
|
||||
box.center.x, box.center.y, box0.center.x, box0.center.y );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
if( box.angle < 0 )
|
||||
box.angle += 180;
|
||||
|
||||
diff_angle = fabs(box0.angle - box.angle);
|
||||
diff_angle = MIN( diff_angle, fabs(box0.angle - box.angle + 180));
|
||||
|
||||
if( fabs(diff_angle) > 30 && box0.size.height > box0.size.width*1.2 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D angle (=%1.f, should be %1.f)\n",
|
||||
box.angle, box0.angle );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
_exit_:
|
||||
|
||||
if( code < 0 )
|
||||
{
|
||||
ts->set_failed_test_info( code );
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////// MeanShift //////////////////////////////
|
||||
|
||||
class CV_MeanShiftTest : public CV_TrackBaseTest
|
||||
{
|
||||
public:
|
||||
CV_MeanShiftTest();
|
||||
|
||||
protected:
|
||||
void run_func(void);
|
||||
int prepare_test_case( int test_case_idx );
|
||||
int validate_test_results( int test_case_idx );
|
||||
void generate_object();
|
||||
|
||||
Rect init_rect, rect;
|
||||
int area0, area;
|
||||
};
|
||||
|
||||
|
||||
CV_MeanShiftTest::CV_MeanShiftTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int CV_MeanShiftTest::prepare_test_case( int test_case_idx )
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
double m;
|
||||
int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
|
||||
int i;
|
||||
|
||||
if( code <= 0 )
|
||||
return code;
|
||||
|
||||
area0 = countNonZero(img);
|
||||
|
||||
for(i = 0; i < 100; i++)
|
||||
{
|
||||
m = (box0.size.width + box0.size.height)*0.5;
|
||||
init_rect.x = cvFloor(box0.center.x - m*(0.4 + cvtest::randReal(rng)*0.2));
|
||||
init_rect.y = cvFloor(box0.center.y - m*(0.4 + cvtest::randReal(rng)*0.2));
|
||||
init_rect.width = cvCeil(box0.center.x + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.x);
|
||||
init_rect.height = cvCeil(box0.center.y + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.y);
|
||||
|
||||
if( init_rect.x < 0 || init_rect.y < 0 ||
|
||||
init_rect.x + init_rect.width >= img_size.width ||
|
||||
init_rect.y + init_rect.height >= img_size.height )
|
||||
continue;
|
||||
|
||||
Mat temp = img(init_rect);
|
||||
area = countNonZero( temp );
|
||||
|
||||
if( area >= 0.5*area0 )
|
||||
break;
|
||||
}
|
||||
|
||||
return i < 100 ? code : 0;
|
||||
}
|
||||
|
||||
|
||||
void CV_MeanShiftTest::run_func(void)
|
||||
{
|
||||
rect = init_rect;
|
||||
meanShift( img, rect, criteria );
|
||||
}
|
||||
|
||||
|
||||
int CV_MeanShiftTest::validate_test_results( int /*test_case_idx*/ )
|
||||
{
|
||||
int code = cvtest::TS::OK;
|
||||
Point2f c;
|
||||
double m = MAX(box0.size.width, box0.size.height), delta;
|
||||
|
||||
c.x = (float)(rect.x + rect.width*0.5);
|
||||
c.y = (float)(rect.y + rect.height*0.5);
|
||||
|
||||
if( fabs(c.x - box0.center.x) > m*0.1 ||
|
||||
fabs(c.y - box0.center.y) > m*0.1 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
|
||||
c.x, c.y, box0.center.x, box0.center.y );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
delta = m*0.7;
|
||||
|
||||
if( rect.x < box0.center.x - delta ||
|
||||
rect.y < box0.center.y - delta ||
|
||||
rect.x + rect.width > box0.center.x + delta ||
|
||||
rect.y + rect.height > box0.center.y + delta )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG,
|
||||
"Incorrect ConnectedComp ((%d,%d,%d,%d) is not within (%.1f,%.1f,%.1f,%.1f))\n",
|
||||
rect.x, rect.y, rect.x + rect.width, rect.y + rect.height,
|
||||
box0.center.x - delta, box0.center.y - delta, box0.center.x + delta, box0.center.y + delta );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
}
|
||||
|
||||
_exit_:
|
||||
|
||||
if( code < 0 )
|
||||
{
|
||||
ts->set_failed_test_info( code );
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
TEST(Video_CAMShift, accuracy) { CV_CamShiftTest test; test.safe_run(); }
|
||||
TEST(Video_MeanShift, accuracy) { CV_MeanShiftTest test; test.safe_run(); }
|
||||
|
||||
}} // namespace
|
||||
/* End of file. */
|
||||
@@ -0,0 +1,475 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test {
|
||||
namespace {
|
||||
|
||||
PARAM_TEST_CASE(Video_ECC, int, bool)
|
||||
{
|
||||
int motionType;
|
||||
bool usePyramids;
|
||||
virtual void SetUp()
|
||||
{
|
||||
motionType = GET_PARAM(0);
|
||||
usePyramids = GET_PARAM(1);
|
||||
}
|
||||
};
|
||||
|
||||
class CV_ECC_Test : public cvtest::BaseTest {
|
||||
public:
|
||||
CV_ECC_Test(int motionType, bool usePyramids);
|
||||
virtual ~CV_ECC_Test();
|
||||
|
||||
protected:
|
||||
int motionType;
|
||||
double MAX_RMS; // upper bound for RMS error
|
||||
|
||||
double computeRMS(const Mat& mat1, const Mat& mat2);
|
||||
bool isMapCorrect(const Mat& mat);
|
||||
|
||||
virtual bool test(const Mat img);
|
||||
bool testAllTypes(const Mat img); // run test for all supported data types (U8, U16, F32, F64)
|
||||
bool testAllChNum(const Mat img); // run test for all supported channels count (gray, RGB)
|
||||
|
||||
void run(int);
|
||||
|
||||
bool checkMap(const Mat& map, const Mat& ground);
|
||||
|
||||
int ntests; // number of tests per motion type
|
||||
int ECC_iterations; // number of iterations for ECC
|
||||
double ECC_epsilon; // we choose a negative value, so that
|
||||
// ECC_iterations are always executed
|
||||
TermCriteria criteria;
|
||||
bool usePyramids; // use version of findTransformECC with pyramids
|
||||
};
|
||||
|
||||
|
||||
CV_ECC_Test::CV_ECC_Test(int a_motionType, bool a_usePyramids) : motionType(a_motionType)
|
||||
, MAX_RMS(0.1)
|
||||
, ntests(3)
|
||||
, ECC_iterations(50)
|
||||
, ECC_epsilon(-1)
|
||||
, criteria(TermCriteria::COUNT + TermCriteria::EPS, ECC_iterations, ECC_epsilon)
|
||||
, usePyramids(a_usePyramids)
|
||||
{}
|
||||
|
||||
|
||||
CV_ECC_Test::~CV_ECC_Test() {}
|
||||
|
||||
bool CV_ECC_Test::isMapCorrect(const Mat& map) {
|
||||
bool tr = true;
|
||||
float mapVal;
|
||||
for (int i = 0; i < map.rows; i++)
|
||||
for (int j = 0; j < map.cols; j++) {
|
||||
mapVal = map.at<float>(i, j);
|
||||
tr = tr & (!cvIsNaN(mapVal) && (fabs(mapVal) < 1e9));
|
||||
}
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
double CV_ECC_Test::computeRMS(const Mat& mat1, const Mat& mat2) {
|
||||
CV_Assert(mat1.rows == mat2.rows);
|
||||
CV_Assert(mat1.cols == mat2.cols);
|
||||
|
||||
Mat errorMat;
|
||||
subtract(mat1, mat2, errorMat);
|
||||
|
||||
return sqrt(errorMat.dot(errorMat) / (mat1.rows * mat1.cols * mat1.channels()));
|
||||
}
|
||||
|
||||
bool CV_ECC_Test::checkMap(const Mat& map, const Mat& ground) {
|
||||
if (!isMapCorrect(map)) {
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (computeRMS(map, ground) > MAX_RMS) {
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
|
||||
ts->printf(ts->LOG, "RMS = %f", computeRMS(map, ground));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CV_ECC_Test::test(const Mat img)
|
||||
{
|
||||
cv::RNG rng = ts->get_rng();
|
||||
|
||||
int progress = 0;
|
||||
|
||||
for (int k = 0; k < ntests; k++) {
|
||||
ts->update_context(this, k, true);
|
||||
progress = update_progress(progress, k, ntests, 0);
|
||||
|
||||
Mat groundMap;
|
||||
switch(motionType)
|
||||
{
|
||||
case MOTION_TRANSLATION:
|
||||
groundMap = (Mat_<float>(2, 3) << 1, 0, (rng.uniform(10.f, 20.f)), 0, 1, (rng.uniform(10.f, 20.f)));
|
||||
break;
|
||||
case MOTION_EUCLIDEAN:
|
||||
{
|
||||
double angle = CV_PI / 30 + CV_PI * rng.uniform((double)-2.f, (double)2.f) / 180;
|
||||
groundMap = (Mat_<float>(2, 3) << cos(angle), -sin(angle), (rng.uniform(10.f, 20.f)), sin(angle),
|
||||
cos(angle), (rng.uniform(10.f, 20.f)));
|
||||
break;
|
||||
}
|
||||
case MOTION_AFFINE:
|
||||
groundMap = (Mat_<float>(2, 3) << (1 - rng.uniform(-0.05f, 0.05f)), (rng.uniform(-0.03f, 0.03f)),
|
||||
(rng.uniform(10.f, 20.f)), (rng.uniform(-0.03f, 0.03f)), (1 - rng.uniform(-0.05f, 0.05f)),
|
||||
(rng.uniform(10.f, 20.f)));
|
||||
break;
|
||||
case MOTION_HOMOGRAPHY:
|
||||
groundMap =
|
||||
(Mat_<float>(3, 3) << (1 - rng.uniform(-0.05f, 0.05f)), (rng.uniform(-0.03f, 0.03f)),
|
||||
(rng.uniform(10.f, 20.f)), (rng.uniform(-0.03f, 0.03f)), (1 - rng.uniform(-0.05f, 0.05f)),
|
||||
(rng.uniform(10.f, 20.f)), (rng.uniform(0.0001f, 0.0003f)), (rng.uniform(0.0001f, 0.0003f)), 1.f);
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "Incorrect motion type");
|
||||
break;
|
||||
}
|
||||
|
||||
Mat warpedImage;
|
||||
|
||||
Mat foundMap;
|
||||
if(motionType == MOTION_HOMOGRAPHY)
|
||||
{
|
||||
warpPerspective(img, warpedImage, groundMap, Size(200, 200), INTER_LINEAR + WARP_INVERSE_MAP);
|
||||
foundMap = Mat::eye(3, 3, CV_32F);
|
||||
}
|
||||
else
|
||||
{
|
||||
warpAffine(img, warpedImage, groundMap, Size(200, 200), INTER_LINEAR + WARP_INVERSE_MAP);
|
||||
foundMap = Mat((Mat_<float>(2, 3) << 1, 0, 0, 0, 1, 0));
|
||||
}
|
||||
|
||||
|
||||
if(usePyramids)
|
||||
{
|
||||
ECCParameters params;
|
||||
params.criteria = criteria;
|
||||
params.motionType = motionType;
|
||||
findTransformECCMultiScale(warpedImage, img, foundMap, params);
|
||||
}
|
||||
else
|
||||
findTransformECC(warpedImage, img, foundMap, motionType, criteria);
|
||||
|
||||
if (!checkMap(foundMap, groundMap))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CV_ECC_Test::testAllTypes(const Mat img) {
|
||||
auto types = {CV_8U, CV_16U, CV_32F, CV_64F};
|
||||
for (auto type : types) {
|
||||
Mat timg;
|
||||
img.convertTo(timg, type);
|
||||
if (!test(timg))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CV_ECC_Test::testAllChNum(const Mat img) {
|
||||
if(!usePyramids)
|
||||
if (!testAllTypes(img))
|
||||
return false;
|
||||
|
||||
Mat gray;
|
||||
cvtColor(img, gray, COLOR_RGB2GRAY);
|
||||
if (!testAllTypes(gray))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CV_ECC_Test::run(int) {
|
||||
Mat img = imread(string(ts->get_data_path()) + "shared/fruits.png");
|
||||
if (img.empty()) {
|
||||
ts->printf(ts->LOG, "test image can not be read");
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
Mat testImg;
|
||||
resize(img, testImg, Size(216, 216), 0, 0, INTER_LINEAR_EXACT);
|
||||
|
||||
testAllChNum(testImg);
|
||||
|
||||
ts->set_failed_test_info(cvtest::TS::OK);
|
||||
}
|
||||
|
||||
TEST_P(Video_ECC, accuracy) {
|
||||
CV_ECC_Test test(motionType, usePyramids);
|
||||
test.safe_run();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ECCfixtures, Video_ECC,
|
||||
testing::Values(testing::make_tuple(MOTION_TRANSLATION, false),
|
||||
testing::make_tuple(MOTION_TRANSLATION, true),
|
||||
testing::make_tuple(MOTION_EUCLIDEAN, false),
|
||||
testing::make_tuple(MOTION_EUCLIDEAN, true),
|
||||
testing::make_tuple(MOTION_AFFINE, false),
|
||||
testing::make_tuple(MOTION_AFFINE, true),
|
||||
testing::make_tuple(MOTION_HOMOGRAPHY, false),
|
||||
testing::make_tuple(MOTION_HOMOGRAPHY, true)));
|
||||
|
||||
class CV_ECC_Test_Mask : public CV_ECC_Test {
|
||||
public:
|
||||
CV_ECC_Test_Mask();
|
||||
|
||||
protected:
|
||||
bool test(const Mat);
|
||||
};
|
||||
|
||||
CV_ECC_Test_Mask::CV_ECC_Test_Mask():CV_ECC_Test(MOTION_TRANSLATION, false) {}
|
||||
|
||||
bool CV_ECC_Test_Mask::test(const Mat testImg) {
|
||||
cv::RNG rng = ts->get_rng();
|
||||
|
||||
int progress = 0;
|
||||
|
||||
for (int k = 0; k < ntests; k++) {
|
||||
ts->update_context(this, k, true);
|
||||
progress = update_progress(progress, k, ntests, 0);
|
||||
|
||||
Mat translationGround = (Mat_<float>(2, 3) << 1, 0, (rng.uniform(10.f, 20.f)), 0, 1, (rng.uniform(10.f, 20.f)));
|
||||
|
||||
Mat warpedImage;
|
||||
|
||||
warpAffine(testImg, warpedImage, translationGround, Size(200, 200), INTER_LINEAR + WARP_INVERSE_MAP);
|
||||
|
||||
Mat mapTranslation = (Mat_<float>(2, 3) << 1, 0, 0, 0, 1, 0);
|
||||
|
||||
Mat_<unsigned char> mask = Mat_<unsigned char>::ones(testImg.rows, testImg.cols);
|
||||
Rect region(testImg.cols * 2 / 3, testImg.rows * 2 / 3, testImg.cols / 3, testImg.rows / 3);
|
||||
|
||||
rectangle(testImg, region, Scalar::all(0), FILLED);
|
||||
rectangle(mask, region, Scalar(0), FILLED);
|
||||
|
||||
findTransformECC(warpedImage, testImg, mapTranslation, 0, criteria, mask);
|
||||
|
||||
if (!checkMap(mapTranslation, translationGround))
|
||||
return false;
|
||||
|
||||
// Test with non-default gaussian blur.
|
||||
findTransformECC(warpedImage, testImg, mapTranslation, 0, criteria, mask, 1);
|
||||
|
||||
if (!checkMap(mapTranslation, translationGround))
|
||||
return false;
|
||||
|
||||
// Test with template mask.
|
||||
Mat_<unsigned char> warpedMask = Mat_<unsigned char>::ones(warpedImage.rows, warpedImage.cols);
|
||||
for (int i=warpedImage.rows*1/3; i<warpedImage.rows*2/3; i++) {
|
||||
for (int j=warpedImage.cols*1/3; j<warpedImage.cols*2/3; j++) {
|
||||
warpedMask(i, j) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
findTransformECCWithMask(warpedImage, testImg, warpedMask, mask, mapTranslation, 0,
|
||||
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon));
|
||||
|
||||
if (!checkMap(mapTranslation, translationGround))
|
||||
return false;
|
||||
|
||||
// Test with non-default gaussian blur.
|
||||
findTransformECCWithMask(warpedImage, testImg, warpedMask, mask, mapTranslation, 0, criteria, 1);
|
||||
|
||||
if (!checkMap(mapTranslation, translationGround))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class CV_ECC_BigPictureTest : public CV_ECC_Test {
|
||||
public:
|
||||
CV_ECC_BigPictureTest(bool a_maskedVersion) : CV_ECC_Test(MOTION_HOMOGRAPHY, true), maskedVersion(a_maskedVersion) {}
|
||||
virtual ~CV_ECC_BigPictureTest() {}
|
||||
protected:
|
||||
void run(int);
|
||||
bool maskedVersion;
|
||||
};
|
||||
|
||||
void CV_ECC_BigPictureTest::run(int)
|
||||
{
|
||||
Mat largeGray0 = imread(string(ts->get_data_path()) + "shared/halmosh0.jpg", IMREAD_GRAYSCALE);
|
||||
Mat largeGray1;
|
||||
Mat roiMask0;
|
||||
Mat roiMask1;
|
||||
Mat expectedRes;
|
||||
bool readError = false;
|
||||
if(maskedVersion)
|
||||
{
|
||||
largeGray1 = imread(string(ts->get_data_path()) + "shared/halmosh2.jpg", IMREAD_GRAYSCALE);
|
||||
roiMask0 = imread(string(ts->get_data_path()) + "shared/halmosh0mask.png", IMREAD_GRAYSCALE);
|
||||
roiMask1 = imread(string(ts->get_data_path()) + "shared/halmosh2mask.png", IMREAD_GRAYSCALE);
|
||||
readError = largeGray0.empty() || largeGray1.empty() || roiMask0.empty() || roiMask1.empty();
|
||||
expectedRes = (Mat_<float>(3, 3) << 1.0225, 0.0606, -28.6452, -0.0475, 1.0314, 11.819, 8.21e-06, -3.65e-07, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
largeGray1 = imread(string(ts->get_data_path()) + "shared/halmosh1.jpg", IMREAD_GRAYSCALE);
|
||||
readError = largeGray0.empty() || largeGray1.empty();
|
||||
expectedRes = (Mat_<float>(3, 3) << 0.9756, -0.0319, 24.685, 0.013, 0.9808, 7.7453, -2.35e-05, -9.12e-06, 1);
|
||||
}
|
||||
|
||||
if(readError)
|
||||
{
|
||||
ts->printf(ts->LOG, "test image can not be read");
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
cv::Mat found = cv::Mat::eye(3, 3, CV_32F);
|
||||
constexpr int N_ITERS = 20;
|
||||
constexpr double TERMINATION_EPS = 1e-6;
|
||||
ECCParameters params;
|
||||
params.criteria = cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, N_ITERS, TERMINATION_EPS);
|
||||
params.motionType = MOTION_HOMOGRAPHY;
|
||||
params.nlevels = 5;
|
||||
params.itersPerLevel = {5, 10, 300, 300, 1000};
|
||||
findTransformECCMultiScale(largeGray0, largeGray1, found, params, roiMask0, roiMask1);
|
||||
ASSERT_EQ(checkMap(found, expectedRes), true);
|
||||
ts->set_failed_test_info(cvtest::TS::OK);
|
||||
}
|
||||
|
||||
void testECCProperties(Mat x, float eps) {
|
||||
// The channels are independent
|
||||
Mat y = x.t();
|
||||
Mat Z = Mat::zeros(x.size(), y.type());
|
||||
Mat O = Mat::ones(x.size(), y.type());
|
||||
|
||||
EXPECT_NEAR(computeECC(x, y), 0.0, eps);
|
||||
if (x.type() != CV_8U && x.type() != CV_8U) {
|
||||
EXPECT_NEAR(computeECC(x + y, x - y), 0.0, eps);
|
||||
}
|
||||
|
||||
EXPECT_NEAR(computeECC(x, x), 1.0, eps);
|
||||
|
||||
Mat R, G, B, X, Y;
|
||||
cv::merge(std::vector<cv::Mat>({O, Z, Z}), R);
|
||||
cv::merge(std::vector<cv::Mat>({Z, O, Z}), G);
|
||||
cv::merge(std::vector<cv::Mat>({Z, Z, O}), B);
|
||||
cv::merge(std::vector<cv::Mat>({x, x, x}), X);
|
||||
cv::merge(std::vector<cv::Mat>({y, y, y}), Y);
|
||||
|
||||
// 1. The channels are orthogonal and independent
|
||||
EXPECT_NEAR(computeECC(X.mul(R), X.mul(G)), 0, eps);
|
||||
EXPECT_NEAR(computeECC(X.mul(R), X.mul(B)), 0, eps);
|
||||
EXPECT_NEAR(computeECC(X.mul(B), X.mul(G)), 0, eps);
|
||||
|
||||
EXPECT_NEAR(computeECC(X.mul(R) + Y.mul(B), X.mul(B) + Y.mul(R)), 0, eps);
|
||||
|
||||
EXPECT_NEAR(computeECC(X.mul(R) + Y.mul(G) + (X + Y).mul(B), Y.mul(R) + X.mul(G) + (X - Y).mul(B)), 0, eps);
|
||||
|
||||
// 2. Each channel contribute equally
|
||||
EXPECT_NEAR(computeECC(X.mul(R) + Y.mul(G + B), X), 1.0 / 3, eps);
|
||||
EXPECT_NEAR(computeECC(X.mul(G) + Y.mul(R + B), X), 1.0 / 3, eps);
|
||||
EXPECT_NEAR(computeECC(X.mul(B) + Y.mul(G + R), X), 1.0 / 3, eps);
|
||||
|
||||
// 3. The coefficient is invariant with respect to the offset of channels
|
||||
EXPECT_NEAR(computeECC(X - R + 2 * G + B, X), 1.0, eps);
|
||||
if (x.type() != CV_8U && x.type() != CV_8U) {
|
||||
EXPECT_NEAR(computeECC(X + R - 2 * G + B, Y), 0.0, eps);
|
||||
}
|
||||
|
||||
// The channels are independent. Check orthogonal combinations
|
||||
// full squares norm = sum of squared norms
|
||||
EXPECT_NEAR(computeECC(X, Y + X), 1.0 / sqrt(2.0), eps);
|
||||
EXPECT_NEAR(computeECC(X, 2 * Y + X), 1.0 / sqrt(5.0), eps);
|
||||
}
|
||||
|
||||
TEST(Video_ECC_Test_Compute, properties) {
|
||||
Mat xline(1, 100, CV_32F), x;
|
||||
for (int i = 0; i < xline.cols; ++i) xline.at<float>(0, i) = (float)i;
|
||||
|
||||
repeat(xline, xline.cols, 1, x);
|
||||
|
||||
Mat x_f64, x_u8, x_u16;
|
||||
x.convertTo(x_f64, CV_64F);
|
||||
x.convertTo(x_u8, CV_8U);
|
||||
x.convertTo(x_u16, CV_16U);
|
||||
|
||||
testECCProperties(x, 1e-5f);
|
||||
testECCProperties(x_f64, 1e-5f);
|
||||
testECCProperties(x_u8, 1);
|
||||
testECCProperties(x_u16, 1);
|
||||
}
|
||||
|
||||
TEST(Video_ECC_Test_Compute, accuracy) {
|
||||
Mat testImg = (Mat_<float>(3, 3) << 1, 0, 0, 1, 0, 0, 1, 0, 0);
|
||||
Mat warpedImage = (Mat_<float>(3, 3) << 0, 1, 0, 0, 1, 0, 0, 1, 0);
|
||||
Mat_<unsigned char> mask = Mat_<unsigned char>::ones(testImg.rows, testImg.cols);
|
||||
double ecc = computeECC(warpedImage, testImg, mask);
|
||||
|
||||
EXPECT_NEAR(ecc, -0.5f, 1e-5f);
|
||||
}
|
||||
|
||||
TEST(Video_ECC_Test_Compute, bug_14657) {
|
||||
/*
|
||||
* Simple test case - a 2 x 2 matrix with 10, 10, 10, 6. When the mean (36 / 4 = 9) is subtracted,
|
||||
* it results in 1, 1, 1, 0 for the unsigned int case - compare to 1, 1, 1, -3 in the signed case.
|
||||
* For this reason, when the same matrix was provided as the input and the template, we didn't get 1 as expected.
|
||||
*/
|
||||
Mat img = (Mat_<uint8_t>(2, 2) << 10, 10, 10, 6);
|
||||
EXPECT_NEAR(computeECC(img, img), 1.0f, 1e-5f);
|
||||
}
|
||||
|
||||
TEST(Video_ECC_Mask, accuracy) {
|
||||
CV_ECC_Test_Mask test;
|
||||
test.safe_run();
|
||||
}
|
||||
TEST(Video_ECC_BigMS, accuracy) {
|
||||
CV_ECC_BigPictureTest test(false);
|
||||
test.safe_run();
|
||||
}
|
||||
TEST(Video_ECC_BigMS_Mask, accuracy) {
|
||||
CV_ECC_BigPictureTest test(true);
|
||||
test.safe_run();
|
||||
}
|
||||
} // namespace
|
||||
} // namespace opencv_test
|
||||
@@ -0,0 +1,184 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
// this is test for a deprecated function. let's ignore deprecated warnings in this file
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning( disable : 4996)
|
||||
#endif
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class CV_RigidTransform_Test : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_RigidTransform_Test();
|
||||
~CV_RigidTransform_Test();
|
||||
protected:
|
||||
void run(int);
|
||||
|
||||
bool testNPoints(int);
|
||||
bool testImage();
|
||||
};
|
||||
|
||||
CV_RigidTransform_Test::CV_RigidTransform_Test()
|
||||
{
|
||||
}
|
||||
CV_RigidTransform_Test::~CV_RigidTransform_Test() {}
|
||||
|
||||
struct WrapAff2D
|
||||
{
|
||||
const double *F;
|
||||
WrapAff2D(const Mat& aff) : F(aff.ptr<double>()) {}
|
||||
Point2f operator()(const Point2f& p)
|
||||
{
|
||||
return Point2f( (float)(p.x * F[0] + p.y * F[1] + F[2]),
|
||||
(float)(p.x * F[3] + p.y * F[4] + F[5]) );
|
||||
}
|
||||
};
|
||||
|
||||
bool CV_RigidTransform_Test::testNPoints(int from)
|
||||
{
|
||||
cv::RNG rng = cv::theRNG();
|
||||
|
||||
int progress = 0;
|
||||
int k, ntests = 10000;
|
||||
|
||||
for( k = from; k < ntests; k++ )
|
||||
{
|
||||
ts->update_context( this, k, true );
|
||||
progress = update_progress(progress, k, ntests, 0);
|
||||
|
||||
Mat aff(2, 3, CV_64F);
|
||||
rng.fill(aff, RNG::UNIFORM, Scalar(-2), Scalar(2));
|
||||
|
||||
int n = (unsigned)rng % 100 + 10;
|
||||
|
||||
Mat fpts(1, n, CV_32FC2);
|
||||
Mat tpts(1, n, CV_32FC2);
|
||||
|
||||
rng.fill(fpts, RNG::UNIFORM, Scalar(0,0), Scalar(10,10));
|
||||
std::transform(fpts.ptr<Point2f>(), fpts.ptr<Point2f>() + n, tpts.ptr<Point2f>(), WrapAff2D(aff));
|
||||
|
||||
Mat noise(1, n, CV_32FC2);
|
||||
rng.fill(noise, RNG::NORMAL, Scalar::all(0), Scalar::all(0.001*(n<=7 ? 0 : n <= 30 ? 1 : 10)));
|
||||
tpts += noise;
|
||||
|
||||
Mat aff_est = estimateRigidTransform(fpts, tpts, true);
|
||||
|
||||
double thres = 0.1*cvtest::norm(aff, NORM_L2);
|
||||
double d = cvtest::norm(aff_est, aff, NORM_L2);
|
||||
if (d > thres)
|
||||
{
|
||||
double dB=0, nB=0;
|
||||
if (n <= 4)
|
||||
{
|
||||
Mat A = fpts.reshape(1, 3);
|
||||
Mat B = A - repeat(A.row(0), 3, 1), Bt = B.t();
|
||||
B = Bt*B;
|
||||
dB = cv::determinant(B);
|
||||
nB = cvtest::norm(B, NORM_L2);
|
||||
if( fabs(dB) < 0.01*nB )
|
||||
continue;
|
||||
}
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
|
||||
ts->printf( cvtest::TS::LOG, "Threshold = %f, norm of difference = %f", thres, d );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CV_RigidTransform_Test::testImage()
|
||||
{
|
||||
Mat img;
|
||||
Mat testImg = imread( string(ts->get_data_path()) + "shared/graffiti.png", 1);
|
||||
if (testImg.empty())
|
||||
{
|
||||
ts->printf( ts->LOG, "test image can not be read");
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
|
||||
return false;
|
||||
}
|
||||
pyrDown(testImg, img);
|
||||
|
||||
Mat aff = cv::getRotationMatrix2D(Point(img.cols/2, img.rows/2), 1, 0.99);
|
||||
aff.ptr<double>()[2]+=3;
|
||||
aff.ptr<double>()[5]+=3;
|
||||
|
||||
Mat rotated;
|
||||
warpAffine(img, rotated, aff, img.size());
|
||||
|
||||
Mat aff_est = estimateRigidTransform(img, rotated, true);
|
||||
|
||||
const double thres = 0.033;
|
||||
if (cvtest::norm(aff_est, aff, NORM_INF) > thres)
|
||||
{
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
|
||||
ts->printf( cvtest::TS::LOG, "Threshold = %f, norm of difference = %f", thres,
|
||||
cvtest::norm(aff_est, aff, NORM_INF) );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CV_RigidTransform_Test::run( int start_from )
|
||||
{
|
||||
cvtest::DefaultRngAuto dra;
|
||||
|
||||
if (!testNPoints(start_from))
|
||||
return;
|
||||
|
||||
if (!testImage())
|
||||
return;
|
||||
|
||||
ts->set_failed_test_info(cvtest::TS::OK);
|
||||
}
|
||||
|
||||
TEST(Video_RigidFlow, accuracy) { CV_RigidTransform_Test test; test.safe_run(); }
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,113 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class CV_KalmanTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_KalmanTest();
|
||||
protected:
|
||||
void run(int);
|
||||
};
|
||||
|
||||
|
||||
CV_KalmanTest::CV_KalmanTest()
|
||||
{
|
||||
}
|
||||
|
||||
void CV_KalmanTest::run( int )
|
||||
{
|
||||
int code = cvtest::TS::OK;
|
||||
const int Dim = 7;
|
||||
const int Steps = 100;
|
||||
const double max_init = 1;
|
||||
const double max_noise = 0.1;
|
||||
|
||||
const double EPSILON = 1.000;
|
||||
RNG& rng = ts->get_rng();
|
||||
int i, j;
|
||||
|
||||
cv::Mat Sample(Dim,1,CV_32F);
|
||||
cv::Mat Temp(Dim,1,CV_32F);
|
||||
|
||||
cv::KalmanFilter Kalm(Dim, Dim);
|
||||
Kalm.transitionMatrix = cv::Mat::eye(Dim, Dim, CV_32F);
|
||||
Kalm.measurementMatrix = cv::Mat::eye(Dim, Dim, CV_32F);
|
||||
Kalm.processNoiseCov = cv::Mat::eye(Dim, Dim, CV_32F);
|
||||
Kalm.errorCovPre = cv::Mat::eye(Dim, Dim, CV_32F);
|
||||
Kalm.errorCovPost = cv::Mat::eye(Dim, Dim, CV_32F);
|
||||
Kalm.measurementNoiseCov = cv::Mat::zeros(Dim, Dim, CV_32F);
|
||||
Kalm.statePre = cv::Mat::zeros(Dim, 1, CV_32F);
|
||||
Kalm.statePost = cv::Mat::zeros(Dim, 1, CV_32F);
|
||||
cvtest::randUni(rng, Sample, Scalar::all(-max_init), Scalar::all(max_init));
|
||||
Kalm.correct(Sample);
|
||||
for(i = 0; i<Steps; i++)
|
||||
{
|
||||
Kalm.predict();
|
||||
const Mat& Dyn = Kalm.transitionMatrix;
|
||||
for(j = 0; j<Dim; j++)
|
||||
{
|
||||
float t = 0;
|
||||
for(int k=0; k<Dim; k++)
|
||||
{
|
||||
t += Dyn.at<float>(j,k)*Sample.at<float>(k);
|
||||
}
|
||||
Temp.at<float>(j) = (float)(t+(cvtest::randReal(rng)*2-1)*max_noise);
|
||||
}
|
||||
Temp.copyTo(Sample);
|
||||
Kalm.correct(Temp);
|
||||
}
|
||||
|
||||
Mat _state_post = Kalm.statePost;
|
||||
code = cvtest::cmpEps2( ts, Sample, _state_post, EPSILON, false, "The final estimated state" );
|
||||
|
||||
if( code < 0 )
|
||||
ts->set_failed_test_info( code );
|
||||
}
|
||||
|
||||
TEST(Video_Kalman, accuracy) { CV_KalmanTest test; test.safe_run(); }
|
||||
|
||||
}} // namespace
|
||||
/* End of file. */
|
||||
@@ -0,0 +1,17 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
#if defined(HAVE_HPX)
|
||||
#include <hpx/hpx_main.hpp>
|
||||
#endif
|
||||
|
||||
static
|
||||
void initTests()
|
||||
{
|
||||
cvtest::addDataSearchEnv("OPENCV_DNN_TEST_DATA_PATH");
|
||||
cvtest::addDataSearchSubDirectory(""); // override "cv" prefix below to access without "../dnn" hacks
|
||||
}
|
||||
|
||||
CV_TEST_MAIN("cv", initTests())
|
||||
@@ -0,0 +1,252 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
/* ///////////////////// pyrlk_test ///////////////////////// */
|
||||
|
||||
class CV_OptFlowPyrLKTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_OptFlowPyrLKTest();
|
||||
protected:
|
||||
void run(int);
|
||||
};
|
||||
|
||||
|
||||
CV_OptFlowPyrLKTest::CV_OptFlowPyrLKTest() {}
|
||||
|
||||
void CV_OptFlowPyrLKTest::run( int )
|
||||
{
|
||||
int code = cvtest::TS::OK;
|
||||
|
||||
const double success_error_level = 0.3;
|
||||
const int bad_points_max = 8;
|
||||
|
||||
/* test parameters */
|
||||
double max_err = 0.;
|
||||
int pt_exceed = 0;
|
||||
int merr_i = 0, merr_nan = 0;
|
||||
char filename[1000];
|
||||
|
||||
cv::Point2f *v = 0, *v2 = 0;
|
||||
cv::Mat _u, _v, _v2;
|
||||
|
||||
cv::Mat imgI, imgJ;
|
||||
|
||||
int n = 0, i = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
snprintf( filename, sizeof(filename), "%soptflow/%s", ts->get_data_path().c_str(), "lk_prev.dat" );
|
||||
|
||||
{
|
||||
FileStorage fs(filename, FileStorage::READ);
|
||||
fs["points"] >> _u;
|
||||
if( _u.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
|
||||
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf( filename, sizeof(filename), "%soptflow/%s", ts->get_data_path().c_str(), "lk_next.dat" );
|
||||
|
||||
{
|
||||
FileStorage fs(filename, FileStorage::READ);
|
||||
fs["points"] >> _v;
|
||||
if( _v.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
|
||||
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( _u.cols != 2 || _u.type() != CV_32F ||
|
||||
_v.cols != 2 || _v.type() != CV_32F ||
|
||||
_v.rows != _u.rows )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "the loaded matrices of points are not valid\n" );
|
||||
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* read first image */
|
||||
snprintf( filename, sizeof(filename), "%soptflow/%s", ts->get_data_path().c_str(), "rock_1.bmp" );
|
||||
imgI = cv::imread( filename, cv::IMREAD_UNCHANGED );
|
||||
|
||||
if( imgI.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
|
||||
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read second image */
|
||||
snprintf( filename, sizeof(filename), "%soptflow/%s", ts->get_data_path().c_str(), "rock_2.bmp" );
|
||||
imgJ = cv::imread( filename, cv::IMREAD_UNCHANGED );
|
||||
|
||||
if( imgJ.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
|
||||
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
n = _u.rows;
|
||||
std::vector<uchar> status(n, (uchar)0);
|
||||
|
||||
/* calculate flow */
|
||||
calcOpticalFlowPyrLK(imgI, imgJ, _u, _v2, status, cv::noArray(), Size( 41, 41 ), 4,
|
||||
TermCriteria( TermCriteria::MAX_ITER + TermCriteria::EPS, 30, 0.01f ), 0 );
|
||||
|
||||
v = (cv::Point2f*)_v.ptr();
|
||||
v2 = (cv::Point2f*)_v2.ptr();
|
||||
|
||||
/* compare results */
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
if( status[i] != 0 )
|
||||
{
|
||||
double err;
|
||||
if( cvIsNaN(v[i].x) || cvIsNaN(v[i].y) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( cvIsNaN(v2[i].x) || cvIsNaN(v2[i].y) )
|
||||
{
|
||||
merr_nan++;
|
||||
continue;
|
||||
}
|
||||
|
||||
err = fabs(v2[i].x - v[i].x) + fabs(v2[i].y - v[i].y);
|
||||
if( err > max_err )
|
||||
{
|
||||
max_err = err;
|
||||
merr_i = i;
|
||||
}
|
||||
|
||||
pt_exceed += err > success_error_level;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !cvIsNaN( v[i].x ))
|
||||
{
|
||||
merr_i = i;
|
||||
ts->printf( cvtest::TS::LOG, "The algorithm lost the point #%d\n", i );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( i < n )
|
||||
break;
|
||||
|
||||
if( pt_exceed > bad_points_max )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG,
|
||||
"The number of poorly tracked points is too big (>=%d)\n", pt_exceed );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
break;
|
||||
}
|
||||
|
||||
if( max_err > 1 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Maximum tracking error is too big (=%g) at %d\n", max_err, merr_i );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
break;
|
||||
}
|
||||
|
||||
if( merr_nan > 0 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "NAN tracking result with status != 0 (%d times)\n", merr_nan );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if( code < 0 )
|
||||
ts->set_failed_test_info( code );
|
||||
}
|
||||
|
||||
|
||||
TEST(Video_OpticalFlowPyrLK, accuracy) { CV_OptFlowPyrLKTest test; test.safe_run(); }
|
||||
|
||||
TEST(Video_OpticalFlowPyrLK, submat)
|
||||
{
|
||||
// see bug #2075
|
||||
std::string path = cvtest::TS::ptr()->get_data_path() + "../cv/shared/lena.png";
|
||||
|
||||
cv::Mat lenaImg = cv::imread(path);
|
||||
ASSERT_FALSE(lenaImg.empty());
|
||||
|
||||
cv::Mat wholeImage;
|
||||
cv::resize(lenaImg, wholeImage, cv::Size(1024, 1024), 0, 0, cv::INTER_LINEAR_EXACT);
|
||||
|
||||
cv::Mat img1 = wholeImage(cv::Rect(0, 0, 640, 360)).clone();
|
||||
cv::Mat img2 = wholeImage(cv::Rect(40, 60, 640, 360));
|
||||
|
||||
std::vector<uchar> status;
|
||||
std::vector<float> error;
|
||||
std::vector<cv::Point2f> prev;
|
||||
std::vector<cv::Point2f> next;
|
||||
|
||||
cv::RNG rng(123123);
|
||||
|
||||
for(int i = 0; i < 50; ++i)
|
||||
{
|
||||
int x = rng.uniform(0, 640);
|
||||
int y = rng.uniform(0, 360);
|
||||
|
||||
prev.push_back(cv::Point2f((float)x, (float)y));
|
||||
}
|
||||
|
||||
ASSERT_NO_THROW(cv::calcOpticalFlowPyrLK(img1, img2, prev, next, status, error));
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,17 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#ifndef __OPENCV_TEST_PRECOMP_HPP__
|
||||
#define __OPENCV_TEST_PRECOMP_HPP__
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/video.hpp"
|
||||
#include "opencv2/geometry.hpp"
|
||||
#include <opencv2/ts/ts_perf.hpp>
|
||||
#include "opencv2/core/utils/configuration.private.hpp"
|
||||
|
||||
namespace opencv_test {
|
||||
using namespace perf;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,164 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
//#define DEBUG_TEST
|
||||
#ifdef DEBUG_TEST
|
||||
#include <opencv2/highgui.hpp>
|
||||
#endif
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
//using namespace cv::tracking;
|
||||
|
||||
#define TESTSET_NAMES testing::Values("david", "dudek", "faceocc2")
|
||||
|
||||
const string TRACKING_DIR = "tracking";
|
||||
const string FOLDER_IMG = "data";
|
||||
const string FOLDER_OMIT_INIT = "initOmit";
|
||||
|
||||
#include "test_trackers.impl.hpp"
|
||||
|
||||
//[TESTDATA]
|
||||
PARAM_TEST_CASE(DistanceAndOverlap, string, int)
|
||||
{
|
||||
string dataset;
|
||||
int numFramesLimit;
|
||||
virtual void SetUp()
|
||||
{
|
||||
dataset = GET_PARAM(0);
|
||||
numFramesLimit = GET_PARAM(1);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(DistanceAndOverlap, MIL)
|
||||
{
|
||||
TrackerTest<Tracker, Rect> test(TrackerMIL::create(), dataset, 30, .65f, NoTransform);
|
||||
test.run(numFramesLimit);
|
||||
}
|
||||
|
||||
TEST_P(DistanceAndOverlap, Shifted_Data_MIL)
|
||||
{
|
||||
TrackerTest<Tracker, Rect> test(TrackerMIL::create(), dataset, 30, .6f, CenterShiftLeft);
|
||||
test.run(numFramesLimit);
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
//Tests with scaled initial window
|
||||
|
||||
TEST_P(DistanceAndOverlap, Scaled_Data_MIL)
|
||||
{
|
||||
TrackerTest<Tracker, Rect> test(TrackerMIL::create(), dataset, 30, .7f, Scale_1_1);
|
||||
test.run(numFramesLimit);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Tracking, DistanceAndOverlap,
|
||||
testing::Combine(
|
||||
TESTSET_NAMES,
|
||||
testing::Values(0)
|
||||
)
|
||||
);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Tracking5Frames, DistanceAndOverlap,
|
||||
testing::Combine(
|
||||
TESTSET_NAMES,
|
||||
testing::Values(5)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
static bool checkIOU(const Rect& r0, const Rect& r1, double threshold)
|
||||
{
|
||||
int interArea = (r0 & r1).area();
|
||||
double iouVal = (interArea * 1.0 )/ (r0.area() + r1.area() - interArea);;
|
||||
|
||||
if (iouVal > threshold)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
std::cout <<"Unmatched IOU: expect IOU val ("<<iouVal <<") > the IOU threadhold ("<<threshold<<")! Box 0 is "
|
||||
<< r0 <<", and Box 1 is "<<r1<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void checkTrackingAccuracy(cv::Ptr<Tracker>& tracker, double iouThreshold = 0.7)
|
||||
{
|
||||
// Template image
|
||||
Mat img0 = imread(findDataFile("tracking/bag/00000001.jpg"), 1);
|
||||
|
||||
// Tracking image sequence.
|
||||
std::vector<Mat> imgs;
|
||||
imgs.push_back(imread(findDataFile("tracking/bag/00000002.jpg"), 1));
|
||||
imgs.push_back(imread(findDataFile("tracking/bag/00000003.jpg"), 1));
|
||||
imgs.push_back(imread(findDataFile("tracking/bag/00000004.jpg"), 1));
|
||||
imgs.push_back(imread(findDataFile("tracking/bag/00000005.jpg"), 1));
|
||||
imgs.push_back(imread(findDataFile("tracking/bag/00000006.jpg"), 1));
|
||||
|
||||
cv::Rect roi(325, 164, 100, 100);
|
||||
std::vector<Rect> targetRois;
|
||||
targetRois.push_back(cv::Rect(278, 133, 99, 104));
|
||||
targetRois.push_back(cv::Rect(293, 88, 93, 110));
|
||||
targetRois.push_back(cv::Rect(287, 76, 89, 116));
|
||||
targetRois.push_back(cv::Rect(297, 74, 82, 122));
|
||||
targetRois.push_back(cv::Rect(311, 83, 78, 125));
|
||||
|
||||
tracker->init(img0, roi);
|
||||
CV_Assert(targetRois.size() == imgs.size());
|
||||
|
||||
for (int i = 0; i < (int)imgs.size(); i++)
|
||||
{
|
||||
bool res = tracker->update(imgs[i], roi);
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_TRUE(checkIOU(roi, targetRois[i], iouThreshold)) << cv::format("Fail at img %d.",i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DaSiamRPN, accuracy)
|
||||
{
|
||||
std::string model = cvtest::findDataFile("dnn/onnx/models/dasiamrpn_model.onnx", false);
|
||||
std::string kernel_r1 = cvtest::findDataFile("dnn/onnx/models/dasiamrpn_kernel_r1.onnx", false);
|
||||
std::string kernel_cls1 = cvtest::findDataFile("dnn/onnx/models/dasiamrpn_kernel_cls1.onnx", false);
|
||||
cv::TrackerDaSiamRPN::Params params;
|
||||
params.model = model;
|
||||
params.kernel_r1 = kernel_r1;
|
||||
params.kernel_cls1 = kernel_cls1;
|
||||
cv::Ptr<Tracker> tracker = TrackerDaSiamRPN::create(params);
|
||||
checkTrackingAccuracy(tracker, 0.7);
|
||||
}
|
||||
|
||||
TEST(NanoTrack, accuracy_NanoTrack_V1)
|
||||
{
|
||||
std::string backbonePath = cvtest::findDataFile("dnn/onnx/models/nanotrack_backbone_sim.onnx", false);
|
||||
std::string neckheadPath = cvtest::findDataFile("dnn/onnx/models/nanotrack_head_sim.onnx", false);
|
||||
|
||||
cv::TrackerNano::Params params;
|
||||
params.backbone = backbonePath;
|
||||
params.neckhead = neckheadPath;
|
||||
cv::Ptr<Tracker> tracker = TrackerNano::create(params);
|
||||
checkTrackingAccuracy(tracker);
|
||||
}
|
||||
|
||||
TEST(NanoTrack, accuracy_NanoTrack_V2)
|
||||
{
|
||||
std::string backbonePath = cvtest::findDataFile("dnn/onnx/models/nanotrack_backbone_sim_v2.onnx", false);
|
||||
std::string neckheadPath = cvtest::findDataFile("dnn/onnx/models/nanotrack_head_sim_v2.onnx", false);
|
||||
|
||||
cv::TrackerNano::Params params;
|
||||
params.backbone = backbonePath;
|
||||
params.neckhead = neckheadPath;
|
||||
cv::Ptr<Tracker> tracker = TrackerNano::create(params);
|
||||
checkTrackingAccuracy(tracker, 0.69);
|
||||
}
|
||||
|
||||
TEST(vittrack, accuracy_vittrack)
|
||||
{
|
||||
std::string model = cvtest::findDataFile("dnn/onnx/models/vitTracker.onnx");
|
||||
cv::TrackerVit::Params params;
|
||||
params.net = model;
|
||||
cv::Ptr<Tracker> tracker = TrackerVit::create(params);
|
||||
checkTrackingAccuracy(tracker, 0.64);
|
||||
}
|
||||
|
||||
}} // namespace opencv_test::
|
||||
@@ -0,0 +1,382 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
/*
|
||||
* The Evaluation Methodologies are partially based on:
|
||||
* ====================================================================================================================
|
||||
* [OTB] Y. Wu, J. Lim, and M.-H. Yang, "Online object tracking: A benchmark," in Computer Vision and Pattern Recognition (CVPR), 2013
|
||||
*
|
||||
*/
|
||||
|
||||
enum BBTransformations
|
||||
{
|
||||
NoTransform = 0,
|
||||
CenterShiftLeft = 1,
|
||||
CenterShiftRight = 2,
|
||||
CenterShiftUp = 3,
|
||||
CenterShiftDown = 4,
|
||||
CornerShiftTopLeft = 5,
|
||||
CornerShiftTopRight = 6,
|
||||
CornerShiftBottomLeft = 7,
|
||||
CornerShiftBottomRight = 8,
|
||||
Scale_0_8 = 9,
|
||||
Scale_0_9 = 10,
|
||||
Scale_1_1 = 11,
|
||||
Scale_1_2 = 12
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::string> splitString(const std::string& s_, const std::string& delimiter)
|
||||
{
|
||||
std::string s = s_;
|
||||
std::vector<string> token;
|
||||
size_t pos = 0;
|
||||
while ((pos = s.find(delimiter)) != std::string::npos)
|
||||
{
|
||||
token.push_back(s.substr(0, pos));
|
||||
s.erase(0, pos + delimiter.length());
|
||||
}
|
||||
token.push_back(s);
|
||||
return token;
|
||||
}
|
||||
|
||||
float calcDistance(const Rect& a, const Rect& b)
|
||||
{
|
||||
Point2f p_a((float)(a.x + a.width / 2), (float)(a.y + a.height / 2));
|
||||
Point2f p_b((float)(b.x + b.width / 2), (float)(b.y + b.height / 2));
|
||||
Point2f diff = p_a - p_b;
|
||||
return sqrt(diff.dot(diff));
|
||||
}
|
||||
|
||||
float calcOverlap(const Rect& a, const Rect& b)
|
||||
{
|
||||
float rectIntersectionArea = (float)(a & b).area();
|
||||
return rectIntersectionArea / (a.area() + b.area() - rectIntersectionArea);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename Tracker, typename ROI_t = Rect2d>
|
||||
class TrackerTest
|
||||
{
|
||||
public:
|
||||
TrackerTest(const Ptr<Tracker>& tracker, const string& video, float distanceThreshold,
|
||||
float overlapThreshold, int shift = NoTransform, int segmentIdx = 1, int numSegments = 10);
|
||||
~TrackerTest() {}
|
||||
void run(int numFramesLimit = 0);
|
||||
|
||||
protected:
|
||||
void checkDataTest();
|
||||
|
||||
void distanceAndOverlapTest();
|
||||
|
||||
Ptr<Tracker> tracker;
|
||||
string video;
|
||||
std::vector<Rect> bbs;
|
||||
int startFrame;
|
||||
string suffix;
|
||||
string prefix;
|
||||
float overlapThreshold;
|
||||
float distanceThreshold;
|
||||
int segmentIdx;
|
||||
int shift;
|
||||
int numSegments;
|
||||
|
||||
int gtStartFrame;
|
||||
int endFrame;
|
||||
vector<int> validSequence;
|
||||
|
||||
private:
|
||||
Rect applyShift(const Rect& bb);
|
||||
};
|
||||
|
||||
template <typename Tracker, typename ROI_t>
|
||||
TrackerTest<Tracker, ROI_t>::TrackerTest(const Ptr<Tracker>& _tracker, const string& _video, float _distanceThreshold,
|
||||
float _overlapThreshold, int _shift, int _segmentIdx, int _numSegments)
|
||||
: tracker(_tracker)
|
||||
, video(_video)
|
||||
, overlapThreshold(_overlapThreshold)
|
||||
, distanceThreshold(_distanceThreshold)
|
||||
, segmentIdx(_segmentIdx)
|
||||
, shift(_shift)
|
||||
, numSegments(_numSegments)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
template <typename Tracker, typename ROI_t>
|
||||
Rect TrackerTest<Tracker, ROI_t>::applyShift(const Rect& bb_)
|
||||
{
|
||||
Rect bb = bb_;
|
||||
Point center(bb.x + (bb.width / 2), bb.y + (bb.height / 2));
|
||||
|
||||
int xLimit = bb.x + bb.width - 1;
|
||||
int yLimit = bb.y + bb.height - 1;
|
||||
|
||||
int h = 0;
|
||||
int w = 0;
|
||||
float ratio = 1.0;
|
||||
|
||||
switch (shift)
|
||||
{
|
||||
case CenterShiftLeft:
|
||||
bb.x = bb.x - (int)ceil(0.1 * bb.width);
|
||||
break;
|
||||
case CenterShiftRight:
|
||||
bb.x = bb.x + (int)ceil(0.1 * bb.width);
|
||||
break;
|
||||
case CenterShiftUp:
|
||||
bb.y = bb.y - (int)ceil(0.1 * bb.height);
|
||||
break;
|
||||
case CenterShiftDown:
|
||||
bb.y = bb.y + (int)ceil(0.1 * bb.height);
|
||||
break;
|
||||
case CornerShiftTopLeft:
|
||||
bb.x = (int)cvRound(bb.x - 0.1 * bb.width);
|
||||
bb.y = (int)cvRound(bb.y - 0.1 * bb.height);
|
||||
|
||||
bb.width = xLimit - bb.x + 1;
|
||||
bb.height = yLimit - bb.y + 1;
|
||||
break;
|
||||
case CornerShiftTopRight:
|
||||
xLimit = (int)cvRound(xLimit + 0.1 * bb.width);
|
||||
|
||||
bb.y = (int)cvRound(bb.y - 0.1 * bb.height);
|
||||
bb.width = xLimit - bb.x + 1;
|
||||
bb.height = yLimit - bb.y + 1;
|
||||
break;
|
||||
case CornerShiftBottomLeft:
|
||||
bb.x = (int)cvRound(bb.x - 0.1 * bb.width);
|
||||
yLimit = (int)cvRound(yLimit + 0.1 * bb.height);
|
||||
|
||||
bb.width = xLimit - bb.x + 1;
|
||||
bb.height = yLimit - bb.y + 1;
|
||||
break;
|
||||
case CornerShiftBottomRight:
|
||||
xLimit = (int)cvRound(xLimit + 0.1 * bb.width);
|
||||
yLimit = (int)cvRound(yLimit + 0.1 * bb.height);
|
||||
|
||||
bb.width = xLimit - bb.x + 1;
|
||||
bb.height = yLimit - bb.y + 1;
|
||||
break;
|
||||
case Scale_0_8:
|
||||
ratio = 0.8f;
|
||||
w = (int)(ratio * bb.width);
|
||||
h = (int)(ratio * bb.height);
|
||||
|
||||
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
|
||||
break;
|
||||
case Scale_0_9:
|
||||
ratio = 0.9f;
|
||||
w = (int)(ratio * bb.width);
|
||||
h = (int)(ratio * bb.height);
|
||||
|
||||
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
|
||||
break;
|
||||
case 11:
|
||||
//scale 1.1
|
||||
ratio = 1.1f;
|
||||
w = (int)(ratio * bb.width);
|
||||
h = (int)(ratio * bb.height);
|
||||
|
||||
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
|
||||
break;
|
||||
case 12:
|
||||
//scale 1.2
|
||||
ratio = 1.2f;
|
||||
w = (int)(ratio * bb.width);
|
||||
h = (int)(ratio * bb.height);
|
||||
|
||||
bb = Rect(center.x - (w / 2), center.y - (h / 2), w, h);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
template <typename Tracker, typename ROI_t>
|
||||
void TrackerTest<Tracker, ROI_t>::distanceAndOverlapTest()
|
||||
{
|
||||
bool initialized = false;
|
||||
|
||||
int fc = (startFrame - gtStartFrame);
|
||||
|
||||
bbs.at(fc) = applyShift(bbs.at(fc));
|
||||
Rect currentBBi = bbs.at(fc);
|
||||
ROI_t currentBB(currentBBi);
|
||||
float sumDistance = 0;
|
||||
float sumOverlap = 0;
|
||||
|
||||
string folder = cvtest::TS::ptr()->get_data_path() + "/" + TRACKING_DIR + "/" + video + "/" + FOLDER_IMG;
|
||||
string videoPath = folder + "/" + video + ".webm";
|
||||
|
||||
VideoCapture c;
|
||||
c.open(videoPath);
|
||||
if (!c.isOpened())
|
||||
throw SkipTestException("Can't open video file");
|
||||
#if 0
|
||||
c.set(CAP_PROP_POS_FRAMES, startFrame);
|
||||
#else
|
||||
if (startFrame)
|
||||
std::cout << "startFrame = " << startFrame << std::endl;
|
||||
for (int i = 0; i < startFrame; i++)
|
||||
{
|
||||
Mat dummy_frame;
|
||||
c >> dummy_frame;
|
||||
ASSERT_FALSE(dummy_frame.empty()) << i << ": " << videoPath;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int frameCounter = startFrame; frameCounter < endFrame; frameCounter++)
|
||||
{
|
||||
Mat frame;
|
||||
c >> frame;
|
||||
|
||||
ASSERT_FALSE(frame.empty()) << "frameCounter=" << frameCounter << " video=" << videoPath;
|
||||
if (!initialized)
|
||||
{
|
||||
tracker->init(frame, currentBB);
|
||||
std::cout << "frame size = " << frame.size() << std::endl;
|
||||
initialized = true;
|
||||
}
|
||||
else if (initialized)
|
||||
{
|
||||
if (frameCounter >= (int)bbs.size())
|
||||
break;
|
||||
tracker->update(frame, currentBB);
|
||||
}
|
||||
float curDistance = calcDistance(currentBB, bbs.at(fc));
|
||||
float curOverlap = calcOverlap(currentBB, bbs.at(fc));
|
||||
|
||||
#ifdef DEBUG_TEST
|
||||
Mat result;
|
||||
repeat(frame, 1, 2, result);
|
||||
rectangle(result, currentBB, Scalar(0, 255, 0), 1);
|
||||
Rect roi2(frame.cols, 0, frame.cols, frame.rows);
|
||||
rectangle(result(roi2), bbs.at(fc), Scalar(0, 0, 255), 1);
|
||||
imshow("result", result);
|
||||
waitKey(1);
|
||||
#endif
|
||||
|
||||
sumDistance += curDistance;
|
||||
sumOverlap += curOverlap;
|
||||
fc++;
|
||||
}
|
||||
|
||||
float meanDistance = sumDistance / (endFrame - startFrame);
|
||||
float meanOverlap = sumOverlap / (endFrame - startFrame);
|
||||
|
||||
EXPECT_LE(meanDistance, distanceThreshold);
|
||||
EXPECT_GE(meanOverlap, overlapThreshold);
|
||||
}
|
||||
|
||||
template <typename Tracker, typename ROI_t>
|
||||
void TrackerTest<Tracker, ROI_t>::checkDataTest()
|
||||
{
|
||||
|
||||
FileStorage fs;
|
||||
fs.open(cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/" + video + ".yml", FileStorage::READ);
|
||||
fs["start"] >> startFrame;
|
||||
fs["prefix"] >> prefix;
|
||||
fs["suffix"] >> suffix;
|
||||
fs.release();
|
||||
|
||||
string gtFile = cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/gt.txt";
|
||||
std::ifstream gt;
|
||||
//open the ground truth
|
||||
gt.open(gtFile.c_str());
|
||||
ASSERT_TRUE(gt.is_open()) << gtFile;
|
||||
string line;
|
||||
int bbCounter = 0;
|
||||
while (getline(gt, line))
|
||||
{
|
||||
bbCounter++;
|
||||
}
|
||||
gt.close();
|
||||
|
||||
int seqLength = bbCounter;
|
||||
for (int i = startFrame; i < seqLength; i++)
|
||||
{
|
||||
validSequence.push_back(i);
|
||||
}
|
||||
|
||||
//exclude from the images sequence, the frames where the target is occluded or out of view
|
||||
string omitFile = cvtest::TS::ptr()->get_data_path() + TRACKING_DIR + "/" + video + "/" + FOLDER_OMIT_INIT + "/" + video + ".txt";
|
||||
std::ifstream omit;
|
||||
omit.open(omitFile.c_str());
|
||||
if (omit.is_open())
|
||||
{
|
||||
string omitLine;
|
||||
while (getline(omit, omitLine))
|
||||
{
|
||||
vector<string> tokens = splitString(omitLine, " ");
|
||||
int s_start = atoi(tokens.at(0).c_str());
|
||||
int s_end = atoi(tokens.at(1).c_str());
|
||||
for (int k = s_start; k <= s_end; k++)
|
||||
{
|
||||
std::vector<int>::iterator position = std::find(validSequence.begin(), validSequence.end(), k);
|
||||
if (position != validSequence.end())
|
||||
validSequence.erase(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
omit.close();
|
||||
gtStartFrame = startFrame;
|
||||
//compute the start and the and for each segment
|
||||
int numFrame = (int)(validSequence.size() / numSegments);
|
||||
startFrame += (segmentIdx - 1) * numFrame;
|
||||
endFrame = startFrame + numFrame;
|
||||
|
||||
std::ifstream gt2;
|
||||
//open the ground truth
|
||||
gt2.open(gtFile.c_str());
|
||||
ASSERT_TRUE(gt2.is_open()) << gtFile;
|
||||
string line2;
|
||||
while (getline(gt2, line2))
|
||||
{
|
||||
vector<string> tokens = splitString(line2, ",");
|
||||
Rect bb(atoi(tokens.at(0).c_str()), atoi(tokens.at(1).c_str()), atoi(tokens.at(2).c_str()), atoi(tokens.at(3).c_str()));
|
||||
ASSERT_EQ((size_t)4, tokens.size()) << "Incorrect ground truth file " << gtFile;
|
||||
|
||||
bbs.push_back(bb);
|
||||
}
|
||||
gt2.close();
|
||||
|
||||
if (segmentIdx == numSegments)
|
||||
endFrame = (int)bbs.size();
|
||||
}
|
||||
|
||||
template <typename Tracker, typename ROI_t>
|
||||
void TrackerTest<Tracker, ROI_t>::run(int numFramesLimit)
|
||||
{
|
||||
srand(1); // FIXIT remove that, ensure that there is no "rand()" in implementation
|
||||
|
||||
ASSERT_TRUE(tracker);
|
||||
|
||||
checkDataTest();
|
||||
|
||||
//check for failure
|
||||
if (::testing::Test::HasFatalFailure())
|
||||
return;
|
||||
|
||||
int numFrames = endFrame - startFrame;
|
||||
std::cout << "Number of frames in test data: " << numFrames << std::endl;
|
||||
|
||||
if (numFramesLimit > 0)
|
||||
{
|
||||
numFrames = std::min(numFrames, numFramesLimit);
|
||||
endFrame = startFrame + numFramesLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_DEBUG_VERYLONG);
|
||||
}
|
||||
|
||||
std::cout << "Number of frames to test: " << numFrames << std::endl;
|
||||
|
||||
distanceAndOverlapTest();
|
||||
}
|
||||
Reference in New Issue
Block a user