|
|
|
@ -61,6 +61,8 @@ Ptr<Filter> cv::gpu::createScharrFilter(int, int, int, int, double, int, int) { |
|
|
|
|
|
|
|
|
|
Ptr<Filter> cv::gpu::createGaussianFilter(int, int, Size, double, double, int, int) { throw_no_cuda(); return Ptr<Filter>(); } |
|
|
|
|
|
|
|
|
|
Ptr<Filter> cv::gpu::createMorphologyFilter(int, int, InputArray, Point, int) { throw_no_cuda(); return Ptr<Filter>(); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -68,18 +70,9 @@ Ptr<Filter> cv::gpu::createGaussianFilter(int, int, Size, double, double, int, i |
|
|
|
|
|
|
|
|
|
Ptr<BaseRowFilter_GPU> cv::gpu::getRowSumFilter_GPU(int, int, int, int) { throw_no_cuda(); return Ptr<BaseRowFilter_GPU>(0); } |
|
|
|
|
Ptr<BaseColumnFilter_GPU> cv::gpu::getColumnSumFilter_GPU(int, int, int, int) { throw_no_cuda(); return Ptr<BaseColumnFilter_GPU>(0); } |
|
|
|
|
Ptr<BaseFilter_GPU> cv::gpu::getMorphologyFilter_GPU(int, int, const Mat&, const Size&, Point) { throw_no_cuda(); return Ptr<BaseFilter_GPU>(0); } |
|
|
|
|
Ptr<FilterEngine_GPU> cv::gpu::createMorphologyFilter_GPU(int, int, const Mat&, const Point&, int) { throw_no_cuda(); return Ptr<FilterEngine_GPU>(0); } |
|
|
|
|
Ptr<FilterEngine_GPU> cv::gpu::createMorphologyFilter_GPU(int, int, const Mat&, GpuMat&, const Point&, int) { throw_no_cuda(); return Ptr<FilterEngine_GPU>(0); } |
|
|
|
|
Ptr<BaseFilter_GPU> cv::gpu::getMaxFilter_GPU(int, int, const Size&, Point) { throw_no_cuda(); return Ptr<BaseFilter_GPU>(0); } |
|
|
|
|
Ptr<BaseFilter_GPU> cv::gpu::getMinFilter_GPU(int, int, const Size&, Point) { throw_no_cuda(); return Ptr<BaseFilter_GPU>(0); } |
|
|
|
|
|
|
|
|
|
void cv::gpu::erode(const GpuMat&, GpuMat&, const Mat&, Point, int) { throw_no_cuda(); } |
|
|
|
|
void cv::gpu::erode(const GpuMat&, GpuMat&, const Mat&, GpuMat&, Point, int, Stream&) { throw_no_cuda(); } |
|
|
|
|
void cv::gpu::dilate(const GpuMat&, GpuMat&, const Mat&, Point, int) { throw_no_cuda(); } |
|
|
|
|
void cv::gpu::dilate(const GpuMat&, GpuMat&, const Mat&, GpuMat&, Point, int, Stream&) { throw_no_cuda(); } |
|
|
|
|
void cv::gpu::morphologyEx(const GpuMat&, GpuMat&, int, const Mat&, Point, int) { throw_no_cuda(); } |
|
|
|
|
void cv::gpu::morphologyEx(const GpuMat&, GpuMat&, int, const Mat&, GpuMat&, GpuMat&, Point, int, Stream&) { throw_no_cuda(); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else |
|
|
|
@ -506,397 +499,431 @@ Ptr<Filter> cv::gpu::createGaussianFilter(int srcType, int dstType, Size ksize, |
|
|
|
|
return createSeparableLinearFilter(srcType, dstType, kx, ky, Point(-1,-1), rowBorderMode, columnBorderMode); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Morphology Filter
|
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
class MorphologyFilter : public Filter |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
MorphologyFilter(int op, int srcType, InputArray kernel, Point anchor, int iterations); |
|
|
|
|
|
|
|
|
|
void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
typedef NppStatus (*nppMorfFilter_t)(const Npp8u* pSrc, Npp32s nSrcStep, Npp8u* pDst, Npp32s nDstStep, NppiSize oSizeROI, |
|
|
|
|
const Npp8u* pMask, NppiSize oMaskSize, NppiPoint oAnchor); |
|
|
|
|
|
|
|
|
|
int type_; |
|
|
|
|
GpuMat kernel_; |
|
|
|
|
Point anchor_; |
|
|
|
|
int iters_; |
|
|
|
|
nppMorfFilter_t func_; |
|
|
|
|
|
|
|
|
|
GpuMat srcBorder_; |
|
|
|
|
GpuMat buf_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
MorphologyFilter::MorphologyFilter(int op, int srcType, InputArray _kernel, Point anchor, int iterations) : |
|
|
|
|
type_(srcType), anchor_(anchor), iters_(iterations) |
|
|
|
|
{ |
|
|
|
|
static const nppMorfFilter_t funcs[2][5] = |
|
|
|
|
{ |
|
|
|
|
{0, nppiErode_8u_C1R, 0, 0, nppiErode_8u_C4R }, |
|
|
|
|
{0, nppiDilate_8u_C1R, 0, 0, nppiDilate_8u_C4R } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE ); |
|
|
|
|
CV_Assert( srcType == CV_8UC1 || srcType == CV_8UC4 ); |
|
|
|
|
|
|
|
|
|
Mat kernel = _kernel.getMat(); |
|
|
|
|
Size ksize = !kernel.empty() ? _kernel.size() : Size(3, 3); |
|
|
|
|
|
|
|
|
|
normalizeAnchor(anchor_, ksize); |
|
|
|
|
|
|
|
|
|
if (kernel.empty()) |
|
|
|
|
{ |
|
|
|
|
kernel = getStructuringElement(MORPH_RECT, Size(1 + iters_ * 2, 1 + iters_ * 2)); |
|
|
|
|
anchor_ = Point(iters_, iters_); |
|
|
|
|
iters_ = 1; |
|
|
|
|
} |
|
|
|
|
else if (iters_ > 1 && countNonZero(kernel) == (int) kernel.total()) |
|
|
|
|
{ |
|
|
|
|
anchor_ = Point(anchor_.x * iters_, anchor_.y * iters_); |
|
|
|
|
kernel = getStructuringElement(MORPH_RECT, |
|
|
|
|
Size(ksize.width + (iters_ - 1) * (ksize.width - 1), |
|
|
|
|
ksize.height + (iters_ - 1) * (ksize.height - 1)), |
|
|
|
|
anchor_); |
|
|
|
|
iters_ = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CV_Assert( kernel.channels() == 1 ); |
|
|
|
|
|
|
|
|
|
Mat kernel8U; |
|
|
|
|
kernel.convertTo(kernel8U, CV_8U); |
|
|
|
|
|
|
|
|
|
kernel_ = gpu::createContinuous(kernel.size(), CV_8UC1); |
|
|
|
|
kernel_.upload(kernel8U); |
|
|
|
|
|
|
|
|
|
func_ = funcs[op][CV_MAT_CN(srcType)]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MorphologyFilter::apply(InputArray _src, OutputArray _dst, Stream& _stream) |
|
|
|
|
{ |
|
|
|
|
GpuMat src = _src.getGpuMat(); |
|
|
|
|
CV_Assert( src.type() == type_ ); |
|
|
|
|
|
|
|
|
|
Size ksize = kernel_.size(); |
|
|
|
|
gpu::copyMakeBorder(src, srcBorder_, ksize.height, ksize.height, ksize.width, ksize.width, BORDER_DEFAULT, Scalar(), _stream); |
|
|
|
|
|
|
|
|
|
GpuMat srcRoi = srcBorder_(Rect(ksize.width, ksize.height, src.cols, src.rows)); |
|
|
|
|
|
|
|
|
|
GpuMat bufRoi; |
|
|
|
|
if (iters_ > 1) |
|
|
|
|
{ |
|
|
|
|
ensureSizeIsEnough(srcBorder_.size(), type_, buf_); |
|
|
|
|
buf_.setTo(Scalar::all(0), _stream); |
|
|
|
|
bufRoi = buf_(Rect(ksize.width, ksize.height, src.cols, src.rows)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_dst.create(src.size(), src.type()); |
|
|
|
|
GpuMat dst = _dst.getGpuMat(); |
|
|
|
|
|
|
|
|
|
cudaStream_t stream = StreamAccessor::getStream(_stream); |
|
|
|
|
NppStreamHandler h(stream); |
|
|
|
|
|
|
|
|
|
NppiSize oSizeROI; |
|
|
|
|
oSizeROI.width = src.cols; |
|
|
|
|
oSizeROI.height = src.rows; |
|
|
|
|
|
|
|
|
|
NppiSize oMaskSize; |
|
|
|
|
oMaskSize.height = ksize.height; |
|
|
|
|
oMaskSize.width = ksize.width; |
|
|
|
|
|
|
|
|
|
NppiPoint oAnchor; |
|
|
|
|
oAnchor.x = anchor_.x; |
|
|
|
|
oAnchor.y = anchor_.y; |
|
|
|
|
|
|
|
|
|
nppSafeCall( func_(srcRoi.ptr<Npp8u>(), static_cast<int>(srcRoi.step), dst.ptr<Npp8u>(), static_cast<int>(dst.step), |
|
|
|
|
oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) ); |
|
|
|
|
|
|
|
|
|
for(int i = 1; i < iters_; ++i) |
|
|
|
|
{ |
|
|
|
|
dst.copyTo(bufRoi, _stream); |
|
|
|
|
|
|
|
|
|
nppSafeCall( func_(bufRoi.ptr<Npp8u>(), static_cast<int>(bufRoi.step), dst.ptr<Npp8u>(), static_cast<int>(dst.step), |
|
|
|
|
oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (stream == 0) |
|
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
inline void normalizeROI(Rect& roi, const Size& ksize, const Point& anchor, const Size& src_size) |
|
|
|
|
class MorphologyExFilter : public Filter |
|
|
|
|
{ |
|
|
|
|
if (roi == Rect(0,0,-1,-1)) |
|
|
|
|
roi = Rect(anchor.x, anchor.y, src_size.width - ksize.width, src_size.height - ksize.height); |
|
|
|
|
public: |
|
|
|
|
MorphologyExFilter(int srcType, InputArray kernel, Point anchor, int iterations); |
|
|
|
|
|
|
|
|
|
CV_Assert(roi.x >= 0 && roi.y >= 0 && roi.width <= src_size.width && roi.height <= src_size.height); |
|
|
|
|
protected: |
|
|
|
|
Ptr<gpu::Filter> erodeFilter_, dilateFilter_; |
|
|
|
|
GpuMat buf_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
MorphologyExFilter::MorphologyExFilter(int srcType, InputArray kernel, Point anchor, int iterations) |
|
|
|
|
{ |
|
|
|
|
erodeFilter_ = gpu::createMorphologyFilter(MORPH_ERODE, srcType, kernel, anchor, iterations); |
|
|
|
|
dilateFilter_ = gpu::createMorphologyFilter(MORPH_DILATE, srcType, kernel, anchor, iterations); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline void normalizeKernel(const Mat& kernel, GpuMat& gpu_krnl, int type = CV_8U, int* nDivisor = 0, bool reverse = false) |
|
|
|
|
// MORPH_OPEN
|
|
|
|
|
|
|
|
|
|
class MorphologyOpenFilter : public MorphologyExFilter |
|
|
|
|
{ |
|
|
|
|
int scale = nDivisor && (kernel.depth() == CV_32F || kernel.depth() == CV_64F) ? 256 : 1; |
|
|
|
|
if (nDivisor) *nDivisor = scale; |
|
|
|
|
public: |
|
|
|
|
MorphologyOpenFilter(int srcType, InputArray kernel, Point anchor, int iterations); |
|
|
|
|
|
|
|
|
|
Mat temp(kernel.size(), type); |
|
|
|
|
kernel.convertTo(temp, type, scale); |
|
|
|
|
Mat cont_krnl = temp.reshape(1, 1); |
|
|
|
|
void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if (reverse) |
|
|
|
|
{ |
|
|
|
|
int count = cont_krnl.cols >> 1; |
|
|
|
|
for (int i = 0; i < count; ++i) |
|
|
|
|
{ |
|
|
|
|
std::swap(cont_krnl.at<int>(0, i), cont_krnl.at<int>(0, cont_krnl.cols - 1 - i)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
MorphologyOpenFilter::MorphologyOpenFilter(int srcType, InputArray kernel, Point anchor, int iterations) : |
|
|
|
|
MorphologyExFilter(srcType, kernel, anchor, iterations) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gpu_krnl.upload(cont_krnl); |
|
|
|
|
void MorphologyOpenFilter::apply(InputArray src, OutputArray dst, Stream& stream) |
|
|
|
|
{ |
|
|
|
|
erodeFilter_->apply(src, buf_, stream); |
|
|
|
|
dilateFilter_->apply(buf_, dst, stream); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// 1D Sum Filter
|
|
|
|
|
// MORPH_CLOSE
|
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
struct NppRowSumFilter : public BaseRowFilter_GPU |
|
|
|
|
class MorphologyCloseFilter : public MorphologyExFilter |
|
|
|
|
{ |
|
|
|
|
NppRowSumFilter(int ksize_, int anchor_) : BaseRowFilter_GPU(ksize_, anchor_) {} |
|
|
|
|
public: |
|
|
|
|
MorphologyCloseFilter(int srcType, InputArray kernel, Point anchor, int iterations); |
|
|
|
|
|
|
|
|
|
virtual void operator()(const GpuMat& src, GpuMat& dst, Stream& s = Stream::Null()) |
|
|
|
|
{ |
|
|
|
|
NppiSize sz; |
|
|
|
|
sz.width = src.cols; |
|
|
|
|
sz.height = src.rows; |
|
|
|
|
void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
cudaStream_t stream = StreamAccessor::getStream(s); |
|
|
|
|
MorphologyCloseFilter::MorphologyCloseFilter(int srcType, InputArray kernel, Point anchor, int iterations) : |
|
|
|
|
MorphologyExFilter(srcType, kernel, anchor, iterations) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
NppStreamHandler h(stream); |
|
|
|
|
void MorphologyCloseFilter::apply(InputArray src, OutputArray dst, Stream& stream) |
|
|
|
|
{ |
|
|
|
|
dilateFilter_->apply(src, buf_, stream); |
|
|
|
|
erodeFilter_->apply(buf_, dst, stream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nppSafeCall( nppiSumWindowRow_8u32f_C1R(src.ptr<Npp8u>(), static_cast<int>(src.step), |
|
|
|
|
dst.ptr<Npp32f>(), static_cast<int>(dst.step), sz, ksize, anchor) ); |
|
|
|
|
// MORPH_GRADIENT
|
|
|
|
|
|
|
|
|
|
if (stream == 0) |
|
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
|
} |
|
|
|
|
class MorphologyGradientFilter : public MorphologyExFilter |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
MorphologyGradientFilter(int srcType, InputArray kernel, Point anchor, int iterations); |
|
|
|
|
|
|
|
|
|
void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ptr<BaseRowFilter_GPU> cv::gpu::getRowSumFilter_GPU(int srcType, int sumType, int ksize, int anchor) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(srcType == CV_8UC1 && sumType == CV_32FC1); |
|
|
|
|
MorphologyGradientFilter::MorphologyGradientFilter(int srcType, InputArray kernel, Point anchor, int iterations) : |
|
|
|
|
MorphologyExFilter(srcType, kernel, anchor, iterations) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
normalizeAnchor(anchor, ksize); |
|
|
|
|
void MorphologyGradientFilter::apply(InputArray src, OutputArray dst, Stream& stream) |
|
|
|
|
{ |
|
|
|
|
erodeFilter_->apply(src, buf_, stream); |
|
|
|
|
dilateFilter_->apply(src, dst, stream); |
|
|
|
|
gpu::subtract(dst, buf_, dst, noArray(), -1, stream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return Ptr<BaseRowFilter_GPU>(new NppRowSumFilter(ksize, anchor)); |
|
|
|
|
} |
|
|
|
|
// MORPH_TOPHAT
|
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
struct NppColumnSumFilter : public BaseColumnFilter_GPU |
|
|
|
|
class MorphologyTophatFilter : public MorphologyExFilter |
|
|
|
|
{ |
|
|
|
|
NppColumnSumFilter(int ksize_, int anchor_) : BaseColumnFilter_GPU(ksize_, anchor_) {} |
|
|
|
|
public: |
|
|
|
|
MorphologyTophatFilter(int srcType, InputArray kernel, Point anchor, int iterations); |
|
|
|
|
|
|
|
|
|
virtual void operator()(const GpuMat& src, GpuMat& dst, Stream& s = Stream::Null()) |
|
|
|
|
{ |
|
|
|
|
NppiSize sz; |
|
|
|
|
sz.width = src.cols; |
|
|
|
|
sz.height = src.rows; |
|
|
|
|
void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
cudaStream_t stream = StreamAccessor::getStream(s); |
|
|
|
|
MorphologyTophatFilter::MorphologyTophatFilter(int srcType, InputArray kernel, Point anchor, int iterations) : |
|
|
|
|
MorphologyExFilter(srcType, kernel, anchor, iterations) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
NppStreamHandler h(stream); |
|
|
|
|
void MorphologyTophatFilter::apply(InputArray src, OutputArray dst, Stream& stream) |
|
|
|
|
{ |
|
|
|
|
erodeFilter_->apply(src, dst, stream); |
|
|
|
|
dilateFilter_->apply(dst, buf_, stream); |
|
|
|
|
gpu::subtract(src, buf_, dst, noArray(), -1, stream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nppSafeCall( nppiSumWindowColumn_8u32f_C1R(src.ptr<Npp8u>(), static_cast<int>(src.step), |
|
|
|
|
dst.ptr<Npp32f>(), static_cast<int>(dst.step), sz, ksize, anchor) ); |
|
|
|
|
// MORPH_BLACKHAT
|
|
|
|
|
|
|
|
|
|
if (stream == 0) |
|
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
|
} |
|
|
|
|
class MorphologyBlackhatFilter : public MorphologyExFilter |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
MorphologyBlackhatFilter(int srcType, InputArray kernel, Point anchor, int iterations); |
|
|
|
|
|
|
|
|
|
void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
MorphologyBlackhatFilter::MorphologyBlackhatFilter(int srcType, InputArray kernel, Point anchor, int iterations) : |
|
|
|
|
MorphologyExFilter(srcType, kernel, anchor, iterations) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void MorphologyBlackhatFilter::apply(InputArray src, OutputArray dst, Stream& stream) |
|
|
|
|
{ |
|
|
|
|
dilateFilter_->apply(src, dst, stream); |
|
|
|
|
erodeFilter_->apply(dst, buf_, stream); |
|
|
|
|
gpu::subtract(buf_, src, dst, noArray(), -1, stream); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ptr<BaseColumnFilter_GPU> cv::gpu::getColumnSumFilter_GPU(int sumType, int dstType, int ksize, int anchor) |
|
|
|
|
Ptr<Filter> cv::gpu::createMorphologyFilter(int op, int srcType, InputArray kernel, Point anchor, int iterations) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(sumType == CV_8UC1 && dstType == CV_32FC1); |
|
|
|
|
switch( op ) |
|
|
|
|
{ |
|
|
|
|
case MORPH_ERODE: |
|
|
|
|
case MORPH_DILATE: |
|
|
|
|
return new MorphologyFilter(op, srcType, kernel, anchor, iterations); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
normalizeAnchor(anchor, ksize); |
|
|
|
|
case MORPH_OPEN: |
|
|
|
|
return new MorphologyOpenFilter(srcType, kernel, anchor, iterations); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
return Ptr<BaseColumnFilter_GPU>(new NppColumnSumFilter(ksize, anchor)); |
|
|
|
|
} |
|
|
|
|
case MORPH_CLOSE: |
|
|
|
|
return new MorphologyCloseFilter(srcType, kernel, anchor, iterations); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Morphology Filter
|
|
|
|
|
case MORPH_GRADIENT: |
|
|
|
|
return new MorphologyGradientFilter(srcType, kernel, anchor, iterations); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case MORPH_TOPHAT: |
|
|
|
|
return new MorphologyTophatFilter(srcType, kernel, anchor, iterations); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case MORPH_BLACKHAT: |
|
|
|
|
return new MorphologyBlackhatFilter(srcType, kernel, anchor, iterations); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
CV_Error(Error::StsBadArg, "Unknown morphological operation"); |
|
|
|
|
return Ptr<Filter>(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
typedef NppStatus (*nppMorfFilter_t)(const Npp8u*, Npp32s, Npp8u*, Npp32s, NppiSize, const Npp8u*, NppiSize, NppiPoint); |
|
|
|
|
|
|
|
|
|
struct NPPMorphFilter : public BaseFilter_GPU |
|
|
|
|
{ |
|
|
|
|
NPPMorphFilter(const Size& ksize_, const Point& anchor_, const GpuMat& kernel_, nppMorfFilter_t func_) : |
|
|
|
|
BaseFilter_GPU(ksize_, anchor_), kernel(kernel_), func(func_) {} |
|
|
|
|
|
|
|
|
|
virtual void operator()(const GpuMat& src, GpuMat& dst, Stream& s = Stream::Null()) |
|
|
|
|
{ |
|
|
|
|
NppiSize sz; |
|
|
|
|
sz.width = src.cols; |
|
|
|
|
sz.height = src.rows; |
|
|
|
|
NppiSize oKernelSize; |
|
|
|
|
oKernelSize.height = ksize.height; |
|
|
|
|
oKernelSize.width = ksize.width; |
|
|
|
|
NppiPoint oAnchor; |
|
|
|
|
oAnchor.x = anchor.x; |
|
|
|
|
oAnchor.y = anchor.y; |
|
|
|
|
|
|
|
|
|
cudaStream_t stream = StreamAccessor::getStream(s); |
|
|
|
|
|
|
|
|
|
NppStreamHandler h(stream); |
|
|
|
|
|
|
|
|
|
nppSafeCall( func(src.ptr<Npp8u>(), static_cast<int>(src.step), |
|
|
|
|
dst.ptr<Npp8u>(), static_cast<int>(dst.step), sz, kernel.ptr<Npp8u>(), oKernelSize, oAnchor) ); |
|
|
|
|
|
|
|
|
|
if (stream == 0) |
|
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GpuMat kernel; |
|
|
|
|
nppMorfFilter_t func; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ptr<BaseFilter_GPU> cv::gpu::getMorphologyFilter_GPU(int op, int type, const Mat& kernel, const Size& ksize, Point anchor) |
|
|
|
|
{ |
|
|
|
|
static const nppMorfFilter_t nppMorfFilter_callers[2][5] = |
|
|
|
|
{ |
|
|
|
|
{0, nppiErode_8u_C1R, 0, 0, nppiErode_8u_C4R }, |
|
|
|
|
{0, nppiDilate_8u_C1R, 0, 0, nppiDilate_8u_C4R } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
CV_Assert(op == MORPH_ERODE || op == MORPH_DILATE); |
|
|
|
|
CV_Assert(type == CV_8UC1 || type == CV_8UC4); |
|
|
|
|
|
|
|
|
|
GpuMat gpu_krnl; |
|
|
|
|
normalizeKernel(kernel, gpu_krnl); |
|
|
|
|
normalizeAnchor(anchor, ksize); |
|
|
|
|
|
|
|
|
|
return Ptr<BaseFilter_GPU>(new NPPMorphFilter(ksize, anchor, gpu_krnl, nppMorfFilter_callers[op][CV_MAT_CN(type)])); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
struct MorphologyFilterEngine_GPU : public FilterEngine_GPU |
|
|
|
|
{ |
|
|
|
|
MorphologyFilterEngine_GPU(const Ptr<BaseFilter_GPU>& filter2D_, int type_, int iters_) : |
|
|
|
|
filter2D(filter2D_), type(type_), iters(iters_) |
|
|
|
|
{ |
|
|
|
|
pbuf = &buf; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
MorphologyFilterEngine_GPU(const Ptr<BaseFilter_GPU>& filter2D_, int type_, int iters_, GpuMat& buf_) : |
|
|
|
|
filter2D(filter2D_), type(type_), iters(iters_) |
|
|
|
|
{ |
|
|
|
|
pbuf = &buf_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
virtual void apply(const GpuMat& src, GpuMat& dst, Rect roi = Rect(0,0,-1,-1), Stream& stream = Stream::Null()) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(src.type() == type); |
|
|
|
|
|
|
|
|
|
Size src_size = src.size(); |
|
|
|
|
|
|
|
|
|
dst.create(src_size, type); |
|
|
|
|
|
|
|
|
|
if (roi.size() != src_size) |
|
|
|
|
{ |
|
|
|
|
dst.setTo(Scalar::all(0), stream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
normalizeROI(roi, filter2D->ksize, filter2D->anchor, src_size); |
|
|
|
|
|
|
|
|
|
if (iters > 1) |
|
|
|
|
pbuf->create(src_size, type); |
|
|
|
|
|
|
|
|
|
GpuMat srcROI = src(roi); |
|
|
|
|
GpuMat dstROI = dst(roi); |
|
|
|
|
|
|
|
|
|
(*filter2D)(srcROI, dstROI, stream); |
|
|
|
|
|
|
|
|
|
for(int i = 1; i < iters; ++i) |
|
|
|
|
{ |
|
|
|
|
dst.swap((*pbuf)); |
|
|
|
|
|
|
|
|
|
dstROI = dst(roi); |
|
|
|
|
GpuMat bufROI = (*pbuf)(roi); |
|
|
|
|
|
|
|
|
|
(*filter2D)(bufROI, dstROI, stream); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ptr<BaseFilter_GPU> filter2D; |
|
|
|
|
|
|
|
|
|
int type; |
|
|
|
|
int iters; |
|
|
|
|
|
|
|
|
|
GpuMat buf; |
|
|
|
|
GpuMat* pbuf; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ptr<FilterEngine_GPU> cv::gpu::createMorphologyFilter_GPU(int op, int type, const Mat& kernel, const Point& anchor, int iterations) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(iterations > 0); |
|
|
|
|
|
|
|
|
|
Size ksize = kernel.size(); |
|
|
|
|
|
|
|
|
|
Ptr<BaseFilter_GPU> filter2D = getMorphologyFilter_GPU(op, type, kernel, ksize, anchor); |
|
|
|
|
|
|
|
|
|
return Ptr<FilterEngine_GPU>(new MorphologyFilterEngine_GPU(filter2D, type, iterations)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ptr<FilterEngine_GPU> cv::gpu::createMorphologyFilter_GPU(int op, int type, const Mat& kernel, GpuMat& buf, const Point& anchor, int iterations) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(iterations > 0); |
|
|
|
|
|
|
|
|
|
Size ksize = kernel.size(); |
|
|
|
|
|
|
|
|
|
Ptr<BaseFilter_GPU> filter2D = getMorphologyFilter_GPU(op, type, kernel, ksize, anchor); |
|
|
|
|
|
|
|
|
|
return Ptr<FilterEngine_GPU>(new MorphologyFilterEngine_GPU(filter2D, type, iterations, buf)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
void morphOp(int op, const GpuMat& src, GpuMat& dst, const Mat& _kernel, GpuMat& buf, Point anchor, int iterations, Stream& stream = Stream::Null()) |
|
|
|
|
inline void normalizeROI(Rect& roi, const Size& ksize, const Point& anchor, const Size& src_size) |
|
|
|
|
{ |
|
|
|
|
Mat kernel; |
|
|
|
|
Size ksize = _kernel.data ? _kernel.size() : Size(3, 3); |
|
|
|
|
if (roi == Rect(0,0,-1,-1)) |
|
|
|
|
roi = Rect(anchor.x, anchor.y, src_size.width - ksize.width, src_size.height - ksize.height); |
|
|
|
|
|
|
|
|
|
normalizeAnchor(anchor, ksize); |
|
|
|
|
CV_Assert(roi.x >= 0 && roi.y >= 0 && roi.width <= src_size.width && roi.height <= src_size.height); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (iterations == 0 || _kernel.rows * _kernel.cols == 1) |
|
|
|
|
{ |
|
|
|
|
src.copyTo(dst, stream); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
inline void normalizeKernel(const Mat& kernel, GpuMat& gpu_krnl, int type = CV_8U, int* nDivisor = 0, bool reverse = false) |
|
|
|
|
{ |
|
|
|
|
int scale = nDivisor && (kernel.depth() == CV_32F || kernel.depth() == CV_64F) ? 256 : 1; |
|
|
|
|
if (nDivisor) *nDivisor = scale; |
|
|
|
|
|
|
|
|
|
dst.create(src.size(), src.type()); |
|
|
|
|
Mat temp(kernel.size(), type); |
|
|
|
|
kernel.convertTo(temp, type, scale); |
|
|
|
|
Mat cont_krnl = temp.reshape(1, 1); |
|
|
|
|
|
|
|
|
|
if (!_kernel.data) |
|
|
|
|
{ |
|
|
|
|
kernel = getStructuringElement(MORPH_RECT, Size(1 + iterations * 2, 1 + iterations * 2)); |
|
|
|
|
anchor = Point(iterations, iterations); |
|
|
|
|
iterations = 1; |
|
|
|
|
} |
|
|
|
|
else if (iterations > 1 && countNonZero(_kernel) == _kernel.rows * _kernel.cols) |
|
|
|
|
if (reverse) |
|
|
|
|
{ |
|
|
|
|
anchor = Point(anchor.x * iterations, anchor.y * iterations); |
|
|
|
|
kernel = getStructuringElement(MORPH_RECT, |
|
|
|
|
Size(ksize.width + (iterations - 1) * (ksize.width - 1), |
|
|
|
|
ksize.height + (iterations - 1) * (ksize.height - 1)), |
|
|
|
|
anchor); |
|
|
|
|
iterations = 1; |
|
|
|
|
int count = cont_krnl.cols >> 1; |
|
|
|
|
for (int i = 0; i < count; ++i) |
|
|
|
|
{ |
|
|
|
|
std::swap(cont_krnl.at<int>(0, i), cont_krnl.at<int>(0, cont_krnl.cols - 1 - i)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
kernel = _kernel; |
|
|
|
|
|
|
|
|
|
Ptr<FilterEngine_GPU> f = createMorphologyFilter_GPU(op, src.type(), kernel, buf, anchor, iterations); |
|
|
|
|
|
|
|
|
|
f->apply(src, dst, Rect(0,0,-1,-1), stream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void morphOp(int op, const GpuMat& src, GpuMat& dst, const Mat& _kernel, Point anchor, int iterations) |
|
|
|
|
{ |
|
|
|
|
GpuMat buf; |
|
|
|
|
morphOp(op, src, dst, _kernel, buf, anchor, iterations); |
|
|
|
|
gpu_krnl.upload(cont_krnl); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void cv::gpu::erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) |
|
|
|
|
{ |
|
|
|
|
morphOp(MORPH_ERODE, src, dst, kernel, anchor, iterations); |
|
|
|
|
} |
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// 1D Sum Filter
|
|
|
|
|
|
|
|
|
|
void cv::gpu::erode( const GpuMat& src, GpuMat& dst, const Mat& kernel, GpuMat& buf, Point anchor, int iterations, Stream& stream) |
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
morphOp(MORPH_ERODE, src, dst, kernel, buf, anchor, iterations, stream); |
|
|
|
|
} |
|
|
|
|
struct NppRowSumFilter : public BaseRowFilter_GPU |
|
|
|
|
{ |
|
|
|
|
NppRowSumFilter(int ksize_, int anchor_) : BaseRowFilter_GPU(ksize_, anchor_) {} |
|
|
|
|
|
|
|
|
|
void cv::gpu::dilate( const GpuMat& src, GpuMat& dst, const Mat& kernel, Point anchor, int iterations) |
|
|
|
|
{ |
|
|
|
|
morphOp(MORPH_DILATE, src, dst, kernel, anchor, iterations); |
|
|
|
|
} |
|
|
|
|
virtual void operator()(const GpuMat& src, GpuMat& dst, Stream& s = Stream::Null()) |
|
|
|
|
{ |
|
|
|
|
NppiSize sz; |
|
|
|
|
sz.width = src.cols; |
|
|
|
|
sz.height = src.rows; |
|
|
|
|
|
|
|
|
|
void cv::gpu::dilate( const GpuMat& src, GpuMat& dst, const Mat& kernel, GpuMat& buf, Point anchor, int iterations, Stream& stream) |
|
|
|
|
{ |
|
|
|
|
morphOp(MORPH_DILATE, src, dst, kernel, buf, anchor, iterations, stream); |
|
|
|
|
cudaStream_t stream = StreamAccessor::getStream(s); |
|
|
|
|
|
|
|
|
|
NppStreamHandler h(stream); |
|
|
|
|
|
|
|
|
|
nppSafeCall( nppiSumWindowRow_8u32f_C1R(src.ptr<Npp8u>(), static_cast<int>(src.step), |
|
|
|
|
dst.ptr<Npp32f>(), static_cast<int>(dst.step), sz, ksize, anchor) ); |
|
|
|
|
|
|
|
|
|
if (stream == 0) |
|
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void cv::gpu::morphologyEx(const GpuMat& src, GpuMat& dst, int op, const Mat& kernel, Point anchor, int iterations) |
|
|
|
|
Ptr<BaseRowFilter_GPU> cv::gpu::getRowSumFilter_GPU(int srcType, int sumType, int ksize, int anchor) |
|
|
|
|
{ |
|
|
|
|
GpuMat buf1; |
|
|
|
|
GpuMat buf2; |
|
|
|
|
morphologyEx(src, dst, op, kernel, buf1, buf2, anchor, iterations); |
|
|
|
|
CV_Assert(srcType == CV_8UC1 && sumType == CV_32FC1); |
|
|
|
|
|
|
|
|
|
normalizeAnchor(anchor, ksize); |
|
|
|
|
|
|
|
|
|
return Ptr<BaseRowFilter_GPU>(new NppRowSumFilter(ksize, anchor)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void cv::gpu::morphologyEx(const GpuMat& src, GpuMat& dst, int op, const Mat& kernel, GpuMat& buf1, GpuMat& buf2, Point anchor, int iterations, Stream& stream) |
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
switch( op ) |
|
|
|
|
struct NppColumnSumFilter : public BaseColumnFilter_GPU |
|
|
|
|
{ |
|
|
|
|
case MORPH_ERODE: |
|
|
|
|
erode(src, dst, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
break; |
|
|
|
|
NppColumnSumFilter(int ksize_, int anchor_) : BaseColumnFilter_GPU(ksize_, anchor_) {} |
|
|
|
|
|
|
|
|
|
case MORPH_DILATE: |
|
|
|
|
dilate(src, dst, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
break; |
|
|
|
|
virtual void operator()(const GpuMat& src, GpuMat& dst, Stream& s = Stream::Null()) |
|
|
|
|
{ |
|
|
|
|
NppiSize sz; |
|
|
|
|
sz.width = src.cols; |
|
|
|
|
sz.height = src.rows; |
|
|
|
|
|
|
|
|
|
case MORPH_OPEN: |
|
|
|
|
erode(src, buf2, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
dilate(buf2, dst, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
break; |
|
|
|
|
cudaStream_t stream = StreamAccessor::getStream(s); |
|
|
|
|
|
|
|
|
|
case MORPH_CLOSE: |
|
|
|
|
dilate(src, buf2, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
erode(buf2, dst, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
break; |
|
|
|
|
NppStreamHandler h(stream); |
|
|
|
|
|
|
|
|
|
case MORPH_GRADIENT: |
|
|
|
|
erode(src, buf2, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
dilate(src, dst, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
gpu::subtract(dst, buf2, dst, GpuMat(), -1, stream); |
|
|
|
|
break; |
|
|
|
|
nppSafeCall( nppiSumWindowColumn_8u32f_C1R(src.ptr<Npp8u>(), static_cast<int>(src.step), |
|
|
|
|
dst.ptr<Npp32f>(), static_cast<int>(dst.step), sz, ksize, anchor) ); |
|
|
|
|
|
|
|
|
|
case MORPH_TOPHAT: |
|
|
|
|
erode(src, dst, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
dilate(dst, buf2, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
gpu::subtract(src, buf2, dst, GpuMat(), -1, stream); |
|
|
|
|
break; |
|
|
|
|
if (stream == 0) |
|
|
|
|
cudaSafeCall( cudaDeviceSynchronize() ); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case MORPH_BLACKHAT: |
|
|
|
|
dilate(src, dst, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
erode(dst, buf2, kernel, buf1, anchor, iterations, stream); |
|
|
|
|
gpu::subtract(buf2, src, dst, GpuMat(), -1, stream); |
|
|
|
|
break; |
|
|
|
|
Ptr<BaseColumnFilter_GPU> cv::gpu::getColumnSumFilter_GPU(int sumType, int dstType, int ksize, int anchor) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(sumType == CV_8UC1 && dstType == CV_32FC1); |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
CV_Error(cv::Error::StsBadArg, "unknown morphological operation"); |
|
|
|
|
} |
|
|
|
|
normalizeAnchor(anchor, ksize); |
|
|
|
|
|
|
|
|
|
return Ptr<BaseColumnFilter_GPU>(new NppColumnSumFilter(ksize, anchor)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Image Rank Filter
|
|
|
|
|
|
|
|
|
|