mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
9.5 KiB
278 lines
9.5 KiB
// 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" |
|
|
|
namespace opencv_test { namespace { |
|
|
|
CV_ENUM(MatchTemplType, CV_TM_CCORR, CV_TM_CCORR_NORMED, |
|
CV_TM_SQDIFF, CV_TM_SQDIFF_NORMED, |
|
CV_TM_CCOEFF, CV_TM_CCOEFF_NORMED) |
|
|
|
class Imgproc_MatchTemplateWithMask : public TestWithParam<std::tuple<MatType,MatType>> |
|
{ |
|
protected: |
|
// Member functions inherited from ::testing::Test |
|
void SetUp() override; |
|
|
|
// Matrices for test calculations (always CV_32) |
|
Mat img_; |
|
Mat templ_; |
|
Mat mask_; |
|
Mat templ_masked_; |
|
Mat img_roi_masked_; |
|
// Matrices for call to matchTemplate (have test type) |
|
Mat img_testtype_; |
|
Mat templ_testtype_; |
|
Mat mask_testtype_; |
|
Mat result_; |
|
|
|
// Constants |
|
static const Size IMG_SIZE; |
|
static const Size TEMPL_SIZE; |
|
static const Point TEST_POINT; |
|
}; |
|
|
|
// Arbitraryly chosen test constants |
|
const Size Imgproc_MatchTemplateWithMask::IMG_SIZE(160, 100); |
|
const Size Imgproc_MatchTemplateWithMask::TEMPL_SIZE(21, 13); |
|
const Point Imgproc_MatchTemplateWithMask::TEST_POINT(8, 9); |
|
|
|
void Imgproc_MatchTemplateWithMask::SetUp() |
|
{ |
|
int type = std::get<0>(GetParam()); |
|
int type_mask = std::get<1>(GetParam()); |
|
|
|
// Matrices are created with the depth to test (for the call to matchTemplate()), but are also |
|
// converted to CV_32 for the test calculations, because matchTemplate() also only operates on |
|
// and returns CV_32. |
|
img_testtype_.create(IMG_SIZE, type); |
|
templ_testtype_.create(TEMPL_SIZE, type); |
|
mask_testtype_.create(TEMPL_SIZE, type_mask); |
|
|
|
randu(img_testtype_, 0, 10); |
|
randu(templ_testtype_, 0, 10); |
|
randu(mask_testtype_, 0, 5); |
|
|
|
img_testtype_.convertTo(img_, CV_32F); |
|
templ_testtype_.convertTo(templ_, CV_32F); |
|
mask_testtype_.convertTo(mask_, CV_32F); |
|
if (CV_MAT_DEPTH(type_mask) == CV_8U) |
|
{ |
|
// CV_8U masks are interpreted as binary masks |
|
mask_.setTo(Scalar::all(1), mask_ != 0); |
|
} |
|
if (mask_.channels() != templ_.channels()) |
|
{ |
|
std::vector<Mat> mask_channels(templ_.channels(), mask_); |
|
merge(mask_channels.data(), templ_.channels(), mask_); |
|
} |
|
|
|
Rect roi(TEST_POINT, TEMPL_SIZE); |
|
img_roi_masked_ = img_(roi).mul(mask_); |
|
templ_masked_ = templ_.mul(mask_); |
|
} |
|
|
|
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplSQDIFF) |
|
{ |
|
matchTemplate(img_testtype_, templ_testtype_, result_, CV_TM_SQDIFF, mask_testtype_); |
|
// Naive implementation for one point |
|
Mat temp = img_roi_masked_ - templ_masked_; |
|
Scalar temp_s = sum(temp.mul(temp)); |
|
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
|
|
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON); |
|
} |
|
|
|
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplSQDIFF_NORMED) |
|
{ |
|
matchTemplate(img_testtype_, templ_testtype_, result_, CV_TM_SQDIFF_NORMED, mask_testtype_); |
|
// Naive implementation for one point |
|
Mat temp = img_roi_masked_ - templ_masked_; |
|
Scalar temp_s = sum(temp.mul(temp)); |
|
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
|
|
// Normalization |
|
temp_s = sum(templ_masked_.mul(templ_masked_)); |
|
double norm = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
temp_s = sum(img_roi_masked_.mul(img_roi_masked_)); |
|
norm *= temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
norm = sqrt(norm); |
|
val /= norm; |
|
|
|
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON); |
|
} |
|
|
|
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCORR) |
|
{ |
|
matchTemplate(img_testtype_, templ_testtype_, result_, CV_TM_CCORR, mask_testtype_); |
|
// Naive implementation for one point |
|
Scalar temp_s = sum(templ_masked_.mul(img_roi_masked_)); |
|
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
|
|
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON); |
|
} |
|
|
|
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCORR_NORMED) |
|
{ |
|
matchTemplate(img_testtype_, templ_testtype_, result_, CV_TM_CCORR_NORMED, mask_testtype_); |
|
// Naive implementation for one point |
|
Scalar temp_s = sum(templ_masked_.mul(img_roi_masked_)); |
|
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
|
|
// Normalization |
|
temp_s = sum(templ_masked_.mul(templ_masked_)); |
|
double norm = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
temp_s = sum(img_roi_masked_.mul(img_roi_masked_)); |
|
norm *= temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
norm = sqrt(norm); |
|
val /= norm; |
|
|
|
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON); |
|
} |
|
|
|
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCOEFF) |
|
{ |
|
matchTemplate(img_testtype_, templ_testtype_, result_, CV_TM_CCOEFF, mask_testtype_); |
|
// Naive implementation for one point |
|
Scalar temp_s = sum(mask_); |
|
for (int i = 0; i < 4; i++) |
|
{ |
|
if (temp_s[i] != 0.0) |
|
temp_s[i] = 1.0 / temp_s[i]; |
|
else |
|
temp_s[i] = 1.0; |
|
} |
|
Mat temp = mask_.clone(); temp = temp_s; // Workaround to multiply Mat by Scalar |
|
Mat temp2 = mask_.clone(); temp2 = sum(templ_masked_); // Workaround to multiply Mat by Scalar |
|
Mat templx = templ_masked_ - mask_.mul(temp).mul(temp2); |
|
temp2 = sum(img_roi_masked_); // Workaround to multiply Mat by Scalar |
|
Mat imgx = img_roi_masked_ - mask_.mul(temp).mul(temp2); |
|
temp_s = sum(templx.mul(imgx)); |
|
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
|
|
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON); |
|
} |
|
|
|
TEST_P(Imgproc_MatchTemplateWithMask, CompareNaiveImplCCOEFF_NORMED) |
|
{ |
|
matchTemplate(img_testtype_, templ_testtype_, result_, CV_TM_CCOEFF_NORMED, mask_testtype_); |
|
// Naive implementation for one point |
|
Scalar temp_s = sum(mask_); |
|
for (int i = 0; i < 4; i++) |
|
{ |
|
if (temp_s[i] != 0.0) |
|
temp_s[i] = 1.0 / temp_s[i]; |
|
else |
|
temp_s[i] = 1.0; |
|
} |
|
Mat temp = mask_.clone(); temp = temp_s; // Workaround to multiply Mat by Scalar |
|
Mat temp2 = mask_.clone(); temp2 = sum(templ_masked_); // Workaround to multiply Mat by Scalar |
|
Mat templx = templ_masked_ - mask_.mul(temp).mul(temp2); |
|
temp2 = sum(img_roi_masked_); // Workaround to multiply Mat by Scalar |
|
Mat imgx = img_roi_masked_ - mask_.mul(temp).mul(temp2); |
|
temp_s = sum(templx.mul(imgx)); |
|
double val = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
|
|
// Normalization |
|
temp_s = sum(templx.mul(templx)); |
|
double norm = temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
temp_s = sum(imgx.mul(imgx)); |
|
norm *= temp_s[0] + temp_s[1] + temp_s[2] + temp_s[3]; |
|
norm = sqrt(norm); |
|
val /= norm; |
|
|
|
EXPECT_NEAR(val, result_.at<float>(TEST_POINT), TEMPL_SIZE.area()*abs(val)*FLT_EPSILON); |
|
} |
|
|
|
INSTANTIATE_TEST_CASE_P(SingleChannelMask, Imgproc_MatchTemplateWithMask, |
|
Combine( |
|
Values(CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3), |
|
Values(CV_32FC1, CV_8UC1))); |
|
|
|
INSTANTIATE_TEST_CASE_P(MultiChannelMask, Imgproc_MatchTemplateWithMask, |
|
Combine( |
|
Values(CV_32FC3, CV_8UC3), |
|
Values(CV_32FC3, CV_8UC3))); |
|
|
|
class Imgproc_MatchTemplateWithMask2 : public TestWithParam<std::tuple<MatType,MatType, |
|
MatchTemplType>> |
|
{ |
|
protected: |
|
// Member functions inherited from ::testing::Test |
|
void SetUp() override; |
|
|
|
// Data members |
|
Mat img_; |
|
Mat templ_; |
|
Mat mask_; |
|
Mat result_withoutmask_; |
|
Mat result_withmask_; |
|
|
|
// Constants |
|
static const Size IMG_SIZE; |
|
static const Size TEMPL_SIZE; |
|
}; |
|
|
|
// Arbitraryly chosen test constants |
|
const Size Imgproc_MatchTemplateWithMask2::IMG_SIZE(160, 100); |
|
const Size Imgproc_MatchTemplateWithMask2::TEMPL_SIZE(21, 13); |
|
|
|
void Imgproc_MatchTemplateWithMask2::SetUp() |
|
{ |
|
int type = std::get<0>(GetParam()); |
|
int type_mask = std::get<1>(GetParam()); |
|
|
|
img_.create(IMG_SIZE, type); |
|
templ_.create(TEMPL_SIZE, type); |
|
mask_.create(TEMPL_SIZE, type_mask); |
|
|
|
randu(img_, 0, 100); |
|
randu(templ_, 0, 100); |
|
|
|
if (CV_MAT_DEPTH(type_mask) == CV_8U) |
|
{ |
|
// CV_8U implies binary mask, so all nonzero values should work |
|
randu(mask_, 1, 255); |
|
} |
|
else |
|
{ |
|
mask_ = Scalar(1, 1, 1, 1); |
|
} |
|
} |
|
|
|
TEST_P(Imgproc_MatchTemplateWithMask2, CompareWithAndWithoutMask) |
|
{ |
|
int method = std::get<2>(GetParam()); |
|
|
|
matchTemplate(img_, templ_, result_withmask_, method, mask_); |
|
matchTemplate(img_, templ_, result_withoutmask_, method); |
|
|
|
// Get maximum result for relative error calculation |
|
double min_val, max_val; |
|
minMaxLoc(abs(result_withmask_), &min_val, &max_val); |
|
|
|
// Get maximum of absolute diff for comparison |
|
double mindiff, maxdiff; |
|
minMaxLoc(abs(result_withmask_ - result_withoutmask_), &mindiff, &maxdiff); |
|
|
|
EXPECT_LT(maxdiff, max_val*TEMPL_SIZE.area()*FLT_EPSILON); |
|
} |
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(SingleChannelMask, Imgproc_MatchTemplateWithMask2, |
|
Combine( |
|
Values(CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3), |
|
Values(CV_32FC1, CV_8UC1), |
|
Values(CV_TM_SQDIFF, CV_TM_SQDIFF_NORMED, CV_TM_CCORR, CV_TM_CCORR_NORMED, |
|
CV_TM_CCOEFF, CV_TM_CCOEFF_NORMED))); |
|
|
|
INSTANTIATE_TEST_CASE_P(MultiChannelMask, Imgproc_MatchTemplateWithMask2, |
|
Combine( |
|
Values(CV_32FC3, CV_8UC3), |
|
Values(CV_32FC3, CV_8UC3), |
|
Values(CV_TM_SQDIFF, CV_TM_SQDIFF_NORMED, CV_TM_CCORR, CV_TM_CCORR_NORMED, |
|
CV_TM_CCOEFF, CV_TM_CCOEFF_NORMED))); |
|
|
|
}} // namespace
|
|
|