zoukankan      html  css  js  c++  java
  • 图像的膨胀与腐蚀——OpenCV与C++的具体实现

    1. 膨胀与腐蚀的原理

    膨胀与腐蚀是数学形态学在图像处理中最基础的操作。在笔者之前的文章《图像的卷积(滤波)运算(一)——图像梯度》《图像的卷积(滤波)运算(二)——高斯滤波》具体介绍了图像卷积滤波的具体的概念与操作,图像的膨胀与腐蚀其实也是一种类似的卷积操作。其卷积操作非常简单,对于图像的每个像素,取其一定的邻域,计算最大值/最小值作为新图像对应像素位置的像素值。其中,取最大值就是膨胀,取最小值就是腐蚀。

    2. 膨胀的具体实现

    1) OpenCV实现

    在OpenCV中实现了图像膨胀的函数dilate(),可以直接调用:

    Mat img = imread(imagename, IMREAD_GRAYSCALE);
    if (img.empty())
    {
    	fprintf(stderr, "Can not load image %s
    ", imagename);
    	return -1;
    }
    
    //OpenCV方法
    Mat dilated_cv;
    dilate(img, dilated_cv, Mat());
    

    dilate()函数第一个参数表示输入影像,第二个参数表示输出影像,第三个表示一个默认的核,在3X3的范围内寻找最大值。

    2) C/C++实现

    在一般的图像处理时,图像读写是由专门的组件进行读取的。这这里仍然使用OpenCV进行读取,以免增加复杂性。而在CV::Mat类中,提供了at()函数访问某一行某一列的像素值,可以通过at()函数去访问每一个像素的领域。

    与之前OpenCV实现的一样,对于每一个像素,遍历以其像素位置为中心的3X3邻域,取最大值作为新图像对应位置的像素值。
    其具体实现如下:

    //从文件中读取成灰度图像
    const char* imagename = "D:\Data\imgDemo\lena.jpg";
    Mat img = imread(imagename, IMREAD_GRAYSCALE);
    if (img.empty())
    {
    	fprintf(stderr, "Can not load image %s
    ", imagename);
    	return -1;
    }
    
    //自定义方法
    Mat dilated_my;
    dilated_my.create(img.rows, img.cols, CV_8UC1);
    for (int i = 0; i < img.rows; ++i)
    {
    	for (int j = 0; j < img.cols; ++j)
    	{	
    		//uchar minV = 255;
    		uchar maxV = 0;
    	
    		//遍历周围最大像素值
    		for (int yi = i-1; yi <= i+1; yi++)
    		{
    			for (int xi = j-1; xi <= j+1; xi++)
    			{					
    				if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
    				{
    					continue;
    				}					
    				//minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
    				maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));			
    			}
    		}
    		dilated_my.at<uchar>(i, j) = maxV;
    	}
    }	
    

    3) 验证与结果

    为了验证自己的算法是否正确,可以通过把两者膨胀的结果通过compare()函数进行比较。compare()函数会逐个比较两者的像素值,如果相同就会返回255(白色),如果不相同就会返回0(黑色)。整个过程的具体实现如下:

    #include <iostream>
    #include <algorithm>
    #include <opencv2opencv.hpp>
    
    using namespace cv;
    using namespace std;
    
    int main()
    {
    	//从文件中读取成灰度图像
    	const char* imagename = "D:\Data\imgDemo\lena.jpg";
    	Mat img = imread(imagename, IMREAD_GRAYSCALE);
    	if (img.empty())
    	{
    		fprintf(stderr, "Can not load image %s
    ", imagename);
    		return -1;
    	}
    	
    	//OpenCV方法
    	Mat dilated_cv;
    	dilate(img, dilated_cv, Mat());
    
    	//自定义方法
    	Mat dilated_my;
    	dilated_my.create(img.rows, img.cols, CV_8UC1);
    	for (int i = 0; i < img.rows; ++i)
    	{
    		for (int j = 0; j < img.cols; ++j)
    		{	
    			//uchar minV = 255;
    			uchar maxV = 0;
    		
    			//遍历周围最大像素值
    			for (int yi = i-1; yi <= i+1; yi++)
    			{
    				for (int xi = j-1; xi <= j+1; xi++)
    				{					
    					if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
    					{
    						continue;
    					}					
    					//minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
    					maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));			
    				}
    			}
    			dilated_my.at<uchar>(i, j) = maxV;
    		}
    	}	
    
    	//比较两者的结果
    	Mat c;
    	compare(dilated_cv, dilated_my, c, CMP_EQ);
    
    	//显示
    	imshow("原始", img);
    	imshow("膨胀_cv", dilated_cv);
    	imshow("膨胀_my", dilated_my);
    	imshow("比较结果", c);
    		
    	waitKey();
    	
    	return 0;
    }
    

    其运行结果如下所示。可以发现最后的比较结果是一张白色的图像,说明自己实现的算法是正确的。

    3. 腐蚀的具体实现

    同样的办法可以实现图像腐蚀的过程,只要将求局部最大值改成局部最小值就可以了。具体实现过程如下:

    #include <iostream>
    #include <algorithm>
    #include <opencv2opencv.hpp>
    
    using namespace cv;
    using namespace std;
    
    int main()
    {
    	//从文件中读取成灰度图像
    	const char* imagename = "D:\Data\imgDemo\lena.jpg";
    	Mat img = imread(imagename, IMREAD_GRAYSCALE);
    	if (img.empty())
    	{
    		fprintf(stderr, "Can not load image %s
    ", imagename);
    		return -1;
    	}
    	
    	//OpenCV方法
    	Mat eroded_cv;
    	erode(img, eroded_cv, Mat());
    
    	//自定义方法
    	Mat eroded_my;
    	eroded_my.create(img.cols, img.rows, CV_8UC1);
    	for (int i = 0; i < img.rows; ++i)
    	{
    		for (int j = 0; j < img.cols; ++j)
    		{	
    			uchar minV = 255;
    			//uchar maxV = 0;
    		
    			//遍历周围最大像素值
    			for (int yi = i-1; yi <= i+1; yi++)
    			{
    				for (int xi = j-1; xi <= j+1; xi++)
    				{					
    					if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
    					{
    						continue;
    					}					
    					minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
    					//maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));			
    				}
    			}
    			eroded_my.at<uchar>(i, j) = minV;
    		}
    	}	
    
    	//比较两者的结果
    	Mat c;
    	compare(eroded_cv, eroded_my, c, CMP_EQ);
    
    	//显示
    	imshow("原始", img);
    	imshow("膨胀_cv", eroded_cv);
    	imshow("膨胀_my", eroded_my);
    	imshow("比较结果", c);
    		
    	waitKey();
    	
    	return 0;
    }
    

    其运行结果如下:

  • 相关阅读:
    关于浮动清除的一些小感悟,4种方法清除浮动
    6号css学习小记
    pexpect-pxssh-登陆Linux-执行命令
    chroot命令
    Loadrunner11点击录制脚本无响应,IE页面弹不出——解决方案汇总
    JAVA实验五(网络编程)
    Java实验三
    JAVA实验二(面向对象)
    JAVA实验一
    Tfs链接错误解决方案
  • 原文地址:https://www.cnblogs.com/charlee44/p/10633890.html
Copyright © 2011-2022 走看看