腐蚀与膨胀
数学形态学运算包括两种算子:腐蚀(erosion)算子和膨胀算子(dilation)。
- 腐蚀运算的原理是对数据集中的每个元素在自定义的结构元素(窗口)内寻求最小值来替代中心元素的值。腐蚀运算的物理意义是具有腐蚀数据集合边缘的功能并迫使集合向内收缩,如果窗口足够的大,就能移除那些面积较小、作用不大的物体。
- 膨胀运算与腐蚀运算的原理相反,它是对数据集合中的每个元素在自定义的结构元素内寻找最大值来代替中心元素的值。膨胀运算的物理意义为扩展数据集合的大小并使其向集合外膨胀,适宜的窗口大小可以填充集合内部的孔洞,使集合更加完整。
通过以上的定义与物理意义我们可以看出来,数学形态学在数字图像滤波上有重要作用,通俗的讲,腐蚀的作用说白了就是让暗的区域变大,而膨胀的作用就是让亮的区域变大。
1.数学定义
腐蚀算子的定义公式如下:
式中,[ εB(X) ] (x)代表结构元素 B 腐蚀来自于集合 X 的子元素 x 的方法,min 代表取最小值,XB代表结构元素 B 内的 x 值。同理,结构元素 B 也在集合 X 内的膨胀算子可表示为:
式中,[δB(X)] (x)代表结构元素B对集合X内的子元素x的膨胀运算的过程,max代表取最大值。
一般而言,结构元素就是我们理解的窗口模板/核/滤波算子,通过选择合适的窗口模板可以实现对图像X的滤波操作
2. 代码
- 腐蚀代码
//使用 3*3窗口进行滤波
//这里使用了Eigen的矩阵元素定义了结构lgrid
void basicfuc::erosion(lgrid &src, lgrid &dst)
{
int x = src.getX();
int y = src.getY();
for (size_t i = 1; i < x - 1; i++)
{
for (size_t j = 1; j < y - 1; j++)
{
float a[9];
//top
a[0] = src.getGrid(i - 1, j - 1);
a[1] = src.getGrid(i - 1, j);
a[2] = src.getGrid(i - 1, j + 1);
//middle
a[3] = src.getGrid(i, j - 1);
a[4] = src.getGrid(i, j);
a[5] = src.getGrid(i, j + 1);
//bottom
a[6] = src.getGrid(i + 1, j - 1);
a[7] = src.getGrid(i + 1, j);
a[8] = src.getGrid(i + 1, j + 1);
float minValue = *std::min_element(a, a + 9);
dst.setGrid(i, j, minValue);
}
}
}
- 膨胀代码
//同样采用3*3算子
void basicfuc::dilation(lgrid &src, lgrid &dst )
{
int x = src.getX();
int y = src.getY();
for (size_t i = 1; i < x - 1; i++)
{
for (size_t j = 1; j < y - 1; j++)
{
float a[9];
//top
a[0] = src.getGrid(i - 1, j - 1);
a[1] = src.getGrid(i - 1, j);
a[2] = src.getGrid(i - 1, j + 1);
//middle
a[3] = src.getGrid(i, j - 1);
a[4] = src.getGrid(i, j);
a[5] = src.getGrid(i, j + 1);
//bottom
a[6] = src.getGrid(i + 1, j - 1);
a[7] = src.getGrid(i + 1, j);
a[8] = src.getGrid(i + 1, j + 1);
float maxValue = *std::max_element(a, a + 9);
dst.setGrid(i, j, maxValue);
}
}
}
3.效果
使用opencv对图像进行显示。
- 原始图像
- 腐蚀图像
- 膨胀图像
4.总结
- 可以看出,腐蚀确实让暗像元区域变大;膨胀则让亮像元区域变大
- 还可以结合本人自己的研究方向进行下一步渐进形态学地面滤波
- 考虑腐蚀结合膨胀,进行开闭操作