38_OpenCV关于图像形态学:腐蚀、膨胀、开闭运算、形态学梯度、顶帽和黑帽及自定义核

OpenCV提供了一种高效且易用的图像形态学变换接口。基本上,所有的形态学操作都基于两种原始操作,接下来的讲述也将以这两点开始、循序渐进发展到更加复杂的操作,每个更加复杂的操作都将通过前面的方法来表示。

1. 膨胀和腐蚀

膨胀和腐蚀是最基础的形态学变换,可以应用到许多方面,比如消除噪声、元素分割和连接等。

膨胀是一种卷积操作,将目标像素的值替换为卷积核覆盖区域的局部最大值。这是一个非线性核的例子。通常膨胀采用的核是一个四边形或圆形的实心核,其锚点在中心。膨胀的作用是使图中填充区域。

与膨胀对应的,腐蚀是与之相反的操作,腐蚀操作计算的是核覆盖范围内的局部最小值。

膨胀和腐蚀的效果可以参考如下:

总的来说,膨胀扩张了明亮区域,腐蚀缩减了明亮区域。
膨胀填充凹面,腐蚀消除突起。

OpenCV提供函数cv::erode()实现腐蚀,提供函数cv::dilate()实现膨胀。

函数原型:

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

cv::erode()和cv::dilate()都需要传入源图像和目标图像,并且都支持就地调用(即源图像和目标图像是同一幅图像)。
参数element是核,可以向它传递一个未被初始化的cv::Mat(),但会导致函数使用默认的锚点在中心的3 x 3核。
参数iterations是迭代次数,如果不为1,会自动重复多次调用这个函数。
参数borderType是边框类型,borderType = cv::BORDER_CONST时,边缘像素会填入borderValue。

腐蚀操作通常用于消除图中斑点一样的噪声,原理是斑点经过腐蚀后会消失,而大的可见区域不会收到影响。
膨胀操作通常用于发现连通分支(大的颜色或强度相似像素的离散区域)。膨胀出现的原因,在许多情况下,由于噪声或者阴影等因素,大的区域可能被分解成多个分支,一些细微的膨胀会导致这些分支相遇并组合成一个整体。

cv::erode()函数运行时,函数内部发生的是将点p处的值设置成核与点p对齐后覆盖区域的最小值,而cv::dilate()是将最小值替换成最大值。

如下是腐蚀和膨胀的示例:

2. 通用形态学函数

当处理的对象是二值图像和像素只可能是开(>0)或关(=0)的图像掩膜时,基本的腐蚀和膨胀操作就够用了,需要对灰度图或彩色图进行处理时,一些其它的操作就非常有用,这些操作可以通过函数cv::morphologyEx()实现,函数原型:

void cv::morphologyEx(
	cv::InputArray src,  // input image
	cv::OutputArray dst,  // result image
	int op,  // operator(eg. cv::MOP_OPEN)
	cv::InputArray element,  // structing element,cv::Mat()
	cv::Point anchor = cv::Point(-1,-1),  // location of anchor point
	int iterations = 1,  // number of times to apply
	int borderType = cv::BORDER_DEFAULT,  // border extrapolation
	const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue()  // 
);

参数op用于指定函数将进行的操作,可选的值如下:

操作值形态学操作是否需要临时图像
cv::MOP_OPEN开操作
cv::MOP_CLOSE闭操作
cv::MOP_GRADIENT形态学梯度总是需要
cv::MOP_TOPHAT顶帽操作就地调用需要(src=dst)
cv::MOP_BLACKHAT黑帽操作就地调用需要(src=dst)

2.1 开操作和闭操作

开操作和闭操作实际上是腐蚀和膨胀操作的组合。

  • 开操作先将图像腐蚀,然后对腐蚀结果膨胀。常用于对二值图像中的区域进行计数。例如,对显微镜载玻片上的细胞的图像做了阈值化处理,在对区域进行计数之前,需要用开操作来将相互靠的很近的细胞分开。
  • 闭操作先将图像进行膨胀,然后对膨胀的结果进行腐蚀。闭操作用于复杂连通分支算法中减少无用或噪声驱动的片段。对于连通分支,通常先进性腐蚀或闭操作消除噪声,然后通过开操作连接相互靠近的大型区域。

对一幅非布尔类型的图像进行形态学操作时,闭操作最明显的效果是消除值小于邻域内的点的孤立异常值,开操作是消除大于邻域内的孤立异常值。

开操作和闭操作的iterations参数,两次的闭操作的迭代不是膨胀-腐蚀-膨胀-腐蚀,而是膨胀-膨胀-腐蚀-腐蚀,这样做不但可以消除孤立的异常值,也能消除邻域内的异常值。

开操作和闭操作对图像的结果如下:

2.2 形态学梯度

形态学梯度可以用如下表达式描述:

gradient(src) = dilate(src) – erode(src)

对于灰度图像,其结果就是计算明暗变换的趋势。形态学梯度通常用于显示明亮区域的边界,然后可以将它们看作目标或者目标的部分。用扩张的图像减去收缩的图像,这样就找出了完整的边界。

形态学梯度操作后的效果如下:

 操作后的效果类似边缘检测???

2.3 顶帽和黑帽

顶帽和黑帽操作分别用于显示与其邻域相比更亮或更暗的部分。

当试图根据物体的亮度变化分离依附于物体的某些部分时,就会用到这些方法,在生物体或细胞的显微镜图像上经常会用到这些方法。这两种操作都是根据如下基础操作定义的:

TopHat(src) = src – open(src)  // Isolate brighter
BlackHat(src) = close(src) – src  // Isolate dimmer

顶帽操作用源图像减去对其开操作后的图像,开操作的效果是放大裂缝和局部小洞,用源图像减去对其开操作后的图像得到了比源图像更亮的环绕部分。

顶帽操作显示的是比源图像更亮的环绕部分。
黑帽操作显示的是比源图像更暗的环绕部分。

如下分别是顶帽操作和黑帽操作后的结果:

 

3. 自定义核

OpenCv可以创建自己的核,在形态学上,核常称为构造元素。供开发者创建自定义形态学核的函数叫cv::getStructuringElement()。

一般常用的是非矩形核,是一种非常规形状,函数cv::getStructuringElement()原型如下:

cv::Mat cv::getStructuringElement(
	int shape,  // element shape,eg,cv::MORPH_RECT
	cv::Size ksize,  // sizeof structuring element (odd num!)
	cv::Point anchor = cv::Point(-1,-1)  // location of anchor point
);

参数shape控制构造元素的基本形状;
参数ksize和anchor确定元素的大小和锚点位置。通常,anchor默认位cv::Point(-1,-1),,表示cv::getStructuringElement()默认锚点在元素中心。

参数shape的形状如下:

形状值元素描述
cv::MORPH_RECT矩形E[i][j] = 1
cv::MORPH_ELLIPSE椭圆形以ksize.width和ksize.height为两个半径做椭圆
cv::MORPH_CROSS交叉E[i][j]  =1, 当i= anchor.y 或 j = anchor.x

 cv::MORPH_CROSS是为旧版接口留下的。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2022年5月11日
下一篇 2022年5月11日

相关推荐