Commit 06738468 authored by Alexander Alekhin's avatar Alexander Alekhin Committed by Andrey Pavlenko

TAPI: stiching: add custom OpenCL kernels for MultiBandBlender

parent c22d92c1
...@@ -598,6 +598,8 @@ CV_EXPORTS int predictOptimalVectorWidth(InputArray src1, InputArray src2 = noAr ...@@ -598,6 +598,8 @@ CV_EXPORTS int predictOptimalVectorWidth(InputArray src1, InputArray src2 = noAr
InputArray src4 = noArray(), InputArray src5 = noArray(), InputArray src6 = noArray(), InputArray src4 = noArray(), InputArray src5 = noArray(), InputArray src6 = noArray(),
InputArray src7 = noArray(), InputArray src8 = noArray(), InputArray src9 = noArray()); InputArray src7 = noArray(), InputArray src8 = noArray(), InputArray src9 = noArray());
CV_EXPORTS void buildOptionsAddMatrixDescription(String& buildOptions, const String& name, InputArray _m);
class CV_EXPORTS Image2D class CV_EXPORTS Image2D
{ {
public: public:
......
...@@ -495,6 +495,11 @@ template<> inline std::string CommandLineParser::get<std::string>(const String& ...@@ -495,6 +495,11 @@ template<> inline std::string CommandLineParser::get<std::string>(const String&
} }
#endif // OPENCV_NOSTL #endif // OPENCV_NOSTL
#if !defined(OPENCV_SKIP_SUPPRESS_WARNING) || !OPENCV_SKIP_SUPPRESS_WARNING
// Use this to bypass "warning C4127: conditional expression is constant"
template <typename T> T SuppressWarning(T v) { return v; }
#endif
} //namespace cv } //namespace cv
#endif //__OPENCV_CORE_UTILITY_H__ #endif //__OPENCV_CORE_UTILITY_H__
...@@ -4404,7 +4404,24 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3, ...@@ -4404,7 +4404,24 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3,
#undef PROCESS_SRC #undef PROCESS_SRC
/////////////////////////////////////////// Image2D ////////////////////////////////////////////////////
// TODO Make this as a method of OpenCL "BuildOptions" class
void buildOptionsAddMatrixDescription(String& buildOptions, const String& name, InputArray _m)
{
if (!buildOptions.empty())
buildOptions += " ";
int type = _m.type(), depth = CV_MAT_DEPTH(type);
buildOptions += format(
"-D %s_T=%s -D %s_T1=%s -D %s_CN=%d -D %s_TSIZE=%d -D %s_T1SIZE=%d -D %s_DEPTH=%d",
name.c_str(), ocl::typeToStr(type),
name.c_str(), ocl::typeToStr(CV_MAKE_TYPE(depth, 1)),
name.c_str(), (int)CV_MAT_CN(type),
name.c_str(), (int)CV_ELEM_SIZE(type),
name.c_str(), (int)CV_ELEM_SIZE1(type),
name.c_str(), (int)depth
);
}
struct Image2D::Impl struct Image2D::Impl
{ {
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
#include "opencl_kernels.hpp"
namespace cv { namespace cv {
namespace detail { namespace detail {
...@@ -245,6 +246,31 @@ void MultiBandBlender::prepare(Rect dst_roi) ...@@ -245,6 +246,31 @@ void MultiBandBlender::prepare(Rect dst_roi)
} }
} }
#ifdef HAVE_OPENCL
static bool ocl_MultiBandBlender_feed(InputArray _src, InputArray _weight,
InputOutputArray _dst, InputOutputArray _dst_weight)
{
String buildOptions = "-D DEFINE_feed";
ocl::buildOptionsAddMatrixDescription(buildOptions, "src", _src);
ocl::buildOptionsAddMatrixDescription(buildOptions, "weight", _weight);
ocl::buildOptionsAddMatrixDescription(buildOptions, "dst", _dst);
ocl::buildOptionsAddMatrixDescription(buildOptions, "dstWeight", _dst_weight);
ocl::Kernel k("feed", ocl::stitching::multibandblend_oclsrc, buildOptions);
if (k.empty())
return false;
UMat src = _src.getUMat();
k.args(ocl::KernelArg::ReadOnly(src),
ocl::KernelArg::ReadOnly(_weight.getUMat()),
ocl::KernelArg::ReadWrite(_dst.getUMat()),
ocl::KernelArg::ReadWrite(_dst_weight.getUMat())
);
size_t globalsize[2] = {src.cols, src.rows };
return k.run(2, globalsize, NULL, false);
}
#endif
void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl)
{ {
...@@ -338,64 +364,62 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl) ...@@ -338,64 +364,62 @@ void MultiBandBlender::feed(InputArray _img, InputArray mask, Point tl)
int x_br = br_new.x - dst_roi_.x; int x_br = br_new.x - dst_roi_.x;
// Add weighted layer of the source image to the final Laplacian pyramid layer // Add weighted layer of the source image to the final Laplacian pyramid layer
if(weight_type_ == CV_32F)
{
for (int i = 0; i <= num_bands_; ++i) for (int i = 0; i <= num_bands_; ++i)
{
Rect rc(x_tl, y_tl, x_br - x_tl, y_br - y_tl);
CV_OPENCL_RUN(SuppressWarning(true),
ocl_MultiBandBlender_feed(src_pyr_laplace[i], weight_pyr_gauss[i],
dst_pyr_laplace_[i](rc),
dst_band_weights_[i](rc)),
goto next_band;)
{ {
Mat _src_pyr_laplace = src_pyr_laplace[i].getMat(ACCESS_READ); Mat _src_pyr_laplace = src_pyr_laplace[i].getMat(ACCESS_READ);
Mat _dst_pyr_laplace = dst_pyr_laplace_[i].getMat(ACCESS_RW); Mat _dst_pyr_laplace = dst_pyr_laplace_[i](rc).getMat(ACCESS_RW);
Mat _weight_pyr_gauss = weight_pyr_gauss[i].getMat(ACCESS_READ); Mat _weight_pyr_gauss = weight_pyr_gauss[i].getMat(ACCESS_READ);
Mat _dst_band_weights = dst_band_weights_[i].getMat(ACCESS_RW); Mat _dst_band_weights = dst_band_weights_[i](rc).getMat(ACCESS_RW);
for (int y = y_tl; y < y_br; ++y) if(weight_type_ == CV_32F)
{
for (int y = 0; y < rc.height; ++y)
{ {
int y_ = y - y_tl; const Point3_<short>* src_row = _src_pyr_laplace.ptr<Point3_<short> >(y);
const Point3_<short>* src_row = _src_pyr_laplace.ptr<Point3_<short> >(y_);
Point3_<short>* dst_row = _dst_pyr_laplace.ptr<Point3_<short> >(y); Point3_<short>* dst_row = _dst_pyr_laplace.ptr<Point3_<short> >(y);
const float* weight_row = _weight_pyr_gauss.ptr<float>(y_); const float* weight_row = _weight_pyr_gauss.ptr<float>(y);
float* dst_weight_row = _dst_band_weights.ptr<float>(y); float* dst_weight_row = _dst_band_weights.ptr<float>(y);
for (int x = x_tl; x < x_br; ++x) for (int x = 0; x < rc.width; ++x)
{ {
int x_ = x - x_tl; dst_row[x].x += static_cast<short>(src_row[x].x * weight_row[x]);
dst_row[x].x += static_cast<short>(src_row[x_].x * weight_row[x_]); dst_row[x].y += static_cast<short>(src_row[x].y * weight_row[x]);
dst_row[x].y += static_cast<short>(src_row[x_].y * weight_row[x_]); dst_row[x].z += static_cast<short>(src_row[x].z * weight_row[x]);
dst_row[x].z += static_cast<short>(src_row[x_].z * weight_row[x_]); dst_weight_row[x] += weight_row[x];
dst_weight_row[x] += weight_row[x_];
} }
} }
x_tl /= 2; y_tl /= 2;
x_br /= 2; y_br /= 2;
}
} }
else // weight_type_ == CV_16S else // weight_type_ == CV_16S
{ {
for (int i = 0; i <= num_bands_; ++i) for (int y = 0; y < y_br - y_tl; ++y)
{
Mat _src_pyr_laplace = src_pyr_laplace[i].getMat(ACCESS_READ);
Mat _dst_pyr_laplace = dst_pyr_laplace_[i].getMat(ACCESS_RW);
Mat _weight_pyr_gauss = weight_pyr_gauss[i].getMat(ACCESS_READ);
Mat _dst_band_weights = dst_band_weights_[i].getMat(ACCESS_RW);
for (int y = y_tl; y < y_br; ++y)
{ {
int y_ = y - y_tl; const Point3_<short>* src_row = _src_pyr_laplace.ptr<Point3_<short> >(y);
const Point3_<short>* src_row = _src_pyr_laplace.ptr<Point3_<short> >(y_);
Point3_<short>* dst_row = _dst_pyr_laplace.ptr<Point3_<short> >(y); Point3_<short>* dst_row = _dst_pyr_laplace.ptr<Point3_<short> >(y);
const short* weight_row = _weight_pyr_gauss.ptr<short>(y_); const short* weight_row = _weight_pyr_gauss.ptr<short>(y);
short* dst_weight_row = _dst_band_weights.ptr<short>(y); short* dst_weight_row = _dst_band_weights.ptr<short>(y);
for (int x = x_tl; x < x_br; ++x) for (int x = 0; x < x_br - x_tl; ++x)
{ {
int x_ = x - x_tl; dst_row[x].x += short((src_row[x].x * weight_row[x]) >> 8);
dst_row[x].x += short((src_row[x_].x * weight_row[x_]) >> 8); dst_row[x].y += short((src_row[x].y * weight_row[x]) >> 8);
dst_row[x].y += short((src_row[x_].y * weight_row[x_]) >> 8); dst_row[x].z += short((src_row[x].z * weight_row[x]) >> 8);
dst_row[x].z += short((src_row[x_].z * weight_row[x_]) >> 8); dst_weight_row[x] += weight_row[x];
dst_weight_row[x] += weight_row[x_];
} }
} }
}
}
#ifdef HAVE_OPENCL
next_band:
#endif
x_tl /= 2; y_tl /= 2; x_tl /= 2; y_tl /= 2;
x_br /= 2; y_br /= 2; x_br /= 2; y_br /= 2;
} }
}
LOGLN(" Add weighted layer of the source image to the final Laplacian pyramid layer, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec"); LOGLN(" Add weighted layer of the source image to the final Laplacian pyramid layer, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
} }
...@@ -411,10 +435,10 @@ void MultiBandBlender::blend(InputOutputArray dst, InputOutputArray dst_mask) ...@@ -411,10 +435,10 @@ void MultiBandBlender::blend(InputOutputArray dst, InputOutputArray dst_mask)
else else
restoreImageFromLaplacePyr(dst_pyr_laplace_); restoreImageFromLaplacePyr(dst_pyr_laplace_);
dst_ = dst_pyr_laplace_[0]; Rect dst_rc(0, 0, dst_roi_final_.width, dst_roi_final_.height);
dst_ = dst_(Range(0, dst_roi_final_.height), Range(0, dst_roi_final_.width)); dst_ = dst_pyr_laplace_[0](dst_rc);
UMat _dst_mask; UMat _dst_mask;
compare(dst_band_weights_[0](Range(0, dst_roi_final_.height), Range(0, dst_roi_final_.width)), WEIGHT_EPS, dst_mask_, CMP_GT); compare(dst_band_weights_[0](dst_rc), WEIGHT_EPS, dst_mask_, CMP_GT);
dst_pyr_laplace_.clear(); dst_pyr_laplace_.clear();
dst_band_weights_.clear(); dst_band_weights_.clear();
...@@ -425,12 +449,38 @@ void MultiBandBlender::blend(InputOutputArray dst, InputOutputArray dst_mask) ...@@ -425,12 +449,38 @@ void MultiBandBlender::blend(InputOutputArray dst, InputOutputArray dst_mask)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Auxiliary functions // Auxiliary functions
#ifdef HAVE_OPENCL
static bool ocl_normalizeUsingWeightMap(InputArray _weight, InputOutputArray _mat)
{
String buildOptions = "-D DEFINE_normalizeUsingWeightMap";
ocl::buildOptionsAddMatrixDescription(buildOptions, "mat", _mat);
ocl::buildOptionsAddMatrixDescription(buildOptions, "weight", _weight);
ocl::Kernel k("normalizeUsingWeightMap", ocl::stitching::multibandblend_oclsrc, buildOptions);
if (k.empty())
return false;
UMat mat = _mat.getUMat();
k.args(ocl::KernelArg::ReadWrite(mat),
ocl::KernelArg::ReadOnly(_weight.getUMat())
);
size_t globalsize[2] = {mat.cols, mat.rows };
return k.run(2, globalsize, NULL, false);
}
#endif
void normalizeUsingWeightMap(InputArray _weight, InputOutputArray _src) void normalizeUsingWeightMap(InputArray _weight, InputOutputArray _src)
{ {
#ifdef HAVE_TEGRA_OPTIMIZATION #ifdef HAVE_TEGRA_OPTIMIZATION
if(tegra::normalizeUsingWeightMap(weight, src)) if(tegra::normalizeUsingWeightMap(weight, src))
return; return;
#endif #endif
CV_OPENCL_RUN(SuppressWarning(true),
ocl_normalizeUsingWeightMap(_weight, _src),
return;)
{
Mat weight = _weight.getMat(); Mat weight = _weight.getMat();
Mat src = _src.getMat(); Mat src = _src.getMat();
...@@ -469,6 +519,7 @@ void normalizeUsingWeightMap(InputArray _weight, InputOutputArray _src) ...@@ -469,6 +519,7 @@ void normalizeUsingWeightMap(InputArray _weight, InputOutputArray _src)
} }
} }
} }
}
} }
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment