码迷,mamicode.com
首页 > 其他好文 > 详细

图像腐蚀、膨胀、基本原理和程序实现

时间:2016-07-19 11:12:14      阅读:392      评论:0      收藏:0      [点我收藏+]

标签:

图像的腐蚀与膨胀

一、原理:

⑴ 图像形态学处理的概念
        数字图像处理中的形态学处理是指将数字形态学作为工具从图像中提取对于表达和描绘区域形状有用处的图像分量,比如边界、骨架以及凸壳,还包括用于预处理或后处理的形态学过滤、细化和修剪等。图像形态学处理中我们感兴趣的主要是二值图像。

⑵ 二值图像的逻辑运算
        逻辑运算尽管本质上很简单,但对于实现以形态学为基础额图像处理算法是一种有力的补充手段。在图像处理中用到的主要逻辑运算是:与、或和非(求补),它们可以互相组合形成其他逻辑运算。

⑶ 膨胀和腐蚀

        膨胀和腐蚀这两种操作是形态学处理的基础,许多形态学算法都是以这两种运算为基础的。

定义结构元素B为:

1 1
1 0
图像元素与结构元素相乘,从而求得右下角元素值
(i-1,j+1) (i,j+1)
(i-1,j) 所求此点(i,j)

① 膨胀
⑴ 用结构元素B,扫描图像A的每一个像素
⑵ 用结构元素与其覆盖的二值图像做“或”操作
⑶ 如果有一个元素为0,结果图像的该像素为0。否则为255

② 腐蚀
         对Z中的集合A和B,B对A进行腐蚀的整个过程如下: 
⑴ 用结构元素B,扫描图像A的每一个像素
⑵ 用结构元素与其覆盖的二值图像做“与”操作
⑶ 如果都为0,结果图像的该像素为0。否则为255

腐蚀处理的结果是使原来的二值图像减小一圈。

二、我再加一个轮廓提取,非常简单的方法:用的是9X9的模板;

(i-1,j+1) (i,j+1) (i+1,j+1)
(i-1,j) 所求此点(i,j) (i+1,j)
(i-1,j-1) (i,j-1) (i+1,j_1)
三、代码

#include<opencv2/opencv.hpp>
#include<iostream>
using  namespace cv;
using namespace std;

Mat srcImage, grayImage, binarygray, erosion, dilation, outline;


static void g_erosion(int, void*);
static void g_dilation(int, void*);
static void g_outline(int, void*);
static void ShowHelpText();

int main()
{
	system("color 3f");
	ShowHelpText();

	srcImage = imread("D://vvoo//cell.jpg");
	cvtColor(srcImage, grayImage, CV_RGB2GRAY);

	int threshold;
	cout << "input threshold: " << endl;
	cin >> threshold;

	//二值化
	binarygray = Mat::zeros(grayImage.rows, grayImage.cols, grayImage.type());
	{
		for (int i = 0; i <grayImage.rows; i++)
		{
			for (int j = 0; j < grayImage.cols; j++)
			{
				if (grayImage.data[i*grayImage.step + j] > threshold)
				{
					binarygray.data[i*binarygray.step + j] = 255;
				}
				else
				{
					binarygray.data[i*binarygray.step + j] = 0;
				}
			}
		}
	}
	//腐蚀
	g_erosion(0, 0);
	//膨胀
	g_dilation(0, 0);
	//轮廓提取
	g_outline(0, 0);

	imshow("原图", srcImage);
	imshow("binarygray", binarygray);

	waitKey(0);
	return 0;
}
static void g_erosion(int, void*)
{
	erosion = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type());
	{
		for (int i = 1; i < binarygray.rows; i++)
		{
			for (int j = 1; j < binarygray.cols; j++)
			{
				if (binarygray.data[(i - 1)*binarygray.step + j] + binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[i*binarygray.step + j + 1] == 0)
				{
					erosion.data[i*erosion.step + j] = 0;
				}
				else
				{
					erosion.data[i*erosion.step + j] = 255;
				}
			}

		}

	}
	imshow("erosion_1", erosion);
}
static void g_dilation(int, void*)
{
	dilation = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type());

	for (int i = 1; i < binarygray.rows; i++)
	{
		for (int j = 1; j < binarygray.cols; j++)
		{
			if (binarygray.data[(i - 1)*binarygray.step + j] == 0 || binarygray.data[(i - 1)*binarygray.step + j - 1] == 0 || binarygray.data[i*binarygray.step + j + 1] == 0)
			{
				dilation.data[i*dilation.step + j] = 0;
			}
			else
			{
				dilation.data[i*dilation.step + j] = 255;
			}
		}

	}

	imshow("dilation_1", dilation);
}
static void g_outline(int, void*)
{
	outline = Mat::zeros(binarygray.rows, binarygray.cols, binarygray.type());

	for (int i = 1; i < binarygray.rows; i++)
	{
		for (int j = 1; j < binarygray.cols; j++)
		{
			if (binarygray.data[i*binarygray.step + j + 1] + binarygray.data[(i - 1)*binarygray.step + j]
				+ binarygray.data[i*binarygray.step + j - 1] + binarygray.data[(i - 1)*binarygray.step + j - 1]
				+ binarygray.data[(i + 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j]
				+ binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[(i + 1)*binarygray.step + j + 1] == 2040)
			{
				outline.data[i*erosion.step + j] = 255;
			}
			if (binarygray.data[i*binarygray.step + j + 1] + binarygray.data[(i - 1)*binarygray.step + j]
				+ binarygray.data[i*binarygray.step + j - 1] + binarygray.data[(i - 1)*binarygray.step + j - 1]
				+ binarygray.data[(i + 1)*binarygray.step + j - 1] + binarygray.data[(i + 1)*binarygray.step + j]
				+ binarygray.data[(i - 1)*binarygray.step + j + 1] + binarygray.data[(i + 1)*binarygray.step + j + 1] == 0)
			{
				outline.data[i*erosion.step + j] = 255;
			}
		}


	}
	imshow("outline", outline);
}
static void ShowHelpText()
{
	cout << "\n\n本程序涉及到:"<<"腐蚀(erosion)、膨胀(dilation)、轮廓提取(outline)。\n\n" << endl;
}
四、运行结果

技术分享

技术分享

五、调用Opencv的erode()函数和dilate()函数实现腐蚀和膨胀功能

1)erode函数,使用像素邻域内的局部极小运算符来腐蚀一张图片,从src输入,由dst输出。支持就地(in-place)操作。

