Merge pull request #6243 from mshabunin:hal_morph

pull/6318/head
Vadim Pisarevsky 9 years ago
commit e792ee89de
  1. 12
      modules/core/include/opencv2/core/private.hpp
  2. 16
      modules/imgproc/include/opencv2/imgproc/hal/hal.hpp
  3. 2
      modules/imgproc/src/filterengine.hpp
  4. 8
      modules/imgproc/src/hal_replacement.hpp
  5. 638
      modules/imgproc/src/morph.cpp

@ -221,6 +221,18 @@ static inline IppiSize ippiSize(const cv::Size & _size)
return size;
}
static inline IppiPoint ippiPoint(const cv::Point & _point)
{
IppiPoint point = { _point.x, _point.y };
return point;
}
static inline IppiPoint ippiPoint(int x, int y)
{
IppiPoint point = { x, y };
return point;
}
static inline IppiBorderType ippiGetBorderType(int borderTypeNI)
{
return borderTypeNI == cv::BORDER_CONSTANT ? ippBorderConst :

@ -44,6 +44,22 @@ struct CV_EXPORTS SepFilter2D
virtual ~SepFilter2D() {}
};
struct CV_EXPORTS MorphContext
{
static Ptr<MorphContext> create(int op, int src_type, int dst_type, int max_width, int max_height,
int kernel_type, uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
int borderType, const double borderValue[4],
int iterations, bool isSubmatrix, bool allowInplace);
virtual void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
int roi_width, int roi_height, int roi_x, int roi_y,
int roi_width2, int roi_height2, int roi_x2, int roi_y2) = 0;
virtual ~MorphContext() {}
};
//! @}
}}

