improved cv::matchTemplate OpenCL part

This commit is contained in:
Ilya Lavrenov
2014-02-22 00:43:03 +04:00
parent 0a90d6dde6
commit 0ef16125ae
3 changed files with 372 additions and 316 deletions

View File

@@ -40,6 +40,7 @@
//M*/
#include "precomp.hpp"
#define CV_OPENCL_RUN_ASSERT
#include "opencl_kernels.hpp"
////////////////////////////////////////////////// matchTemplate //////////////////////////////////////////////////////////
@@ -49,80 +50,87 @@ namespace cv
#ifdef HAVE_OPENCL
static bool useNaive(int method, int depth, const Size & size)
{
#ifdef HAVE_CLAMDFFT
if (method == TM_SQDIFF && depth == CV_32F)
return true;
else if(method == TM_CCORR || (method == TM_SQDIFF && depth == CV_8U))
return size.height < 18 && size.width < 18;
else
return false;
#else
(void)(method);
(void)(depth);
(void)(size);
return true;
#endif
}
/////////////////////////////////////////////////// CCORR //////////////////////////////////////////////////////////////
enum
{
SUM_1 = 0, SUM_2 = 1
};
static bool sumTemplate(InputArray _templ, UMat & result, int sum_type)
{
CV_Assert(sum_type == SUM_1 || sum_type == SUM_2);
int type = _templ.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
int wdepth = std::max(CV_32S, depth), wtype = CV_MAKE_TYPE(wdepth, cn);
char cvt[40];
const char * const sumTypeToStr[] = { "SUM_1", "SUM_2" };
ocl::Kernel k("calcSum", ocl::imgproc::match_template_oclsrc,
format("-D CALC_SUM -D %s -D T=%s -D WT=%s -D convertToWT=%s -D cn=%d -D wdepth=%d",
sumTypeToStr[sum_type], ocl::typeToStr(type), ocl::typeToStr(wtype),
ocl::convertTypeStr(depth, wdepth, cn, cvt), cn, wdepth));
if (k.empty())
return false;
result.create(1, 1, CV_32FC1);
UMat templ = _templ.getUMat();
k.args(ocl::KernelArg::ReadOnly(templ), ocl::KernelArg::PtrWriteOnly(result));
return k.runTask(false);
}
static bool matchTemplateNaive_CCORR(InputArray _image, InputArray _templ, OutputArray _result)
{
int type = _image.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
int wdepth = std::max(depth, CV_32S), wtype = CV_MAKE_TYPE(wdepth, cn);
char cvt[40];
ocl::Kernel k("matchTemplate_Naive_CCORR", ocl::imgproc::match_template_oclsrc,
format("-D type=%s -D elem_type=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), cn));
format("-D CCORR -D T=%s -D WT=%s -D convertToWT=%s -D cn=%d -D wdepth=%d", ocl::typeToStr(type), ocl::typeToStr(wtype),
ocl::convertTypeStr(depth, wdepth, cn, cvt), cn, wdepth));
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);
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
UMat result = _result.getUMat();
k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ),
ocl::KernelArg::WriteOnly(result));
size_t globalsize[2] = { result.cols, result.rows };
return k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ),
ocl::KernelArg::WriteOnly(result)).run(2, globalsize, NULL, false);
return k.run(2, globalsize, NULL, false);
}
static bool matchTemplate_CCORR_NORMED(InputArray _image, InputArray _templ, OutputArray _result)
{
matchTemplate(_image, _templ, _result, CV_TM_CCORR);
int type = _image.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
int type = _image.type(), cn = CV_MAT_CN(type);
ocl::Kernel k("matchTemplate_CCORR_NORMED", ocl::imgproc::match_template_oclsrc,
format("-D type=%s -D elem_type=%s -D cn=%d", ocl::typeToStr(type),
ocl::typeToStr(depth), cn));
format("-D CCORR_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);
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
UMat result = _result.getUMat();
UMat image_sums, image_sqsums;
integral(image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F);
UMat temp;
multiply(templ, templ, temp, 1, CV_32F);
Scalar s = sum(temp);
float templ_sqsum = 0;
for (int i = 0; i < cn; ++i)
templ_sqsum += static_cast<float>(s[i]);
UMat templ_sqsum;
if (!sumTemplate(templ, templ_sqsum, SUM_2))
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] = { result.cols, result.rows };
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result),
templ.rows, templ.cols, templ_sqsum).run(2, globalsize, NULL, false);
}
static bool matchTemplate_CCORR(InputArray _image, InputArray _templ, OutputArray _result)
{
if (useNaive(TM_CCORR, _image.depth(), _templ.size()) )
return matchTemplateNaive_CCORR(_image, _templ, _result);
else
return false;
return k.run(2, globalsize, NULL, false);
}
////////////////////////////////////// SQDIFF //////////////////////////////////////////////////////////////
@@ -130,10 +138,12 @@ static bool matchTemplate_CCORR(InputArray _image, InputArray _templ, OutputArra
static bool matchTemplateNaive_SQDIFF(InputArray _image, InputArray _templ, OutputArray _result)
{
int type = _image.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
int wdepth = std::max(depth, CV_32S), wtype = CV_MAKE_TYPE(wdepth, cn);
char cvt[40];
ocl::Kernel k("matchTemplate_Naive_SQDIFF", ocl::imgproc::match_template_oclsrc,
format("-D type=%s -D elem_type=%s -D cn=%d", ocl::typeToStr(type),
ocl::typeToStr(depth), cn));
format("-D SQDIFF -D T=%s -D WT=%s -D convertToWT=%s -D cn=%d -D wdepth=%d", ocl::typeToStr(type),
ocl::typeToStr(wtype), ocl::convertTypeStr(depth, wdepth, cn, cvt), cn, wdepth));
if (k.empty())
return false;
@@ -141,20 +151,21 @@ static bool matchTemplateNaive_SQDIFF(InputArray _image, InputArray _templ, Outp
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32F);
UMat result = _result.getUMat();
k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ),
ocl::KernelArg::WriteOnly(result));
size_t globalsize[2] = { result.cols, result.rows };
return k.args(ocl::KernelArg::ReadOnlyNoSize(image), ocl::KernelArg::ReadOnly(templ),
ocl::KernelArg::WriteOnly(result)).run(2, globalsize, NULL, false);
return k.run(2, globalsize, NULL, false);
}
static bool matchTemplate_SQDIFF_NORMED(InputArray _image, InputArray _templ, OutputArray _result)
{
matchTemplate(_image, _templ, _result, CV_TM_CCORR);
int type = _image.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
int type = _image.type(), cn = CV_MAT_CN(type);
ocl::Kernel k("matchTemplate_SQDIFF_NORMED", ocl::imgproc::match_template_oclsrc,
format("-D type=%s -D elem_type=%s -D cn=%d",
ocl::typeToStr(type), ocl::typeToStr(depth), cn));
format("-D SQDIFF_NORMED -D T=%s -D cn=%d", ocl::typeToStr(type), cn));
if (k.empty())
return false;
@@ -165,24 +176,15 @@ static bool matchTemplate_SQDIFF_NORMED(InputArray _image, InputArray _templ, Ou
UMat image_sums, image_sqsums;
integral(image.reshape(1), image_sums, image_sqsums, CV_32F, CV_32F);
UMat temp;
multiply(templ, templ, temp, 1, CV_32F);
Scalar s = sum(temp);
float templ_sqsum = 0;
for (int i = 0; i < cn; ++i)
templ_sqsum += (float)s[i];
UMat templ_sqsum;
if (!sumTemplate(_templ, templ_sqsum, SUM_2))
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] = { result.cols, result.rows };
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sqsums), ocl::KernelArg::ReadWrite(result),
templ.rows, templ.cols, templ_sqsum).run(2, globalsize, NULL, false);
}
static bool matchTemplate_SQDIFF(InputArray _image, InputArray _templ, OutputArray _result)
{
if (useNaive(TM_SQDIFF, _image.depth(), _templ.size()))
return matchTemplateNaive_SQDIFF(_image, _templ, _result);
else
return false;
return k.run(2, globalsize, NULL, false);
}
///////////////////////////////////// CCOEFF /////////////////////////////////////////////////////////////////
@@ -194,15 +196,15 @@ static bool matchTemplate_CCOEFF(InputArray _image, InputArray _templ, OutputArr
UMat image_sums, temp;
integral(_image, temp);
if(temp.depth() == CV_64F)
if (temp.depth() == CV_64F)
temp.convertTo(image_sums, CV_32F);
else
image_sums = temp;
int type = image_sums.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
ocl::Kernel k(cv::format("matchTemplate_Prepared_CCOEFF_C%d", cn).c_str(), ocl::imgproc::match_template_oclsrc,
format("-D type=%s -D elem_type=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), cn));
ocl::Kernel k("matchTemplate_Prepared_CCOEFF", ocl::imgproc::match_template_oclsrc,
format("-D CCOEFF -D T=%s -D elem_type=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), cn));
if (k.empty())
return false;
@@ -211,25 +213,28 @@ static bool matchTemplate_CCOEFF(InputArray _image, InputArray _templ, OutputArr
_result.create(size.height - templ.rows + 1, size.width - templ.cols + 1, CV_32F);
UMat result = _result.getUMat();
size_t globalsize[2] = { result.cols, result.rows };
if (cn == 1)
{
float templ_sum = static_cast<float>(sum(_templ)[0]) / tsize.area();
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result),
templ.rows, templ.cols, templ_sum).run(2, globalsize, NULL, false);
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result),
templ.rows, templ.cols, templ_sum);
}
else
{
Vec4f templ_sum = Vec4f::all(0);
templ_sum = sum(templ) / tsize.area();
if (cn == 2)
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols,
templ_sum[0], templ_sum[1]).run(2, globalsize, NULL, false);
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols,
templ_sum[0], templ_sum[1], templ_sum[2], templ_sum[3]).run(2, globalsize, NULL, false);
if (cn == 2)
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols,
templ_sum[0], templ_sum[1]);
else
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols,
templ_sum[0], templ_sum[1], templ_sum[2], templ_sum[3]);
}
size_t globalsize[2] = { result.cols, result.rows };
return k.run(2, globalsize, NULL, false);
}
static bool matchTemplate_CCOEFF_NORMED(InputArray _image, InputArray _templ, OutputArray _result)
@@ -241,8 +246,8 @@ static bool matchTemplate_CCOEFF_NORMED(InputArray _image, InputArray _templ, Ou
int type = image_sums.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
ocl::Kernel k(format("matchTemplate_CCOEFF_NORMED_C%d", cn).c_str(), ocl::imgproc::match_template_oclsrc,
format("-D type=%s -D elem_type=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), cn));
ocl::Kernel k("matchTemplate_CCOEFF_NORMED", ocl::imgproc::match_template_oclsrc,
format("-D CCOEFF_NORMED -D type=%s -D elem_type=%s -D cn=%d", ocl::typeToStr(type), ocl::typeToStr(depth), cn));
if (k.empty())
return false;
@@ -251,7 +256,6 @@ static bool matchTemplate_CCOEFF_NORMED(InputArray _image, InputArray _templ, Ou
_result.create(size.height - templ.rows + 1, size.width - templ.cols + 1, CV_32F);
UMat result = _result.getUMat();
size_t globalsize[2] = { result.cols, result.rows };
float scale = 1.f / tsize.area();
if (cn == 1)
@@ -270,9 +274,8 @@ static bool matchTemplate_CCOEFF_NORMED(InputArray _image, InputArray _templ, Ou
return true;
}
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums),
ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale, templ_sum, templ_sqsum)
.run(2,globalsize,NULL,false);
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums),
ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale, templ_sum, templ_sqsum);
}
else
{
@@ -295,15 +298,17 @@ static bool matchTemplate_CCOEFF_NORMED(InputArray _image, InputArray _templ, Ou
}
if (cn == 2)
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums),
ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale,
templ_sum[0], templ_sum[1], templ_sqsum_sum).run(2, globalsize, NULL, false);
return k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums),
ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale,
templ_sum[0], templ_sum[1], templ_sum[2], templ_sum[3],
templ_sqsum_sum).run(2, globalsize, NULL, false);
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums),
ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale,
templ_sum[0], templ_sum[1], templ_sqsum_sum);
else
k.args(ocl::KernelArg::ReadOnlyNoSize(image_sums), ocl::KernelArg::ReadOnlyNoSize(image_sqsums),
ocl::KernelArg::ReadWrite(result), templ.rows, templ.cols, scale,
templ_sum[0], templ_sum[1], templ_sum[2], templ_sum[3], templ_sqsum_sum);
}
size_t globalsize[2] = { result.cols, result.rows };
return k.run(2, globalsize, NULL, false);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -319,7 +324,7 @@ static bool ocl_matchTemplate( InputArray _img, InputArray _templ, OutputArray _
static const Caller callers[] =
{
matchTemplate_SQDIFF, matchTemplate_SQDIFF_NORMED, matchTemplate_CCORR,
matchTemplateNaive_SQDIFF, matchTemplate_SQDIFF_NORMED, matchTemplateNaive_CCORR,
matchTemplate_CCORR_NORMED, matchTemplate_CCOEFF, matchTemplate_CCOEFF_NORMED
};
const Caller caller = callers[method];