精华内容
下载资源
问答
  • 基于形态学滤波去噪matlab代码
  • 形态学滤波matlab程序

    2018-03-20 17:21:23
    自己写的matlab形态学滤波function函数,方便调用,且实用
  • MATLAB实现形态学滤波

    2018-04-17 12:58:49
    用MATLAB代码实现形态学滤波,包括形态学中各种运算方法。
  • Task07 OpenCV框架实现形态学滤波一、前言二、形态学概述三、基本形态学操作3.1腐蚀3.2膨胀四、高级形态学操作4.1开闭运算4.2形态学梯度4.3黑帽顶帽五、基于OpenCV的C++代码实现 一、前言 图像形态学滤波是图像滤波...

    一、前言

    图像形态学滤波是图像滤波的一个重要分支,与之前介绍过的空间域滤波(方框滤波、高斯滤波、中值滤波)以及图像边缘提取过程中的滤波相同的是,他们都是通过滤波算子掩膜计算图像(中心)像素点的过程,不同的是滤波算子(内核)和计算方式,概括如下:

    • 形态学滤波:采用结构元素(Structure element)作为内核,中心像素是通过内核区域集合运算得到的。
    • 空域平滑、锐化滤波:采用卷积元素(Convolution element)作为内核,中心像素通过内核区域算数运算(有积分、微分等)得到的。

    总体来说,图像的形态学操作是基于形状的一系列图像处理操作,在OpenCV中对图像的形态学变换提供了方便快捷的函数,包括基本形态学操作和高级形态学操作。

    二、形态学概述

    图像形态学,也叫做数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论,在图像处理中占有相当重要的地位。

    在图像处理中,对于图像形态学的应用相当的广泛,主要应用在对于图像的预处理操作当中,尤其是在对二值图像的预处理和分析方面。

    结构元素
    形态学滤波最主要特征在集合运算,而集合运算是通过由0/1组成的不同形态的结构元素实现的,首先明确结构元素的概念:
    结构元素是由元素为1或者0的矩阵组成,结构元素为1的区域定义了图像的邻域,领域内的像素在进行态学操作时要进行考虑。一般来说,二维或者平面结构的结构元素要比处理的图像小得多。结构元素的中心像素,即结构元素的原点,与输入图像中感兴趣的像素值(即要处理的像素值)相对应。

    OpenCV中获取结构元素的函数为getStructuringElement,原型为:

    Mat getStructuringElement(int shape,  //内核的形状
    						  Size esize,  //内核的尺寸
    						  Point anchor = Point(-1, -1) //锚点的位置						  )
    

    内核的形状,有三种形状可以选择。

    • 矩形:MORPH_RECT;
    • 交叉形:MORPH_CROSS;
    • 椭圆形:MORPH_ELLIPSE;

    三、基本形态学操作

    基本形态学操作有腐蚀和膨胀,在腐蚀和膨胀上面通过不同运算方式可得到高级形态学操作,其主要作用有:

    • 消除噪声(低尺寸结构元素的腐蚀操作很容易去掉分散的椒盐噪声点)
    • 分割出独立的图像元素(腐蚀),在图像中连接相邻的元素(膨胀)
    • 寻找图像中明显的极大值区域或极小值区域
    • 求出图像的梯度
    • 图像轮廓提取、图像分割、寻找图像中的明显的极大值区域或极小值区域等

    【注】:OpenCV里面的腐蚀和膨胀操作是针对白色目标区域

    3.1腐蚀

    腐蚀:用结构元素的中心点对准当前正在遍历的这个像素,然后取当前结构元素所覆盖下的原图对应区域内的所有像素的最小值,用这个最小值替换当前像素值,删除对象边界的某些像素,使二值图像减小一圈

    腐蚀是一种最大值滤波,即用结构元素内的最大值去替换锚点的像素值,具体操作为:

    1. 用结构元素,扫描图像的每一个像素

    2. 用结构元素与其覆盖的二值图像做 “与”操作

    3. 如果都为1,结果图像的该像素为1。否则为0,也就是查找被处理图像中能不能找到和结构元素相同的矩阵。如果存在那么中心点所对应的点就为1,否则为0

    简单来说,就是腐蚀图像白色边缘(像素值为1)缩小一圈,图示如下:
    在这里插入图片描述
    若图中原始图像边界点像素为src(x,y),采用结构元素element(x’,y’)处理后得到dst(x,y),公式表述为:
    dst(x,y)=max(x,y):element(x,y)0src(x+x,y+y)dst(x,y)=\underset{(x',y'):element(x',y')\neq 0}{max}src(x+x',y+y')

    在OpenCV中进行腐蚀操作可以采用函数erode(),或者采用morphologyEx() 函数并输出需要进行的形态学操作类型。如下为erode()函数原型:

    void erode(InputArray src,  //原始图像
        	   OutputArray dst, //目标图像,和源图片有一样的尺寸和类型
       		   InputArray kernel, //内核,可以使用getStructuringElement来创建结构元素
               Point anchor=Point(-1,-1), //锚点的位置,其有默认值(-1,-1),表示锚位于中心
               int iterations=1,  //迭代使用该函数的次数,默认值为1
               int borderType=BORDER_CONSTANT,  //用于推断图像外部像素的某种边界模式,默认值BORDER_DEFAULT
               const Scalar& borderValue=morphologyDefaultBorderValue()  //当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),
                )
    

    3.2膨胀

    膨胀:用结构元素的中心点对准当前正在遍历的这个像素,然后取当前结构元素所覆盖下的原图对应区域内的所有像素的最大值,用这个最大值替换当前像素值,给图像中的对象边界添加像素,使图像扩大一圈

    膨胀是一种最小值滤波,即用结构元素内的最小值去替换锚点的像素值,具体操作:

    1. 用结构元素,扫描图像的每一个像素

    2. 用结构元素与其覆盖的二值图像做 “与”操作

    3. 如果都为0,结果图像的该像素为0。否则为1
      也就是在结构元素覆盖范围下,只要有一个像素符和结构元素像素相同,那么中心点对应点就为1,否则为0

    简单来说,就是膨胀图像边缘白色(像素值为1)扩大一圈,图示如下:
    在这里插入图片描述
    类似上,公式表述为:
    dst(x,y)=min(x,y):element(x,y)0src(x+x,y+y)dst(x,y)=\underset{(x',y'):element(x',y')\neq 0}{min}src(x+x',y+y')

    在OpenCV中进行膨胀操作可以采用函数dilate(),或者采用morphologyEx() 函数并输出需要进行的形态学操作类型。如下为cv::dilate()的函数原型,和erode类似

    void dilate(InputArray src,  //原始图像
        	    OutputArray dst, //目标图像,和源图片有一样的尺寸和类型
       		    InputArray kernel, //内核,可以使用getStructuringElement来创建结构元素
                Point anchor=Point(-1,-1), //锚点的位置,其有默认值(-1,-1),表示锚位于中心
                int iterations=1,  //迭代使用该函数的次数,默认值为1
                int borderType=BORDER_CONSTANT,  //用于推断图像外部像素的某种边界模式,默认值BORDER_DEFAULT
                const Scalar& borderValue=morphologyDefaultBorderValue()  //当边界为常数时的边界值,有默认值morphologyDefaultBorderValue()
                )
    

    【注】腐蚀:删除对象边界的某些像素
              ~~~~~~~~~~膨胀:给图像中的对象边界添加像素

    四、高级形态学操作

    4.1开闭运算

    开运算:先腐蚀,再膨胀,可清除一些亮的像素点,放大局部低亮度的区域,在纤细点处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积。

    闭运算:先膨胀,再腐蚀,可清除一些暗的像素点,即排除小型黑洞(黑色区域)。

    4.2形态学梯度

    膨胀图与腐蚀图之差提取物体边缘,对二值图像进行这一操作可以将边缘突出出来。

    4.3黑帽顶帽

    顶帽:原图像-开运算图,突出原图像中比周围的区域
    黑帽:闭运算图-原图像,突出原图像中比周围的区域

    morphologyEx函数利用基本的膨胀和腐蚀技术,来执行更加高级形态学变换,函数原型为:

    void morphologyEx(InputArray src,  //原始图像
    			      OutputArray dst,  //目标图像
                      int op,  //形态学操作
                      InputArray kernel, //内核
                      Point anchor=Point(-1,-1), //锚点 ,其有默认值(-1,-1),表示锚位于中心
                      int iterations=1,  //迭代使用该函数的次数,默认值为1
                      int borderType=BORDER_CONSTANT,  //用于推断图像外部像素的某种边界模式,默认值BORDER_DEFAULT
                      const Scalar& borderValue=morphologyDefaultBorderValue()  //当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),
                      )
    

    表示形态学操作的类型OP可取值如下:
    在这里插入图片描述

    五、基于OpenCV的C++代码实现

    下面这段代码分为两个部分,一部分使用OpenCV自带形态学处理函数实现的,一部分使用自己构造函数实现的。
    在实现My_open开运算的同时,使用双滚动条控制结构元素的宽(W)和高(H),具体代码如下:

    #include<opencv2/opencv.hpp>
    #include<iostream>
    using namespace cv;
    //函数声明
    void my_erode(Mat& src,Mat& dst,Size dsize); 
    void my_dilate(Mat& src,Mat& dst,Size dsize);
    void my_open(Mat& src, Mat& dst, Size dsize);
    void my_close(Mat& src, Mat& dst, Size dsize);
    
    //全局定义:比较耗内存
    int h=1,w=1;
    Mat newSrc;
    Mat dst_open1;  
    
    void on_Track(int ,void*){  //回调函数
        my_open(newSrc,dst_open1,Size(2*h+1,2*w+1));
        imshow("WIN_NAME",dst_open1);
        
    }
    int main(){  //主函数
        Mat src=imread("C:/Users/Administrator/Desktop/beauty.jpg");
        Size dsize=Size(round(0.3*src.cols),round(0.3*src.rows));
        resize(src,src,dsize,0,0,CV_INTER_LINEAR);
    
        //Part1:OpenCV自带函数实现腐蚀膨胀、开闭运算、顶帽底帽等
        Mat dst_erode,dst_dilate;
        double t_beg=getTickCount();
        Mat element=getStructuringElement(MORPH_RECT,Size(7,7)); //矩形内核
        erode(src,dst_erode,element); //腐蚀:计时
        double t_end=getTickCount();
        std::cout<<"OpenCV_erode time:"<<((t_end-t_beg)*1000)/getTickFrequency()<<"ms"<<std::endl;
        
        dilate(src,dst_dilate,element);  //膨胀
        Mat dst_open;
        morphologyEx(src,dst_open,MORPH_OPEN,element);   //开运算
        /*腐蚀和膨胀也可以应用此模板,对应的参数为
        MORPH_OPEN : 开运算
        MORPH_CLOSE : 闭运算
        MORPH_ERODE : 腐蚀
        MORPH_DILATE : 膨胀
        MORPH_TOPHAT : 顶帽
        MORPH_BLACKHAT : 黑帽
        */
    
    
        //Part2:C++构造函数实现腐蚀、膨胀、开闭操作
        Mat dst_erode1(src.size(),src.type()),dst_dilate1(src.size(),src.type());
        //Size dsize(7,7);
        double t_beg1=getTickCount();
        my_erode(src,dst_erode1,Size(7,7)); //腐蚀:计时
        double t_end1=getTickCount();
        std::cout<<"My_erode time:"<<((t_end1-t_beg1)*1000)/getTickFrequency()<<"ms"<<std::endl;
        my_dilate(src,dst_dilate1,Size(7,7));
        
        //设置滚动条C++实现开运算
        int max_value=5; //设置滚动条最大值
        src.copyTo(newSrc);
        src.copyTo(dst_open1);
        namedWindow("WIN_NAME",WINDOW_AUTOSIZE); //创建窗口
        createTrackbar("h","WIN_NAME",&h,max_value,on_Track); //h滚动条
        createTrackbar("w","WIN_NAME",&w,max_value,on_Track); //w滚动条
        on_Track(0,0); //调用回调函数,并显示
        
        //进行显示、写入等操作
        waitKey(0);
        return 0;
    }
    void my_erode(Mat& src,Mat& dst,Size wsize){
        if((wsize.height%2==0) || (wsize.width%2==0)){
            printf("The length and width must be odds!");
            exit(-1);
        }
        int center_y=wsize.height/2;
        int center_x=wsize.width/2;
    
        Mat borderDst;
        copyMakeBorder(src,borderDst,center_x,center_x,center_y,center_y,BORDER_REFLECT101); //对称扩展边界
     
        for(int row=center_y;row<src.rows+center_y;row++){
            for(int col=center_x;col<src.cols+center_x;col++){
                //对模板覆盖图像区域处理
                if(src.channels() == 1){  //单通道
                    int min_Value=255;
                    for(int i=row-center_y;i<row+center_y+1;i++){
                        for(int j=col-center_x;j<col+center_x+1;j++){
                            min_Value=MIN(min_Value,borderDst.at<uchar>(i,j)); //掩膜最小值:白色区域(255)缩小一圈
                        }
                    }
                    dst.at<uchar>(row-center_y,col-center_x)=min_Value;
                }
                else{
                    for(int channel=0;channel<3;channel++){  //多通道
                        int min_Value=255;
                        //对模板覆盖图像区域处理
                        for(int i=row-center_y;i<row+center_y+1;i++){
                            for(int j=col-center_x;j<col+center_x+1;j++){
                                min_Value=MIN(min_Value,borderDst.at<Vec3b>(i,j)[channel]); //掩膜最小值:白色区域(255)缩小一圈
                            }
                        }
                        dst.at<Vec3b>(row-center_y,col-center_x)[channel]=min_Value;
                    }
                }
    
                
            }
        }
          
    }
    
    void my_dilate(Mat& src,Mat& dst,Size dsize){   //类似my_erode处理
        if(dsize.width%2 == 0 || dsize.height%2 == 0){
            printf("Kernel size do not be odds!");
            exit(-1);
        }
        int h=dsize.height/2; //row
        int w=dsize.width/2;  //col
        Mat borderSrc;
        copyMakeBorder(src,borderSrc,h,h,w,w,BORDER_REFLECT101);
    
        //对图像每一个像素遍历
        for(int row=h;row<src.rows+h;row++){
            for(int col=w;col<src.cols+w;col++){
    
                //对每一个掩膜区域逻辑处理
                if(src.channels() == 1){ //单通道
                    int max_Value=0;
                    for(int i=row-h;i<row+h+1;i++){
                        for(int j=col-w;j<col+w+1;j++){
                            max_Value=MAX(max_Value,borderSrc.at<uchar>(i,j));
                        }
                    }
                    dst.at<uchar>(row-h,col-w)=max_Value;
                }
    
                else{
                    for(int channel=0;channel<3;channel++){  //多通道
                        int max_Value=0;
                        for(int i=row-h;i<row+h+1;i++){
                            for(int j=col-w;j<col+w+1;j++){
                                max_Value=MAX(max_Value,borderSrc.at<Vec3b>(i,j)[channel]);
                            }
                        }
                        dst.at<Vec3b>(row-h,col-w)[channel]=max_Value;
                    }
                }
            }
        }
    
    }
    
    void my_open(Mat& src, Mat& dst, Size dsize) {  //开运算:先腐蚀再膨胀
    	Mat dst1;
    	src.copyTo(dst1);
    	my_erode(src, dst1,dsize);
    	my_dilate(dst1, dst,dsize);
    }
    void my_close(Mat& src, Mat& dst, Size dsize) {  //闭运算:先膨胀再腐蚀
    	Mat dst1;
    	src.copyTo(dst1);
    	my_erode(src, dst1,dsize);
    	my_dilate(dst1, dst,dsize);
    }
    
    void my_tophat(Mat src, Mat dst, Size dsize) { //顶帽:原图-开运算(注意防溢出)
    	Mat dst1;
    	src.copyTo(dst1);
    	my_open(src, dst1, dsize);
    	imshow("open", dst1);
    	for (int rows = 0; rows < src.rows; rows++) {
    		for (int cols = 0; cols < src.cols; cols++) {
                if(src.channels() == 1){
    			    dst.at<uchar>(rows, cols) = saturate_cast<uchar>(src.at<uchar>(rows, cols) - dst1.at<uchar>(rows, cols));
                }
                else{
                    dst.at<Vec3b>(rows, cols)[0] = saturate_cast<uchar>(src.at<Vec3b>(rows, cols)[0] - dst1.at<Vec3b>(rows, cols)[0]);
                    dst.at<Vec3b>(rows, cols)[1] = saturate_cast<uchar>(src.at<Vec3b>(rows, cols)[1] - dst1.at<Vec3b>(rows, cols)[1]);
                    dst.at<Vec3b>(rows, cols)[2] = saturate_cast<uchar>(src.at<Vec3b>(rows, cols)[2] - dst1.at<Vec3b>(rows, cols)[2]);
                }
            }
    	}
    	imshow("顶帽", dst);
    }
    
    
    void my_underhat(Mat src, Mat dst, Size dsize) {  //黑帽:闭运算-原图
    	Mat dst1;
    	src.copyTo(dst1);
    	my_close(src, dst1, dsize);
    	imshow("colse", dst1);
    	for (int rows = 0; rows < src.rows; rows++) {
    		for (int cols = 0; cols < src.cols; cols++) {
                if(src.channels() == 1){
    			dst.at<uchar>(rows, cols) = saturate_cast<uchar>(dst1.at<uchar>(rows, cols) - src.at<uchar>(rows, cols));
                }
                else{
                    dst.at<Vec3b>(rows, cols)[0] = saturate_cast<uchar>(dst1.at<Vec3b>(rows, cols)[0] - src.at<Vec3b>(rows, cols)[0]);
                    dst.at<Vec3b>(rows, cols)[1] = saturate_cast<uchar>(dst1.at<Vec3b>(rows, cols)[1] - src.at<Vec3b>(rows, cols)[1]);
                    dst.at<Vec3b>(rows, cols)[2] = saturate_cast<uchar>(dst1.at<Vec3b>(rows, cols)[2] - src.at<Vec3b>(rows, cols)[2]);
                }
            }
    	}
    	namedWindow("黑帽", CV_WINDOW_AUTOSIZE);
    	imshow("黑帽", dst);
    }
    

    滚动条控制内核kernel的W和H得到开运算目标图像,显示如下:
    在这里插入图片描述
    其他效果续更…

    参考博客:
    【1】【OpenCV(C++)】图像处理:形态学滤波
    【2】形态学操作——腐蚀膨胀、开闭运算、顶帽变换底帽变换 c++实现

    展开全文
  • 形态学滤波角点提取

    2018-06-04 09:48:12
    形态学滤波角点提取 形态学边缘检测的原理是利用膨胀与腐蚀变化区域特征来完成边缘检测,膨胀操作是将目标物体向周围领域扩展,而腐蚀操作是将目标物体向领域收缩,图像的边缘恰好反应在形态学腐蚀与膨胀中变化的...

    形态学滤波角点提取

    形态学边缘检测的原理是利用膨胀与腐蚀变化区域特征来完成边缘检测,膨胀操作是将目标物体向周围领域扩展,而腐蚀操作是将目标物体向领域收缩,图像的边缘恰好反应在形态学腐蚀与膨胀中变化的区域,因此只需要将膨胀得到的结果图与腐蚀的得到的结果图进行差运算,就可以得到物体的边缘。形态学边缘检测可以形态学梯度操作函数morphologyEx直接得到,具体是通过计算形态学膨胀结果图与腐蚀结果图之差,在进行相应阈值化操作实现的。
    具体过程如下:
    这里写图片描述
    示例代码如下:

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <iostream>
    using namespace cv;
    int main()
    {
        cv::Mat srcImage = cv::imread("..\\images\\sea.jpg");
        if (!srcImage.data)
            return 1;
        cv::Mat srcGray;
        cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);
        // 定义结构元素
        Mat CrossMat(5, 5, CV_8U, Scalar(0));
        Mat diamondMat(5, 5, CV_8U, Scalar(1));
        Mat squareMat(5, 5, CV_8U, Scalar(1));
        Mat x(5, 5, CV_8U, Scalar(0));
        //  十字形形状  
        for (int i = 0; i<5; i++)
        {
            CrossMat.at<uchar>(2, i) = 1;
            CrossMat.at<uchar>(i, 2) = 1;
        }
        // 菱形形状
        diamondMat.at<uchar>(0, 0) = 0;
        diamondMat.at<uchar>(0, 1) = 0;
        diamondMat.at<uchar>(1, 0) = 0;
        diamondMat.at<uchar>(4, 4) = 0;
        diamondMat.at<uchar>(3, 4) = 0;
        diamondMat.at<uchar>(4, 3) = 0;
        diamondMat.at<uchar>(4, 0) = 0;
        diamondMat.at<uchar>(4, 1) = 0;
        diamondMat.at<uchar>(3, 0) = 0;
        diamondMat.at<uchar>(0, 4) = 0;
        diamondMat.at<uchar>(0, 3) = 0;
        diamondMat.at<uchar>(1, 4) = 0;
        // X形状
        for (int i = 0; i<5; i++){
            x.at<uchar>(i, i) = 1;
            x.at<uchar>(4 - i, i) = 1;
        }
        // 第1步:十字形对原图进行膨胀
        Mat result;
        dilate(srcGray, result, CrossMat);
        // 第2步:菱形对上步进行腐蚀
        erode(result, result, diamondMat);
        Mat result2;
        // 第3步:X形对原图进行腐蚀
        dilate(srcGray, result2, x);
        // 第4步:正方形对上步进行腐蚀
        erode(result2, result2, squareMat);
        // 第4步:计算差值
        absdiff(result2, result, result);
        threshold(result, result, 40, 255, THRESH_BINARY);
        // 绘图
        for (int i = 0; i < result.rows; i++)
        {
            // 获取行指针
            const uchar* data = result.ptr<uchar>(i);
            for (int j = 0; j < result.cols; j++)
            {
                // 如果是角点 则进行绘制圆圈
                if (data[j])
                   circle(srcImage, Point(j, i), 8, 
                    Scalar(0, 255, 0));
            }
        }
        cv::imshow("result", result);
        cv::imshow("srcImage", srcImage);
        cv::waitKey(0);
        return 0;
    }
    展开全文
  • 提出了一种基于区域预测的LiDAR 点云数据形态学滤波算法,该算法由点云数据建立规则格网、去除粗差点,对实验区域进行分块,然后使用各个分块区域的高程标准差预测地形坡度参数s 从而进行渐进式形态学滤波,最终确定...
  • 【计算机视觉】形态学滤波

    万次阅读 2015-11-28 16:30:59
    说明:本文主要想弄清楚形态学滤波在图象处理和信号处理中的应用,图像处理中非常直观的通过腐蚀膨胀获得开闭运算的效果,而在数据实时滤波中,形态学滤波也是可以使用的。形态学滤波基本知识 原理:在特殊领域运算...

    【计算机视觉】形态学滤波

    标签(空格分隔): 【图像处理】 【信号处理】

    版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/lg1259156776/


    说明:本文主要想弄清楚形态学滤波在图象处理和信号处理中的应用,图像处理中非常直观的通过腐蚀膨胀获得开闭运算的效果,而在数据实时滤波中,形态学滤波也是可以使用的。


    形态学滤波基本知识

    原理:在特殊领域运算形式——结构元素(Sturcture Element),在每个像素位置上与二值图像对应的区域进行特定的逻辑运算。运算结构是输出图像的相应像素。运算效果取决于结构元素大小内容以及逻辑运算性质。

    膨胀、腐蚀、开、闭运算是数学形态学最基本的变换。

    结构元素简单地定义为像素的结构(形状)以及一个原点(又称为锚点),使用形态学滤波涉及对图像的每个像素应用这个结构元素,当结构元素的原点与给定的像素对齐时,它与图像相交部分定义了一组进行形态学运算的像素。原则上,结构元素可以是任何形状,但通常使用简单的形状,比如方形、圆形和菱形,而原点位于中心位置(基于效率的考虑)。

    腐蚀和膨胀两个滤波操作也运算在每个像素周围像素集合上(邻域),这是由结构元素定义的。当应用到一个给定的像素时,结构元素的锚点与该像素的位置对齐,而所有与他相交的像素都被包括在当前像素集合中。腐蚀替换当前像素为像素集合中找到的最小的像素值,而膨胀则替换为像素集合中找到的最大像素值。当然,对于二值图像,每个像素只能被替换为白色像素或黑色像素。

    这一段的论述,可以参考Opencv计算机视觉 编程手册。对于腐蚀和膨胀的差别,可以通过想象,腐蚀呢, 如果给定像素的结构元素触碰到背景,那么该像素被设置为背景,而在膨胀的情况下,如果触碰到前景,该像素被设置为前景,所以很明显,腐蚀操作后物体的尺寸会减小,而膨胀操作后物体的尺寸会增大,同时内部的一些洞被填满。

    事实上,腐蚀一副图像两次,就像是让结构元素对自己进行膨胀后再去腐蚀同一幅图像;反过来对膨胀也是合适的。

    有下面两种说法:

    1. 对图像的腐蚀操作等于对图像负片的膨胀操作的负片;
    2. 对图像的膨胀操作等于对图像负片的腐蚀操作的负片;

    实际上说的是对目标进行的腐蚀,等效于对背景进行的膨胀;反之亦然。

    腐蚀的最简单的应用是从图中消除不相关的细节,而膨胀的最简单的应用是将裂缝桥接起来。开运算是先腐蚀再膨胀,开运算一般断开狭窄的间断和消除细的突出物,而闭操作通常消弥狭窄的间断和长细的鸿沟,消除小的孔洞,并填充轮廓线中的断裂。开运算与闭运算的结合使用能使作用对象的轮廓变得光滑

    开运算是先腐蚀再膨胀,而闭运算是先膨胀再腐蚀;
    在检验闭滤波器的结果时,可以看到白色前景物体中的小洞被填充,该滤波器同时连接多个相邻物体,基本上,无法完全包含结构元素的洞洞或者缝隙都将被滤波器移除。反过来,开滤波器则是移除掉场景中比较小的物体,因为它门无法完全包含结构元素。

    这些滤波器通常在物体检测中应用,闭滤波器将误分割为碎片的物体重新连接起来,而开滤波器则去除掉图像噪声点引起的小像素块(Blob)。因此,在视频序列中使用他们很有帮助,如果测试的二值图像相继使用闭、开操作,获得图像将只显示场景中的主要物体。如果优先处理噪点,也可以先进行开运算,再进行闭运算,但是有可能去除掉一些分散的物体。

    需要注意的是,对于对于一幅图像多次使用相同的开运算或者闭运算是没有效果的,因为在第一次闭(开)运算填充图像中的洞洞后,再次应用相同的滤波,不会对图像产生任何变化。用数学的术语讲,这些运算是等幂的。

    使用形态学滤波对图像进行边缘及角点检测

    形态学滤波可以用于检测图像中指定的特征。
    一种比较形象的方法是将灰度图像看做是“等高线”(比如分水岭图像分割算法):亮的区域代表山峰,而暗的区域代表山谷,图像的边沿就对应于峭壁。如果腐蚀一幅图像,会导致山谷被扩展,而峭壁减少了。相反的,如果膨胀一幅图像,峭壁则会增加。但是这两种情况下,中间的部分(大片的谷底和高原)基本保持不变。

    在上述理解的基础上,如果我们对图像的腐蚀和膨胀的结果做差,就能提取图像的边界:因为边界区域,二者完全不同。(实际上,我们也可以用腐蚀或者膨胀的结果与源图像做差得出类似结果,但提取的边界会比较细)。可以看出,结构元越大,边界越粗。在OpenCV中,将形态学操作函数morphologyEx 的第4个参数设为MORPH_GRADIENT,就能完成上述工作。

    利用形态学操作获取角点稍微有一些复杂,它试用了四种不同的结构元素,基本方法是对一幅图像先腐蚀,在膨胀但是这两次操作使用的结构元却不同。这些结构元的选取使得直线保持不变,但是由于他们各自作用的效果,角点处的边沿被影响了。我们结合一幅图来说明:

    此处输入图片的描述

    第一幅图是原图。在被十字形元素膨胀后,方块的边缘被扩张,而由于十字形元素没有击中角点,此处不受影响。中间的方块描述了这个结果;膨胀后的图像接着被菱形元素腐蚀,这次运算将大多数的边缘恢复到原始位置,但之前没有膨胀过的角点被向内推动,之后得到了左边的方块,可以看到,他缺少明显的角点。同样的处理过程通过X形与方形元素得到重复。这两个元素结构是先前元素的旋转版本,捕获的将是45°旋转后的角点。最后,对两次过程的结果做差值,提取角点特征。

    代码可以参考参考文献3.

    形态学滤波之图象处理

    一般腐蚀操作对二值图进行处理,腐蚀操作如下图,中心位置的像素点是否与周围领域的像素点颜色一样(即是否是白色点,即值是否为255),若一致,则保留,不一致则该点变为黑色(值即为0)
    此处输入图片的描述
    opencv中的腐蚀操作:

    CVAPI(void)  cvErode( const CvArr* src, CvArr* dst,
                          IplConvKernel* element CV_DEFAULT(NULL),
                          int iterations CV_DEFAULT(1) );
    

    前两个参数比较熟悉,第三个参数是用于传递模板的信息,默认是(NULL),即为3*3的模板,第四个参数是迭代的次数(即该腐蚀操作做几次);

    opencv中的膨胀操作其实就是腐蚀的反操作:

    CVAPI(void)  cvDilate( const CvArr* src, CvArr* dst,
                           IplConvKernel* element CV_DEFAULT(NULL),
                           int iterations CV_DEFAULT(1) );
    

    测试代码:
    #include “stdafx.h”
    #include “cv.h”
    #include “highgui.h”

    int main(){
        IplImage *img= cvLoadImage("C:/fu.jpg");//读取图片
        cvNamedWindow("Example1",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example3",CV_WINDOW_AUTOSIZE);
    
        cvShowImage("Example1",img);//在Example1显示图片
        //    cvCopy(img,temp);
        IplImage* temp=cvCreateImage( //创建一个size为image,三通道8位的彩色图
            cvGetSize(img),
            IPL_DEPTH_8U,
            3
            );
    
        cvErode(img,temp,0,1);//腐蚀
        cvShowImage("Example2",temp);
    
        cvDilate(img,temp,0,1);//膨胀
        cvShowImage("Example3",temp);
    
    
        cvWaitKey(0);//暂停用于显示图片
    
    
        cvReleaseImage(&img);//释放img所指向的内存空间并且
        cvDestroyWindow("Example1");
        cvDestroyWindow("Example2");
        cvDestroyWindow("Example3");
    
        return 0;
    }
    

    此处输入图片的描述
    以上都是在模板3*3的情况下处理的,要是我们期望使用自己定义的模板时候,就需要自己做模板。

    CVAPI(IplConvKernel*)  cvCreateStructuringElementEx(
                int cols, int  rows, int  anchor_x, int  anchor_y,
                int shape, int* values CV_DEFAULT(NULL) );
    

    前两个参数是定义模板的大小,后两个参数是参考点的坐标(比如默认3*3模板的参考点坐标是2*2),第五个参数是模板的类型(可以是矩形,十字形,椭圆形,甚至是用户自己定义形状),最后一个参数是在使用自自定义形状的时候,通过value传递模板的形状。

    模板的类型:
    此处输入图片的描述

    CVAPI(void)  cvReleaseStructuringElement( IplConvKernel** element ); //释放模板所占用的内存
    

    自定义5*5,参考点(3,3)的矩形模板的测试代码:

    #include "stdafx.h"
    #include "cv.h"
    #include "highgui.h"
    
    int main(){
        IplImage *img= cvLoadImage("C:/fu.jpg");//读取图片
        cvNamedWindow("Example1",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Example3",CV_WINDOW_AUTOSIZE);
    
        cvShowImage("Example1",img);//在Example1显示图片
        //    cvCopy(img,temp);
        IplImage* temp=cvCreateImage( //创建一个size为image,三通道8位的彩色图
            cvGetSize(img),
            IPL_DEPTH_8U,
            3
            );
    
        IplConvKernel * myModel;
        myModel=cvCreateStructuringElementEx( //自定义5*5,参考点(3,3)的矩形模板
            5,5,2,2,CV_SHAPE_RECT
            );
    
        cvErode(img,temp,myModel,1);
        cvShowImage("Example2",temp);
    
        cvDilate(img,temp,myModel,1);
        cvShowImage("Example3",temp);
    
    
        cvWaitKey(0);//暂停用于显示图片
    
        cvReleaseStructuringElement(&myModel);
        cvReleaseImage(&img);//释放img所指向的内存空间并且
        cvDestroyWindow("Example1");
        cvDestroyWindow("Example2");
        cvDestroyWindow("Example3");
    
        return 0;
    }
    

    效果图:
    此处输入图片的描述

    形态学滤波之信号处理

    数学形态学的方法可以理解为一个具有一定直径的小球滚过一段特定的路径,各种信号可以看作是路径上的小坑。由于所有的噪声都有个共同特征一一高频低峰(它们构成非常复杂,由各种混合在眼电信号中的其他成份或眼球快速、微小、空间大小不超过1“的运动导致),这些小坑的径长明显小于小球直径,因此小球球心的滚动轨迹不会受噪声的干扰一一小球球心滚动轨迹即可以看成数学形态学处理后的信号。本系统中用到的数学形态学算子包括腐蚀运算、膨胀运算、开操作、闭操作。

    腐蚀的最简单的应用是从图中消除不相关的细节,而膨胀的最简单的应用是将裂缝桥接起来。开运算是先腐蚀再膨胀,开运算一般断开狭窄的间断和消除细的突出物,而闭操作通常消弥狭窄的间断和长细的鸿沟,消除小的孔洞,并填充轮廓线中的断裂。开运算与闭运算的结合使用能使作用对象的轮廓变得光滑

    #include <stdio.h>
    #include <fcntl.h>
    //#include <sys/types.h>
    //#include <sys/stats.h>
    #include <time.h>
    #define N 5  //结构元素。大小设置根据滤除波形一个周期中点个数来定。例如:采样率250,滤除50hz,
                                                                     //因为50hz一个周期中有5个点,所以N设为5。          
    
    
    float x[3*N+2]={0.0};
    
    void openoperate(float input[],float dilation[]) //开运算:先腐蚀再膨胀
    {
        int i,k,t;
        float tmp;
        t=2*N+3;
        float erosion[2*N+3];
        for(k=0;k<t;k++){
            tmp=input[k];
            for(i=k+1;i<k+N;i++){
                if(tmp>input[i])
                    tmp=input[i];
            }
            erosion[k]=tmp;
        }
        t=t-3;
        for(k=0;k<t;k++){
            tmp=erosion[k];
            for(i=k+1;i<k+N;i++){
                if(tmp<erosion[i])
                    tmp=erosion[i];
            }
            dilation[k]=tmp;
        }
    }
    
    float closeoperate(float input[]) //闭运算:先膨胀再腐蚀
    {
        int i,k,t;
        float tmp;
    
        t=N*2-1;
        float dilation[N];
    
        for(k=0;k<N;k++){
            tmp=input[k];
            for(i=k+1;i<k+N;i++){
                if(tmp<input[i])
                    tmp=input[i];
            }
            dilation[k]=tmp;
        }
    
        tmp=dilation[0];
        for(k=1;k<N;k++){
            if(tmp>dilation[k])
                tmp=dilation[k];
        }
        return tmp;
    }
    
    int main()
    {
        clock_t start,end;
        double duration;
        FILE *fd,*m_fd;
        float buffer;
        float filter_data;
        float openresult[2*N-1];
    
        m_fd=fopen("D:/data.txt","r+");
        if(m_fd==NULL){
            perror("open error!");
            return -1;
        }
    
        fd=fopen("D:/data1.txt","w+");  
        if(fd==NULL){
            perror("open error!");
            return -1;
        }
        start=clock();
        while(fscanf(m_fd,"%f",&buffer)!=EOF){
              x[3*N+1]=buffer;
    
              openoperate(x,openresult);
              filter_data=closeoperate(openresult);
              fprintf(fd,"%f ",filter_data);
    
              for(int y=0;y<3*N+1;y++)
                   x[y]=x[y+1];
        }
        end=clock();
        duration=(double)(end-start)/CLOCKS_PER_SEC;
        printf("%f seconds\n",duration);
        fclose(fd);
        fclose(m_fd);
        return 0;
    }
    

    结果如下图所示,对有干扰原始眼电数据进行形态学滤波处理,其中结构元素17个,窗宽5.有图可以看到,形态学对于尖峰的滤波效果特别明显。
    此处输入图片的描述

    图二,将形态学滤波算法加入Qt中,对眼电进行实时滤波处理,效果如图:

    此处输入图片的描述

    【引】这部分内容主要来自参考文献2

    总结

    以前认为形态学滤波只在图像处理中有所应用,现在看了参考文献2,才发觉自己实在有点固步自封,对知识的来龙去脉掌握的不够清楚,一言以蔽之,囫囵吞枣,并不清楚思考方向,而只掌握具体的技巧细节,不注重顶层设计,所以才会有此感慨。

    在进行数据处理中,常常用到的滤波方法有中值滤波,均值滤波,FIR,IIR,卡尔曼滤波,自适应滤波等。而很多知识都是相符相通的,切不可死学死记。

    参考文献:
    1. http://blog.csdn.net/thefutureisour/article/details/7574819
    2. http://m.blog.csdn.net/blog/gylltq/33799347
    3. OpenCV 2 计算机视觉编程手册


    2015-11-28 学习笔记 张朋艺

    展开全文
  • 在噪声基底变化较快时,以往基于形态学滤波的噪声基底估计算法存在基底估计精度和大带宽信号漏检的矛盾。本文提出多尺度的形态学滤波,通过检测不同滤波尺度下噪声基底估值的变化,实现不同频点使用不同尺度的结构...
  • 基于多尺度形态学滤波的CT图像疑似肺结节提取
  • 形态学滤波

    千次阅读 2018-11-30 16:01:30
    createTrackbar("迭代值:", "【形态学梯度】", &g_nGradientNum, g_nMaxIterationNum + 1, on_Gradient); while (1) { int c; on_OpenClose(g_nOpenCloseNum, 0); on_ErodeDilate(g_nErodeDilateNum, 0);...
    // ConsoleApplication36.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //
    
    #include "pch.h"
    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    using namespace std;
    using namespace cv;
    
    //************************************
    //		形态学
    //************************************
    
    Mat g_srcImage, g_dstImage;
    int g_nElementShape = MORPH_RECT;
    
    int g_nMaxIterationNum = 10;
    int g_nOpenCloseNum = 0;
    int g_nErodeDilateNum = 0;
    int g_nTopBlackHatNum = 0;
    int g_nGradientNum = 0;
    static void on_OpenClose(int, void *);
    static void on_ErodeDilate(int, void *);
    static void on_TopBlackHat(int, void *);
    static void on_Gradient(int, void *);
    static void ShowHelpText();
    
    int main()
    {
    	system("color 5E");
    	ShowHelpText();
    	g_srcImage = imread("C:/Users/hasee-pc/Desktop/girl.jpg");
    	if (!g_srcImage.data)
    	{
    		printf("error in srcImage\n");
    		return -1;
    	}
    
    	namedWindow("【原始图】");
    	imshow("【原始图】", g_srcImage);
    
    	namedWindow("【开运算/闭运算】", 1);
    	namedWindow("【腐蚀/膨胀】", 1);
    	namedWindow("【顶帽/黑帽】", 1);
    	namedWindow("【形态学梯度】", 1);
    
    	g_nOpenCloseNum = 9;
    	g_nErodeDilateNum = 9;
    	g_nTopBlackHatNum = 2;
    
    	createTrackbar("迭代值:", "【开运算/闭运算】", &g_nOpenCloseNum, g_nMaxIterationNum * 2 + 1, on_OpenClose);
    	createTrackbar("迭代值:", "【腐蚀/膨胀】", &g_nErodeDilateNum, g_nMaxIterationNum * 2 + 1, on_ErodeDilate);
    	createTrackbar("迭代值:", "【顶帽/黑帽】", &g_nTopBlackHatNum, g_nMaxIterationNum * 2 + 1, on_TopBlackHat);
    	createTrackbar("迭代值:", "【形态学梯度】", &g_nGradientNum, g_nMaxIterationNum + 1, on_Gradient);
    
    	while (1)
    	{
    		int c;
    		on_OpenClose(g_nOpenCloseNum, 0);
    		on_ErodeDilate(g_nErodeDilateNum, 0);
    		on_TopBlackHat(g_nTopBlackHatNum, 0);
    		on_Gradient(g_nGradientNum, 0);
    
    		c = waitKey(0);
    
    		if ((char)c == 'q' || char(c) == 27)
    			break;
    		if ((char)c == 49)//1  椭圆形
    			g_nElementShape = MORPH_ELLIPSE;
    		else if ((char)c == 50)//2 矩形
    			g_nElementShape = MORPH_RECT;
    		else if ((char)c == 51)//3 十字形
    			g_nElementShape = MORPH_CROSS;
    		else if ((char)c == ' ')// 空格 三种情况循环
    			g_nElementShape = (g_nElementShape + 1) % 3;
    	}
    //	while (char(waitKey(1) != 'q')) {}
    	waitKey(0);
    }
    
    static void on_Gradient(int, void *)
    {
    	int Absolute_offset = g_nGradientNum;
    
    	Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
    
    	morphologyEx(g_srcImage, g_dstImage, MORPH_GRADIENT, element);
    
    	imshow("【形态学梯度】", g_dstImage);
    }
    static void on_OpenClose(int, void *)
    {
    	int offset = g_nOpenCloseNum - g_nMaxIterationNum;//偏移量
    	int Absolute_offset = offset > 0 ? offset : -offset;//偏移量绝对值
    
    	Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
    	if (offset < 0)
    	{
    		morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);
    	}
    	else
    	{
    		morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);
    	}
    	imshow("【开运算/闭运算】", g_dstImage);
    }
    static void on_ErodeDilate(int, void *)
    {
    	int offset = g_nErodeDilateNum - g_nMaxIterationNum;
    	int Absolute_offset = offset > 0 ? offset : -offset;
    	
    	Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
    	if (offset < 0)
    		erode(g_srcImage, g_dstImage, element);
    	else
    		dilate(g_srcImage, g_dstImage, element);
    	imshow("【腐蚀/膨胀】", g_dstImage);
    }
    static void on_TopBlackHat(int, void *)
    {
    	int offset = g_nTopBlackHatNum - g_nMaxIterationNum;
    	int Absolute_offset = offset > 0 ? offset : -offset;
    
    	Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1,Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
    
    	if (offset < 0)
    		morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);
    	else
    		morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
    	imshow("【顶帽/黑帽】", g_dstImage);
    }
    static void ShowHelpText()
    {
    	cout << "1  ----> 表示椭圆形\n";
    	cout << "2  ----> 表示矩形\n";
    	cout << "3  ----> 表示十字形\n";
    	cout << "q  ----> 退出\n";
    }
    // 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
    // 调试程序: F5 或调试 >“开始调试”菜单
    
    // 入门提示: 
    //   1. 使用解决方案资源管理器窗口添加/管理文件
    //   2. 使用团队资源管理器窗口连接到源代码管理
    //   3. 使用输出窗口查看生成输出和其他消息
    //   4. 使用错误列表窗口查看错误
    //   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
    //   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
    

     

    展开全文
  • 形态学滤波:腐蚀与膨胀(浅谈)

    千次阅读 2016-10-27 21:03:13
    形态学滤波:腐蚀与膨胀(浅谈) 一 关于二值化、膨胀、腐蚀以及拟合椭圆中心的代码如下** 二 关于腐蚀和膨胀,在此做一些浅显的总结。 三 对于上述代码中所生成的图片,进行一些说明。 四 接下来谈谈自己对腐蚀膨胀...
  • C++实现图像形态学滤波 包括图像的膨胀、腐蚀、开闭、边缘检测
  • 形态学滤波算法

    千次阅读 2014-06-23 22:31:00
    由于系统需要对数据进行实时滤波,所以研究了一下fir,iir和
  • 形态学(morphology)一词通常表示生物学的一个分支,该分支主要研究动植物的形态和结构。而我们图像处理中的形态学,往往指的是数学形态学。下面一起来了解数学形态学的概念。 数学形态学(Mathematical morphology)是...
  • 本文介绍形态学滤波,包括腐蚀与膨胀、开闭运算、形态学梯度和顶帽和黑帽7中操作。其中膨胀与腐蚀是的最基本的形态学操作,其余的都是基于腐蚀和膨胀的。
  • 形态学滤波】——腐蚀和膨胀

    千次阅读 2019-06-12 10:45:50
    图像处理中的形态学往往指的是数学形态学。 2、数学形态学 建立在格论和拓扑学基础之上的图像分析学科,是数字形态学图像图像处理的基本理论。 其基本的运算包括二值化腐蚀和膨胀、二值开闭...
  • FPGA形态学滤波设计

    2019-04-29 10:52:27
    文章目录顶层框架设计子模块设计比较子模块(min_max)设计一维形态学腐蚀/膨胀子模块(morph_1d)设计二维形态学腐蚀/膨胀子模块(morph_2d)设计二维形态学开运算子模块(morph_open_2d)设计二维形态学Tophat变换模块...
  • 若该文为原创文章,未经允许不得转载 原博主博客地址:...本文章博客地址: OpenCV开发笔记(二十二):算法基础之形态学滤波-腐蚀 前言 本篇章开始学习形态学滤波-腐蚀。 ...
  • 形态学滤波 定义:在我们图像处理中的形态学,往往指的时数学形态学——是一门建立在格论和拓扑学基础上的图像分析学科。 形态学基本操作:膨胀、腐蚀 膨胀 dilate 介绍:膨胀就是求局部最大值的操作。从...
  • 一、背景介绍 基于二值图像的滤波算法即形态学滤波,在图像目标采集的预处理中经常被使用到,针对不同的使用场景涉及到腐蚀、膨胀、开闭运算等处理。实际使用中对于不同的分辨率大小以及模板窗...
  • OpenCV4Android开发实录(6):形态学滤波

    千次阅读 2018-06-08 18:04:14
    转载请注明出处: 前言 1. 腐蚀与膨胀 2. 开运算、闭运算、形态学梯度
  • 形态学滤波-角点检测 就是利用形态学处理中的腐蚀和膨胀操作进行的角点检测、边缘检测。 基本步骤 第一步:十字型核--------&gt;【对原图:膨胀操作】 效果:原图在水平和垂直方向会扩展,而45度.135度...
  • 《opencv形态学滤波:腐蚀与膨胀》 开运算:先腐蚀后膨胀的过程 闭运算:先膨胀后腐蚀的过程 形态学梯度:膨胀图与腐蚀图之差 对二值图进行这一操作可以将团块的边缘突出出来,可以用形态学梯度来保留物体边缘轮廓 ...
  • 代码主要介绍形态学滤波的作用,其中基础滤波方式为:腐蚀与膨胀。后续的开运算、闭运算、形态学梯度、顶帽、黑帽都是结合两者的不同使用方式。
  • // TODO: 在此添加控件通知处理程序代码 // TODO: 在此添加控件通知处理程序代码 Mat image = imread("source.jpg", 0); Mat structure_element = getStructuringElement(0, Size(13, 12)); Mat dst_erode, dst...
  • 在点云滤波中,可以基于模型进行平面、球、圆柱等进行分割,现采用渐进式形态学滤波进行地面分割。通过创建pcl::ProgressiveMorphologicalFilter滤波器对象和添加相关参数,如:增加滤波器的窗口大小和高差阈值将...
  • 使用形态学滤波设计对图像的每个元素应用这个结构元素。当结构元素的原点与给定的像素对齐时,它与图像的相交部分定义了一组进行形态学运算的像素。 3. 腐蚀:每个像素与结构相交的集合替换成最小的像

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,487
精华内容 1,394
关键字:

形态学滤波代码