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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user