Merge pull request #6243 from mshabunin:hal_morph
This commit is contained in:
commit
e792ee89de
@ -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;
|
||||
|
||||
nStripes = _nStripes;
|
||||
iterations = _iterations;
|
||||
|
||||
op = _op;
|
||||
kernel = _kernel;
|
||||
anchor = _anchor;
|
||||
rowBorderType = _rowBorderType;
|
||||
columnBorderType = _columnBorderType;
|
||||
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 operator () ( const Range& range ) const
|
||||
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)
|
||||
{
|
||||
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(0)
|
||||
printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n",
|
||||
src.rows, src.cols, range.start, range.end, row0, row1);*/
|
||||
|
||||
Mat srcStripe = src.rowRange(row0, row1);
|
||||
Mat dstStripe = dst.rowRange(row0, row1);
|
||||
|
||||
Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(), kernel, anchor,
|
||||
rowBorderType, columnBorderType, borderValue );
|
||||
|
||||
if (isInitialized)
|
||||
{
|
||||
Point ofs;
|
||||
Size wsz(srcStripe.cols, srcStripe.rows);
|
||||
srcStripe.locateROI( wsz, ofs );
|
||||
|
||||
f->apply( srcStripe, dstStripe, wsz, ofs );
|
||||
}
|
||||
|
||||
{
|
||||
Point ofs;
|
||||
Size wsz(dstStripe.cols, dstStripe.rows);
|
||||
dstStripe.locateROI( wsz, ofs );
|
||||
|
||||
for( int i = 1; i < iterations; i++ )
|
||||
f->apply( dstStripe, dstStripe, wsz, ofs );
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Mat src;
|
||||
Mat dst;
|
||||
int nStripes;
|
||||
int iterations;
|
||||
|
||||
int op;
|
||||
Mat kernel;
|
||||
Point anchor;
|
||||
int rowBorderType;
|
||||
int columnBorderType;
|
||||
Scalar borderValue;
|
||||
};
|
||||
|
||||
// ===== 2. IPP implementation
|
||||
|
||||
#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)
|
||||
{
|
||||
|
||||
#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};
|
||||
template <int cvtype> struct IppMorphTrait {};
|
||||
|
||||
if (!rectKernel)
|
||||
{
|
||||
#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;
|
||||
|
||||
#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); }\
|
||||
};
|
||||
|
||||
#else
|
||||
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.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)
|
||||
{
|
||||
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:
|
||||
;
|
||||
}
|
||||
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 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);}\
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
CV_SUPPRESS_DEPRECATED_START
|
||||
switch (type)
|
||||
{
|
||||
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:
|
||||
;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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})
|
||||
|
||||
static bool ipp_MorphOp(int op, InputArray _src, OutputArray _dst,
|
||||
const Mat& _kernel, Point anchor, int iterations,
|
||||
int borderType, const Scalar &borderValue)
|
||||
#undef INIT_TRAIT
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
struct IppMorphBaseImpl : public hal::MorphContext
|
||||
{
|
||||
Mat src = _src.getMat(), kernel = _kernel;
|
||||
int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
|
||||
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( !( 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;
|
||||
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;
|
||||
|
||||
// In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only
|
||||
if( borderType == cv::BORDER_CONSTANT && kernel.data )
|
||||
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)
|
||||
{
|
||||
int x, y;
|
||||
for( y = 0; y < kernel.rows; 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;
|
||||
|
||||
// In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only
|
||||
if( borderType == cv::BORDER_CONSTANT && kernel.data )
|
||||
{
|
||||
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;
|
||||
int x, y;
|
||||
for( y = 0; y < kernel.rows; y++ )
|
||||
{
|
||||
if( kernel.at<uchar>(y,x) != 0 )
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Size ksize = !kernel.empty() ? kernel.size() : Size(3,3);
|
||||
|
||||
rectKernel = false;
|
||||
if( kernel.empty() )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: implement the case of iterations > 1.
|
||||
if( iterations > 1 )
|
||||
return false;
|
||||
|
||||
IppiSize roiSize = {max_width, max_height};
|
||||
kernelSize = ippiSize(ksize);
|
||||
op = _op;
|
||||
|
||||
IppStatus res;
|
||||
if (!rectKernel)
|
||||
{
|
||||
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)
|
||||
{
|
||||
specBuf.Alloc(specSize);
|
||||
workBuf.Alloc(bufferSize);
|
||||
res = trait.morphInit(roiSize, kernel.ptr(), kernelSize, specBuf, workBuf);
|
||||
if (res >= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((kernelSize.width - 1) / 2 != anchor.x) || ((kernelSize.height - 1) / 2 != anchor.y))
|
||||
return false;
|
||||
if (op == MORPH_ERODE)
|
||||
{
|
||||
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();
|
||||
|
||||
if( iterations == 0 || kernel.rows*kernel.cols == 1 )
|
||||
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)
|
||||
{
|
||||
src.copyTo(dst);
|
||||
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");
|
||||
}
|
||||
};
|
||||
|
||||
static IppMorphBaseImpl * createIppImpl(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
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
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool rectKernel = false;
|
||||
if( kernel.empty() )
|
||||
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(1+iterations*2,1+iterations*2);
|
||||
anchor = Point(iterations, iterations);
|
||||
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 );
|
||||
}
|
||||
}
|
||||
else if( iterations >= 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
|
||||
};
|
||||
|
||||
// ===== HAL interface implementation
|
||||
|
||||
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)
|
||||
{
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement the case of iterations > 1.
|
||||
if( iterations > 1 )
|
||||
return false;
|
||||
|
||||
return ipp_MorphReplicate( op, src, dst, kernel, ksize, anchor, rectKernel );
|
||||
}
|
||||
#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
|
||||
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);
|
||||
|
||||
parallel_for_(Range(0, nStripes),
|
||||
MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue));
|
||||
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…
x
Reference in New Issue
Block a user