mirror of
https://github.com/opencv/opencv.git
synced 2024-11-24 03:00:14 +08:00
Merge pull request #25842 from mshabunin:cpp-imgproc-test-4.x
imgproc: remove C-API usage from tests #25842 Final cleanup will be done in 5.x after regular merge. Some tests have been reworked, some required only slight modifications.
This commit is contained in:
parent
efbc9f0b66
commit
94b7a2d320
@ -43,130 +43,7 @@
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class CV_CannyTest : public cvtest::ArrayTest
|
||||
{
|
||||
public:
|
||||
CV_CannyTest(bool custom_deriv = false);
|
||||
|
||||
protected:
|
||||
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
|
||||
double get_success_error_level( int test_case_idx, int i, int j );
|
||||
int prepare_test_case( int test_case_idx );
|
||||
void run_func();
|
||||
void prepare_to_validation( int );
|
||||
int validate_test_results( int /*test_case_idx*/ );
|
||||
|
||||
int aperture_size;
|
||||
bool use_true_gradient;
|
||||
double threshold1, threshold2;
|
||||
bool test_cpp;
|
||||
bool test_custom_deriv;
|
||||
|
||||
Mat img;
|
||||
};
|
||||
|
||||
|
||||
CV_CannyTest::CV_CannyTest(bool custom_deriv)
|
||||
{
|
||||
test_array[INPUT].push_back(NULL);
|
||||
test_array[OUTPUT].push_back(NULL);
|
||||
test_array[REF_OUTPUT].push_back(NULL);
|
||||
element_wise_relative_error = true;
|
||||
aperture_size = 0;
|
||||
use_true_gradient = false;
|
||||
threshold1 = threshold2 = 0;
|
||||
test_custom_deriv = custom_deriv;
|
||||
|
||||
const char imgPath[] = "shared/fruits.png";
|
||||
img = cv::imread(cvtest::TS::ptr()->get_data_path() + imgPath, IMREAD_GRAYSCALE);
|
||||
}
|
||||
|
||||
|
||||
void CV_CannyTest::get_test_array_types_and_sizes( int test_case_idx,
|
||||
vector<vector<Size> >& sizes,
|
||||
vector<vector<int> >& types )
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
double thresh_range;
|
||||
|
||||
cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
|
||||
types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8U;
|
||||
|
||||
aperture_size = cvtest::randInt(rng) % 2 ? 5 : 3;
|
||||
thresh_range = aperture_size == 3 ? 300 : 1000;
|
||||
|
||||
threshold1 = cvtest::randReal(rng)*thresh_range;
|
||||
threshold2 = cvtest::randReal(rng)*thresh_range*0.3;
|
||||
|
||||
if( cvtest::randInt(rng) % 2 )
|
||||
CV_SWAP( threshold1, threshold2, thresh_range );
|
||||
|
||||
use_true_gradient = cvtest::randInt(rng) % 2 != 0;
|
||||
test_cpp = (cvtest::randInt(rng) & 256) == 0;
|
||||
|
||||
ts->printf(cvtest::TS::LOG, "Canny(size = %d x %d, aperture_size = %d, threshold1 = %g, threshold2 = %g, L2 = %s) test_cpp = %s (test case #%d)\n",
|
||||
sizes[0][0].width, sizes[0][0].height, aperture_size, threshold1, threshold2, use_true_gradient ? "TRUE" : "FALSE", test_cpp ? "TRUE" : "FALSE", test_case_idx);
|
||||
}
|
||||
|
||||
|
||||
int CV_CannyTest::prepare_test_case( int test_case_idx )
|
||||
{
|
||||
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
|
||||
if( code > 0 )
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
Mat& src = test_mat[INPUT][0];
|
||||
//GaussianBlur(src, src, Size(11, 11), 5, 5);
|
||||
if(src.cols > img.cols || src.rows > img.rows)
|
||||
resize(img, src, src.size(), 0, 0, INTER_LINEAR_EXACT);
|
||||
else
|
||||
img(
|
||||
Rect(
|
||||
cvtest::randInt(rng) % (img.cols-src.cols),
|
||||
cvtest::randInt(rng) % (img.rows-src.rows),
|
||||
src.cols,
|
||||
src.rows
|
||||
)
|
||||
).copyTo(src);
|
||||
GaussianBlur(src, src, Size(5, 5), 0);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
double CV_CannyTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CV_CannyTest::run_func()
|
||||
{
|
||||
if (test_custom_deriv)
|
||||
{
|
||||
cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
|
||||
cv::Mat src = cv::cvarrToMat(test_array[INPUT][0]);
|
||||
cv::Mat dx, dy;
|
||||
int m = aperture_size;
|
||||
Point anchor(m/2, m/2);
|
||||
Mat dxkernel = cvtest::calcSobelKernel2D( 1, 0, m, 0 );
|
||||
Mat dykernel = cvtest::calcSobelKernel2D( 0, 1, m, 0 );
|
||||
cvtest::filter2D(src, dx, CV_16S, dxkernel, anchor, 0, BORDER_REPLICATE);
|
||||
cvtest::filter2D(src, dy, CV_16S, dykernel, anchor, 0, BORDER_REPLICATE);
|
||||
cv::Canny(dx, dy, _out, threshold1, threshold2, use_true_gradient);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
|
||||
cv::Canny(cv::cvarrToMat(test_array[INPUT][0]), _out, threshold1, threshold2,
|
||||
aperture_size, use_true_gradient);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cannyFollow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst )
|
||||
static void Canny_reference_follow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst )
|
||||
{
|
||||
static const int ofs[][2] = {{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}};
|
||||
int i;
|
||||
@ -181,16 +58,15 @@ cannyFollow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst )
|
||||
(unsigned)y1 < (unsigned)mag.rows &&
|
||||
mag.at<float>(y1, x1) > lowThreshold &&
|
||||
!dst.at<uchar>(y1, x1) )
|
||||
cannyFollow( x1, y1, lowThreshold, mag, dst );
|
||||
Canny_reference_follow( x1, y1, lowThreshold, mag, dst );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_Canny( const Mat& src, Mat& dst,
|
||||
static void Canny_reference( const Mat& src, Mat& dst,
|
||||
double threshold1, double threshold2,
|
||||
int aperture_size, bool use_true_gradient )
|
||||
{
|
||||
dst.create(src.size(), src.type());
|
||||
int m = aperture_size;
|
||||
Point anchor(m/2, m/2);
|
||||
const double tan_pi_8 = tan(CV_PI/8.);
|
||||
@ -273,47 +149,80 @@ test_Canny( const Mat& src, Mat& dst,
|
||||
{
|
||||
for( x = 0; x < width; x++ )
|
||||
if( mag.at<float>(y, x) > highThreshold && !dst.at<uchar>(y, x) )
|
||||
cannyFollow( x, y, lowThreshold, mag, dst );
|
||||
Canny_reference_follow( x, y, lowThreshold, mag, dst );
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void CV_CannyTest::prepare_to_validation( int )
|
||||
// aperture, true gradient
|
||||
typedef testing::TestWithParam<testing::tuple<int, bool>> Canny_Modes;
|
||||
|
||||
TEST_P(Canny_Modes, accuracy)
|
||||
{
|
||||
Mat src = test_mat[INPUT][0], dst = test_mat[REF_OUTPUT][0];
|
||||
test_Canny( src, dst, threshold1, threshold2, aperture_size, use_true_gradient );
|
||||
const int aperture = get<0>(GetParam());
|
||||
const bool trueGradient = get<1>(GetParam());
|
||||
const double range = aperture == 3 ? 300. : 1000.;
|
||||
RNG & rng = TS::ptr()->get_rng();
|
||||
|
||||
for (int ITER = 0; ITER < 20; ++ITER)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("iteration %d", ITER));
|
||||
|
||||
const std::string fname = cvtest::findDataFile("shared/fruits.png");
|
||||
const Mat original = cv::imread(fname, IMREAD_GRAYSCALE);
|
||||
|
||||
const double thresh1 = rng.uniform(0., range);
|
||||
const double thresh2 = rng.uniform(0., range * 0.3);
|
||||
const Size sz(rng.uniform(127, 800), rng.uniform(127, 600));
|
||||
const Size osz = original.size();
|
||||
|
||||
// preparation
|
||||
Mat img;
|
||||
if (sz.width >= osz.width || sz.height >= osz.height)
|
||||
{
|
||||
// larger image -> scale
|
||||
resize(original, img, sz, 0, 0, INTER_LINEAR_EXACT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// smaller image -> crop
|
||||
Point origin(rng.uniform(0, osz.width - sz.width), rng.uniform(0, osz.height - sz.height));
|
||||
Rect roi(origin, sz);
|
||||
original(roi).copyTo(img);
|
||||
}
|
||||
GaussianBlur(img, img, Size(5, 5), 0);
|
||||
|
||||
// regular function
|
||||
Mat result;
|
||||
{
|
||||
cv::Canny(img, result, thresh1, thresh2, aperture, trueGradient);
|
||||
}
|
||||
|
||||
// custom derivatives
|
||||
Mat customResult;
|
||||
{
|
||||
Mat dxkernel = cvtest::calcSobelKernel2D(1, 0, aperture, 0);
|
||||
Mat dykernel = cvtest::calcSobelKernel2D(0, 1, aperture, 0);
|
||||
Point anchor(aperture / 2, aperture / 2);
|
||||
cv::Mat dx, dy;
|
||||
cvtest::filter2D(img, dx, CV_16S, dxkernel, anchor, 0, BORDER_REPLICATE);
|
||||
cvtest::filter2D(img, dy, CV_16S, dykernel, anchor, 0, BORDER_REPLICATE);
|
||||
cv::Canny(dx, dy, customResult, thresh1, thresh2, trueGradient);
|
||||
}
|
||||
|
||||
Mat reference;
|
||||
Canny_reference(img, reference, thresh1, thresh2, aperture, trueGradient);
|
||||
|
||||
EXPECT_MAT_NEAR(result, reference, 0);
|
||||
EXPECT_MAT_NEAR(customResult, reference, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CV_CannyTest::validate_test_results( int test_case_idx )
|
||||
{
|
||||
int code = cvtest::TS::OK, nz0;
|
||||
prepare_to_validation(test_case_idx);
|
||||
|
||||
double err = cvtest::norm(test_mat[OUTPUT][0], test_mat[REF_OUTPUT][0], CV_L1);
|
||||
if( err == 0 )
|
||||
return code;
|
||||
|
||||
if( err != cvRound(err) || cvRound(err)%255 != 0 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Some of the pixels, produced by Canny, are not 0's or 255's; the difference is %g\n", err );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
return code;
|
||||
}
|
||||
|
||||
nz0 = cvRound(cvtest::norm(test_mat[REF_OUTPUT][0], CV_L1)/255);
|
||||
err = (err/255/MAX(nz0,100))*100;
|
||||
if( err > 1 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Too high percentage of non-matching edge pixels = %g%%\n", err);
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
TEST(Imgproc_Canny, accuracy) { CV_CannyTest test; test.safe_run(); }
|
||||
TEST(Imgproc_Canny, accuracy_deriv) { CV_CannyTest test(true); test.safe_run(); }
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Canny_Modes,
|
||||
testing::Combine(
|
||||
testing::Values(3, 5),
|
||||
testing::Values(true, false)));
|
||||
|
||||
|
||||
/*
|
||||
|
@ -76,7 +76,6 @@ protected:
|
||||
bool inplace;
|
||||
bool custom_inv_transform;
|
||||
int fwd_code, inv_code;
|
||||
bool test_cpp;
|
||||
int hue_range;
|
||||
bool srgb;
|
||||
};
|
||||
@ -97,7 +96,6 @@ CV_ColorCvtBaseTest::CV_ColorCvtBaseTest( bool _custom_inv_transform, bool _allo
|
||||
|
||||
fwd_code_str = inv_code_str = 0;
|
||||
|
||||
test_cpp = false;
|
||||
hue_range = 0;
|
||||
blue_idx = 0;
|
||||
srgb = false;
|
||||
@ -147,7 +145,6 @@ void CV_ColorCvtBaseTest::get_test_array_types_and_sizes( int test_case_idx,
|
||||
types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(depth, cn);
|
||||
|
||||
inplace = cn == 3 && cvtest::randInt(rng) % 2 != 0;
|
||||
test_cpp = (cvtest::randInt(rng) & 256) == 0;
|
||||
}
|
||||
|
||||
|
||||
@ -161,23 +158,17 @@ int CV_ColorCvtBaseTest::prepare_test_case( int test_case_idx )
|
||||
|
||||
void CV_ColorCvtBaseTest::run_func()
|
||||
{
|
||||
CvArr* out0 = test_array[OUTPUT][0];
|
||||
cv::Mat _out0 = cv::cvarrToMat(out0), _out1 = cv::cvarrToMat(test_array[OUTPUT][1]);
|
||||
cv::Mat out0 = test_mat[OUTPUT][0];
|
||||
cv::Mat _out0 = out0, _out1 = test_mat[OUTPUT][1];
|
||||
|
||||
if(!test_cpp)
|
||||
cvCvtColor( inplace ? out0 : test_array[INPUT][0], out0, fwd_code );
|
||||
else
|
||||
cv::cvtColor( cv::cvarrToMat(inplace ? out0 : test_array[INPUT][0]), _out0, fwd_code, _out0.channels());
|
||||
cv::cvtColor( inplace ? out0 : test_mat[INPUT][0], _out0, fwd_code, _out0.channels());
|
||||
|
||||
if( inplace )
|
||||
{
|
||||
cvCopy( out0, test_array[OUTPUT][1] );
|
||||
out0 = test_array[OUTPUT][1];
|
||||
out0.copyTo(test_mat[OUTPUT][1]);
|
||||
out0 = test_mat[OUTPUT][1];
|
||||
}
|
||||
if(!test_cpp)
|
||||
cvCvtColor( out0, test_array[OUTPUT][1], inv_code );
|
||||
else
|
||||
cv::cvtColor(cv::cvarrToMat(out0), _out1, inv_code, _out1.channels());
|
||||
cv::cvtColor(out0, _out1, inv_code, _out1.channels());
|
||||
}
|
||||
|
||||
|
||||
@ -1730,13 +1721,8 @@ double CV_ColorBayerTest::get_success_error_level( int /*test_case_idx*/, int /*
|
||||
|
||||
void CV_ColorBayerTest::run_func()
|
||||
{
|
||||
if(!test_cpp)
|
||||
cvCvtColor( test_array[INPUT][0], test_array[OUTPUT][0], fwd_code );
|
||||
else
|
||||
{
|
||||
cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
|
||||
cv::cvtColor(cv::cvarrToMat(test_array[INPUT][0]), _out, fwd_code, _out.channels());
|
||||
}
|
||||
cv::Mat _out = test_mat[OUTPUT][0];
|
||||
cv::cvtColor(test_mat[INPUT][0], _out, fwd_code, _out.channels());
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -470,7 +470,7 @@ void CV_DerivBaseTest::get_test_array_types_and_sizes( int test_case_idx,
|
||||
int sameDepth = cvtest::randInt(rng) % 2;
|
||||
types[OUTPUT][0] = types[REF_OUTPUT][0] = sameDepth ? depth : CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1);
|
||||
_aperture_size = (cvtest::randInt(rng)%5)*2 - 1;
|
||||
sizes[INPUT][1] = aperture_size = cvSize(_aperture_size, _aperture_size);
|
||||
sizes[INPUT][1] = aperture_size = Size(_aperture_size, _aperture_size);
|
||||
}
|
||||
|
||||
|
||||
@ -519,21 +519,21 @@ void CV_SobelTest::get_test_array_types_and_sizes( int test_case_idx,
|
||||
}
|
||||
|
||||
if( _aperture_size < 0 )
|
||||
aperture_size = cvSize(3, 3);
|
||||
aperture_size = Size(3, 3);
|
||||
else if( _aperture_size == 1 )
|
||||
{
|
||||
if( dx == 0 )
|
||||
aperture_size = cvSize(1, 3);
|
||||
aperture_size = Size(1, 3);
|
||||
else if( dy == 0 )
|
||||
aperture_size = cvSize(3, 1);
|
||||
aperture_size = Size(3, 1);
|
||||
else
|
||||
{
|
||||
_aperture_size = 3;
|
||||
aperture_size = cvSize(3, 3);
|
||||
aperture_size = Size(3, 3);
|
||||
}
|
||||
}
|
||||
else
|
||||
aperture_size = cvSize(_aperture_size, _aperture_size);
|
||||
aperture_size = Size(_aperture_size, _aperture_size);
|
||||
|
||||
sizes[INPUT][1] = aperture_size;
|
||||
anchor.x = aperture_size.width / 2;
|
||||
@ -647,10 +647,10 @@ void CV_LaplaceTest::get_test_array_types_and_sizes( int test_case_idx,
|
||||
{
|
||||
if( _aperture_size < 0 )
|
||||
_aperture_size = 1;
|
||||
aperture_size = cvSize(3, 3);
|
||||
aperture_size = Size(3, 3);
|
||||
}
|
||||
else
|
||||
aperture_size = cvSize(_aperture_size, _aperture_size);
|
||||
aperture_size = Size(_aperture_size, _aperture_size);
|
||||
|
||||
sizes[INPUT][1] = aperture_size;
|
||||
anchor.x = aperture_size.width / 2;
|
||||
@ -1575,7 +1575,7 @@ CV_PreCornerDetectTest::CV_PreCornerDetectTest() : CV_FeatureSelBaseTest( 1 )
|
||||
|
||||
void CV_PreCornerDetectTest::run_func()
|
||||
{
|
||||
cvPreCornerDetect( test_array[INPUT][0], test_array[OUTPUT][0], aperture_size );
|
||||
cv::preCornerDetect( test_mat[INPUT][0], test_mat[OUTPUT][0], aperture_size, BORDER_REPLICATE );
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "opencv2/ts/ocl_test.hpp"
|
||||
#include "opencv2/ts/ts_gtest.h"
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
@ -768,8 +770,8 @@ void CV_RemapTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
|
||||
|
||||
void CV_RemapTest::run_func()
|
||||
{
|
||||
cvRemap( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
|
||||
test_array[INPUT][1], test_array[INPUT][2], interpolation );
|
||||
cv::remap(test_mat[INPUT][0], test_mat[INPUT_OUTPUT][0],
|
||||
test_mat[INPUT][1], test_mat[INPUT][2], interpolation );
|
||||
}
|
||||
|
||||
|
||||
@ -873,7 +875,7 @@ protected:
|
||||
double get_success_error_level( int test_case_idx, int i, int j );
|
||||
void fill_array( int test_case_idx, int i, int j, Mat& arr );
|
||||
|
||||
CvPoint2D32f center;
|
||||
Point2f center;
|
||||
bool test_cpp;
|
||||
};
|
||||
|
||||
@ -925,13 +927,8 @@ void CV_GetRectSubPixTest::fill_array( int test_case_idx, int i, int j, Mat& arr
|
||||
|
||||
void CV_GetRectSubPixTest::run_func()
|
||||
{
|
||||
if(!test_cpp)
|
||||
cvGetRectSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], center );
|
||||
else
|
||||
{
|
||||
cv::Mat _out = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]);
|
||||
cv::getRectSubPix( cv::cvarrToMat(test_array[INPUT][0]), _out.size(), center, _out, _out.type());
|
||||
}
|
||||
cv::Mat _out = test_mat[INPUT_OUTPUT][0];
|
||||
cv::getRectSubPix(test_mat[INPUT][0], _out.size(), center, _out, _out.type());
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,6 +42,8 @@
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
#define CV_DXT_MUL_CONJ 8
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
/// phase correlation
|
||||
@ -181,7 +183,7 @@ void CV_DivSpectrumsTest::get_test_array_types_and_sizes( int test_case_idx, vec
|
||||
|
||||
// Get the flag of the input.
|
||||
const int rand_int_flags = cvtest::randInt(rng);
|
||||
flags = rand_int_flags & (CV_DXT_MUL_CONJ | CV_DXT_ROWS);
|
||||
flags = rand_int_flags & (CV_DXT_MUL_CONJ | DFT_ROWS);
|
||||
|
||||
// Get input type.
|
||||
const int rand_int_type = cvtest::randInt(rng);
|
||||
|
@ -43,299 +43,6 @@
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class CV_TemplMatchTest : public cvtest::ArrayTest
|
||||
{
|
||||
public:
|
||||
CV_TemplMatchTest();
|
||||
|
||||
protected:
|
||||
int read_params( const cv::FileStorage& fs );
|
||||
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
|
||||
void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
|
||||
double get_success_error_level( int test_case_idx, int i, int j );
|
||||
void run_func();
|
||||
void prepare_to_validation( int );
|
||||
|
||||
int max_template_size;
|
||||
int method;
|
||||
bool test_cpp;
|
||||
};
|
||||
|
||||
|
||||
CV_TemplMatchTest::CV_TemplMatchTest()
|
||||
{
|
||||
test_array[INPUT].push_back(NULL);
|
||||
test_array[INPUT].push_back(NULL);
|
||||
test_array[OUTPUT].push_back(NULL);
|
||||
test_array[REF_OUTPUT].push_back(NULL);
|
||||
element_wise_relative_error = false;
|
||||
max_template_size = 100;
|
||||
method = 0;
|
||||
test_cpp = false;
|
||||
}
|
||||
|
||||
|
||||
int CV_TemplMatchTest::read_params( const cv::FileStorage& fs )
|
||||
{
|
||||
int code = cvtest::ArrayTest::read_params( fs );
|
||||
if( code < 0 )
|
||||
return code;
|
||||
|
||||
read( find_param( fs, "max_template_size" ), max_template_size, max_template_size );
|
||||
max_template_size = cvtest::clipInt( max_template_size, 1, 100 );
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
void CV_TemplMatchTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
|
||||
{
|
||||
cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
|
||||
int depth = CV_MAT_DEPTH(type);
|
||||
if( depth == CV_32F )
|
||||
{
|
||||
low = Scalar::all(-10.);
|
||||
high = Scalar::all(10.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CV_TemplMatchTest::get_test_array_types_and_sizes( int test_case_idx,
|
||||
vector<vector<Size> >& sizes, vector<vector<int> >& types )
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
int depth = cvtest::randInt(rng) % 2, cn = cvtest::randInt(rng) & 1 ? 3 : 1;
|
||||
cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
|
||||
depth = depth == 0 ? CV_8U : CV_32F;
|
||||
|
||||
types[INPUT][0] = types[INPUT][1] = CV_MAKETYPE(depth,cn);
|
||||
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;
|
||||
|
||||
sizes[INPUT][1].width = cvtest::randInt(rng)%MIN(sizes[INPUT][1].width,max_template_size) + 1;
|
||||
sizes[INPUT][1].height = cvtest::randInt(rng)%MIN(sizes[INPUT][1].height,max_template_size) + 1;
|
||||
sizes[OUTPUT][0].width = sizes[INPUT][0].width - sizes[INPUT][1].width + 1;
|
||||
sizes[OUTPUT][0].height = sizes[INPUT][0].height - sizes[INPUT][1].height + 1;
|
||||
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
|
||||
|
||||
method = cvtest::randInt(rng)%6;
|
||||
test_cpp = (cvtest::randInt(rng) & 256) == 0;
|
||||
}
|
||||
|
||||
|
||||
double CV_TemplMatchTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
|
||||
{
|
||||
if( test_mat[INPUT][1].depth() == CV_8U ||
|
||||
(method >= cv::TM_CCOEFF && test_mat[INPUT][1].cols*test_mat[INPUT][1].rows <= 2) )
|
||||
return 1e-2;
|
||||
else
|
||||
return 1e-3;
|
||||
}
|
||||
|
||||
|
||||
void CV_TemplMatchTest::run_func()
|
||||
{
|
||||
if(!test_cpp)
|
||||
cvMatchTemplate( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0], method );
|
||||
else
|
||||
{
|
||||
cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
|
||||
cv::matchTemplate(cv::cvarrToMat(test_array[INPUT][0]), cv::cvarrToMat(test_array[INPUT][1]), _out, method);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void cvTsMatchTemplate( const CvMat* img, const CvMat* templ, CvMat* result, int method )
|
||||
{
|
||||
int i, j, k, l;
|
||||
int depth = CV_MAT_DEPTH(img->type), cn = CV_MAT_CN(img->type);
|
||||
int width_n = templ->cols*cn, height = templ->rows;
|
||||
int a_step = img->step / CV_ELEM_SIZE(img->type & CV_MAT_DEPTH_MASK);
|
||||
int b_step = templ->step / CV_ELEM_SIZE(templ->type & CV_MAT_DEPTH_MASK);
|
||||
CvScalar b_mean = CV_STRUCT_INITIALIZER, b_sdv = CV_STRUCT_INITIALIZER;
|
||||
double b_denom = 1., b_sum2 = 0;
|
||||
int area = templ->rows*templ->cols;
|
||||
|
||||
cvAvgSdv(templ, &b_mean, &b_sdv);
|
||||
|
||||
for( i = 0; i < cn; i++ )
|
||||
b_sum2 += (b_sdv.val[i]*b_sdv.val[i] + b_mean.val[i]*b_mean.val[i])*area;
|
||||
|
||||
if( b_sdv.val[0]*b_sdv.val[0] + b_sdv.val[1]*b_sdv.val[1] +
|
||||
b_sdv.val[2]*b_sdv.val[2] + b_sdv.val[3]*b_sdv.val[3] < DBL_EPSILON &&
|
||||
method == cv::TM_CCOEFF_NORMED )
|
||||
{
|
||||
cvSet( result, cvScalarAll(1.) );
|
||||
return;
|
||||
}
|
||||
|
||||
if( method & 1 )
|
||||
{
|
||||
b_denom = 0;
|
||||
if( method != cv::TM_CCOEFF_NORMED )
|
||||
{
|
||||
b_denom = b_sum2;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < cn; i++ )
|
||||
b_denom += b_sdv.val[i]*b_sdv.val[i]*area;
|
||||
}
|
||||
b_denom = sqrt(b_denom);
|
||||
if( b_denom == 0 )
|
||||
b_denom = 1.;
|
||||
}
|
||||
|
||||
CV_Assert( cv::TM_SQDIFF <= method && method <= cv::TM_CCOEFF_NORMED );
|
||||
|
||||
for( i = 0; i < result->rows; i++ )
|
||||
{
|
||||
for( j = 0; j < result->cols; j++ )
|
||||
{
|
||||
Scalar a_sum(0), a_sum2(0);
|
||||
Scalar ccorr(0);
|
||||
double value = 0.;
|
||||
|
||||
if( depth == CV_8U )
|
||||
{
|
||||
const uchar* a = img->data.ptr + i*img->step + j*cn;
|
||||
const uchar* b = templ->data.ptr;
|
||||
|
||||
if( cn == 1 || method < cv::TM_CCOEFF )
|
||||
{
|
||||
for( k = 0; k < height; k++, a += a_step, b += b_step )
|
||||
for( l = 0; l < width_n; l++ )
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( k = 0; k < height; k++, a += a_step, b += b_step )
|
||||
for( l = 0; l < width_n; l += 3 )
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
ccorr.val[1] += a[l+1]*b[l+1];
|
||||
ccorr.val[2] += a[l+2]*b[l+2];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum.val[1] += a[l+1];
|
||||
a_sum.val[2] += a[l+2];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
a_sum2.val[1] += a[l+1]*a[l+1];
|
||||
a_sum2.val[2] += a[l+2]*a[l+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const float* a = (const float*)(img->data.ptr + i*img->step) + j*cn;
|
||||
const float* b = (const float*)templ->data.ptr;
|
||||
|
||||
if( cn == 1 || method < cv::TM_CCOEFF )
|
||||
{
|
||||
for( k = 0; k < height; k++, a += a_step, b += b_step )
|
||||
for( l = 0; l < width_n; l++ )
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( k = 0; k < height; k++, a += a_step, b += b_step )
|
||||
for( l = 0; l < width_n; l += 3 )
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
ccorr.val[1] += a[l+1]*b[l+1];
|
||||
ccorr.val[2] += a[l+2]*b[l+2];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum.val[1] += a[l+1];
|
||||
a_sum.val[2] += a[l+2];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
a_sum2.val[1] += a[l+1]*a[l+1];
|
||||
a_sum2.val[2] += a[l+2]*a[l+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch( method )
|
||||
{
|
||||
case cv::TM_CCORR:
|
||||
case cv::TM_CCORR_NORMED:
|
||||
value = ccorr.val[0];
|
||||
break;
|
||||
case cv::TM_SQDIFF:
|
||||
case cv::TM_SQDIFF_NORMED:
|
||||
value = (a_sum2.val[0] + b_sum2 - 2*ccorr.val[0]);
|
||||
break;
|
||||
default:
|
||||
value = (ccorr.val[0] - a_sum.val[0]*b_mean.val[0]+
|
||||
ccorr.val[1] - a_sum.val[1]*b_mean.val[1]+
|
||||
ccorr.val[2] - a_sum.val[2]*b_mean.val[2]);
|
||||
}
|
||||
|
||||
if( method & 1 )
|
||||
{
|
||||
double denom;
|
||||
|
||||
// calc denominator
|
||||
if( method != cv::TM_CCOEFF_NORMED )
|
||||
{
|
||||
denom = a_sum2.val[0] + a_sum2.val[1] + a_sum2.val[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
denom = a_sum2.val[0] - (a_sum.val[0]*a_sum.val[0])/area;
|
||||
denom += a_sum2.val[1] - (a_sum.val[1]*a_sum.val[1])/area;
|
||||
denom += a_sum2.val[2] - (a_sum.val[2]*a_sum.val[2])/area;
|
||||
}
|
||||
denom = sqrt(MAX(denom,0))*b_denom;
|
||||
if( fabs(value) < denom )
|
||||
value /= denom;
|
||||
else if( fabs(value) < denom*1.125 )
|
||||
value = value > 0 ? 1 : -1;
|
||||
else
|
||||
value = method != cv::TM_SQDIFF_NORMED ? 0 : 1;
|
||||
}
|
||||
|
||||
((float*)(result->data.ptr + result->step*i))[j] = (float)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CV_TemplMatchTest::prepare_to_validation( int /*test_case_idx*/ )
|
||||
{
|
||||
CvMat _input = cvMat(test_mat[INPUT][0]), _templ = cvMat(test_mat[INPUT][1]);
|
||||
CvMat _output = cvMat(test_mat[REF_OUTPUT][0]);
|
||||
cvTsMatchTemplate( &_input, &_templ, &_output, method );
|
||||
|
||||
//if( ts->get_current_test_info()->test_case_idx == 0 )
|
||||
/*{
|
||||
CvFileStorage* fs = cvOpenFileStorage( "_match_template.yml", 0, CV_STORAGE_WRITE );
|
||||
cvWrite( fs, "image", &test_mat[INPUT][0] );
|
||||
cvWrite( fs, "template", &test_mat[INPUT][1] );
|
||||
cvWrite( fs, "ref", &test_mat[REF_OUTPUT][0] );
|
||||
cvWrite( fs, "opencv", &test_mat[OUTPUT][0] );
|
||||
cvWriteInt( fs, "method", method );
|
||||
cvReleaseFileStorage( &fs );
|
||||
}*/
|
||||
|
||||
if( method >= cv::TM_CCOEFF )
|
||||
{
|
||||
// avoid numerical stability problems in singular cases (when the results are near to 0)
|
||||
const double delta = 10.;
|
||||
test_mat[REF_OUTPUT][0] += Scalar::all(delta);
|
||||
test_mat[OUTPUT][0] += Scalar::all(delta);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgproc_MatchTemplate, accuracy) { CV_TemplMatchTest test; test.safe_run(); }
|
||||
|
||||
}
|
||||
|
||||
TEST(Imgproc_MatchTemplate, bug_9597) {
|
||||
const uint8_t img[] = {
|
||||
245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245,
|
||||
@ -425,4 +132,214 @@ TEST(Imgproc_MatchTemplate, bug_9597) {
|
||||
cv::minMaxLoc(result, &minValue, NULL, NULL, NULL);
|
||||
ASSERT_GE(minValue, 0);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//==============================================================================
|
||||
|
||||
static void matchTemplate_reference(Mat & img, Mat & templ, Mat & result, const int method)
|
||||
{
|
||||
CV_Assert(cv::TM_SQDIFF <= method && method <= cv::TM_CCOEFF_NORMED);
|
||||
|
||||
const Size res_sz(img.cols - templ.cols + 1, img.rows - templ.rows + 1);
|
||||
result.create(res_sz, CV_32FC1);
|
||||
|
||||
const int depth = img.depth();
|
||||
const int cn = img.channels();
|
||||
const int area = templ.size().area();
|
||||
const int width_n = templ.cols * cn;
|
||||
const int height = templ.rows;
|
||||
int a_step = (int)(img.step / img.elemSize1());
|
||||
int b_step = (int)(templ.step / templ.elemSize1());
|
||||
|
||||
Scalar b_mean = Scalar::all(0);
|
||||
Scalar b_sdv = Scalar::all(0);
|
||||
cv::meanStdDev(templ, b_mean, b_sdv);
|
||||
|
||||
double b_sum2 = 0.;
|
||||
for (int i = 0; i < cn; i++ )
|
||||
b_sum2 += (b_sdv.val[i] * b_sdv.val[i] + b_mean.val[i] * b_mean.val[i]) * area;
|
||||
|
||||
if (b_sdv.val[0] * b_sdv.val[0] + b_sdv.val[1] * b_sdv.val[1] +
|
||||
b_sdv.val[2] * b_sdv.val[2] + b_sdv.val[3] * b_sdv.val[3] < DBL_EPSILON &&
|
||||
method == cv::TM_CCOEFF_NORMED)
|
||||
{
|
||||
result = Scalar::all(1.);
|
||||
return;
|
||||
}
|
||||
|
||||
double b_denom = 1.;
|
||||
if (method & 1) // _NORMED
|
||||
{
|
||||
b_denom = 0;
|
||||
if (method != cv::TM_CCOEFF_NORMED)
|
||||
{
|
||||
b_denom = b_sum2;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cn; i++)
|
||||
b_denom += b_sdv.val[i] * b_sdv.val[i] * area;
|
||||
}
|
||||
b_denom = sqrt(b_denom);
|
||||
if (b_denom == 0)
|
||||
b_denom = 1.;
|
||||
}
|
||||
|
||||
for (int i = 0; i < result.rows; i++)
|
||||
{
|
||||
for (int j = 0; j < result.cols; j++)
|
||||
{
|
||||
Scalar a_sum(0), a_sum2(0);
|
||||
Scalar ccorr(0);
|
||||
double value = 0.;
|
||||
|
||||
if (depth == CV_8U)
|
||||
{
|
||||
const uchar* a = img.ptr<uchar>(i, j); // ??? ->data.ptr + i*img->step + j*cn;
|
||||
const uchar* b = templ.ptr<uchar>();
|
||||
|
||||
if( cn == 1 || method < cv::TM_CCOEFF )
|
||||
{
|
||||
for (int k = 0; k < height; k++, a += a_step, b += b_step)
|
||||
for (int l = 0; l < width_n; l++)
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int k = 0; k < height; k++, a += a_step, b += b_step)
|
||||
for (int l = 0; l < width_n; l += 3)
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
ccorr.val[1] += a[l+1]*b[l+1];
|
||||
ccorr.val[2] += a[l+2]*b[l+2];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum.val[1] += a[l+1];
|
||||
a_sum.val[2] += a[l+2];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
a_sum2.val[1] += a[l+1]*a[l+1];
|
||||
a_sum2.val[2] += a[l+2]*a[l+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else // CV_32F
|
||||
{
|
||||
const float* a = img.ptr<float>(i, j); // ???? (const float*)(img->data.ptr + i*img->step) + j*cn;
|
||||
const float* b = templ.ptr<float>();
|
||||
|
||||
if( cn == 1 || method < cv::TM_CCOEFF )
|
||||
{
|
||||
for (int k = 0; k < height; k++, a += a_step, b += b_step)
|
||||
for (int l = 0; l < width_n; l++)
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int k = 0; k < height; k++, a += a_step, b += b_step)
|
||||
for (int l = 0; l < width_n; l += 3)
|
||||
{
|
||||
ccorr.val[0] += a[l]*b[l];
|
||||
ccorr.val[1] += a[l+1]*b[l+1];
|
||||
ccorr.val[2] += a[l+2]*b[l+2];
|
||||
a_sum.val[0] += a[l];
|
||||
a_sum.val[1] += a[l+1];
|
||||
a_sum.val[2] += a[l+2];
|
||||
a_sum2.val[0] += a[l]*a[l];
|
||||
a_sum2.val[1] += a[l+1]*a[l+1];
|
||||
a_sum2.val[2] += a[l+2]*a[l+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch( method )
|
||||
{
|
||||
case cv::TM_CCORR:
|
||||
case cv::TM_CCORR_NORMED:
|
||||
value = ccorr.val[0];
|
||||
break;
|
||||
case cv::TM_SQDIFF:
|
||||
case cv::TM_SQDIFF_NORMED:
|
||||
value = (a_sum2.val[0] + b_sum2 - 2*ccorr.val[0]);
|
||||
break;
|
||||
default:
|
||||
value = (ccorr.val[0] - a_sum.val[0]*b_mean.val[0]+
|
||||
ccorr.val[1] - a_sum.val[1]*b_mean.val[1]+
|
||||
ccorr.val[2] - a_sum.val[2]*b_mean.val[2]);
|
||||
}
|
||||
|
||||
if( method & 1 )
|
||||
{
|
||||
double denom;
|
||||
|
||||
// calc denominator
|
||||
if( method != cv::TM_CCOEFF_NORMED )
|
||||
{
|
||||
denom = a_sum2.val[0] + a_sum2.val[1] + a_sum2.val[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
denom = a_sum2.val[0] - (a_sum.val[0]*a_sum.val[0])/area;
|
||||
denom += a_sum2.val[1] - (a_sum.val[1]*a_sum.val[1])/area;
|
||||
denom += a_sum2.val[2] - (a_sum.val[2]*a_sum.val[2])/area;
|
||||
}
|
||||
denom = sqrt(MAX(denom,0))*b_denom;
|
||||
if( fabs(value) < denom )
|
||||
value /= denom;
|
||||
else if( fabs(value) < denom*1.125 )
|
||||
value = value > 0 ? 1 : -1;
|
||||
else
|
||||
value = method != cv::TM_SQDIFF_NORMED ? 0 : 1;
|
||||
}
|
||||
result.at<float>(i, j) = (float)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
CV_ENUM(MatchModes, TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED);
|
||||
|
||||
typedef testing::TestWithParam<testing::tuple<perf::MatDepth, int, MatchModes>> matchTemplate_Modes;
|
||||
|
||||
TEST_P(matchTemplate_Modes, accuracy)
|
||||
{
|
||||
const int data_type = CV_MAKE_TYPE(get<0>(GetParam()), get<1>(GetParam()));
|
||||
const int method = get<2>(GetParam());
|
||||
RNG & rng = TS::ptr()->get_rng();
|
||||
|
||||
for (int ITER = 0; ITER < 20; ++ITER)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("iteration %d", ITER));
|
||||
|
||||
const Size imgSize(rng.uniform(128, 320), rng.uniform(128, 240));
|
||||
const Size templSize(rng.uniform(1, 100), rng.uniform(1, 100));
|
||||
Mat img(imgSize, data_type, Scalar::all(0));
|
||||
Mat templ(templSize, data_type, Scalar::all(0));
|
||||
cvtest::randUni(rng, img, Scalar::all(0), Scalar::all(255));
|
||||
cvtest::randUni(rng, templ, Scalar::all(0), Scalar::all(255));
|
||||
|
||||
Mat result;
|
||||
cv::matchTemplate(img, templ, result, method);
|
||||
|
||||
Mat reference;
|
||||
matchTemplate_reference(img, templ, reference, method);
|
||||
|
||||
EXPECT_MAT_NEAR_RELATIVE(result, reference, 1e-3);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/,
|
||||
matchTemplate_Modes,
|
||||
testing::Combine(
|
||||
testing::Values(CV_8U, CV_32F),
|
||||
testing::Values(1, 3),
|
||||
testing::Values(TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED)));
|
||||
|
||||
|
||||
}} // namespace
|
||||
|
Loading…
Reference in New Issue
Block a user