看一下函数原型:

 void erode(
  InputArray src,
  OutputArray dst,
  InputArray kernel,
  Point anchor=Point(-1,-1),
  int iterations=1,
  int borderType=BORDER_CONSTANT,
  const Scalar& borderValue=morphologyDefaultBorderValue()
 );

参数原型

  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
  • 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的kernel,腐蚀操作的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。(具体看上文中浅出部分dilate函数的第三个参数讲解部分)
  • 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于单位(element)的中心,我们一般不用管它。
  • 第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1。
  • 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
  • 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。

同样的,使用erode函数,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。

2)dilate函数原型

函数原型:

C++: void dilate(
  InputArray src,
  OutputArray dst,
  InputArray kernel,
  Point anchor=Point(-1,-1),
  int iterations=1,
  int borderType=BORDER_CONSTANT,
  const Scalar& borderValue=morphologyDefaultBorderValue() 
);

参数详解:

  • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
  • 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
  • 第三个参数,InputArray类型的kernel,膨胀操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核。

我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵。其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:

矩形: MORPH_RECT

    • 交叉形: MORPH_CROSS
    • 椭圆形: MORPH_ELLIPSE

而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。

3)代码实现

#include<opencv2/opencv.hpp>
#include<iostream>
using  namespace cv;
using namespace std;

#define WINDOWN_NAME_1 "原图"
#define WINDOWN_NAME_2 "腐蚀图"
#define WINDOWN_NAME_3 "膨胀图"

int main()
{
	Mat srcImage = imread("D://vvoo//cell.jpg");

	//获取自定义核
	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
	Mat out_erosion, out_dilate;

	//进行膨胀操作
	erode(srcImage, out_erosion, element);
	dilate(srcImage, out_dilate, element);

	imshow(WINDOWN_NAME_1, srcImage);
	imshow(WINDOWN_NAME_2, out_erosion);
	imshow(WINDOWN_NAME_3, out_dilate);

	waitKey(0);
	return 0;

}

4)运行结果

技术分享


和自己写的比较下比较一下,差别比较大,主要是因为结构元素大小的关系,我的是2*2,Opencv是15*15的。

我也是初学者,欢迎纠正!



六、参考资料

1.system("color 3f");//输出窗口和字体颜色可变化,3代表窗口颜色(绿色),f代表窗口里字体颜色(白色)

全部颜色为:

技术分享

2.图像腐蚀、膨胀、细化基本原理

3. 形态学图像处理(一): 膨胀与腐蚀

图像腐蚀、膨胀、基本原理和程序实现

标签:

原文地址:http://blog.csdn.net/qq_29540745/article/details/51931770

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!