@ -37,6 +37,8 @@ the use of this software, even if advised of the possibility of such damage.
#ifndef __OPENCV_IMGPROC_FILTERENGINE_HPP__
#define __OPENCV_IMGPROC_FILTERENGINE_HPP__
#include "opencv2/imgproc.hpp"
namespace cv
{

@ -21,6 +21,14 @@ inline int hal_ni_sepFilterFree(cvhalFilter2D *) { return CV_HAL_ERROR_NOT_IMPLE
#define cv_hal_sepFilter hal_ni_sepFilter
#define cv_hal_sepFilterFree hal_ni_sepFilterFree
inline int hal_ni_morphInit(cvhalFilter2D **, int, int, int, int, int, int, uchar *, size_t, int, int, int, int, int, const double[4], int, bool, bool) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
inline int hal_ni_morph(cvhalFilter2D *, uchar *, size_t, uchar *, size_t, int, int, int, int, int, int, int, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
inline int hal_ni_morphFree(cvhalFilter2D *) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
#define cv_hal_morphInit hal_ni_morphInit
#define cv_hal_morph hal_ni_morph
#define cv_hal_morphFree hal_ni_morphFree
#include "custom_hal.hpp"
#endif // OPENCV_IMGPROC_HAL_REPLACEMENT_HPP

@ -43,11 +43,15 @@
#include "precomp.hpp"
#include <limits.h>
#include "opencl_kernels_imgproc.hpp"
#include <iostream>
#include "hal_replacement.hpp"
/****************************************************************************************\
Basic Morphological Operations: Erosion & Dilation
\****************************************************************************************/
using namespace std;
namespace cv
{
@ -584,19 +588,11 @@ typedef MorphFVec<VMax32f> DilateVec32f;
#else
#ifdef HAVE_TEGRA_OPTIMIZATION
using tegra::ErodeRowVec8u;
using tegra::DilateRowVec8u;
using tegra::ErodeColumnVec8u;
using tegra::DilateColumnVec8u;
#else
typedef MorphRowNoVec ErodeRowVec8u;
typedef MorphRowNoVec DilateRowVec8u;
typedef MorphColumnNoVec ErodeColumnVec8u;
typedef MorphColumnNoVec DilateColumnVec8u;
#endif
typedef MorphRowNoVec ErodeRowVec16u;
typedef MorphRowNoVec DilateRowVec16u;
@ -1081,311 +1077,399 @@ cv::Mat cv::getStructuringElement(int shape, Size ksize, Point anchor)
namespace cv
{
class MorphologyRunner : public ParallelLoopBody
// ===== 1. replacement implementation
struct ReplacementMorphImpl : public hal::MorphContext
{
public:
MorphologyRunner(Mat _src, Mat _dst, int _nStripes, int _iterations,
int _op, Mat _kernel, Point _anchor,
int _rowBorderType, int _columnBorderType, const Scalar& _borderValue) :
borderValue(_borderValue)
cvhalFilter2D * ctx;
bool isInitialized;
bool init(int op, int src_type, int dst_type, int max_width, int max_height,
int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
int borderType, const double borderValue[4],
int iterations, bool isSubmatrix, bool allowInplace)
{
src = _src;
dst = _dst;
int res = cv_hal_morphInit(&ctx, op, src_type, dst_type, max_width, max_height,
kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
anchor_x, anchor_y,
borderType, borderValue,
iterations, isSubmatrix, allowInplace);
isInitialized = (res == CV_HAL_ERROR_OK);
return isInitialized;
}
void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
int roi_width, int roi_height, int roi_x, int roi_y,
int roi_width2, int roi_height2, int roi_x2, int roi_y2)
{
if (isInitialized)
{
int res = cv_hal_morph(ctx, src_data, src_step, dst_data, dst_step, width, height,
roi_width, roi_height,
roi_x, roi_y,
roi_width2, roi_height2,
roi_x2, roi_y2);
if (res != CV_HAL_ERROR_OK)
CV_Error(Error::StsNotImplemented, "Failed to run HAL morph implementation");
}
}
~ReplacementMorphImpl()
{
if (isInitialized)
{
int res = cv_hal_morphFree(ctx);
if (res != CV_HAL_ERROR_OK)
CV_Error(Error::StsNotImplemented, "Failed to run HAL morph implementation");
}
}
};
nStripes = _nStripes;
iterations = _iterations;
// ===== 2. IPP implementation
op = _op;
kernel = _kernel;
anchor = _anchor;
rowBorderType = _rowBorderType;
columnBorderType = _columnBorderType;
}
#ifdef HAVE_IPP
void operator () ( const Range& range ) const
{
int row0 = std::min(cvRound(range.start * src.rows / nStripes), src.rows);
int row1 = std::min(cvRound(range.end * src.rows / nStripes), src.rows);
#if IPP_VERSION_X100 >= 810
/*if(0)
printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n",
src.rows, src.cols, range.start, range.end, row0, row1);*/
template <int cvtype> struct IppMorphTrait {};
Mat srcStripe = src.rowRange(row0, row1);
Mat dstStripe = dst.rowRange(row0, row1);
#if IPP_VERSION_X100 >= 900
Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(), kernel, anchor,
rowBorderType, columnBorderType, borderValue );
#define INIT_TRAIT(cvtype, ipptype, flavor, channels, zerodef)\
template <>\
struct IppMorphTrait<cvtype>\
{\
typedef Ipp##ipptype ipp_data_type;\
enum { cn = channels };\
IppDataType getDataType() {return ipp##ipptype;}\
\
IppStatus getMorphSize(IppiSize roiSize, IppiSize maskSize, int* pSpecSize, int* pBufferSize) {return ippiMorphologyBorderGetSize_##flavor(roiSize, maskSize, pSpecSize, pBufferSize);}\
IppStatus morphInit(IppiSize roiSize, const Ipp8u* pMask, IppiSize maskSize, IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiMorphologyBorderInit_##flavor(roiSize, pMask, maskSize, pMorphSpec, pBuffer);}\
IppStatus filterGetMinSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType dataType, int numChannels, int* pBufferSize) {return ippiFilterMinBorderGetBufferSize(dstRoiSize, maskSize, dataType, numChannels, pBufferSize);}\
IppStatus filterGetMaxSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType dataType, int numChannels, int* pBufferSize) {return ippiFilterMaxBorderGetBufferSize(dstRoiSize, maskSize, dataType, numChannels, pBufferSize);}\
IppStatus filterMinBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint, Ipp8u* pBuffer) { ipp_data_type zerodef; return ippiFilterMinBorder_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, ippBorderRepl, zero, pBuffer); }\
IppStatus filterMaxBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint, Ipp8u* pBuffer) { ipp_data_type zerodef; return ippiFilterMaxBorder_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, ippBorderRepl, zero, pBuffer); }\
IppStatus morphDilate(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) { ipp_data_type zerodef; return ippiDilateBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, zero, pMorphSpec, pBuffer); }\
IppStatus morphErode(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) { ipp_data_type zerodef; return ippiErodeBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, zero, pMorphSpec, pBuffer); }\
};
{
Point ofs;
Size wsz(srcStripe.cols, srcStripe.rows);
srcStripe.locateROI( wsz, ofs );
#else
f->apply( srcStripe, dstStripe, wsz, ofs );
}
#define INIT_TRAIT(cvtype, ipptype, flavor, channels, zerodef)\
template <>\
struct IppMorphTrait<cvtype>\
{\
typedef Ipp##ipptype ipp_data_type;\
enum { cn = channels };\
IppDataType getDataType() {return ipp##ipptype;}\
\
IppStatus getMorphSize(IppiSize roiSize, IppiSize maskSize, int* pSpecSize, int* pBufferSize) {return ippiMorphologyBorderGetSize_##flavor(roiSize.width, maskSize, pSpecSize, pBufferSize);}\
IppStatus morphInit(IppiSize roiSize, const Ipp8u* pMask, IppiSize maskSize, IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiMorphologyBorderInit_##flavor(roiSize.width, pMask, maskSize, pMorphSpec, pBuffer);}\
IppStatus filterGetMinSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType, int, int* pBufferSize) {return ippiFilterMinGetBufferSize_##flavor(dstRoiSize.width, maskSize, pBufferSize);}\
IppStatus filterGetMaxSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType, int, int* pBufferSize) {return ippiFilterMinGetBufferSize_##flavor(dstRoiSize.width, maskSize, pBufferSize);}\
IppStatus filterMinBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint anchor, Ipp8u* pBuffer) { return ippiFilterMinBorderReplicate_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, anchor, pBuffer); }\
IppStatus filterMaxBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint anchor, Ipp8u* pBuffer) { return ippiFilterMaxBorderReplicate_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, anchor, pBuffer); }\
IppStatus morphDilate(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiDilateBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, 0, pMorphSpec, pBuffer);}\
IppStatus morphErode(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiErodeBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, 0, pMorphSpec, pBuffer);}\
};
{
Point ofs;
Size wsz(dstStripe.cols, dstStripe.rows);
dstStripe.locateROI( wsz, ofs );
#endif
for( int i = 1; i < iterations; i++ )
f->apply( dstStripe, dstStripe, wsz, ofs );
}
}
INIT_TRAIT(CV_8UC1, 8u, 8u_C1R, 1, zero = 0)
INIT_TRAIT(CV_8UC3, 8u, 8u_C3R, 3, zero[3] = {0})
INIT_TRAIT(CV_8UC4, 8u, 8u_C4R, 4, zero[4] = {0})
INIT_TRAIT(CV_32FC1, 32f, 32f_C1R, 1, zero = 0)
INIT_TRAIT(CV_32FC3, 32f, 32f_C3R, 3, zero[3] = {0})
INIT_TRAIT(CV_32FC4, 32f, 32f_C4R, 4, zero[4] = {0})
private:
Mat src;
Mat dst;
int nStripes;
int iterations;
#undef INIT_TRAIT
int op;
Mat kernel;
Point anchor;
int rowBorderType;
int columnBorderType;
Scalar borderValue;
};
//--------------------------------------
#ifdef HAVE_IPP
static bool ipp_MorphReplicate(int op, const Mat &src, Mat &dst, const Mat &kernel,
const Size& ksize, const Point &anchor, bool rectKernel)
struct IppMorphBaseImpl : public hal::MorphContext
{
#if IPP_VERSION_X100 >= 810
int type = src.type();
const Mat* _src = &src;
Mat temp;
if (src.data == dst.data)
{
src.copyTo(temp);
_src = &temp;
}
IppiSize roiSize = {src.cols, src.rows};
IppiSize kernelSize = {ksize.width, ksize.height};
virtual bool init(int _op, int _src_type, int dst_type, int max_width, int max_height,
int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
int borderType, const double borderValue[4],
int iterations, bool isSubmatrix, bool allowInplace) = 0;
};
if (!rectKernel)
template <int cvtype>
struct IppMorphImpl : public IppMorphBaseImpl
{
IppMorphTrait<cvtype> trait;
typedef typename IppMorphTrait<cvtype>::ipp_data_type ipp_data_type;
IppAutoBuffer<IppiMorphState> specBuf;
IppAutoBuffer<Ipp8u> workBuf;
IppiSize kernelSize;
bool rectKernel;
IppiPoint anchor;
int op;
int src_type;
int border;
bool init(int _op, int _src_type, int dst_type, int max_width, int max_height,
int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
int borderType, const double borderValue[4],
int iterations, bool isSubmatrix, bool allowInplace)
{
#if IPP_VERSION_X100 >= 900
if (((kernel.cols - 1) / 2 != anchor.x) || ((kernel.rows - 1) / 2 != anchor.y))
return false;
#define IPP_MORPH_CASE(cvtype, flavor, data_type) \
case cvtype: \
{\
int specSize = 0, bufferSize = 0;\
if (0 > ippiMorphologyBorderGetSize_##flavor(roiSize, kernelSize, &specSize, &bufferSize))\
return false;\
IppiMorphState *pSpec = (IppiMorphState*)ippMalloc(specSize);\
Ipp8u *pBuffer = (Ipp8u*)ippMalloc(bufferSize);\
if (0 > ippiMorphologyBorderInit_##flavor(roiSize, kernel.ptr(), kernelSize, pSpec, pBuffer))\
{\
ippFree(pBuffer);\
ippFree(pSpec);\
return false;\
}\
bool ok = false;\
if (op == MORPH_ERODE)\
ok = (0 <= ippiErodeBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
else\
ok = (0 <= ippiDilateBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
ippFree(pBuffer);\
ippFree(pSpec);\
return ok;\
}\
break;
#else
if (((kernel.cols - 1) / 2 != anchor.x) || ((kernel.rows - 1) / 2 != anchor.y))
border = borderType; // TODO: remove
anchor = ippiPoint(anchor_x, anchor_y);
CV_UNUSED(dst_type);
src_type = _src_type;
Mat kernel(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
int depth = CV_MAT_DEPTH(src_type), cn = CV_MAT_CN(src_type);
if( !( depth == CV_8U || depth == CV_32F )
|| !(cn == 1 || cn == 3 || cn == 4)
|| !( borderType == cv::BORDER_REPLICATE
|| (borderType == cv::BORDER_CONSTANT && Vec<double, 4>(borderValue) == morphologyDefaultBorderValue() && kernel.size() == Size(3,3)))
|| !( op == MORPH_DILATE || op == MORPH_ERODE)
|| isSubmatrix
|| allowInplace)
return false;
#define IPP_MORPH_CASE(cvtype, flavor, data_type) \
case cvtype: \
{\
int specSize = 0, bufferSize = 0;\
if (0 > ippiMorphologyBorderGetSize_##flavor(roiSize.width, kernelSize, &specSize, &bufferSize))\
return false;\
IppiMorphState *pSpec = (IppiMorphState*)ippMalloc(specSize);\
Ipp8u *pBuffer = (Ipp8u*)ippMalloc(bufferSize);\
if (0 > ippiMorphologyBorderInit_##flavor(roiSize.width, kernel.ptr(), kernelSize, pSpec, pBuffer))\
{\
ippFree(pBuffer);\
ippFree(pSpec);\
return false;\
}\
bool ok = false;\
if (op == MORPH_ERODE)\
ok = (0 <= ippiErodeBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
else\
ok = (0 <= ippiDilateBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
ippFree(pBuffer);\
ippFree(pSpec);\
return ok;\
}\
break;
#endif
CV_SUPPRESS_DEPRECATED_START
switch (type)
// In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only
if( borderType == cv::BORDER_CONSTANT && kernel.data )
{
IPP_MORPH_CASE(CV_8UC1, 8u_C1R, 8u);
IPP_MORPH_CASE(CV_8UC3, 8u_C3R, 8u);
IPP_MORPH_CASE(CV_8UC4, 8u_C4R, 8u);
IPP_MORPH_CASE(CV_32FC1, 32f_C1R, 32f);
IPP_MORPH_CASE(CV_32FC3, 32f_C3R, 32f);
IPP_MORPH_CASE(CV_32FC4, 32f_C4R, 32f);
default:
;
int x, y;
for( y = 0; y < kernel.rows; y++ )
{
if( kernel.at<uchar>(y, anchor.x) != 0 )
continue;
for( x = 0; x < kernel.cols; x++ )
{
if( kernel.at<uchar>(y,x) != 0 )
return false;
}
}
for( x = 0; x < kernel.cols; x++ )
{
if( kernel.at<uchar>(anchor.y, x) != 0 )
continue;
for( y = 0; y < kernel.rows; y++ )
{
if( kernel.at<uchar>(y,x) != 0 )
return false;
}
}
}
CV_SUPPRESS_DEPRECATED_END
#undef IPP_MORPH_CASE
}
else
{
#if IPP_VERSION_X100 != 900 // Problems with accuracy in 9.0.0
#if IPP_VERSION_X100 >= 900
if (((kernelSize.width - 1) / 2 != anchor.x) || ((kernelSize.height - 1) / 2 != anchor.y)) // Arbitrary anchor is no longer supporeted since IPP 9.0.0
return false;
#define IPP_MORPH_CASE(cvtype, flavor, data_type, cn) \
case cvtype: \
{\
if (op == MORPH_ERODE)\
{\
int bufSize = 0;\
if (0 > ippiFilterMinBorderGetBufferSize(roiSize, kernelSize, ipp##data_type, cn, &bufSize))\
return false;\
AutoBuffer<uchar> buf(bufSize + 64);\
uchar* buffer = alignPtr((uchar*)buf, 32);\
return (0 <= ippiFilterMinBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, ippBorderRepl, 0, buffer));\
}\
else\
{\
int bufSize = 0;\
if (0 > ippiFilterMaxBorderGetBufferSize(roiSize, kernelSize, ipp##data_type, cn, &bufSize))\
return false;\
AutoBuffer<uchar> buf(bufSize + 64);\
uchar* buffer = alignPtr((uchar*)buf, 32);\
return (0 <= ippiFilterMaxBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, ippBorderRepl, 0, buffer));\
}\
}\
break;
#else
IppiPoint point = {anchor.x, anchor.y};
#define IPP_MORPH_CASE(cvtype, flavor, data_type, cn) \
case cvtype: \
{\
int bufSize = 0;\
if (0 > ippiFilterMinGetBufferSize_##flavor(src.cols, kernelSize, &bufSize))\
return false;\
AutoBuffer<uchar> buf(bufSize + 64);\
uchar* buffer = alignPtr((uchar*)buf, 32);\
if (op == MORPH_ERODE)\
return (0 <= ippiFilterMinBorderReplicate_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, point, buffer));\
return (0 <= ippiFilterMaxBorderReplicate_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, point, buffer));\
}\
break;
#endif
Size ksize = !kernel.empty() ? kernel.size() : Size(3,3);
CV_SUPPRESS_DEPRECATED_START
switch (type)
rectKernel = false;
if( kernel.empty() )
{
IPP_MORPH_CASE(CV_8UC1, 8u_C1R, 8u, 1);
IPP_MORPH_CASE(CV_8UC3, 8u_C3R, 8u, 3);
IPP_MORPH_CASE(CV_8UC4, 8u_C4R, 8u, 4);
IPP_MORPH_CASE(CV_32FC1, 32f_C1R, 32f, 1);
IPP_MORPH_CASE(CV_32FC3, 32f_C3R, 32f, 3);
IPP_MORPH_CASE(CV_32FC4, 32f_C4R, 32f, 4);
default:
;
ksize = Size(1+iterations*2,1+iterations*2);
anchor = ippiPoint(iterations, iterations);
rectKernel = true;
iterations = 1;
}
else if( iterations >= 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
{
ksize = Size(ksize.width + (iterations-1)*(ksize.width-1),
ksize.height + (iterations-1)*(ksize.height-1)),
anchor = ippiPoint(anchor.x*iterations, anchor.y*iterations);
kernel = Mat();
rectKernel = true;
iterations = 1;
}
CV_SUPPRESS_DEPRECATED_END
#undef IPP_MORPH_CASE
#endif
}
#else
CV_UNUSED(op); CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(kernel); CV_UNUSED(ksize); CV_UNUSED(anchor); CV_UNUSED(rectKernel);
#endif
return false;
}
static bool ipp_MorphOp(int op, InputArray _src, OutputArray _dst,
const Mat& _kernel, Point anchor, int iterations,
int borderType, const Scalar &borderValue)
{
Mat src = _src.getMat(), kernel = _kernel;
int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
// TODO: implement the case of iterations > 1.
if( iterations > 1 )
return false;
if( !( depth == CV_8U || depth == CV_32F ) || !(cn == 1 || cn == 3 || cn == 4) ||
!( borderType == cv::BORDER_REPLICATE || (borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue() &&
kernel.size() == Size(3,3)) ) || !( op == MORPH_DILATE || op == MORPH_ERODE) || _src.isSubmatrix() )
return false;
IppiSize roiSize = {max_width, max_height};
kernelSize = ippiSize(ksize);
op = _op;
// In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only
if( borderType == cv::BORDER_CONSTANT && kernel.data )
{
int x, y;
for( y = 0; y < kernel.rows; y++ )
IppStatus res;
if (!rectKernel)
{
if( kernel.at<uchar>(y, anchor.x) != 0 )
continue;
for( x = 0; x < kernel.cols; x++ )
if (((kernel.cols - 1) / 2 != anchor.x) || ((kernel.rows - 1) / 2 != anchor.y))
return false;
int specSize = 0, bufferSize = 0;
res = trait.getMorphSize(roiSize, kernelSize, &specSize, &bufferSize);
if (res >= 0)
{
if( kernel.at<uchar>(y,x) != 0 )
return false;
specBuf.Alloc(specSize);
workBuf.Alloc(bufferSize);
res = trait.morphInit(roiSize, kernel.ptr(), kernelSize, specBuf, workBuf);
if (res >= 0)
return true;
}
}
for( x = 0; x < kernel.cols; x++ )
else
{
if( kernel.at<uchar>(anchor.y, x) != 0 )
continue;
for( y = 0; y < kernel.rows; y++ )
if (((kernelSize.width - 1) / 2 != anchor.x) || ((kernelSize.height - 1) / 2 != anchor.y))
return false;
if (op == MORPH_ERODE)
{
if( kernel.at<uchar>(y,x) != 0 )
return false;
int bufSize = 0;
res = trait.filterGetMinSize(roiSize, kernelSize, trait.getDataType(), trait.cn, &bufSize);
if (res >= 0)
{
workBuf.Alloc(bufSize);
return true;
}
}
else
{
int bufSize = 0;
res = trait.filterGetMaxSize(roiSize, kernelSize, trait.getDataType(), trait.cn, &bufSize);
if (res >= 0)
{
workBuf.Alloc(bufSize);
return true;
}
}
}
return false;
}
Size ksize = !kernel.empty() ? kernel.size() : Size(3,3);
_dst.create( src.size(), src.type() );
Mat dst = _dst.getMat();
void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
int roi_width, int roi_height, int roi_x, int roi_y,
int roi_width2, int roi_height2, int roi_x2, int roi_y2)
{
CV_UNUSED(roi_width); CV_UNUSED(roi_height); CV_UNUSED(roi_x); CV_UNUSED(roi_y);
CV_UNUSED(roi_width2); CV_UNUSED(roi_height2); CV_UNUSED(roi_x2); CV_UNUSED(roi_y2);
if (src_data == dst_data)
CV_Error(Error::StsBadArg, "IPP Morph inplace is not alowed");
IppiSize roiSize = {width, height};
IppStatus res;
if (!rectKernel)
{
if (op == MORPH_ERODE)
res = (trait.morphErode((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, specBuf, workBuf));
else
res = (trait.morphDilate((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, specBuf, workBuf));
}
else
{
if (op == MORPH_ERODE)
res = (trait.filterMinBorder((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, kernelSize, anchor, workBuf));
else
res = (trait.filterMaxBorder((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, kernelSize, anchor, workBuf));
}
if (res < 0)
CV_Error(Error::StsBadArg, "Failed to run IPP morph");
}
};
if( iterations == 0 || kernel.rows*kernel.cols == 1 )
static IppMorphBaseImpl * createIppImpl(int type)
{
switch (type)
{
src.copyTo(dst);
return true;
case CV_8UC1: return new IppMorphImpl<CV_8UC1>();
case CV_8UC3: return new IppMorphImpl<CV_8UC3>();
case CV_8UC4: return new IppMorphImpl<CV_8UC4>();
case CV_32FC1: return new IppMorphImpl<CV_32FC1>();
case CV_32FC3: return new IppMorphImpl<CV_32FC3>();
case CV_32FC4: return new IppMorphImpl<CV_32FC4>();
}
return 0;
}
#endif // IPP_VERSION_X100 >= 810
#endif // HAVE_IPP
// ===== 3. Fallback implementation
bool rectKernel = false;
if( kernel.empty() )
struct OcvMorphImpl : public hal::MorphContext
{
Ptr<FilterEngine> f;
int iterations;
int src_type;
int dst_type;
bool init(int op, int _src_type, int _dst_type, int, int,
int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
int borderType, const double _borderValue[4],
int _iterations, bool, bool)
{
ksize = Size(1+iterations*2,1+iterations*2);
anchor = Point(iterations, iterations);
rectKernel = true;
iterations = 1;
iterations = _iterations;
src_type = _src_type;
dst_type = _dst_type;
Mat kernel(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
Point anchor(anchor_x, anchor_y);
Vec<double, 4> borderValue(_borderValue);
f = createMorphologyFilter(op, src_type, kernel, anchor, borderType, borderType, borderValue );
return true;
}
else if( iterations >= 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
int roi_width, int roi_height, int roi_x, int roi_y,
int roi_width2, int roi_height2, int roi_x2, int roi_y2)
{
ksize = Size(ksize.width + (iterations-1)*(ksize.width-1),
ksize.height + (iterations-1)*(ksize.height-1)),
anchor = Point(anchor.x*iterations, anchor.y*iterations);
kernel = Mat();
rectKernel = true;
iterations = 1;
Mat src(Size(width, height), src_type, src_data, src_step);
Mat dst(Size(width, height), dst_type, dst_data, dst_step);
{
Point ofs(roi_x, roi_y);
Size wsz(roi_width, roi_height);
f->apply( src, dst, wsz, ofs );
}
{
Point ofs(roi_x2, roi_y2);
Size wsz(roi_width2, roi_height2);
for( int i = 1; i < iterations; i++ )
f->apply( dst, dst, wsz, ofs );
}
}
};
// TODO: implement the case of iterations > 1.
if( iterations > 1 )
return false;
// ===== HAL interface implementation
return ipp_MorphReplicate( op, src, dst, kernel, ksize, anchor, rectKernel );
}
namespace hal {
Ptr<MorphContext> MorphContext ::create(int op, int src_type, int dst_type, int max_width, int max_height,
int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
int borderType, const double borderValue[4],
int iterations, bool isSubmatrix, bool allowInplace)
{
{
ReplacementMorphImpl * impl = new ReplacementMorphImpl();
if (impl->init(op, src_type, dst_type, max_width, max_height,
kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
anchor_x, anchor_y,
borderType, borderValue, iterations, isSubmatrix, allowInplace))
{
return Ptr<MorphContext>(impl);
}
delete impl;
}
#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 810
CV_IPP_CHECK()
{
IppMorphBaseImpl * impl = createIppImpl(src_type);
if (impl)
{
if (impl->init(op, src_type, dst_type, max_width, max_height,
kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
anchor_x, anchor_y,
borderType, borderValue, iterations, isSubmatrix, allowInplace))
{
return Ptr<MorphContext>(impl);
}
delete impl;
}
}
#endif
{
OcvMorphImpl * impl = new OcvMorphImpl();
impl->init(op, src_type, dst_type, max_width, max_height,
kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
anchor_x, anchor_y,
borderType, borderValue, iterations, isSubmatrix, allowInplace);
return Ptr<MorphContext>(impl);
}
}
} // cv::hal
#ifdef HAVE_OPENCL
@ -1763,22 +1847,24 @@ static void morphOp( int op, InputArray _src, OutputArray _dst,
iterations = 1;
}
CV_IPP_RUN(IPP_VERSION_X100 >= 810, ipp_MorphOp(op, _src, _dst, kernel, anchor, iterations, borderType, borderValue))
Mat src = _src.getMat();
_dst.create( src.size(), src.type() );
Mat dst = _dst.getMat();
int nStripes = 1;
#if defined HAVE_TEGRA_OPTIMIZATION
if (src.data != dst.data && iterations == 1 && //NOTE: threads are not used for inplace processing
(borderType & BORDER_ISOLATED) == 0 && //TODO: check border types
src.rows >= 64 ) //NOTE: just heuristics
nStripes = 4;
#endif
parallel_for_(Range(0, nStripes),
MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue));
Point s_ofs;
Size s_wsz(src.cols, src.rows);
src.locateROI(s_wsz, s_ofs);
Point d_ofs;
Size d_wsz(dst.cols, dst.rows);
dst.locateROI(d_wsz, d_ofs);
Ptr<hal::MorphContext> ctx = hal::MorphContext::create(op, src.type(), dst.type(), src.cols, src.rows,
kernel.type(), kernel.data, kernel.step, kernel.cols, kernel.rows,
anchor.x, anchor.y, borderType, borderValue.val, iterations,
src.isSubmatrix(), src.data == dst.data);
ctx->apply(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
s_wsz.width, s_wsz.height, s_ofs.x, s_ofs.y,
d_wsz.width, d_wsz.height, d_ofs.x, d_ofs.y);
}
}

Loading…
Cancel
Save