美文网首页
形态学滤波

形态学滤波

作者: 轻歌若雪 | 来源:发表于2018-03-12 13:05 被阅读0次

    getStructuringElement

    @brief Returns a structuring element of the specified size and shape for morphological operations.
    The function constructs and returns the structuring element that can be further passed to cv::erode,
    cv::dilate or cv::morphologyEx. But you can also construct an arbitrary binary mask yourself and use it as
    the structuring element.
    @param shape Element shape that could be one of cv::MorphShapes
    @param ksize Size of the structuring element.
    @param anchor Anchor position within the element. The default value \f$(-1, -1)\f$ means that the
    anchor is at the center. Note that only the shape of a cross-shaped element depends on the anchor
    position. In other cases the anchor just regulates how much the result of the morphological
    operation is shifted.

    cv::Mat cv::getStructuringElement(int shape, Size ksize, Point anchor)
    {
        int i, j;
        int r = 0, c = 0;
        double inv_r2 = 0;
    
        CV_Assert( shape == MORPH_RECT || shape == MORPH_CROSS || shape == MORPH_ELLIPSE );
    
        anchor = normalizeAnchor(anchor, ksize);
    
        if( ksize == Size(1,1) )
            shape = MORPH_RECT;
    
        if( shape == MORPH_ELLIPSE )
        {
            r = ksize.height/2;
            c = ksize.width/2;
            inv_r2 = r ? 1./((double)r*r) : 0;
        }
    
        Mat elem(ksize, CV_8U);
    
        for( i = 0; i < ksize.height; i++ )
        {
            uchar* ptr = elem.ptr(i);
            int j1 = 0, j2 = 0;
    
            if( shape == MORPH_RECT || (shape == MORPH_CROSS && i == anchor.y) )
                j2 = ksize.width;
            else if( shape == MORPH_CROSS )
                j1 = anchor.x, j2 = j1 + 1;
            else
            {
                int dy = i - r;
                if( std::abs(dy) <= r )
                {
                    int dx = saturate_cast<int>(c*std::sqrt((r*r - dy*dy)*inv_r2));
                    j1 = std::max( c - dx, 0 );
                    j2 = std::min( c + dx + 1, ksize.width );
                }
            }
    
            for( j = 0; j < j1; j++ )
                ptr[j] = 0;
            for( ; j < j2; j++ )
                ptr[j] = 1;
            for( ; j < ksize.width; j++ )
                ptr[j] = 0;
        }
    
        return elem;
    }
    

    erode

    #ifndef FBC_CV_ERODE_HPP_  
    #define FBC_CV_ERODE_HPP_  
    
    /* reference: include/opencv2/imgproc.hpp 
                  modules/imgproc/src/morph.cpp 
    */  
    
    #include <typeinfo>  
    #include "core/mat.hpp"  
    #include "imgproc.hpp"  
    #include "filterengine.hpp"  
    #include "core/core.hpp"  
    #include "morph.hpp"  
    
    namespace fbc {  
    
    // Erodes an image by using a specific structuring element  
    // \f[\texttt{ dst } (x, y) = \min _{ (x',y') : \, \texttt{ element } (x',y') \ne0 } \texttt{ src } (x + x',y+y')\f]  
    // In case of multi - channel images, each channel is processed independently.  
    // Erosion can be applied several ( iterations ) times.  
    // support type: uchar/float, multi-channels  
    template<typename _Tp, int chs>  
    int erode(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, Mat_<uchar, 1>& kernel,  
        Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = Scalar::all(DBL_MAX))  
    {  
        FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float  
        if (dst.empty()) {  
            dst = Mat_<_Tp, chs>(src.rows, src.cols);  
        } else {  
            FBC_Assert(src.rows == dst.rows && src.cols == dst.cols);  
        }  
    
        Size ksize = !kernel.empty() ? kernel.size() : Size(3, 3);  
        anchor = normalizeAnchor(anchor, ksize);  
    
        if (iterations == 0 || kernel.rows * kernel.cols == 1) {  
            src.copyTo(dst);  
            return 0;  
        }  
    
        if (kernel.empty()) {  
            kernel = Mat_<uchar, 1>(1 + iterations * 2, 1 + iterations * 2);  
            getStructuringElement(kernel, 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 = Mat_<uchar, 1>(ksize.height + (iterations - 1)*(ksize.height - 1), ksize.width + (iterations - 1)*(ksize.width - 1));  
            getStructuringElement(kernel, MORPH_RECT,  
                Size(ksize.width + (iterations - 1)*(ksize.width - 1), ksize.height + (iterations - 1)*(ksize.height - 1)), anchor);  
            iterations = 1;  
        }  
    
        anchor = normalizeAnchor(anchor, kernel.size());  
    
        Ptr<BaseRowFilter> rowFilter;  
        Ptr<BaseColumnFilter> columnFilter;  
        Ptr<BaseFilter> filter2D;  
    
        if (countNonZero(kernel) == kernel.rows*kernel.cols) {  
            // rectangular structuring element  
            rowFilter = getMorphologyRowFilter<_Tp, chs>(0, kernel.cols, anchor.x);  
            columnFilter = getMorphologyColumnFilter<_Tp, chs>(0, kernel.rows, anchor.y);  
        } else {  
            filter2D = getMorphologyFilter<_Tp, chs>(0, kernel, anchor);  
        }  
    
        Scalar borderValue_ = borderValue;  
        if (borderType == BORDER_CONSTANT && borderValue_ == Scalar::all(DBL_MAX)) {  
            if (sizeof(_Tp) == 1) // CV_8U  
                borderValue_ = Scalar::all((double)UCHAR_MAX);  
            else // CV_32F  
                borderValue_ = Scalar::all((double)FLT_MAX);  
        }  
    
        Ptr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>> f = makePtr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>>(filter2D, rowFilter, columnFilter, borderType, borderType, borderValue_);  
        f->apply(src, dst);  
        for (int i = 1; i < iterations; i++)  
            f->apply(dst, dst);  
    
        return 0;  
    }  
    
    } // namespace fbc  
    
    #endif // FBC_CV_ERODE_HPP_  
    

    dilate

    #ifndef FBC_CV_DILATE_HPP_  
    #define FBC_CV_DILATE_HPP_  
    
    /* reference: include/opencv2/imgproc.hpp 
                  modules/imgproc/src/morph.cpp 
    */  
    
    #include <typeinfo>  
    #include "core/mat.hpp"  
    #include "imgproc.hpp"  
    #include "filterengine.hpp"  
    #include "core/core.hpp"  
    #include "morph.hpp"  
    
    namespace fbc {  
    
    // Dilates an image by using a specific structuring element  
    // \f[\texttt{dst} (x,y) =  \max _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]  
    // In case of multi - channel images, each channel is processed independently.  
    // support type: uchar/float, multi-channels  
    template<typename _Tp, int chs>  
    int dilate(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, Mat_<uchar, 1>& kernel,  
        Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = Scalar::all(DBL_MAX))  
    {  
        FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float  
        if (dst.empty()) {  
            dst = Mat_<_Tp, chs>(src.rows, src.cols);  
        } else {  
            FBC_Assert(src.rows == dst.rows && src.cols == dst.cols);  
        }  
    
        Size ksize = !kernel.empty() ? kernel.size() : Size(3, 3);  
        anchor = normalizeAnchor(anchor, ksize);  
    
        if (iterations == 0 || kernel.rows * kernel.cols == 1) {  
            src.copyTo(dst);  
            return 0;  
        }  
    
        if (kernel.empty()) {  
            kernel = Mat_<uchar, 1>(1 + iterations * 2, 1 + iterations * 2);  
            getStructuringElement(kernel, 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 = Mat_<uchar, 1>(ksize.height + (iterations - 1)*(ksize.height - 1), ksize.width + (iterations - 1)*(ksize.width - 1));  
            getStructuringElement(kernel, MORPH_RECT,  
                Size(ksize.width + (iterations - 1)*(ksize.width - 1), ksize.height + (iterations - 1)*(ksize.height - 1)), anchor);  
            iterations = 1;  
        }  
    
        anchor = normalizeAnchor(anchor, kernel.size());  
    
        Ptr<BaseRowFilter> rowFilter;  
        Ptr<BaseColumnFilter> columnFilter;  
        Ptr<BaseFilter> filter2D;  
    
        if (countNonZero(kernel) == kernel.rows*kernel.cols) {  
            // rectangular structuring element  
            rowFilter = getMorphologyRowFilter<_Tp, chs>(1, kernel.cols, anchor.x);  
            columnFilter = getMorphologyColumnFilter<_Tp, chs>(1, kernel.rows, anchor.y);  
        } else {  
            filter2D = getMorphologyFilter<_Tp, chs>(1, kernel, anchor);  
        }  
    
        Scalar borderValue_ = borderValue;  
        if (borderType == BORDER_CONSTANT && borderValue_ == Scalar::all(DBL_MAX)) {  
            if (sizeof(_Tp) == 1) // CV_8U  
                borderValue_ = Scalar::all(0.);  
            else // CV_32F  
                borderValue_ = Scalar::all(-FLT_MAX);  
        }  
    
        Ptr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>> f = makePtr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>>(filter2D, rowFilter, columnFilter, borderType, borderType, borderValue_);  
        f->apply(src, dst);  
        for (int i = 1; i < iterations; i++)  
            f->apply(dst, dst);  
    
        return 0;  
    }  
    
    } // namespace fbc  
    
    #endif // FBC_CV_DILATE_HPP_  
    

    morphologyEx

    #ifndef FBC_CV_MORPHOLOGYEX_HPP_  
    #define FBC_CV_MORPHOLOGYEX_HPP_  
    
    /* reference: include/opencv2/imgproc.hpp 
                  modules/imgproc/src/morph.cpp 
    */  
    
    #include <typeinfo>  
    #include "erode.hpp"  
    #include "dilate.hpp"  
    
    namespace fbc {  
    
    // perform advanced morphological transformations using an erosion and dilation as basic operations  
    // In case of multi - channel images, each channel is processed independently.  
    // morphologyEx can be applied several ( iterations ) times.  
    // op ==> enum MorphTypes  
    // support type: uchar/float, multi-channels  
    template<typename _Tp, int chs>  
    int morphologyEx(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, int op, const Mat_<uchar, 1>& kernel,  
        Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = Scalar::all(DBL_MAX))  
    {  
        FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float  
        if (dst.empty()) {  
            dst = Mat_<_Tp, chs>(src.rows, src.cols);  
        } else {  
            FBC_Assert(src.rows == dst.rows && src.cols == dst.cols);  
        }  
    
        Mat_<uchar, 1> kernel_ = kernel;  
        if (kernel_.empty()) {  
            kernel_ = Mat_<uchar, 1>(3, 3);  
            getStructuringElement(kernel_, MORPH_RECT, Size(3, 3), Point(1, 1));  
        }  
    
        switch (op) {  
            case MORPH_ERODE: {  
                erode(src, dst, kernel_, anchor, iterations, borderType, borderValue);  
                break;  
            }  
            case MORPH_DILATE: {  
                dilate(src, dst, kernel_, anchor, iterations, borderType, borderValue);  
                break;  
            }  
            case MORPH_OPEN: {  
                erode(src, dst, kernel_, anchor, iterations, borderType, borderValue);  
                dilate(dst, dst, kernel_, anchor, iterations, borderType, borderValue);  
                break;  
            }  
            case CV_MOP_CLOSE: {  
                dilate(src, dst, kernel_, anchor, iterations, borderType, borderValue);  
                erode(dst, dst, kernel_, anchor, iterations, borderType, borderValue);  
                break;  
            }  
            case CV_MOP_GRADIENT: {  
                Mat_<_Tp, chs> temp(src.rows, src.cols);  
                erode(src, temp, kernel_, anchor, iterations, borderType, borderValue);  
                dilate(src, dst, kernel_, anchor, iterations, borderType, borderValue);  
                dst -= temp;  
                break;  
            }  
            case CV_MOP_TOPHAT: {  
                Mat_<_Tp, chs> temp(src.rows, src.cols);  
                if (src.data != dst.data)  
                    temp = dst;  
                erode(src, temp, kernel_, anchor, iterations, borderType, borderValue);  
                dilate(temp, temp, kernel_, anchor, iterations, borderType, borderValue);  
                dst = src - temp;  
                break;  
            }  
            case CV_MOP_BLACKHAT: {  
                Mat_<_Tp, chs> temp(src.rows, src.cols);  
                if (src.data != dst.data)  
                    temp = dst;  
                dilate(src, temp, kernel_, anchor, iterations, borderType, borderValue);  
                erode(temp, temp, kernel_, anchor, iterations, borderType, borderValue);  
                dst = temp - src;  
                break;  
            }  
            case MORPH_HITMISS: {  
                FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() && chs == 1);  
                Mat_<uchar, 1> k1 = (kernel_ == Mat_<uchar, 1>(kernel_.rows, kernel_.cols, Scalar::all(1)));  
                Mat_<uchar, 1> k2 = (kernel_ == Mat_<int, 1>(kernel_.rows, kernel_.cols, Scalar::all(-1)));  
                Mat_<_Tp, chs> e1, e2;  
    
                if (countNonZero(k1) <= 0)  
                    e1 = src;  
                else  
                    erode(src, e1, k1, anchor, iterations, borderType, borderValue);  
                if (countNonZero(k2) <= 0) {  
                    e2 = src;  
                } else {  
                    Mat_<_Tp, chs> src_complement;  
                    bitwise_not(src, src_complement);  
                    erode(src_complement, e2, k2, anchor, iterations, borderType, borderValue);  
                }  
                bitwise_and(e1, e2, dst);  
                break;  
            }  
            default:  
                FBC_Assert("unknown morphological operation");  
        }  
    
        return 0;  
    }  
    
    } // namespace fbc  
    
    #endif // FBC_CV_MORPHOLOGYEX_HPP_  
    

    相关文章

      网友评论

          本文标题:形态学滤波

          本文链接:https://www.haomeiwen.com/subject/tysnfftx.html