mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 04:43:22 -05:00
Merge pull request #29071 from zitonwei:fix-masked-ccoeff-normed-constant-template
imgproc: avoid NaN in masked TM_CCOEFF_NORMED for constant templates - #29071 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake ### Summary Fixes #23257. This patch handles a degenerate masked `TM_CCOEFF_NORMED` case in `matchTemplate()`. When the template is constant over the effective mask area, the template norm can become zero or NaN, which may propagate NaN/Inf values into the result. The masked path now returns all ones for this case, matching the existing behavior of the unmasked `TM_CCOEFF_NORMED` implementation for constant templates. ### Tests - `cmake --build build_project4 --target opencv_test_imgproc -j4` - `./build_project4/bin/opencv_test_imgproc '--gtest_filter=Imgproc_MatchTemplateWithMask.regression_23257_constant_template'` - `./build_project4/bin/opencv_test_imgproc '--gtest_filter=*MatchTemplate*'` The MatchTemplate-related test filter ran 147 tests successfully.
This commit is contained in:
@@ -869,6 +869,11 @@ static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _
|
||||
// norm(T')
|
||||
double norm_templx = norm(mask.mul(templ - sum(mask.mul(templ)).div(mask_sum)),
|
||||
NORM_L2);
|
||||
if (norm_templx < DBL_EPSILON || cvIsNaN(norm_templx))
|
||||
{
|
||||
result = Scalar::all(1);
|
||||
return;
|
||||
}
|
||||
// norm(I') = sqrt{ CCorr(I^2, M^2) - 2*CCorr(I, M^2)/sum(M)*CCorr(I, M)
|
||||
// + sum(M^2)*CCorr(I, M)^2/sum(M)^2 }
|
||||
// = sqrt{ CCorr(I^2, M^2)
|
||||
|
||||
@@ -287,4 +287,45 @@ TEST(Imgproc_MatchTemplateWithMask, bug_26389) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef testing::tuple<MatType, MatType, Scalar> ConstantTemplateParams;
|
||||
|
||||
typedef testing::TestWithParam<ConstantTemplateParams> ConstantTemplateWithMask;
|
||||
|
||||
TEST_P(ConstantTemplateWithMask, regression_23257)
|
||||
{
|
||||
int type = std::get<0>(GetParam());
|
||||
int maskType = std::get<1>(GetParam());
|
||||
Scalar templValue = std::get<2>(GetParam());
|
||||
|
||||
Mat image(Size(16, 16), type);
|
||||
randu(image, 0, 255);
|
||||
|
||||
const Mat templ(Size(3, 3), type, templValue);
|
||||
Mat mask = Mat::ones(templ.size(), maskType);
|
||||
mask(Rect(1, 0, 1, 3)) = Scalar::all(0);
|
||||
|
||||
Mat result;
|
||||
matchTemplate(image, templ, result, TM_CCOEFF_NORMED, mask);
|
||||
|
||||
for (int y = 0; y < result.rows; ++y)
|
||||
{
|
||||
for (int x = 0; x < result.cols; ++x)
|
||||
{
|
||||
const float value = result.at<float>(y, x);
|
||||
EXPECT_FALSE(cvIsNaN(value));
|
||||
EXPECT_FALSE(cvIsInf(value));
|
||||
EXPECT_EQ(1.0f, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ConstantTemplateParams> ctparams = {
|
||||
{CV_8UC1, CV_8UC1, Scalar::all(1)},
|
||||
{CV_32FC1, CV_32FC1, Scalar::all(3.5)},
|
||||
{CV_8UC3, CV_8UC1, Scalar(1, 2, 3)},
|
||||
{CV_32FC3, CV_32FC3, Scalar(1.5, 2.5, 3.5)}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, ConstantTemplateWithMask, testing::ValuesIn(ctparams));
|
||||
|
||||
}} // namespace
|
||||
|
||||
Reference in New Issue
Block a user