opencv erode
void cv::erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor, int iterations, int borderType, const Scalar& borderValue ) { CV_INSTRUMENT_REGION() morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue ); }
opencv morphOp
static void morphOp( int op, InputArray _src, OutputArray _dst, InputArray _kernel, Point anchor, int iterations, int borderType, const Scalar& borderValue ) { CV_INSTRUMENT_REGION() Mat kernel = _kernel.getMat(); Size ksize = !kernel.empty() ? kernel.size() : Size(3,3); anchor = normalizeAnchor(anchor, ksize); CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && _src.channels() <= 4 && borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue() && (op == MORPH_ERODE || op == MORPH_DILATE) && anchor.x == ksize.width >> 1 && anchor.y == ksize.height >> 1, ocl_morphOp(_src, _dst, kernel, anchor, iterations, op, borderType, borderValue) ) if (iterations == 0 || kernel.rows*kernel.cols == 1) { _src.copyTo(_dst); return; } if (kernel.empty()) { 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 ) { 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; } Mat src = _src.getMat(); _dst.create( src.size(), src.type() ); Mat dst = _dst.getMat(); Point s_ofs; Size s_wsz(src.cols, src.rows); Point d_ofs; Size d_wsz(dst.cols, dst.rows); bool isolated = (borderType&BORDER_ISOLATED)?true:false; borderType = (borderType&~BORDER_ISOLATED); if(!isolated) { src.locateROI(s_wsz, s_ofs); dst.locateROI(d_wsz, d_ofs); } hal::morph(op, src.type(), dst.type(), 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, kernel.type(), kernel.data, kernel.step, kernel.cols, kernel.rows, anchor.x, anchor.y, borderType, borderValue.val, iterations, (src.isSubmatrix() && !isolated)); } }
opencv ocl_morphOp
static bool ocl_morphOp(InputArray _src, OutputArray _dst, InputArray _kernel, Point anchor, int iterations, int op, int borderType, const Scalar &, int actual_op = -1, InputArray _extraMat = noArray()) { const ocl::Device & dev = ocl::Device::getDefault(); int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); Mat kernel = _kernel.getMat(); Size ksize = !kernel.empty() ? kernel.size() : Size(3, 3), ssize = _src.size(); bool doubleSupport = dev.doubleFPConfig() > 0; if ((depth == CV_64F && !doubleSupport) || borderType != BORDER_CONSTANT) return false; bool haveExtraMat = !_extraMat.empty(); CV_Assert(actual_op <= 3 || haveExtraMat); if (kernel.empty()) { 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 ) { 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; } #ifndef __APPLE__ int esz = CV_ELEM_SIZE(type); // try to use OpenCL kernel adopted for small morph kernel if (dev.isIntel() && ((ksize.width < 5 && ksize.height < 5 && esz <= 4) || (ksize.width == 5 && ksize.height == 5 && cn == 1)) && (iterations == 1) ) { if (ocl_morph3x3_8UC1(_src, _dst, kernel, anchor, op, actual_op, _extraMat)) return true; if (ocl_morphSmall(_src, _dst, kernel, anchor, borderType, op, actual_op, _extraMat)) return true; } #endif if (iterations == 0 || kernel.rows*kernel.cols == 1) { _src.copyTo(_dst); return true; } #ifdef __ANDROID__ size_t localThreads[2] = { 16, 8 }; #else size_t localThreads[2] = { 16, 16 }; #endif size_t globalThreads[2] = { (size_t)ssize.width, (size_t)ssize.height }; #ifdef __APPLE__ if( actual_op != MORPH_ERODE && actual_op != MORPH_DILATE ) localThreads[0] = localThreads[1] = 4; #endif if (localThreads[0]*localThreads[1] * 2 < (localThreads[0] + ksize.width - 1) * (localThreads[1] + ksize.height - 1)) return false; #ifdef __ANDROID__ if (dev.isNVidia()) return false; #endif // build processing String processing; Mat kernel8u; kernel.convertTo(kernel8u, CV_8U); for (int y = 0; y < kernel8u.rows; ++y) for (int x = 0; x < kernel8u.cols; ++x) if (kernel8u.at<uchar>(y, x) != 0) processing += format("PROCESS(%d,%d)", y, x); static const char * const op2str[] = { "OP_ERODE", "OP_DILATE", NULL, NULL, "OP_GRADIENT", "OP_TOPHAT", "OP_BLACKHAT" }; char cvt[2][50]; int wdepth = std::max(depth, CV_32F), scalarcn = cn == 3 ? 4 : cn; if (actual_op < 0) actual_op = op; std::vector<ocl::Kernel> kernels(iterations); for (int i = 0; i < iterations; i++) { int current_op = iterations == i + 1 ? actual_op : op; String buildOptions = format("-D RADIUSX=%d -D RADIUSY=%d -D LSIZE0=%d -D LSIZE1=%d -D %s%s" " -D PROCESS_ELEMS=%s -D T=%s -D DEPTH_%d -D cn=%d -D T1=%s" " -D convertToWT=%s -D convertToT=%s -D ST=%s%s", anchor.x, anchor.y, (int)localThreads[0], (int)localThreads[1], op2str[op], doubleSupport ? " -D DOUBLE_SUPPORT" : "", processing.c_str(), ocl::typeToStr(type), depth, cn, ocl::typeToStr(depth), ocl::convertTypeStr(depth, wdepth, cn, cvt[0]), ocl::convertTypeStr(wdepth, depth, cn, cvt[1]), ocl::typeToStr(CV_MAKE_TYPE(depth, scalarcn)), current_op == op ? "" : cv::format(" -D %s", op2str[current_op]).c_str()); kernels[i].create("morph", ocl::imgproc::morph_oclsrc, buildOptions); if (kernels[i].empty()) return false; } UMat src = _src.getUMat(), extraMat = _extraMat.getUMat(); _dst.create(src.size(), src.type()); UMat dst = _dst.getUMat(); if (iterations == 1 && src.u != dst.u) { Size wholesize; Point ofs; src.locateROI(wholesize, ofs); int wholecols = wholesize.width, wholerows = wholesize.height; if (haveExtraMat) kernels[0].args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnlyNoSize(dst), ofs.x, ofs.y, src.cols, src.rows, wholecols, wholerows, ocl::KernelArg::ReadOnlyNoSize(extraMat)); else kernels[0].args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnlyNoSize(dst), ofs.x, ofs.y, src.cols, src.rows, wholecols, wholerows); return kernels[0].run(2, globalThreads, localThreads, false); } for (int i = 0; i < iterations; i++) { UMat source; Size wholesize; Point ofs; if (i == 0) { int cols = src.cols, rows = src.rows; src.locateROI(wholesize, ofs); src.adjustROI(ofs.y, wholesize.height - rows - ofs.y, ofs.x, wholesize.width - cols - ofs.x); if(src.u != dst.u) source = src; else src.copyTo(source); src.adjustROI(-ofs.y, -wholesize.height + rows + ofs.y, -ofs.x, -wholesize.width + cols + ofs.x); source.adjustROI(-ofs.y, -wholesize.height + rows + ofs.y, -ofs.x, -wholesize.width + cols + ofs.x); } else { int cols = dst.cols, rows = dst.rows; dst.locateROI(wholesize, ofs); dst.adjustROI(ofs.y, wholesize.height - rows - ofs.y, ofs.x, wholesize.width - cols - ofs.x); dst.copyTo(source); dst.adjustROI(-ofs.y, -wholesize.height + rows + ofs.y, -ofs.x, -wholesize.width + cols + ofs.x); source.adjustROI(-ofs.y, -wholesize.height + rows + ofs.y, -ofs.x, -wholesize.width + cols + ofs.x); } source.locateROI(wholesize, ofs); if (haveExtraMat && iterations == i + 1) kernels[i].args(ocl::KernelArg::ReadOnlyNoSize(source), ocl::KernelArg::WriteOnlyNoSize(dst), ofs.x, ofs.y, source.cols, source.rows, wholesize.width, wholesize.height, ocl::KernelArg::ReadOnlyNoSize(extraMat)); else kernels[i].args(ocl::KernelArg::ReadOnlyNoSize(source), ocl::KernelArg::WriteOnlyNoSize(dst), ofs.x, ofs.y, source.cols, source.rows, wholesize.width, wholesize.height); if (!kernels[i].run(2, globalThreads, localThreads, false)) return false; } return true; }
opencv cv::hal::morph
void morph(int op, int src_type, int dst_type, 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 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 res = halMorph(op, src_type, dst_type, 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, kernel_type, kernel_data, kernel_step, kernel_width, kernel_height, anchor_x, anchor_y, borderType, borderValue, iterations, isSubmatrix); if (res) return; } CV_IPP_RUN_FAST(ippMorph(op, src_type, dst_type, 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, kernel_type, kernel_data, kernel_step, kernel_width, kernel_height, anchor_x, anchor_y, borderType, borderValue, iterations, isSubmatrix)); ocvMorph(op, src_type, dst_type, 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, kernel_type, kernel_data, kernel_step, kernel_width, kernel_height, anchor_x, anchor_y, borderType, borderValue, iterations); }
代码参考:opencv3_4_1opencv-3.4.1modulesimgprocsrcmorph.cpp
##############################################