1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00

Merge pull request #29466 from Akansha-977:templatematch_IPP_5.x

Extracting IPP to HAL for matchTemplate function in 5.x #29466

### 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
This commit is contained in:
Akansha-977
2026-07-15 15:04:01 +05:30
committed by GitHub
parent 60c705e93b
commit 8ee67ccb65
2 changed files with 47 additions and 100 deletions
+3 -2
View File
@@ -132,8 +132,9 @@ int ipp_hal_matchTemplate(const uchar* src_data, size_t src_step, int src_width,
else if(method == cv::TM_SQDIFF_NORMED || method == cv::TM_CCORR ||
method == cv::TM_CCOEFF || method == cv::TM_CCOEFF_NORMED)
{
// Raw cross-correlation; caller finishes SQDIFF_NORMED/CCOEFF/CCOEFF_NORMED via
// common_matchTemplate (TM_CCORR is already final).
// Raw cross-correlation only. TM_CCORR is already the final result; the caller
// (cv::matchTemplate) runs common_matchTemplate() to finish TM_SQDIFF_NORMED /
// TM_CCOEFF / TM_CCOEFF_NORMED.
if(ipp_crossCorr(img, templ, result, false))
return CV_HAL_ERROR_OK;
}
+44 -98
View File
@@ -47,6 +47,12 @@
namespace cv
{
static inline Size matchResultSize(Size imageSize, Size templSize)
{
return Size(imageSize.width - templSize.width + 1,
imageSize.height - templSize.height + 1);
}
#ifdef HAVE_OPENCL
/////////////////////////////////////////////////// CCORR //////////////////////////////////////////////////////////////
@@ -234,7 +240,7 @@ static bool convolve_dft(InputArray _image, InputArray _templ, OutputArray _resu
static bool convolve_32F(InputArray _image, InputArray _templ, OutputArray _result)
{
_result.create(_image.rows() - _templ.rows() + 1, _image.cols() - _templ.cols() + 1, CV_32F);
_result.create(matchResultSize(_image.size(), _templ.size()), CV_32F);
if (_image.channels() == 1)
return(convolve_dft(_image, _templ, _result));
@@ -280,7 +286,7 @@ static bool matchTemplateNaive_CCORR(InputArray _image, InputArray _templ, Outpu
return false;
UMat image = _image.getUMat(), templ = _templ.getUMat();
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
_result.create(matchResultSize(image.size(), templ.size()), CV_32FC1);
UMat result = _result.getUMat();
k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ),
@@ -313,26 +319,27 @@ static bool matchTemplate_CCORR(InputArray _image, InputArray _templ, OutputArra
}
}
static bool matchTemplate_CCORR_NORMED(InputArray _image, InputArray _templ, OutputArray _result)
static bool matchTemplatePrepared(InputArray _image, InputArray _templ, OutputArray _result,
const char* kernelName, const char* buildDef)
{
matchTemplate(_image, _templ, _result, cv::TM_CCORR);
int type = _image.type(), cn = CV_MAT_CN(type);
ocl::Kernel k("matchTemplate_CCORR_NORMED", ocl::imgproc::match_template_oclsrc,
format("-D CCORR_NORMED -D T=%s -D cn=%d", ocl::typeToStr(type), cn));
ocl::Kernel k(kernelName, ocl::imgproc::match_template_oclsrc,
format("-D %s -D T=%s -D cn=%d", buildDef, ocl::typeToStr(type), cn));
if (k.empty())
return false;
UMat image = _image.getUMat(), templ = _templ.getUMat();
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
_result.create(matchResultSize(image.size(), templ.size()), CV_32F);
UMat result = _result.getUMat();
UMat image_sums, image_sqsums;
integral(image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F);
UMat templ_sqsum;
if (!sumTemplate(templ, templ_sqsum))
if (!sumTemplate(_templ, templ_sqsum))
return false;
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result),
@@ -342,6 +349,11 @@ static bool matchTemplate_CCORR_NORMED(InputArray _image, InputArray _templ, Out
return k.run(2, globalsize, NULL, false);
}
static bool matchTemplate_CCORR_NORMED(InputArray _image, InputArray _templ, OutputArray _result)
{
return matchTemplatePrepared(_image, _templ, _result, "matchTemplate_CCORR_NORMED", "CCORR_NORMED");
}
////////////////////////////////////// SQDIFF //////////////////////////////////////////////////////////////
static bool matchTemplateNaive_SQDIFF(InputArray _image, InputArray _templ, OutputArray _result)
@@ -357,7 +369,7 @@ static bool matchTemplateNaive_SQDIFF(InputArray _image, InputArray _templ, Outp
return false;
UMat image = _image.getUMat(), templ = _templ.getUMat();
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F);
_result.create(matchResultSize(image.size(), templ.size()), CV_32F);
UMat result = _result.getUMat();
k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ),
@@ -372,64 +384,12 @@ static bool matchTemplate_SQDIFF(InputArray _image, InputArray _templ, OutputArr
if (useNaive(_templ.size()))
return( matchTemplateNaive_SQDIFF(_image, _templ, _result));
else
{
matchTemplate(_image, _templ, _result, cv::TM_CCORR);
int type = _image.type(), cn = CV_MAT_CN(type);
ocl::Kernel k("matchTemplate_Prepared_SQDIFF", ocl::imgproc::match_template_oclsrc,
format("-D SQDIFF_PREPARED -D T=%s -D cn=%d", ocl::typeToStr(type), cn));
if (k.empty())
return false;
UMat image = _image.getUMat(), templ = _templ.getUMat();
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F);
UMat result = _result.getUMat();
UMat image_sums, image_sqsums;
integral(image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F);
UMat templ_sqsum;
if (!sumTemplate(_templ, templ_sqsum))
return false;
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result),
templ.rows, templ.cols, ocl::KernelArg::PtrReadOnly(templ_sqsum));
size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows };
return k.run(2, globalsize, NULL, false);
}
return matchTemplatePrepared(_image, _templ, _result, "matchTemplate_Prepared_SQDIFF", "SQDIFF_PREPARED");
}
static bool matchTemplate_SQDIFF_NORMED(InputArray _image, InputArray _templ, OutputArray _result)
{
matchTemplate(_image, _templ, _result, cv::TM_CCORR);
int type = _image.type(), cn = CV_MAT_CN(type);
ocl::Kernel k("matchTemplate_SQDIFF_NORMED", ocl::imgproc::match_template_oclsrc,
format("-D SQDIFF_NORMED -D T=%s -D cn=%d", ocl::typeToStr(type), cn));
if (k.empty())
return false;
UMat image = _image.getUMat(), templ = _templ.getUMat();
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F);
UMat result = _result.getUMat();
UMat image_sums, image_sqsums;
integral(image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F);
UMat templ_sqsum;
if (!sumTemplate(_templ, templ_sqsum))
return false;
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result),
templ.rows, templ.cols, ocl::KernelArg::PtrReadOnly(templ_sqsum));
size_t globalsize[2] = { (size_t)result.cols, (size_t)result.rows };
return k.run(2, globalsize, NULL, false);
return matchTemplatePrepared(_image, _templ, _result, "matchTemplate_SQDIFF_NORMED", "SQDIFF_NORMED");
}
///////////////////////////////////// CCOEFF /////////////////////////////////////////////////////////////////
@@ -486,7 +446,7 @@ static bool matchTemplate_CCOEFF_NORMED(InputArray _image, InputArray _templ, Ou
UMat templ = _templ.getUMat();
Size size = _image.size(), tsize = templ.size();
_result.create(size.height - templ.rows + 1, size.width - templ.cols + 1, CV_32F);
_result.create(matchResultSize(size, tsize), CV_32F);
UMat result = _result.getUMat();
float scale = 1.f / tsize.area();
@@ -758,6 +718,20 @@ void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
}
}
static void crossCorrImgSq( const Mat& img, const Mat& mask2, Mat& dst )
{
crossCorr(img.mul(img), mask2, dst, Point(0, 0), 0, 0);
}
static Mat sumChannels( const Mat& e, int rows )
{
if (e.channels() == 1)
return e;
Mat r = e.reshape(1, e.rows * e.cols);
reduce(r, r, 1, REDUCE_SUM);
return r.reshape(1, rows);
}
static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _result, int method, InputArray _mask )
{
CV_Assert(_mask.depth() == CV_8U || _mask.depth() == CV_32F);
@@ -783,7 +757,7 @@ static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _
maskBin.convertTo(mask, CV_32F);
}
Size corrSize(img.cols - templ.cols + 1, img.rows - templ.rows + 1);
Size corrSize = matchResultSize(img.size(), templ.size());
_result.create(corrSize, CV_32F);
Mat result = _result.getMat();
@@ -798,12 +772,11 @@ static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _
if (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED)
{
Mat temp_result(corrSize, CV_32F);
Mat img2 = img.mul(img);
Mat mask2 = mask.mul(mask);
// If the mul() is ever unnested, declare MatExpr, *not* Mat, to be more efficient.
// NORM_L2SQR calculates sum of squares
double templ2_mask2_sum = norm(templ.mul(mask), NORM_L2SQR);
crossCorr(img2, mask2, temp_result, Point(0,0), 0, 0);
crossCorrImgSq(img, mask2, temp_result);
crossCorr(img, templ.mul(mask2), result, Point(0,0), 0, 0);
// result and temp_result should not be switched, because temp_result is potentially needed
// for normalization.
@@ -824,11 +797,10 @@ static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _
if (method == cv::TM_CCORR_NORMED)
{
Mat temp_result(corrSize, CV_32F);
Mat img2 = img.mul(img);
Mat mask2 = mask.mul(mask);
// NORM_L2SQR calculates sum of squares
double templ2_mask2_sum = norm(templ.mul(mask), NORM_L2SQR);
crossCorr( img2, mask2, temp_result, Point(0,0), 0, 0 );
crossCorrImgSq(img, mask2, temp_result);
sqrt(templ2_mask2_sum * temp_result, temp_result);
result /= temp_result;
}
@@ -851,19 +823,7 @@ static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _
// It does not matter what to use Mat/MatExpr, it should be evaluated to perform assign subtraction
Mat temp_res;
multiply(img_mask_corr, sum(templx_mask).div(mask_sum), temp_res);
if (img.channels() == 1)
{
result -= temp_res;
}
else
{
// Sum channels of expression
temp_res = temp_res.reshape(1, result.rows * result.cols);
// channels are now columns
reduce(temp_res, temp_res, 1, REDUCE_SUM);
// transform back, but now with only one channel
result -= temp_res.reshape(1, result.rows);
}
result -= sumChannels(temp_res, result.rows);
if (method == cv::TM_CCOEFF_NORMED)
{
// norm(T')
@@ -875,31 +835,17 @@ static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _
// + CCorr(I, M)/sum(M)*{ sum(M^2) / sum(M) * CCorr(I,M)
// - 2 * CCorr(I, M^2) } }
Mat norm_imgx(corrSize, CV_32F);
Mat img2 = img.mul(img);
Mat mask2 = mask.mul(mask);
Scalar mask2_sum = sum(mask2);
Mat img_mask2_corr(corrSize, img.type());
crossCorr(img2, mask2, norm_imgx, Point(0,0), 0, 0);
crossCorrImgSq(img, mask2, norm_imgx);
crossCorr(img, mask2, img_mask2_corr, Point(0,0), 0, 0);
Mat temp_res1;
multiply(img_mask_corr, Scalar(1.0, 1.0, 1.0, 1.0).div(mask_sum), temp_res1);
Mat temp_res2;
multiply(img_mask_corr, mask2_sum.div(mask_sum), temp_res2);
temp_res = temp_res1.mul(temp_res2 - 2 * img_mask2_corr);
if (img.channels() == 1)
{
norm_imgx += temp_res;
}
else
{
// Sum channels of expression
temp_res = temp_res.reshape(1, result.rows*result.cols);
// channels are now columns
// reduce sums columns (= channels)
reduce(temp_res, temp_res, 1, REDUCE_SUM);
// transform back, but now with only one channel
norm_imgx += temp_res.reshape(1, result.rows);
}
norm_imgx += sumChannels(temp_res, result.rows);
sqrt(norm_imgx, norm_imgx);
result /= norm_imgx * norm_templx;
}
@@ -1063,7 +1009,7 @@ void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result,
if (needswap)
std::swap(img, templ);
Size corrSize(img.cols - templ.cols + 1, img.rows - templ.rows + 1);
Size corrSize = matchResultSize(img.size(), templ.size());
_result.create(corrSize, CV_32F);
Mat result = _result.getMat();