Commit 9a8dbfd5 authored by Alexander Alekhin's avatar Alexander Alekhin

imgproc: dispatch filter.cpp

parent 756a98a3
set(the_description "Image Processing")
ocv_add_dispatched_file(accum SSE4_1 AVX AVX2)
ocv_add_dispatched_file(filter SSE2 SSE4_1 AVX2)
ocv_add_dispatched_file(color_hsv SSE2 SSE4_1 AVX2)
ocv_add_dispatched_file(color_rgb SSE2 SSE4_1 AVX2)
ocv_add_dispatched_file(color_yuv SSE2 SSE4_1 AVX2)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -56,6 +56,8 @@ namespace cv
InputArray _kernelX, InputArray _kernelY, Point anchor,
double delta, int borderType );
#endif
void preprocess2DKernel(const Mat& kernel, std::vector<Point>& coords, std::vector<uchar>& coeffs);
}
#endif
......
......@@ -41,160 +41,85 @@
//M*/
#include "precomp.hpp"
#include "opencv2/core/opencl/ocl_defs.hpp"
#include "opencl_kernels_imgproc.hpp"
#include "hal_replacement.hpp"
#include "opencv2/core/hal/intrin.hpp"
#include "filter.hpp"
/****************************************************************************************\
Base Image Filter
\****************************************************************************************/
#if defined(CV_CPU_BASELINE_MODE)
#if IPP_VERSION_X100 >= 710
#define USE_IPP_SEP_FILTERS 1
#else
#undef USE_IPP_SEP_FILTERS
#endif
#endif
namespace cv
{
BaseRowFilter::BaseRowFilter() { ksize = anchor = -1; }
BaseRowFilter::~BaseRowFilter() {}
BaseColumnFilter::BaseColumnFilter() { ksize = anchor = -1; }
BaseColumnFilter::~BaseColumnFilter() {}
void BaseColumnFilter::reset() {}
BaseFilter::BaseFilter() { ksize = Size(-1,-1); anchor = Point(-1,-1); }
BaseFilter::~BaseFilter() {}
void BaseFilter::reset() {}
FilterEngine::FilterEngine()
: srcType(-1), dstType(-1), bufType(-1), maxWidth(0), wholeSize(-1, -1), dx1(0), dx2(0),
rowBorderType(BORDER_REPLICATE), columnBorderType(BORDER_REPLICATE),
borderElemSize(0), bufStep(0), startY(0), startY0(0), endY(0), rowCount(0), dstY(0)
{
}
FilterEngine::FilterEngine( const Ptr<BaseFilter>& _filter2D,
const Ptr<BaseRowFilter>& _rowFilter,
const Ptr<BaseColumnFilter>& _columnFilter,
int _srcType, int _dstType, int _bufType,
int _rowBorderType, int _columnBorderType,
const Scalar& _borderValue )
: srcType(-1), dstType(-1), bufType(-1), maxWidth(0), wholeSize(-1, -1), dx1(0), dx2(0),
rowBorderType(BORDER_REPLICATE), columnBorderType(BORDER_REPLICATE),
borderElemSize(0), bufStep(0), startY(0), startY0(0), endY(0), rowCount(0), dstY(0)
{
init(_filter2D, _rowFilter, _columnFilter, _srcType, _dstType, _bufType,
_rowBorderType, _columnBorderType, _borderValue);
}
FilterEngine::~FilterEngine()
{
}
void FilterEngine::init( const Ptr<BaseFilter>& _filter2D,
const Ptr<BaseRowFilter>& _rowFilter,
const Ptr<BaseColumnFilter>& _columnFilter,
int _srcType, int _dstType, int _bufType,
int _rowBorderType, int _columnBorderType,
const Scalar& _borderValue )
{
_srcType = CV_MAT_TYPE(_srcType);
_bufType = CV_MAT_TYPE(_bufType);
_dstType = CV_MAT_TYPE(_dstType);
srcType = _srcType;
int srcElemSize = (int)getElemSize(srcType);
dstType = _dstType;
bufType = _bufType;
filter2D = _filter2D;
rowFilter = _rowFilter;
columnFilter = _columnFilter;
if( _columnBorderType < 0 )
_columnBorderType = _rowBorderType;
rowBorderType = _rowBorderType;
columnBorderType = _columnBorderType;
CV_Assert( columnBorderType != BORDER_WRAP );
/****************************************************************************************\
Base Image Filter
\****************************************************************************************/
if( isSeparable() )
{
CV_Assert( rowFilter && columnFilter );
ksize = Size(rowFilter->ksize, columnFilter->ksize);
anchor = Point(rowFilter->anchor, columnFilter->anchor);
}
else
{
CV_Assert( bufType == srcType );
ksize = filter2D->ksize;
anchor = filter2D->anchor;
}
namespace cv {
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
// forward declarations
int FilterEngine__start(FilterEngine& this_, const Size &_wholeSize, const Size &sz, const Point &ofs);
int FilterEngine__proceed(FilterEngine& this_, const uchar* src, int srcstep, int count,
uchar* dst, int dststep);
void FilterEngine__apply(FilterEngine& this_, const Mat& src, Mat& dst, const Size& wsz, const Point& ofs);
CV_Assert( 0 <= anchor.x && anchor.x < ksize.width &&
0 <= anchor.y && anchor.y < ksize.height );
Ptr<BaseRowFilter> getLinearRowFilter(
int srcType, int bufType,
const Mat& kernel, int anchor,
int symmetryType);
borderElemSize = srcElemSize/(CV_MAT_DEPTH(srcType) >= CV_32S ? sizeof(int) : 1);
int borderLength = std::max(ksize.width - 1, 1);
borderTab.resize(borderLength*borderElemSize);
Ptr<BaseColumnFilter> getLinearColumnFilter(
int bufType, int dstType,
const Mat& kernel, int anchor,
int symmetryType, double delta,
int bits);
maxWidth = bufStep = 0;
constBorderRow.clear();
Ptr<BaseFilter> getLinearFilter(
int srcType, int dstType,
const Mat& filter_kernel, Point anchor,
double delta, int bits);
if( rowBorderType == BORDER_CONSTANT || columnBorderType == BORDER_CONSTANT )
{
constBorderValue.resize(srcElemSize*borderLength);
int srcType1 = CV_MAKETYPE(CV_MAT_DEPTH(srcType), MIN(CV_MAT_CN(srcType), 4));
scalarToRawData(_borderValue, &constBorderValue[0], srcType1,
borderLength*CV_MAT_CN(srcType));
}
wholeSize = Size(-1,-1);
}
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
#define VEC_ALIGN CV_MALLOC_ALIGN
int FilterEngine::start(const Size &_wholeSize, const Size &sz, const Point &ofs)
int FilterEngine__start(FilterEngine& this_, const Size &_wholeSize, const Size &sz, const Point &ofs)
{
CV_INSTRUMENT_REGION();
int i, j;
wholeSize = _wholeSize;
roi = Rect(ofs, sz);
CV_Assert( roi.x >= 0 && roi.y >= 0 && roi.width >= 0 && roi.height >= 0 &&
roi.x + roi.width <= wholeSize.width &&
roi.y + roi.height <= wholeSize.height );
this_.wholeSize = _wholeSize;
this_.roi = Rect(ofs, sz);
CV_Assert( this_.roi.x >= 0 && this_.roi.y >= 0 && this_.roi.width >= 0 && this_.roi.height >= 0 &&
this_.roi.x + this_.roi.width <= this_.wholeSize.width &&
this_.roi.y + this_.roi.height <= this_.wholeSize.height );
int esz = (int)getElemSize(srcType);
int bufElemSize = (int)getElemSize(bufType);
const uchar* constVal = !constBorderValue.empty() ? &constBorderValue[0] : 0;
int esz = (int)getElemSize(this_.srcType);
int bufElemSize = (int)getElemSize(this_.bufType);
const uchar* constVal = !this_.constBorderValue.empty() ? &this_.constBorderValue[0] : 0;
int _maxBufRows = std::max(ksize.height + 3,
std::max(anchor.y,
ksize.height-anchor.y-1)*2+1);
int _maxBufRows = std::max(this_.ksize.height + 3,
std::max(this_.anchor.y,
this_.ksize.height-this_.anchor.y-1)*2+1);
if( maxWidth < roi.width || _maxBufRows != (int)rows.size() )
if (this_.maxWidth < this_.roi.width || _maxBufRows != (int)this_.rows.size() )
{
rows.resize(_maxBufRows);
maxWidth = std::max(maxWidth, roi.width);
int cn = CV_MAT_CN(srcType);
srcRow.resize(esz*(maxWidth + ksize.width - 1));
if( columnBorderType == BORDER_CONSTANT )
this_.rows.resize(_maxBufRows);
this_.maxWidth = std::max(this_.maxWidth, this_.roi.width);
int cn = CV_MAT_CN(this_.srcType);
this_.srcRow.resize(esz*(this_.maxWidth + this_.ksize.width - 1));
if (this_.columnBorderType == BORDER_CONSTANT)
{
CV_Assert(constVal != NULL);
constBorderRow.resize(getElemSize(bufType)*(maxWidth + ksize.width - 1 + VEC_ALIGN));
uchar *dst = alignPtr(&constBorderRow[0], VEC_ALIGN), *tdst;
int n = (int)constBorderValue.size(), N;
N = (maxWidth + ksize.width - 1)*esz;
tdst = isSeparable() ? &srcRow[0] : dst;
this_.constBorderRow.resize(getElemSize(this_.bufType)*(this_.maxWidth + this_.ksize.width - 1 + VEC_ALIGN));
uchar *dst = alignPtr(&this_.constBorderRow[0], VEC_ALIGN);
int n = (int)this_.constBorderValue.size();
int N = (this_.maxWidth + this_.ksize.width - 1)*esz;
uchar *tdst = this_.isSeparable() ? &this_.srcRow[0] : dst;
for( i = 0; i < N; i += n )
{
......@@ -203,126 +128,113 @@ int FilterEngine::start(const Size &_wholeSize, const Size &sz, const Point &ofs
tdst[i+j] = constVal[j];
}
if( isSeparable() )
(*rowFilter)(&srcRow[0], dst, maxWidth, cn);
if (this_.isSeparable())
(*this_.rowFilter)(&this_.srcRow[0], dst, this_.maxWidth, cn);
}
int maxBufStep = bufElemSize*(int)alignSize(maxWidth +
(!isSeparable() ? ksize.width - 1 : 0),VEC_ALIGN);
ringBuf.resize(maxBufStep*rows.size()+VEC_ALIGN);
int maxBufStep = bufElemSize*(int)alignSize(this_.maxWidth +
(!this_.isSeparable() ? this_.ksize.width - 1 : 0), VEC_ALIGN);
this_.ringBuf.resize(maxBufStep*this_.rows.size()+VEC_ALIGN);
}
// adjust bufstep so that the used part of the ring buffer stays compact in memory
bufStep = bufElemSize*(int)alignSize(roi.width + (!isSeparable() ? ksize.width - 1 : 0),VEC_ALIGN);
this_.bufStep = bufElemSize*(int)alignSize(this_.roi.width + (!this_.isSeparable() ? this_.ksize.width - 1 : 0), VEC_ALIGN);
dx1 = std::max(anchor.x - roi.x, 0);
dx2 = std::max(ksize.width - anchor.x - 1 + roi.x + roi.width - wholeSize.width, 0);
this_.dx1 = std::max(this_.anchor.x - this_.roi.x, 0);
this_.dx2 = std::max(this_.ksize.width - this_.anchor.x - 1 + this_.roi.x + this_.roi.width - this_.wholeSize.width, 0);
// recompute border tables
if( dx1 > 0 || dx2 > 0 )
if (this_.dx1 > 0 || this_.dx2 > 0)
{
if( rowBorderType == BORDER_CONSTANT )
if (this_.rowBorderType == BORDER_CONSTANT )
{
CV_Assert(constVal != NULL);
int nr = isSeparable() ? 1 : (int)rows.size();
int nr = this_.isSeparable() ? 1 : (int)this_.rows.size();
for( i = 0; i < nr; i++ )
{
uchar* dst = isSeparable() ? &srcRow[0] : alignPtr(&ringBuf[0],VEC_ALIGN) + bufStep*i;
memcpy( dst, constVal, dx1*esz );
memcpy( dst + (roi.width + ksize.width - 1 - dx2)*esz, constVal, dx2*esz );
uchar* dst = this_.isSeparable() ? &this_.srcRow[0] : alignPtr(&this_.ringBuf[0], VEC_ALIGN) + this_.bufStep*i;
memcpy(dst, constVal, this_.dx1*esz);
memcpy(dst + (this_.roi.width + this_.ksize.width - 1 - this_.dx2)*esz, constVal, this_.dx2*esz);
}
}
else
{
int xofs1 = std::min(roi.x, anchor.x) - roi.x;
int xofs1 = std::min(this_.roi.x, this_.anchor.x) - this_.roi.x;
int btab_esz = borderElemSize, wholeWidth = wholeSize.width;
int* btab = (int*)&borderTab[0];
int btab_esz = this_.borderElemSize, wholeWidth = this_.wholeSize.width;
int* btab = (int*)&this_.borderTab[0];
for( i = 0; i < dx1; i++ )
for( i = 0; i < this_.dx1; i++ )
{
int p0 = (borderInterpolate(i-dx1, wholeWidth, rowBorderType) + xofs1)*btab_esz;
int p0 = (borderInterpolate(i-this_.dx1, wholeWidth, this_.rowBorderType) + xofs1)*btab_esz;
for( j = 0; j < btab_esz; j++ )
btab[i*btab_esz + j] = p0 + j;
}
for( i = 0; i < dx2; i++ )
for( i = 0; i < this_.dx2; i++ )
{
int p0 = (borderInterpolate(wholeWidth + i, wholeWidth, rowBorderType) + xofs1)*btab_esz;
int p0 = (borderInterpolate(wholeWidth + i, wholeWidth, this_.rowBorderType) + xofs1)*btab_esz;
for( j = 0; j < btab_esz; j++ )
btab[(i + dx1)*btab_esz + j] = p0 + j;
btab[(i + this_.dx1)*btab_esz + j] = p0 + j;
}
}
}
rowCount = dstY = 0;
startY = startY0 = std::max(roi.y - anchor.y, 0);
endY = std::min(roi.y + roi.height + ksize.height - anchor.y - 1, wholeSize.height);
if( columnFilter )
columnFilter->reset();
if( filter2D )
filter2D->reset();
return startY;
}
this_.rowCount = this_.dstY = 0;
this_.startY = this_.startY0 = std::max(this_.roi.y - this_.anchor.y, 0);
this_.endY = std::min(this_.roi.y + this_.roi.height + this_.ksize.height - this_.anchor.y - 1, this_.wholeSize.height);
if (this_.columnFilter)
this_.columnFilter->reset();
if (this_.filter2D)
this_.filter2D->reset();
int FilterEngine::start(const Mat& src, const Size &wsz, const Point &ofs)
{
start( wsz, src.size(), ofs);
return startY - ofs.y;
return this_.startY;
}
int FilterEngine::remainingInputRows() const
{
return endY - startY - rowCount;
}
int FilterEngine::remainingOutputRows() const
int FilterEngine__proceed(FilterEngine& this_, const uchar* src, int srcstep, int count,
uchar* dst, int dststep)
{
return roi.height - dstY;
}
CV_INSTRUMENT_REGION();
int FilterEngine::proceed( const uchar* src, int srcstep, int count,
uchar* dst, int dststep )
{
CV_Assert( wholeSize.width > 0 && wholeSize.height > 0 );
const int *btab = &borderTab[0];
int esz = (int)getElemSize(srcType), btab_esz = borderElemSize;
uchar** brows = &rows[0];
int bufRows = (int)rows.size();
int cn = CV_MAT_CN(bufType);
int width = roi.width, kwidth = ksize.width;
int kheight = ksize.height, ay = anchor.y;
int _dx1 = dx1, _dx2 = dx2;
int width1 = roi.width + kwidth - 1;
int xofs1 = std::min(roi.x, anchor.x);
bool isSep = isSeparable();
bool makeBorder = (_dx1 > 0 || _dx2 > 0) && rowBorderType != BORDER_CONSTANT;
CV_DbgAssert(this_.wholeSize.width > 0 && this_.wholeSize.height > 0 );
const int *btab = &this_.borderTab[0];
int esz = (int)getElemSize(this_.srcType), btab_esz = this_.borderElemSize;
uchar** brows = &this_.rows[0];
int bufRows = (int)this_.rows.size();
int cn = CV_MAT_CN(this_.bufType);
int width = this_.roi.width, kwidth = this_.ksize.width;
int kheight = this_.ksize.height, ay = this_.anchor.y;
int _dx1 = this_.dx1, _dx2 = this_.dx2;
int width1 = this_.roi.width + kwidth - 1;
int xofs1 = std::min(this_.roi.x, this_.anchor.x);
bool isSep = this_.isSeparable();
bool makeBorder = (_dx1 > 0 || _dx2 > 0) && this_.rowBorderType != BORDER_CONSTANT;
int dy = 0, i = 0;
src -= xofs1*esz;
count = std::min(count, remainingInputRows());
count = std::min(count, this_.remainingInputRows());
CV_Assert( src && dst && count > 0 );
CV_Assert(src && dst && count > 0);
for(;; dst += dststep*i, dy += i)
{
int dcount = bufRows - ay - startY - rowCount + roi.y;
int dcount = bufRows - ay - this_.startY - this_.rowCount + this_.roi.y;
dcount = dcount > 0 ? dcount : bufRows - kheight + 1;
dcount = std::min(dcount, count);
count -= dcount;
for( ; dcount-- > 0; src += srcstep )
{
int bi = (startY - startY0 + rowCount) % bufRows;
uchar* brow = alignPtr(&ringBuf[0], VEC_ALIGN) + bi*bufStep;
uchar* row = isSep ? &srcRow[0] : brow;
int bi = (this_.startY - this_.startY0 + this_.rowCount) % bufRows;
uchar* brow = alignPtr(&this_.ringBuf[0], VEC_ALIGN) + bi*this_.bufStep;
uchar* row = isSep ? &this_.srcRow[0] : brow;
if( ++rowCount > bufRows )
if (++this_.rowCount > bufRows)
{
--rowCount;
++startY;
--this_.rowCount;
++this_.startY;
}
memcpy( row + _dx1*esz, src, (width1 - _dx2 - _dx1)*esz );
......@@ -349,99 +261,55 @@ int FilterEngine::proceed( const uchar* src, int srcstep, int count,
}
if( isSep )
(*rowFilter)(row, brow, width, CV_MAT_CN(srcType));
(*this_.rowFilter)(row, brow, width, CV_MAT_CN(this_.srcType));
}
int max_i = std::min(bufRows, roi.height - (dstY + dy) + (kheight - 1));
int max_i = std::min(bufRows, this_.roi.height - (this_.dstY + dy) + (kheight - 1));
for( i = 0; i < max_i; i++ )
{
int srcY = borderInterpolate(dstY + dy + i + roi.y - ay,
wholeSize.height, columnBorderType);
int srcY = borderInterpolate(this_.dstY + dy + i + this_.roi.y - ay,
this_.wholeSize.height, this_.columnBorderType);
if( srcY < 0 ) // can happen only with constant border type
brows[i] = alignPtr(&constBorderRow[0], VEC_ALIGN);
brows[i] = alignPtr(&this_.constBorderRow[0], VEC_ALIGN);
else
{
CV_Assert( srcY >= startY );
if( srcY >= startY + rowCount )
CV_Assert(srcY >= this_.startY);
if( srcY >= this_.startY + this_.rowCount)
break;
int bi = (srcY - startY0) % bufRows;
brows[i] = alignPtr(&ringBuf[0], VEC_ALIGN) + bi*bufStep;
int bi = (srcY - this_.startY0) % bufRows;
brows[i] = alignPtr(&this_.ringBuf[0], VEC_ALIGN) + bi*this_.bufStep;
}
}
if( i < kheight )
break;
i -= kheight - 1;
if( isSeparable() )
(*columnFilter)((const uchar**)brows, dst, dststep, i, roi.width*cn);
if (isSep)
(*this_.columnFilter)((const uchar**)brows, dst, dststep, i, this_.roi.width*cn);
else
(*filter2D)((const uchar**)brows, dst, dststep, i, roi.width, cn);
(*this_.filter2D)((const uchar**)brows, dst, dststep, i, this_.roi.width, cn);
}
dstY += dy;
CV_Assert( dstY <= roi.height );
this_.dstY += dy;
CV_Assert(this_.dstY <= this_.roi.height);
return dy;
}
void FilterEngine::apply(const Mat& src, Mat& dst, const Size & wsz, const Point & ofs)
void FilterEngine__apply(FilterEngine& this_, const Mat& src, Mat& dst, const Size& wsz, const Point& ofs)
{
CV_INSTRUMENT_REGION();
CV_Assert( src.type() == srcType && dst.type() == dstType );
CV_DbgAssert(src.type() == this_.srcType && dst.type() == this_.dstType);
int y = start(src, wsz, ofs);
proceed(src.ptr() + y*src.step,
FilterEngine__start(this_, wsz, src.size(), ofs);
int y = this_.startY - ofs.y;
FilterEngine__proceed(this_,
src.ptr() + y*src.step,
(int)src.step,
endY - startY,
this_.endY - this_.startY,
dst.ptr(),
(int)dst.step );
}
}
/****************************************************************************************\
* Separable linear filter *
\****************************************************************************************/
int cv::getKernelType(InputArray filter_kernel, Point anchor)
{
Mat _kernel = filter_kernel.getMat();
CV_Assert( _kernel.channels() == 1 );
int i, sz = _kernel.rows*_kernel.cols;
Mat kernel;
_kernel.convertTo(kernel, CV_64F);
const double* coeffs = kernel.ptr<double>();
double sum = 0;
int type = KERNEL_SMOOTH + KERNEL_INTEGER;
if( (_kernel.rows == 1 || _kernel.cols == 1) &&
anchor.x*2 + 1 == _kernel.cols &&
anchor.y*2 + 1 == _kernel.rows )
type |= (KERNEL_SYMMETRICAL + KERNEL_ASYMMETRICAL);
for( i = 0; i < sz; i++ )
{
double a = coeffs[i], b = coeffs[sz - i - 1];
if( a != b )
type &= ~KERNEL_SYMMETRICAL;
if( a != -b )
type &= ~KERNEL_ASYMMETRICAL;
if( a < 0 )
type &= ~KERNEL_SMOOTH;
if( a != saturate_cast<int>(a) )
type &= ~KERNEL_INTEGER;
sum += a;
}
if( fabs(sum - 1) > FLT_EPSILON*(fabs(sum) + 1) )
type &= ~KERNEL_SMOOTH;
return type;
}
namespace cv
{
struct RowNoVec
{
RowNoVec() {}
......@@ -503,6 +371,8 @@ struct RowVec_8u32s
int operator()(const uchar* _src, uchar* _dst, int width, int cn) const
{
CV_INSTRUMENT_REGION();
int i = 0, k, _ksize = kernel.rows + kernel.cols - 1;
int* dst = (int*)_dst;
const int* _kx = kernel.ptr<int>();
......@@ -587,7 +457,6 @@ struct RowVec_8u32s
i += v_uint32::nlanes;
}
}
vx_cleanup();
return i;
}
......@@ -618,6 +487,8 @@ struct SymmRowSmallVec_8u32s
int operator()(const uchar* src, uchar* _dst, int width, int cn) const
{
CV_INSTRUMENT_REGION();
int i = 0, j, k, _ksize = kernel.rows + kernel.cols - 1;
int* dst = (int*)_dst;
bool symmetrical = (symmetryType & KERNEL_SYMMETRICAL) != 0;
......@@ -1083,8 +954,6 @@ struct SymmRowSmallVec_8u32s
}
}
}
vx_cleanup();
return i;
}
......@@ -1107,6 +976,8 @@ struct SymmColumnVec_32s8u
int operator()(const uchar** _src, uchar* dst, int width) const
{
CV_INSTRUMENT_REGION();
int _ksize = kernel.rows + kernel.cols - 1;
if( _ksize == 1 )
return 0;
......@@ -1237,8 +1108,6 @@ struct SymmColumnVec_32s8u
i += v_int32x4::nlanes;
}
}
vx_cleanup();
return i;
}
......@@ -1261,6 +1130,8 @@ struct SymmColumnSmallVec_32s16s
int operator()(const uchar** _src, uchar* _dst, int width) const
{
CV_INSTRUMENT_REGION();
int ksize2 = (kernel.rows + kernel.cols - 1)/2;
const float* ky = kernel.ptr<float>() + ksize2;
int i = 0;
......@@ -1420,8 +1291,6 @@ struct SymmColumnSmallVec_32s16s
}
}
}
vx_cleanup();
return i;
}
......@@ -1443,6 +1312,8 @@ struct RowVec_16s32f
int operator()(const uchar* _src, uchar* _dst, int width, int cn) const
{
CV_INSTRUMENT_REGION();
int i = 0, k, _ksize = kernel.rows + kernel.cols - 1;
float* dst = (float*)_dst;
const float* _kx = kernel.ptr<float>();
......@@ -1495,7 +1366,6 @@ struct RowVec_16s32f
v_store(dst + i, s0);
i += v_float32::nlanes;
}
vx_cleanup();
return i;
}
......@@ -1516,6 +1386,8 @@ struct SymmColumnVec_32f16s
int operator()(const uchar** _src, uchar* _dst, int width) const
{
CV_INSTRUMENT_REGION();
int _ksize = kernel.rows + kernel.cols - 1;
if( _ksize == 1 )
return 0;
......@@ -1620,7 +1492,6 @@ struct SymmColumnVec_32f16s
}
}
vx_cleanup();
return i;
}
......@@ -1653,6 +1524,8 @@ struct RowVec_32f
int operator()(const uchar* _src, uchar* _dst, int width, int cn) const
{
CV_INSTRUMENT_REGION();
#if defined USE_IPP_SEP_FILTERS
CV_IPP_CHECK()
{
......@@ -1722,7 +1595,6 @@ struct RowVec_32f
v_store(dst + i, s0);
i += v_float32::nlanes;
}
vx_cleanup();
return i;
}
......@@ -1782,6 +1654,8 @@ struct SymmRowSmallVec_32f
int operator()(const uchar* _src, uchar* _dst, int width, int cn) const
{
CV_INSTRUMENT_REGION();
int i = 0, _ksize = kernel.rows + kernel.cols - 1;
if( _ksize == 1 )
return 0;
......@@ -1868,8 +1742,6 @@ struct SymmRowSmallVec_32f
v_store(dst + i, v_muladd(vx_load(src + 2*cn) - vx_load(src - 2*cn), k2, (vx_load(src + cn) - vx_load(src - cn)) * k1));
}
}
vx_cleanup();
return i;
}
......@@ -1896,6 +1768,8 @@ struct SymmColumnVec_32f
int operator()(const uchar** _src, uchar* _dst, int width) const
{
CV_INSTRUMENT_REGION();
int ksize2 = (kernel.rows + kernel.cols - 1)/2;
const float* ky = kernel.ptr<float>() + ksize2;
int i = 0, k;
......@@ -2005,8 +1879,6 @@ struct SymmColumnVec_32f
i += v_float32::nlanes;
}
}
vx_cleanup();
return i;
}
......@@ -2030,6 +1902,8 @@ struct SymmColumnSmallVec_32f
int operator()(const uchar** _src, uchar* _dst, int width) const
{
CV_INSTRUMENT_REGION();
int ksize2 = (kernel.rows + kernel.cols - 1)/2;
const float* ky = kernel.ptr<float>() + ksize2;
int i = 0;
......@@ -2085,8 +1959,6 @@ struct SymmColumnSmallVec_32f
v_store(dst + i, v_muladd(vx_load(S2 + i) - vx_load(S0 + i), k1, d4));
}
}
vx_cleanup();
return i;
}
......@@ -2115,6 +1987,8 @@ struct FilterVec_8u
int operator()(const uchar** src, uchar* dst, int width) const
{
CV_INSTRUMENT_REGION();
CV_DbgAssert(_nz > 0);
const float* kf = (const float*)&coeffs[0];
int i = 0, k, nz = _nz;
......@@ -2175,8 +2049,6 @@ struct FilterVec_8u
*(int*)(dst + i) = v_reinterpret_as_s32(v_pack_u(s16, s16)).get0();
i += v_int32x4::nlanes;
}
vx_cleanup();
return i;
}
......@@ -2201,6 +2073,8 @@ struct FilterVec_8u16s
int operator()(const uchar** src, uchar* _dst, int width) const
{
CV_INSTRUMENT_REGION();
CV_DbgAssert(_nz > 0);
const float* kf = (const float*)&coeffs[0];
short* dst = (short*)_dst;
......@@ -2251,8 +2125,6 @@ struct FilterVec_8u16s
v_pack_store(dst + i, v_round(s0));
i += v_int32::nlanes;
}
vx_cleanup();
return i;
}
......@@ -2275,6 +2147,8 @@ struct FilterVec_32f
int operator()(const uchar** _src, uchar* _dst, int width) const
{
CV_INSTRUMENT_REGION();
const float* kf = (const float*)&coeffs[0];
const float** src = (const float**)_src;
float* dst = (float*)_dst;
......@@ -2323,8 +2197,6 @@ struct FilterVec_32f
v_store(dst + i, s0);
i += v_float32::nlanes;
}
vx_cleanup();
return i;
}
......@@ -2369,6 +2241,8 @@ template<typename ST, typename DT, class VecOp> struct RowFilter : public BaseRo
void operator()(const uchar* src, uchar* dst, int width, int cn) CV_OVERRIDE
{
CV_INSTRUMENT_REGION();
int _ksize = ksize;
const DT* kx = kernel.ptr<DT>();
const ST* S;
......@@ -2427,6 +2301,8 @@ template<typename ST, typename DT, class VecOp> struct SymmRowSmallFilter :
void operator()(const uchar* src, uchar* dst, int width, int cn) CV_OVERRIDE
{
CV_INSTRUMENT_REGION();
int ksize2 = this->ksize/2, ksize2n = ksize2*cn;
const DT* kx = this->kernel.template ptr<DT>() + ksize2;
bool symmetrical = (this->symmetryType & KERNEL_SYMMETRICAL) != 0;
......@@ -2566,6 +2442,8 @@ template<class CastOp, class VecOp> struct ColumnFilter : public BaseColumnFilte
void operator()(const uchar** src, uchar* dst, int dststep, int count, int width) CV_OVERRIDE
{
CV_INSTRUMENT_REGION();
const ST* ky = kernel.template ptr<ST>();
ST _delta = delta;
int _ksize = ksize;
......@@ -2629,6 +2507,8 @@ template<class CastOp, class VecOp> struct SymmColumnFilter : public ColumnFilte
void operator()(const uchar** src, uchar* dst, int dststep, int count, int width) CV_OVERRIDE
{
CV_INSTRUMENT_REGION();
int ksize2 = this->ksize/2;
const ST* ky = this->kernel.template ptr<ST>() + ksize2;
int i, k;
......@@ -2735,6 +2615,8 @@ struct SymmColumnSmallFilter : public SymmColumnFilter<CastOp, VecOp>
void operator()(const uchar** src, uchar* dst, int dststep, int count, int width) CV_OVERRIDE
{
CV_INSTRUMENT_REGION();
int ksize2 = this->ksize/2;
const ST* ky = this->kernel.template ptr<ST>() + ksize2;
int i;
......@@ -2904,13 +2786,14 @@ template<typename ST, typename DT> struct FixedPtCastEx
int SHIFT, DELTA;
};
}
cv::Ptr<cv::BaseRowFilter> cv::getLinearRowFilter( int srcType, int bufType,
InputArray _kernel, int anchor,
int symmetryType )
Ptr<BaseRowFilter> getLinearRowFilter(
int srcType, int bufType,
const Mat& kernel, int anchor,
int symmetryType)
{
Mat kernel = _kernel.getMat();
CV_INSTRUMENT_REGION();
int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(bufType);
int cn = CV_MAT_CN(srcType);
CV_Assert( cn == CV_MAT_CN(bufType) &&
......@@ -2958,12 +2841,14 @@ cv::Ptr<cv::BaseRowFilter> cv::getLinearRowFilter( int srcType, int bufType,
}
cv::Ptr<cv::BaseColumnFilter> cv::getLinearColumnFilter( int bufType, int dstType,
InputArray _kernel, int anchor,
int symmetryType, double delta,
int bits )
Ptr<BaseColumnFilter> getLinearColumnFilter(
int bufType, int dstType,
const Mat& kernel, int anchor,
int symmetryType, double delta,
int bits)
{
Mat kernel = _kernel.getMat();
CV_INSTRUMENT_REGION();
int sdepth = CV_MAT_DEPTH(bufType), ddepth = CV_MAT_DEPTH(dstType);
int cn = CV_MAT_CN(dstType);
CV_Assert( cn == CV_MAT_CN(bufType) &&
......@@ -3053,131 +2938,6 @@ cv::Ptr<cv::BaseColumnFilter> cv::getLinearColumnFilter( int bufType, int dstTyp
}
cv::Ptr<cv::FilterEngine> cv::createSeparableLinearFilter(
int _srcType, int _dstType,
InputArray __rowKernel, InputArray __columnKernel,
Point _anchor, double _delta,
int _rowBorderType, int _columnBorderType,
const Scalar& _borderValue )
{
Mat _rowKernel = __rowKernel.getMat(), _columnKernel = __columnKernel.getMat();
_srcType = CV_MAT_TYPE(_srcType);
_dstType = CV_MAT_TYPE(_dstType);
int sdepth = CV_MAT_DEPTH(_srcType), ddepth = CV_MAT_DEPTH(_dstType);
int cn = CV_MAT_CN(_srcType);
CV_Assert( cn == CV_MAT_CN(_dstType) );
int rsize = _rowKernel.rows + _rowKernel.cols - 1;
int csize = _columnKernel.rows + _columnKernel.cols - 1;
if( _anchor.x < 0 )
_anchor.x = rsize/2;
if( _anchor.y < 0 )
_anchor.y = csize/2;
int rtype = getKernelType(_rowKernel,
_rowKernel.rows == 1 ? Point(_anchor.x, 0) : Point(0, _anchor.x));
int ctype = getKernelType(_columnKernel,
_columnKernel.rows == 1 ? Point(_anchor.y, 0) : Point(0, _anchor.y));
Mat rowKernel, columnKernel;
int bdepth = std::max(CV_32F,std::max(sdepth, ddepth));
int bits = 0;
if( sdepth == CV_8U &&
((rtype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL &&
ctype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL &&
ddepth == CV_8U) ||
((rtype & (KERNEL_SYMMETRICAL+KERNEL_ASYMMETRICAL)) &&
(ctype & (KERNEL_SYMMETRICAL+KERNEL_ASYMMETRICAL)) &&
(rtype & ctype & KERNEL_INTEGER) &&
ddepth == CV_16S)) )
{
bdepth = CV_32S;
bits = ddepth == CV_8U ? 8 : 0;
_rowKernel.convertTo( rowKernel, CV_32S, 1 << bits );
_columnKernel.convertTo( columnKernel, CV_32S, 1 << bits );
bits *= 2;
_delta *= (1 << bits);
}
else
{
if( _rowKernel.type() != bdepth )
_rowKernel.convertTo( rowKernel, bdepth );
else
rowKernel = _rowKernel;
if( _columnKernel.type() != bdepth )
_columnKernel.convertTo( columnKernel, bdepth );
else
columnKernel = _columnKernel;
}
int _bufType = CV_MAKETYPE(bdepth, cn);
Ptr<BaseRowFilter> _rowFilter = getLinearRowFilter(
_srcType, _bufType, rowKernel, _anchor.x, rtype);
Ptr<BaseColumnFilter> _columnFilter = getLinearColumnFilter(
_bufType, _dstType, columnKernel, _anchor.y, ctype, _delta, bits );
return Ptr<FilterEngine>( new FilterEngine(Ptr<BaseFilter>(), _rowFilter, _columnFilter,
_srcType, _dstType, _bufType, _rowBorderType, _columnBorderType, _borderValue ));
}
/****************************************************************************************\
* Non-separable linear filter *
\****************************************************************************************/
namespace cv
{
void preprocess2DKernel( const Mat& kernel, std::vector<Point>& coords, std::vector<uchar>& coeffs )
{
int i, j, k, nz = countNonZero(kernel), ktype = kernel.type();
if(nz == 0)
nz = 1;
CV_Assert( ktype == CV_8U || ktype == CV_32S || ktype == CV_32F || ktype == CV_64F );
coords.resize(nz);
coeffs.resize(nz*getElemSize(ktype));
uchar* _coeffs = &coeffs[0];
for( i = k = 0; i < kernel.rows; i++ )
{
const uchar* krow = kernel.ptr(i);
for( j = 0; j < kernel.cols; j++ )
{
if( ktype == CV_8U )
{
uchar val = krow[j];
if( val == 0 )
continue;
coords[k] = Point(j,i);
_coeffs[k++] = val;
}
else if( ktype == CV_32S )
{
int val = ((const int*)krow)[j];
if( val == 0 )
continue;
coords[k] = Point(j,i);
((int*)_coeffs)[k++] = val;
}
else if( ktype == CV_32F )
{
float val = ((const float*)krow)[j];
if( val == 0 )
continue;
coords[k] = Point(j,i);
((float*)_coeffs)[k++] = val;
}
else
{
double val = ((const double*)krow)[j];
if( val == 0 )
continue;
coords[k] = Point(j,i);
((double*)_coeffs)[k++] = val;
}
}
}
}
template<typename ST, class CastOp, class VecOp> struct Filter2D : public BaseFilter
{
......@@ -3253,489 +3013,14 @@ template<typename ST, class CastOp, class VecOp> struct Filter2D : public BaseFi
VecOp vecOp;
};
#ifdef HAVE_OPENCL
#define DIVUP(total, grain) (((total) + (grain) - 1) / (grain))
#define ROUNDUP(sz, n) ((sz) + (n) - 1 - (((sz) + (n) - 1) % (n)))
// prepare kernel: transpose and make double rows (+align). Returns size of aligned row
// Samples:
// a b c
// Input: d e f
// g h i
// Output, last two zeros is the alignment:
// a d g a d g 0 0
// b e h b e h 0 0
// c f i c f i 0 0
template <typename T>
static int _prepareKernelFilter2D(std::vector<T> & data, const Mat & kernel)
{
Mat _kernel; kernel.convertTo(_kernel, DataDepth<T>::value);
int size_y_aligned = ROUNDUP(kernel.rows * 2, 4);
data.clear(); data.resize(size_y_aligned * kernel.cols, 0);
for (int x = 0; x < kernel.cols; x++)
{
for (int y = 0; y < kernel.rows; y++)
{
data[x * size_y_aligned + y] = _kernel.at<T>(y, x);
data[x * size_y_aligned + y + kernel.rows] = _kernel.at<T>(y, x);
}
}
return size_y_aligned;
}
static bool ocl_filter2D( InputArray _src, OutputArray _dst, int ddepth,
InputArray _kernel, Point anchor,
double delta, int borderType )
{
int type = _src.type(), sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
ddepth = ddepth < 0 ? sdepth : ddepth;
int dtype = CV_MAKE_TYPE(ddepth, cn), wdepth = std::max(std::max(sdepth, ddepth), CV_32F),
wtype = CV_MAKE_TYPE(wdepth, cn);
if (cn > 4)
return false;
Size ksize = _kernel.size();
if (anchor.x < 0)
anchor.x = ksize.width / 2;
if (anchor.y < 0)
anchor.y = ksize.height / 2;
bool isolated = (borderType & BORDER_ISOLATED) != 0;
borderType &= ~BORDER_ISOLATED;
const cv::ocl::Device &device = cv::ocl::Device::getDefault();
bool doubleSupport = device.doubleFPConfig() > 0;
if (wdepth == CV_64F && !doubleSupport)
return false;
const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT",
"BORDER_WRAP", "BORDER_REFLECT_101" };
cv::Mat kernelMat = _kernel.getMat();
cv::Size sz = _src.size(), wholeSize;
size_t globalsize[2] = { (size_t)sz.width, (size_t)sz.height };
size_t localsize_general[2] = {0, 1};
size_t* localsize = NULL;
ocl::Kernel k;
UMat src = _src.getUMat();
if (!isolated)
{
Point ofs;
src.locateROI(wholeSize, ofs);
}
size_t tryWorkItems = device.maxWorkGroupSize();
if (device.isIntel() && 128 < tryWorkItems)
tryWorkItems = 128;
char cvt[2][40];
// For smaller filter kernels, there is a special kernel that is more
// efficient than the general one.
UMat kernalDataUMat;
if (device.isIntel() && (device.type() & ocl::Device::TYPE_GPU) &&
((ksize.width < 5 && ksize.height < 5) ||
(ksize.width == 5 && ksize.height == 5 && cn == 1)))
{
kernelMat = kernelMat.reshape(0, 1);
String kerStr = ocl::kernelToStr(kernelMat, CV_32F);
int h = isolated ? sz.height : wholeSize.height;
int w = isolated ? sz.width : wholeSize.width;
if (w < ksize.width || h < ksize.height)
return false;
// Figure out what vector size to use for loading the pixels.
int pxLoadNumPixels = cn != 1 || sz.width % 4 ? 1 : 4;
int pxLoadVecSize = cn * pxLoadNumPixels;
// Figure out how many pixels per work item to compute in X and Y
// directions. Too many and we run out of registers.
int pxPerWorkItemX = 1;
int pxPerWorkItemY = 1;
if (cn <= 2 && ksize.width <= 4 && ksize.height <= 4)
{
pxPerWorkItemX = sz.width % 8 ? sz.width % 4 ? sz.width % 2 ? 1 : 2 : 4 : 8;
pxPerWorkItemY = sz.height % 2 ? 1 : 2;
}
else if (cn < 4 || (ksize.width <= 4 && ksize.height <= 4))
{
pxPerWorkItemX = sz.width % 2 ? 1 : 2;
pxPerWorkItemY = sz.height % 2 ? 1 : 2;
}
globalsize[0] = sz.width / pxPerWorkItemX;
globalsize[1] = sz.height / pxPerWorkItemY;
// Need some padding in the private array for pixels
int privDataWidth = ROUNDUP(pxPerWorkItemX + ksize.width - 1, pxLoadNumPixels);
// Make the global size a nice round number so the runtime can pick
// from reasonable choices for the workgroup size
const int wgRound = 256;
globalsize[0] = ROUNDUP(globalsize[0], wgRound);
char build_options[1024];
sprintf(build_options, "-D cn=%d "
"-D ANCHOR_X=%d -D ANCHOR_Y=%d -D KERNEL_SIZE_X=%d -D KERNEL_SIZE_Y=%d "
"-D PX_LOAD_VEC_SIZE=%d -D PX_LOAD_NUM_PX=%d "
"-D PX_PER_WI_X=%d -D PX_PER_WI_Y=%d -D PRIV_DATA_WIDTH=%d -D %s -D %s "
"-D PX_LOAD_X_ITERATIONS=%d -D PX_LOAD_Y_ITERATIONS=%d "
"-D srcT=%s -D srcT1=%s -D dstT=%s -D dstT1=%s -D WT=%s -D WT1=%s "
"-D convertToWT=%s -D convertToDstT=%s %s",
cn, anchor.x, anchor.y, ksize.width, ksize.height,
pxLoadVecSize, pxLoadNumPixels,
pxPerWorkItemX, pxPerWorkItemY, privDataWidth, borderMap[borderType],
isolated ? "BORDER_ISOLATED" : "NO_BORDER_ISOLATED",
privDataWidth / pxLoadNumPixels, pxPerWorkItemY + ksize.height - 1,
ocl::typeToStr(type), ocl::typeToStr(sdepth), ocl::typeToStr(dtype),
ocl::typeToStr(ddepth), ocl::typeToStr(wtype), ocl::typeToStr(wdepth),
ocl::convertTypeStr(sdepth, wdepth, cn, cvt[0]),
ocl::convertTypeStr(wdepth, ddepth, cn, cvt[1]), kerStr.c_str());
if (!k.create("filter2DSmall", cv::ocl::imgproc::filter2DSmall_oclsrc, build_options))
return false;
}
else
{
localsize = localsize_general;
std::vector<float> kernelMatDataFloat;
int kernel_size_y2_aligned = _prepareKernelFilter2D<float>(kernelMatDataFloat, kernelMat);
String kerStr = ocl::kernelToStr(kernelMatDataFloat, CV_32F);
for ( ; ; )
{
size_t BLOCK_SIZE = tryWorkItems;
while (BLOCK_SIZE > 32 && BLOCK_SIZE >= (size_t)ksize.width * 2 && BLOCK_SIZE > (size_t)sz.width * 2)
BLOCK_SIZE /= 2;
if ((size_t)ksize.width > BLOCK_SIZE)
return false;
int requiredTop = anchor.y;
int requiredLeft = (int)BLOCK_SIZE; // not this: anchor.x;
int requiredBottom = ksize.height - 1 - anchor.y;
int requiredRight = (int)BLOCK_SIZE; // not this: ksize.width - 1 - anchor.x;
int h = isolated ? sz.height : wholeSize.height;
int w = isolated ? sz.width : wholeSize.width;
bool extra_extrapolation = h < requiredTop || h < requiredBottom || w < requiredLeft || w < requiredRight;
if ((w < ksize.width) || (h < ksize.height))
return false;
String opts = format("-D LOCAL_SIZE=%d -D cn=%d "
"-D ANCHOR_X=%d -D ANCHOR_Y=%d -D KERNEL_SIZE_X=%d -D KERNEL_SIZE_Y=%d "
"-D KERNEL_SIZE_Y2_ALIGNED=%d -D %s -D %s -D %s%s%s "
"-D srcT=%s -D srcT1=%s -D dstT=%s -D dstT1=%s -D WT=%s -D WT1=%s "
"-D convertToWT=%s -D convertToDstT=%s",
(int)BLOCK_SIZE, cn, anchor.x, anchor.y,
ksize.width, ksize.height, kernel_size_y2_aligned, borderMap[borderType],
extra_extrapolation ? "EXTRA_EXTRAPOLATION" : "NO_EXTRA_EXTRAPOLATION",
isolated ? "BORDER_ISOLATED" : "NO_BORDER_ISOLATED",
doubleSupport ? " -D DOUBLE_SUPPORT" : "", kerStr.c_str(),
ocl::typeToStr(type), ocl::typeToStr(sdepth), ocl::typeToStr(dtype),
ocl::typeToStr(ddepth), ocl::typeToStr(wtype), ocl::typeToStr(wdepth),
ocl::convertTypeStr(sdepth, wdepth, cn, cvt[0]),
ocl::convertTypeStr(wdepth, ddepth, cn, cvt[1]));
localsize[0] = BLOCK_SIZE;
globalsize[0] = DIVUP(sz.width, BLOCK_SIZE - (ksize.width - 1)) * BLOCK_SIZE;
globalsize[1] = sz.height;
if (!k.create("filter2D", cv::ocl::imgproc::filter2D_oclsrc, opts))
return false;
size_t kernelWorkGroupSize = k.workGroupSize();
if (localsize[0] <= kernelWorkGroupSize)
break;
if (BLOCK_SIZE < kernelWorkGroupSize)
return false;
tryWorkItems = kernelWorkGroupSize;
}
}
_dst.create(sz, dtype);
UMat dst = _dst.getUMat();
int srcOffsetX = (int)((src.offset % src.step) / src.elemSize());
int srcOffsetY = (int)(src.offset / src.step);
int srcEndX = (isolated ? (srcOffsetX + sz.width) : wholeSize.width);
int srcEndY = (isolated ? (srcOffsetY + sz.height) : wholeSize.height);
k.args(ocl::KernelArg::PtrReadOnly(src), (int)src.step, srcOffsetX, srcOffsetY,
srcEndX, srcEndY, ocl::KernelArg::WriteOnly(dst), (float)delta);
return k.run(2, globalsize, localsize, false);
}
const int shift_bits = 8;
static bool ocl_sepRowFilter2D(const UMat & src, UMat & buf, const Mat & kernelX, int anchor,
int borderType, int ddepth, bool fast8uc1, bool int_arithm)
Ptr<BaseFilter> getLinearFilter(
int srcType, int dstType,
const Mat& _kernel, Point anchor,
double delta, int bits)
{
int type = src.type(), cn = CV_MAT_CN(type), sdepth = CV_MAT_DEPTH(type);
bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
Size bufSize = buf.size();
int buf_type = buf.type(), bdepth = CV_MAT_DEPTH(buf_type);
if (!doubleSupport && (sdepth == CV_64F || ddepth == CV_64F))
return false;
#ifdef __ANDROID__
size_t localsize[2] = {16, 10};
#else
size_t localsize[2] = {16, 16};
#endif
size_t globalsize[2] = {DIVUP(bufSize.width, localsize[0]) * localsize[0], DIVUP(bufSize.height, localsize[1]) * localsize[1]};
if (fast8uc1)
globalsize[0] = DIVUP((bufSize.width + 3) >> 2, localsize[0]) * localsize[0];
int radiusX = anchor, radiusY = (buf.rows - src.rows) >> 1;
bool isolated = (borderType & BORDER_ISOLATED) != 0;
const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", "BORDER_WRAP", "BORDER_REFLECT_101" },
* const btype = borderMap[borderType & ~BORDER_ISOLATED];
bool extra_extrapolation = src.rows < (int)((-radiusY + globalsize[1]) >> 1) + 1;
extra_extrapolation |= src.rows < radiusY;
extra_extrapolation |= src.cols < (int)((-radiusX + globalsize[0] + 8 * localsize[0] + 3) >> 1) + 1;
extra_extrapolation |= src.cols < radiusX;
char cvt[40];
cv::String build_options = cv::format("-D RADIUSX=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d -D %s -D %s -D %s"
" -D srcT=%s -D dstT=%s -D convertToDstT=%s -D srcT1=%s -D dstT1=%s%s%s",
radiusX, (int)localsize[0], (int)localsize[1], cn, btype,
extra_extrapolation ? "EXTRA_EXTRAPOLATION" : "NO_EXTRA_EXTRAPOLATION",
isolated ? "BORDER_ISOLATED" : "NO_BORDER_ISOLATED",
ocl::typeToStr(type), ocl::typeToStr(buf_type),
ocl::convertTypeStr(sdepth, bdepth, cn, cvt),
ocl::typeToStr(sdepth), ocl::typeToStr(bdepth),
doubleSupport ? " -D DOUBLE_SUPPORT" : "",
int_arithm ? " -D INTEGER_ARITHMETIC" : "");
build_options += ocl::kernelToStr(kernelX, bdepth);
Size srcWholeSize; Point srcOffset;
src.locateROI(srcWholeSize, srcOffset);
String kernelName("row_filter");
if (fast8uc1)
kernelName += "_C1_D0";
ocl::Kernel k(kernelName.c_str(), cv::ocl::imgproc::filterSepRow_oclsrc,
build_options);
if (k.empty())
return false;
if (fast8uc1)
k.args(ocl::KernelArg::PtrReadOnly(src), (int)(src.step / src.elemSize()), srcOffset.x,
srcOffset.y, src.cols, src.rows, srcWholeSize.width, srcWholeSize.height,
ocl::KernelArg::PtrWriteOnly(buf), (int)(buf.step / buf.elemSize()),
buf.cols, buf.rows, radiusY);
else
k.args(ocl::KernelArg::PtrReadOnly(src), (int)src.step, srcOffset.x,
srcOffset.y, src.cols, src.rows, srcWholeSize.width, srcWholeSize.height,
ocl::KernelArg::PtrWriteOnly(buf), (int)buf.step, buf.cols, buf.rows, radiusY);
return k.run(2, globalsize, localsize, false);
}
static bool ocl_sepColFilter2D(const UMat & buf, UMat & dst, const Mat & kernelY, double delta, int anchor, bool int_arithm)
{
bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
if (dst.depth() == CV_64F && !doubleSupport)
return false;
#ifdef __ANDROID__
size_t localsize[2] = { 16, 10 };
#else
size_t localsize[2] = { 16, 16 };
#endif
size_t globalsize[2] = { 0, 0 };
int dtype = dst.type(), cn = CV_MAT_CN(dtype), ddepth = CV_MAT_DEPTH(dtype);
Size sz = dst.size();
int buf_type = buf.type(), bdepth = CV_MAT_DEPTH(buf_type);
globalsize[1] = DIVUP(sz.height, localsize[1]) * localsize[1];
globalsize[0] = DIVUP(sz.width, localsize[0]) * localsize[0];
char cvt[40];
cv::String build_options = cv::format("-D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D CN=%d"
" -D srcT=%s -D dstT=%s -D convertToDstT=%s"
" -D srcT1=%s -D dstT1=%s -D SHIFT_BITS=%d%s%s",
anchor, (int)localsize[0], (int)localsize[1], cn,
ocl::typeToStr(buf_type), ocl::typeToStr(dtype),
ocl::convertTypeStr(bdepth, ddepth, cn, cvt),
ocl::typeToStr(bdepth), ocl::typeToStr(ddepth),
2*shift_bits, doubleSupport ? " -D DOUBLE_SUPPORT" : "",
int_arithm ? " -D INTEGER_ARITHMETIC" : "");
build_options += ocl::kernelToStr(kernelY, bdepth);
ocl::Kernel k("col_filter", cv::ocl::imgproc::filterSepCol_oclsrc,
build_options);
if (k.empty())
return false;
k.args(ocl::KernelArg::ReadOnly(buf), ocl::KernelArg::WriteOnly(dst),
static_cast<float>(delta));
return k.run(2, globalsize, localsize, false);
}
const int optimizedSepFilterLocalWidth = 16;
const int optimizedSepFilterLocalHeight = 8;
static bool ocl_sepFilter2D_SinglePass(InputArray _src, OutputArray _dst,
Mat row_kernel, Mat col_kernel,
double delta, int borderType, int ddepth, int bdepth, bool int_arithm)
{
Size size = _src.size(), wholeSize;
Point origin;
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype),
esz = CV_ELEM_SIZE(stype), wdepth = std::max(std::max(sdepth, ddepth), bdepth),
dtype = CV_MAKE_TYPE(ddepth, cn);
size_t src_step = _src.step(), src_offset = _src.offset();
bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0;
if (esz == 0 || src_step == 0
|| (src_offset % src_step) % esz != 0
|| (!doubleSupport && (sdepth == CV_64F || ddepth == CV_64F))
|| !(borderType == BORDER_CONSTANT
|| borderType == BORDER_REPLICATE
|| borderType == BORDER_REFLECT
|| borderType == BORDER_WRAP
|| borderType == BORDER_REFLECT_101))
return false;
size_t lt2[2] = { optimizedSepFilterLocalWidth, optimizedSepFilterLocalHeight };
size_t gt2[2] = { lt2[0] * (1 + (size.width - 1) / lt2[0]), lt2[1]};
char cvt[2][40];
const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", "BORDER_WRAP",
"BORDER_REFLECT_101" };
String opts = cv::format("-D BLK_X=%d -D BLK_Y=%d -D RADIUSX=%d -D RADIUSY=%d%s%s"
" -D srcT=%s -D convertToWT=%s -D WT=%s -D dstT=%s -D convertToDstT=%s"
" -D %s -D srcT1=%s -D dstT1=%s -D WT1=%s -D CN=%d -D SHIFT_BITS=%d%s",
(int)lt2[0], (int)lt2[1], row_kernel.cols / 2, col_kernel.cols / 2,
ocl::kernelToStr(row_kernel, wdepth, "KERNEL_MATRIX_X").c_str(),
ocl::kernelToStr(col_kernel, wdepth, "KERNEL_MATRIX_Y").c_str(),
ocl::typeToStr(stype), ocl::convertTypeStr(sdepth, wdepth, cn, cvt[0]),
ocl::typeToStr(CV_MAKE_TYPE(wdepth, cn)), ocl::typeToStr(dtype),
ocl::convertTypeStr(wdepth, ddepth, cn, cvt[1]), borderMap[borderType],
ocl::typeToStr(sdepth), ocl::typeToStr(ddepth), ocl::typeToStr(wdepth),
cn, 2*shift_bits, int_arithm ? " -D INTEGER_ARITHMETIC" : "");
ocl::Kernel k("sep_filter", ocl::imgproc::filterSep_singlePass_oclsrc, opts);
if (k.empty())
return false;
UMat src = _src.getUMat();
_dst.create(size, dtype);
UMat dst = _dst.getUMat();
int src_offset_x = static_cast<int>((src_offset % src_step) / esz);
int src_offset_y = static_cast<int>(src_offset / src_step);
src.locateROI(wholeSize, origin);
k.args(ocl::KernelArg::PtrReadOnly(src), (int)src_step, src_offset_x, src_offset_y,
wholeSize.height, wholeSize.width, ocl::KernelArg::WriteOnly(dst),
static_cast<float>(delta));
return k.run(2, gt2, lt2, false);
}
bool ocl_sepFilter2D( InputArray _src, OutputArray _dst, int ddepth,
InputArray _kernelX, InputArray _kernelY, Point anchor,
double delta, int borderType )
{
const ocl::Device & d = ocl::Device::getDefault();
Size imgSize = _src.size();
int type = _src.type(), sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
if (cn > 4)
return false;
Mat kernelX = _kernelX.getMat().reshape(1, 1);
if (kernelX.cols % 2 != 1)
return false;
Mat kernelY = _kernelY.getMat().reshape(1, 1);
if (kernelY.cols % 2 != 1)
return false;
if (ddepth < 0)
ddepth = sdepth;
if (anchor.x < 0)
anchor.x = kernelX.cols >> 1;
if (anchor.y < 0)
anchor.y = kernelY.cols >> 1;
int rtype = getKernelType(kernelX,
kernelX.rows == 1 ? Point(anchor.x, 0) : Point(0, anchor.x));
int ctype = getKernelType(kernelY,
kernelY.rows == 1 ? Point(anchor.y, 0) : Point(0, anchor.y));
int bdepth = CV_32F;
bool int_arithm = false;
if( sdepth == CV_8U && ddepth == CV_8U &&
rtype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL &&
ctype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL)
{
if (ocl::Device::getDefault().isIntel())
{
for (int i=0; i<kernelX.cols; i++)
kernelX.at<float>(0, i) = (float) cvRound(kernelX.at<float>(0, i) * (1 << shift_bits));
if (kernelX.data != kernelY.data)
for (int i=0; i<kernelX.cols; i++)
kernelY.at<float>(0, i) = (float) cvRound(kernelY.at<float>(0, i) * (1 << shift_bits));
} else
{
bdepth = CV_32S;
kernelX.convertTo( kernelX, bdepth, 1 << shift_bits );
kernelY.convertTo( kernelY, bdepth, 1 << shift_bits );
}
int_arithm = true;
}
CV_OCL_RUN_(kernelY.cols <= 21 && kernelX.cols <= 21 &&
imgSize.width > optimizedSepFilterLocalWidth + anchor.x &&
imgSize.height > optimizedSepFilterLocalHeight + anchor.y &&
(!(borderType & BORDER_ISOLATED) || _src.offset() == 0) &&
anchor == Point(kernelX.cols >> 1, kernelY.cols >> 1) &&
OCL_PERFORMANCE_CHECK(d.isIntel()), // TODO FIXIT
ocl_sepFilter2D_SinglePass(_src, _dst, kernelX, kernelY, delta,
borderType & ~BORDER_ISOLATED, ddepth, bdepth, int_arithm), true)
UMat src = _src.getUMat();
Size srcWholeSize; Point srcOffset;
src.locateROI(srcWholeSize, srcOffset);
bool fast8uc1 = type == CV_8UC1 && srcOffset.x % 4 == 0 &&
src.cols % 4 == 0 && src.step % 4 == 0;
Size srcSize = src.size();
Size bufSize(srcSize.width, srcSize.height + kernelY.cols - 1);
UMat buf(bufSize, CV_MAKETYPE(bdepth, cn));
if (!ocl_sepRowFilter2D(src, buf, kernelX, anchor.x, borderType, ddepth, fast8uc1, int_arithm))
return false;
_dst.create(srcSize, CV_MAKETYPE(ddepth, cn));
UMat dst = _dst.getUMat();
return ocl_sepColFilter2D(buf, dst, kernelY, delta, anchor.y, int_arithm);
}
#endif
}
CV_INSTRUMENT_REGION();
cv::Ptr<cv::BaseFilter> cv::getLinearFilter(int srcType, int dstType,
InputArray filter_kernel, Point anchor,
double delta, int bits)
{
Mat _kernel = filter_kernel.getMat();
int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(dstType);
int cn = CV_MAT_CN(srcType), kdepth = _kernel.depth();
CV_Assert( cn == CV_MAT_CN(dstType) && ddepth >= sdepth );
......@@ -3806,476 +3091,6 @@ cv::Ptr<cv::BaseFilter> cv::getLinearFilter(int srcType, int dstType,
srcType, dstType));
}
cv::Ptr<cv::FilterEngine> cv::createLinearFilter( int _srcType, int _dstType,
InputArray filter_kernel,
Point _anchor, double _delta,
int _rowBorderType, int _columnBorderType,
const Scalar& _borderValue )
{
Mat _kernel = filter_kernel.getMat();
_srcType = CV_MAT_TYPE(_srcType);
_dstType = CV_MAT_TYPE(_dstType);
int cn = CV_MAT_CN(_srcType);
CV_Assert( cn == CV_MAT_CN(_dstType) );
Mat kernel = _kernel;
int bits = 0;
/*int sdepth = CV_MAT_DEPTH(_srcType), ddepth = CV_MAT_DEPTH(_dstType);
int ktype = _kernel.depth() == CV_32S ? KERNEL_INTEGER : getKernelType(_kernel, _anchor);
if( sdepth == CV_8U && (ddepth == CV_8U || ddepth == CV_16S) &&
_kernel.rows*_kernel.cols <= (1 << 10) )
{
bits = (ktype & KERNEL_INTEGER) ? 0 : 11;
_kernel.convertTo(kernel, CV_32S, 1 << bits);
}*/
Ptr<BaseFilter> _filter2D = getLinearFilter(_srcType, _dstType,
kernel, _anchor, _delta, bits);
return makePtr<FilterEngine>(_filter2D, Ptr<BaseRowFilter>(),
Ptr<BaseColumnFilter>(), _srcType, _dstType, _srcType,
_rowBorderType, _columnBorderType, _borderValue );
}
//================================================================
// HAL interface
//================================================================
using namespace cv;
static bool replacementFilter2D(int stype, int dtype, int kernel_type,
uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
double delta, int borderType, bool isSubmatrix)
{
cvhalFilter2D* ctx;
int res = cv_hal_filterInit(&ctx, kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, width, height,
stype, dtype, borderType, delta, anchor_x, anchor_y, isSubmatrix, src_data == dst_data);
if (res != CV_HAL_ERROR_OK)
return false;
res = cv_hal_filter(ctx, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
bool success = (res == CV_HAL_ERROR_OK);
res = cv_hal_filterFree(ctx);
if (res != CV_HAL_ERROR_OK)
return false;
return success;
}
#ifdef HAVE_IPP
static bool ippFilter2D(int stype, int dtype, int kernel_type,
uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
double delta, int borderType,
bool isSubmatrix)
{
#ifdef HAVE_IPP_IW
CV_INSTRUMENT_REGION_IPP();
::ipp::IwiSize iwSize(width, height);
::ipp::IwiSize kernelSize(kernel_width, kernel_height);
IppDataType type = ippiGetDataType(CV_MAT_DEPTH(stype));
int channels = CV_MAT_CN(stype);
CV_UNUSED(isSubmatrix);
#if IPP_VERSION_X100 >= 201700 && IPP_VERSION_X100 <= 201702 // IPP bug with 1x1 kernel
if(kernel_width == 1 && kernel_height == 1)
return false;
#endif
#if IPP_DISABLE_FILTER2D_BIG_MASK
// Too big difference compared to OpenCV FFT-based convolution
if(kernel_type == CV_32FC1 && (type == ipp16s || type == ipp16u) && (kernel_width > 7 || kernel_height > 7))
return false;
// Poor optimization for big kernels
if(kernel_width > 7 || kernel_height > 7)
return false;
#endif
if(src_data == dst_data)
return false;
if(stype != dtype)
return false;
if(kernel_type != CV_16SC1 && kernel_type != CV_32FC1)
return false;
// TODO: Implement offset for 8u, 16u
if(std::fabs(delta) >= DBL_EPSILON)
return false;
if(!ippiCheckAnchor(anchor_x, anchor_y, kernel_width, kernel_height))
return false;
try
{
::ipp::IwiBorderSize iwBorderSize;
::ipp::IwiBorderType iwBorderType;
::ipp::IwiImage iwKernel(ippiSize(kernel_width, kernel_height), ippiGetDataType(CV_MAT_DEPTH(kernel_type)), CV_MAT_CN(kernel_type), 0, (void*)kernel_data, kernel_step);
::ipp::IwiImage iwSrc(iwSize, type, channels, ::ipp::IwiBorderSize(offset_x, offset_y, full_width-offset_x-width, full_height-offset_y-height), (void*)src_data, src_step);
::ipp::IwiImage iwDst(iwSize, type, channels, ::ipp::IwiBorderSize(offset_x, offset_y, full_width-offset_x-width, full_height-offset_y-height), (void*)dst_data, dst_step);
iwBorderSize = ::ipp::iwiSizeToBorderSize(kernelSize);
iwBorderType = ippiGetBorder(iwSrc, borderType, iwBorderSize);
if(!iwBorderType)
return false;
CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilter, iwSrc, iwDst, iwKernel, ::ipp::IwiFilterParams(1, 0, ippAlgHintNone, ippRndFinancial), iwBorderType);
}
catch(const ::ipp::IwException& ex)
{
CV_UNUSED(ex);
return false;
}
return true;
#else
CV_UNUSED(stype); CV_UNUSED(dtype); CV_UNUSED(kernel_type); CV_UNUSED(src_data); CV_UNUSED(src_step);
CV_UNUSED(dst_data); CV_UNUSED(dst_step); CV_UNUSED(width); CV_UNUSED(height); CV_UNUSED(full_width);
CV_UNUSED(full_height); CV_UNUSED(offset_x); CV_UNUSED(offset_y); CV_UNUSED(kernel_data); CV_UNUSED(kernel_step);
CV_UNUSED(kernel_width); CV_UNUSED(kernel_height); CV_UNUSED(anchor_x); CV_UNUSED(anchor_y); CV_UNUSED(delta);
CV_UNUSED(borderType); CV_UNUSED(isSubmatrix);
return false;
#endif
}
#endif
static bool dftFilter2D(int stype, int dtype, int kernel_type,
uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
double delta, int borderType)
{
{
int sdepth = CV_MAT_DEPTH(stype);
int ddepth = CV_MAT_DEPTH(dtype);
int dft_filter_size = checkHardwareSupport(CV_CPU_SSE3) && ((sdepth == CV_8U && (ddepth == CV_8U || ddepth == CV_16S)) || (sdepth == CV_32F && ddepth == CV_32F)) ? 130 : 50;
if (kernel_width * kernel_height < dft_filter_size)
return false;
}
Point anchor = Point(anchor_x, anchor_y);
Mat kernel = Mat(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
Mat src(Size(full_width-offset_x, full_height-offset_y), stype, src_data, src_step);
Mat dst(Size(full_width, full_height), dtype, dst_data, dst_step);
Mat temp;
int src_channels = CV_MAT_CN(stype);
int dst_channels = CV_MAT_CN(dtype);
int ddepth = CV_MAT_DEPTH(dtype);
// crossCorr doesn't accept non-zero delta with multiple channels
if (src_channels != 1 && delta != 0) {
// The semantics of filter2D require that the delta be applied
// as floating-point math. So wee need an intermediate Mat
// with a float datatype. If the dest is already floats,
// we just use that.
int corrDepth = ddepth;
if ((ddepth == CV_32F || ddepth == CV_64F) && src_data != dst_data) {
temp = Mat(Size(full_width, full_height), dtype, dst_data, dst_step);
} else {
corrDepth = ddepth == CV_64F ? CV_64F : CV_32F;
temp.create(Size(full_width, full_height), CV_MAKETYPE(corrDepth, dst_channels));
}
crossCorr(src, kernel, temp, src.size(),
CV_MAKETYPE(corrDepth, src_channels),
anchor, 0, borderType);
add(temp, delta, temp);
if (temp.data != dst_data) {
temp.convertTo(dst, dst.type());
}
} else {
if (src_data != dst_data)
temp = Mat(Size(full_width, full_height), dtype, dst_data, dst_step);
else
temp.create(Size(full_width, full_height), dtype);
crossCorr(src, kernel, temp, src.size(),
CV_MAKETYPE(ddepth, src_channels),
anchor, delta, borderType);
if (temp.data != dst_data)
temp.copyTo(dst);
}
return true;
}
static void ocvFilter2D(int stype, int dtype, int kernel_type,
uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
double delta, int borderType)
{
int borderTypeValue = borderType & ~BORDER_ISOLATED;
Mat kernel = Mat(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
Ptr<FilterEngine> f = createLinearFilter(stype, dtype, kernel, Point(anchor_x, anchor_y), delta,
borderTypeValue);
Mat src(Size(width, height), stype, src_data, src_step);
Mat dst(Size(width, height), dtype, dst_data, dst_step);
f->apply(src, dst, Size(full_width, full_height), Point(offset_x, offset_y));
}
static bool replacementSepFilter(int stype, int dtype, int ktype,
uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernelx_data, int kernelx_len,
uchar * kernely_data, int kernely_len,
int anchor_x, int anchor_y, double delta, int borderType)
{
cvhalFilter2D *ctx;
int res = cv_hal_sepFilterInit(&ctx, stype, dtype, ktype,
kernelx_data, kernelx_len,
kernely_data, kernely_len,
anchor_x, anchor_y, delta, borderType);
if (res != CV_HAL_ERROR_OK)
return false;
res = cv_hal_sepFilter(ctx, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
bool success = (res == CV_HAL_ERROR_OK);
res = cv_hal_sepFilterFree(ctx);
if (res != CV_HAL_ERROR_OK)
return false;
return success;
}
static void ocvSepFilter(int stype, int dtype, int ktype,
uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernelx_data, int kernelx_len,
uchar * kernely_data, int kernely_len,
int anchor_x, int anchor_y, double delta, int borderType)
{
Mat kernelX(Size(kernelx_len, 1), ktype, kernelx_data);
Mat kernelY(Size(kernely_len, 1), ktype, kernely_data);
Ptr<FilterEngine> f = createSeparableLinearFilter(stype, dtype, kernelX, kernelY,
Point(anchor_x, anchor_y),
delta, borderType & ~BORDER_ISOLATED);
Mat src(Size(width, height), stype, src_data, src_step);
Mat dst(Size(width, height), dtype, dst_data, dst_step);
f->apply(src, dst, Size(full_width, full_height), Point(offset_x, offset_y));
};
//===================================================================
// HAL functions
//===================================================================
namespace cv {
namespace hal {
CV_DEPRECATED Ptr<hal::Filter2D> Filter2D::create(uchar * , size_t , int ,
int , int ,
int , int ,
int , int ,
int , double ,
int , int ,
bool , bool ) { return Ptr<hal::Filter2D>(); }
CV_DEPRECATED Ptr<hal::SepFilter2D> SepFilter2D::create(int , int , int ,
uchar * , int ,
uchar * , int ,
int , int ,
double , int ) { return Ptr<hal::SepFilter2D>(); }
void filter2D(int stype, int dtype, int kernel_type,
uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
double delta, int borderType,
bool isSubmatrix)
{
bool res;
res = replacementFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
width, height,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType, isSubmatrix);
if (res)
return;
CV_IPP_RUN_FAST(ippFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
width, height,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType, isSubmatrix))
res = dftFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType);
if (res)
return;
ocvFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
width, height,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType);
}
//---------------------------------------------------------------
void sepFilter2D(int stype, int dtype, int ktype,
uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernelx_data, int kernelx_len,
uchar * kernely_data, int kernely_len,
int anchor_x, int anchor_y, double delta, int borderType)
{
bool res = replacementSepFilter(stype, dtype, ktype,
src_data, src_step, dst_data, dst_step,
width, height, full_width, full_height,
offset_x, offset_y,
kernelx_data, kernelx_len,
kernely_data, kernely_len,
anchor_x, anchor_y, delta, borderType);
if (res)
return;
ocvSepFilter(stype, dtype, ktype,
src_data, src_step, dst_data, dst_step,
width, height, full_width, full_height,
offset_x, offset_y,
kernelx_data, kernelx_len,
kernely_data, kernely_len,
anchor_x, anchor_y, delta, borderType);
}
} // cv::hal::
} // cv::
//================================================================
// Main interface
//================================================================
void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth,
InputArray _kernel, Point anchor0,
double delta, int borderType )
{
CV_INSTRUMENT_REGION();
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
ocl_filter2D(_src, _dst, ddepth, _kernel, anchor0, delta, borderType))
Mat src = _src.getMat(), kernel = _kernel.getMat();
if( ddepth < 0 )
ddepth = src.depth();
_dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
Mat dst = _dst.getMat();
Point anchor = normalizeAnchor(anchor0, kernel.size());
Point ofs;
Size wsz(src.cols, src.rows);
if( (borderType & BORDER_ISOLATED) == 0 )
src.locateROI( wsz, ofs );
hal::filter2D(src.type(), dst.type(), kernel.type(),
src.data, src.step, dst.data, dst.step,
dst.cols, dst.rows, wsz.width, wsz.height, ofs.x, ofs.y,
kernel.data, kernel.step, kernel.cols, kernel.rows,
anchor.x, anchor.y,
delta, borderType, src.isSubmatrix());
}
void cv::sepFilter2D( InputArray _src, OutputArray _dst, int ddepth,
InputArray _kernelX, InputArray _kernelY, Point anchor,
double delta, int borderType )
{
CV_INSTRUMENT_REGION();
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && (size_t)_src.rows() > _kernelY.total() && (size_t)_src.cols() > _kernelX.total(),
ocl_sepFilter2D(_src, _dst, ddepth, _kernelX, _kernelY, anchor, delta, borderType))
Mat src = _src.getMat(), kernelX = _kernelX.getMat(), kernelY = _kernelY.getMat();
if( ddepth < 0 )
ddepth = src.depth();
_dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
Mat dst = _dst.getMat();
Point ofs;
Size wsz(src.cols, src.rows);
if( (borderType & BORDER_ISOLATED) == 0 )
src.locateROI( wsz, ofs );
CV_Assert( kernelX.type() == kernelY.type() &&
(kernelX.cols == 1 || kernelX.rows == 1) &&
(kernelY.cols == 1 || kernelY.rows == 1) );
Mat contKernelX = kernelX.isContinuous() ? kernelX : kernelX.clone();
Mat contKernelY = kernelY.isContinuous() ? kernelY : kernelY.clone();
hal::sepFilter2D(src.type(), dst.type(), kernelX.type(),
src.data, src.step, dst.data, dst.step,
dst.cols, dst.rows, wsz.width, wsz.height, ofs.x, ofs.y,
contKernelX.data, kernelX.cols + kernelX.rows - 1,
contKernelY.data, kernelY.cols + kernelY.rows - 1,
anchor.x, anchor.y, delta, borderType & ~BORDER_ISOLATED);
}
CV_IMPL void
cvFilter2D( const CvArr* srcarr, CvArr* dstarr, const CvMat* _kernel, CvPoint anchor )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
cv::Mat kernel = cv::cvarrToMat(_kernel);
CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() );
cv::filter2D( src, dst, dst.depth(), kernel, anchor, 0, cv::BORDER_REPLICATE );
}
/* End of file. */
CV_CPU_OPTIMIZATION_NAMESPACE_END
} // namespace
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