Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
e792ee89
Commit
e792ee89
authored
Mar 23, 2016
by
Vadim Pisarevsky
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6243 from mshabunin:hal_morph
parents
e547916e
83379695
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
400 additions
and
276 deletions
+400
-276
private.hpp
modules/core/include/opencv2/core/private.hpp
+12
-0
hal.hpp
modules/imgproc/include/opencv2/imgproc/hal/hal.hpp
+16
-0
filterengine.hpp
modules/imgproc/src/filterengine.hpp
+2
-0
hal_replacement.hpp
modules/imgproc/src/hal_replacement.hpp
+8
-0
morph.cpp
modules/imgproc/src/morph.cpp
+362
-276
No files found.
modules/core/include/opencv2/core/private.hpp
View file @
e792ee89
...
...
@@ -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
:
...
...
modules/imgproc/include/opencv2/imgproc/hal/hal.hpp
View file @
e792ee89
...
...
@@ -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
()
{}
};
//! @}
}}
...
...
modules/imgproc/src/filterengine.hpp
View file @
e792ee89
...
...
@@ -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
{
...
...
modules/imgproc/src/hal_replacement.hpp
View file @
e792ee89
...
...
@@ -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
modules/imgproc/src/morph.cpp
View file @
e792ee89
...
...
@@ -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
,
32
f
,
32
f_C1R
,
1
,
zero
=
0
)
INIT_TRAIT
(
CV_32FC3
,
32
f
,
32
f_C3R
,
3
,
zero
[
3
]
=
{
0
})
INIT_TRAIT
(
CV_32FC4
,
32
f
,
32
f_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
,
32
f_C1R
,
32
f
);
IPP_MORPH_CASE
(
CV_32FC3
,
32
f_C3R
,
32
f
);
IPP_MORPH_CASE
(
CV_32FC4
,
32
f_C4R
,
32
f
);
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
,
32
f_C1R
,
32
f
,
1
);
IPP_MORPH_CASE
(
CV_32FC3
,
32
f_C3R
,
32
f
,
3
);
IPP_MORPH_CASE
(
CV_32FC4
,
32
f_C4R
,
32
f
,
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
)
continu
e
;
for
(
y
=
0
;
y
<
kernel
.
rows
;
y
++
)
if
(((
kernelSize
.
width
-
1
)
/
2
!=
anchor
.
x
)
||
((
kernelSize
.
height
-
1
)
/
2
!=
anchor
.
y
)
)
return
fals
e
;
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
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment