mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +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 {
|
namespace opencv_test { namespace {
|
||||||
|
|
||||||
class CV_CannyTest : public cvtest::ArrayTest
|
static void Canny_reference_follow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst )
|
||||||
{
|
|
||||||
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 const int ofs[][2] = {{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}};
|
static const int ofs[][2] = {{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}};
|
||||||
int i;
|
int i;
|
||||||
@ -181,16 +58,15 @@ cannyFollow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst )
|
|||||||
(unsigned)y1 < (unsigned)mag.rows &&
|
(unsigned)y1 < (unsigned)mag.rows &&
|
||||||
mag.at<float>(y1, x1) > lowThreshold &&
|
mag.at<float>(y1, x1) > lowThreshold &&
|
||||||
!dst.at<uchar>(y1, x1) )
|
!dst.at<uchar>(y1, x1) )
|
||||||
cannyFollow( x1, y1, lowThreshold, mag, dst );
|
Canny_reference_follow( x1, y1, lowThreshold, mag, dst );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Canny_reference( const Mat& src, Mat& dst,
|
||||||
static void
|
|
||||||
test_Canny( const Mat& src, Mat& dst,
|
|
||||||
double threshold1, double threshold2,
|
double threshold1, double threshold2,
|
||||||
int aperture_size, bool use_true_gradient )
|
int aperture_size, bool use_true_gradient )
|
||||||
{
|
{
|
||||||
|
dst.create(src.size(), src.type());
|
||||||
int m = aperture_size;
|
int m = aperture_size;
|
||||||
Point anchor(m/2, m/2);
|
Point anchor(m/2, m/2);
|
||||||
const double tan_pi_8 = tan(CV_PI/8.);
|
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++ )
|
for( x = 0; x < width; x++ )
|
||||||
if( mag.at<float>(y, x) > highThreshold && !dst.at<uchar>(y, 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];
|
const int aperture = get<0>(GetParam());
|
||||||
test_Canny( src, dst, threshold1, threshold2, aperture_size, use_true_gradient );
|
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)
|
||||||
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 );
|
SCOPED_TRACE(cv::format("iteration %d", ITER));
|
||||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
|
||||||
return code;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
nz0 = cvRound(cvtest::norm(test_mat[REF_OUTPUT][0], CV_L1)/255);
|
// custom derivatives
|
||||||
err = (err/255/MAX(nz0,100))*100;
|
Mat customResult;
|
||||||
if( err > 1 )
|
|
||||||
{
|
{
|
||||||
ts->printf( cvtest::TS::LOG, "Too high percentage of non-matching edge pixels = %g%%\n", err);
|
Mat dxkernel = cvtest::calcSobelKernel2D(1, 0, aperture, 0);
|
||||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return code;
|
Mat reference;
|
||||||
|
Canny_reference(img, reference, thresh1, thresh2, aperture, trueGradient);
|
||||||
|
|
||||||
|
EXPECT_MAT_NEAR(result, reference, 0);
|
||||||
|
EXPECT_MAT_NEAR(customResult, reference, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Imgproc_Canny, accuracy) { CV_CannyTest test; test.safe_run(); }
|
INSTANTIATE_TEST_CASE_P(/**/, Canny_Modes,
|
||||||
TEST(Imgproc_Canny, accuracy_deriv) { CV_CannyTest test(true); test.safe_run(); }
|
testing::Combine(
|
||||||
|
testing::Values(3, 5),
|
||||||
|
testing::Values(true, false)));
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -76,7 +76,6 @@ protected:
|
|||||||
bool inplace;
|
bool inplace;
|
||||||
bool custom_inv_transform;
|
bool custom_inv_transform;
|
||||||
int fwd_code, inv_code;
|
int fwd_code, inv_code;
|
||||||
bool test_cpp;
|
|
||||||
int hue_range;
|
int hue_range;
|
||||||
bool srgb;
|
bool srgb;
|
||||||
};
|
};
|
||||||
@ -97,7 +96,6 @@ CV_ColorCvtBaseTest::CV_ColorCvtBaseTest( bool _custom_inv_transform, bool _allo
|
|||||||
|
|
||||||
fwd_code_str = inv_code_str = 0;
|
fwd_code_str = inv_code_str = 0;
|
||||||
|
|
||||||
test_cpp = false;
|
|
||||||
hue_range = 0;
|
hue_range = 0;
|
||||||
blue_idx = 0;
|
blue_idx = 0;
|
||||||
srgb = false;
|
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);
|
types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(depth, cn);
|
||||||
|
|
||||||
inplace = cn == 3 && cvtest::randInt(rng) % 2 != 0;
|
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()
|
void CV_ColorCvtBaseTest::run_func()
|
||||||
{
|
{
|
||||||
CvArr* out0 = test_array[OUTPUT][0];
|
cv::Mat out0 = test_mat[OUTPUT][0];
|
||||||
cv::Mat _out0 = cv::cvarrToMat(out0), _out1 = cv::cvarrToMat(test_array[OUTPUT][1]);
|
cv::Mat _out0 = out0, _out1 = test_mat[OUTPUT][1];
|
||||||
|
|
||||||
if(!test_cpp)
|
cv::cvtColor( inplace ? out0 : test_mat[INPUT][0], _out0, fwd_code, _out0.channels());
|
||||||
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());
|
|
||||||
|
|
||||||
if( inplace )
|
if( inplace )
|
||||||
{
|
{
|
||||||
cvCopy( out0, test_array[OUTPUT][1] );
|
out0.copyTo(test_mat[OUTPUT][1]);
|
||||||
out0 = test_array[OUTPUT][1];
|
out0 = test_mat[OUTPUT][1];
|
||||||
}
|
}
|
||||||
if(!test_cpp)
|
cv::cvtColor(out0, _out1, inv_code, _out1.channels());
|
||||||
cvCvtColor( out0, test_array[OUTPUT][1], inv_code );
|
|
||||||
else
|
|
||||||
cv::cvtColor(cv::cvarrToMat(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()
|
void CV_ColorBayerTest::run_func()
|
||||||
{
|
{
|
||||||
if(!test_cpp)
|
cv::Mat _out = test_mat[OUTPUT][0];
|
||||||
cvCvtColor( test_array[INPUT][0], test_array[OUTPUT][0], fwd_code );
|
cv::cvtColor(test_mat[INPUT][0], _out, fwd_code, _out.channels());
|
||||||
else
|
|
||||||
{
|
|
||||||
cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
|
|
||||||
cv::cvtColor(cv::cvarrToMat(test_array[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;
|
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);
|
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;
|
_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 )
|
if( _aperture_size < 0 )
|
||||||
aperture_size = cvSize(3, 3);
|
aperture_size = Size(3, 3);
|
||||||
else if( _aperture_size == 1 )
|
else if( _aperture_size == 1 )
|
||||||
{
|
{
|
||||||
if( dx == 0 )
|
if( dx == 0 )
|
||||||
aperture_size = cvSize(1, 3);
|
aperture_size = Size(1, 3);
|
||||||
else if( dy == 0 )
|
else if( dy == 0 )
|
||||||
aperture_size = cvSize(3, 1);
|
aperture_size = Size(3, 1);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_aperture_size = 3;
|
_aperture_size = 3;
|
||||||
aperture_size = cvSize(3, 3);
|
aperture_size = Size(3, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
aperture_size = cvSize(_aperture_size, _aperture_size);
|
aperture_size = Size(_aperture_size, _aperture_size);
|
||||||
|
|
||||||
sizes[INPUT][1] = aperture_size;
|
sizes[INPUT][1] = aperture_size;
|
||||||
anchor.x = aperture_size.width / 2;
|
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 )
|
if( _aperture_size < 0 )
|
||||||
_aperture_size = 1;
|
_aperture_size = 1;
|
||||||
aperture_size = cvSize(3, 3);
|
aperture_size = Size(3, 3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
aperture_size = cvSize(_aperture_size, _aperture_size);
|
aperture_size = Size(_aperture_size, _aperture_size);
|
||||||
|
|
||||||
sizes[INPUT][1] = aperture_size;
|
sizes[INPUT][1] = aperture_size;
|
||||||
anchor.x = aperture_size.width / 2;
|
anchor.x = aperture_size.width / 2;
|
||||||
@ -1575,7 +1575,7 @@ CV_PreCornerDetectTest::CV_PreCornerDetectTest() : CV_FeatureSelBaseTest( 1 )
|
|||||||
|
|
||||||
void CV_PreCornerDetectTest::run_func()
|
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*/
|
//M*/
|
||||||
|
|
||||||
|
#include "opencv2/ts/ocl_test.hpp"
|
||||||
|
#include "opencv2/ts/ts_gtest.h"
|
||||||
#include "test_precomp.hpp"
|
#include "test_precomp.hpp"
|
||||||
|
|
||||||
namespace opencv_test { namespace {
|
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()
|
void CV_RemapTest::run_func()
|
||||||
{
|
{
|
||||||
cvRemap( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
|
cv::remap(test_mat[INPUT][0], test_mat[INPUT_OUTPUT][0],
|
||||||
test_array[INPUT][1], test_array[INPUT][2], interpolation );
|
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 );
|
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 );
|
void fill_array( int test_case_idx, int i, int j, Mat& arr );
|
||||||
|
|
||||||
CvPoint2D32f center;
|
Point2f center;
|
||||||
bool test_cpp;
|
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()
|
void CV_GetRectSubPixTest::run_func()
|
||||||
{
|
{
|
||||||
if(!test_cpp)
|
cv::Mat _out = test_mat[INPUT_OUTPUT][0];
|
||||||
cvGetRectSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], center );
|
cv::getRectSubPix(test_mat[INPUT][0], _out.size(), center, _out, _out.type());
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
|
|
||||||
#include "test_precomp.hpp"
|
#include "test_precomp.hpp"
|
||||||
|
|
||||||
|
#define CV_DXT_MUL_CONJ 8
|
||||||
|
|
||||||
namespace opencv_test { namespace {
|
namespace opencv_test { namespace {
|
||||||
|
|
||||||
/// phase correlation
|
/// 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.
|
// Get the flag of the input.
|
||||||
const int rand_int_flags = cvtest::randInt(rng);
|
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.
|
// Get input type.
|
||||||
const int rand_int_type = cvtest::randInt(rng);
|
const int rand_int_type = cvtest::randInt(rng);
|
||||||
|
@ -43,299 +43,6 @@
|
|||||||
|
|
||||||
namespace opencv_test { namespace {
|
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) {
|
TEST(Imgproc_MatchTemplate, bug_9597) {
|
||||||
const uint8_t img[] = {
|
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,
|
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);
|
cv::minMaxLoc(result, &minValue, NULL, NULL, NULL);
|
||||||
ASSERT_GE(minValue, 0);
|
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