前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenCV 滤波与卷积之 —— 形态学操作

OpenCV 滤波与卷积之 —— 形态学操作

作者头像
为为为什么
发布2022-08-09 15:05:15
7280
发布2022-08-09 15:05:15
举报
文章被收录于专栏:又见苍岚

本文摘录OpenCV 中的卷积、滤波相关操作内容,重点介绍 Opencv 中的形态学操作。

形态学操作

OpenCV 还提供了一种高效且易用的图像形态学变换接口。图像形态学有其特定的发展领域,特别是在计算机视觉发展早期,已经发展出了很多的形态学方法。大部分都是为某个特定目的而产生的,其中一些更是沿用了很长一段时间。基本上,所有的形态学操作都基于两种原始操作,接下来的讲述也将以这两点开始,循序渐进发展到更加复杂的操作,每个更加复杂的操作都将通过前面的方法来表示。

膨胀和腐蚀

最基础的形态学变换是膨胀和腐蚀,它们在许多方面得到了应用,比如消除噪声、元素分割和连接等。基于这两种操作,可以实现更复杂的形态学操作,用来定位强度峰值或孔洞、另一种形式的图像梯度等。

膨胀 / cv2.dilate

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

\operatorname{dst}(x, y)=\max _{\left(x^{\prime}, y^{\prime}\right): \operatorname{ement}\left(x^{\prime}, y^{\prime}\right) \neq 0} \operatorname{src}\left(x+x^{\prime}, y+y^{\prime}\right)
  • 函数使用
代码语言:javascript
复制
cv2.dilate(
	src, 					# 源图像
	kernel[, 				# 膨胀核
	dst[, 					# 输出图像
	anchor[, 				# 锚在元素中的位置,默认为 (-1, -1),表示锚点在核中心
	iterations[, 			# 膨胀轮数
	borderType[, 			# 像素外推法
	borderValue]]]]]		# 如果使用常数外推的话需要配置该值
	) → dst

  • 示例代码
代码语言:javascript
复制
img = mt.cv_rgb_imread('img1.jpg', gray=False)
kernal = np.ones([1, 58])
res = cv2.dilate(img, kernal)
PIS(img, res)

腐蚀 / cv2.erode

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

图像的形态学操作通常在阈值化操作后的布尔图像上进行,不过由于膨胀和腐蚀只是最大和最小操作,因此形态学操作也可以在强度图像上进行。

\operatorname{dst}(x, y)=\min _{\left(x^{\prime}, y^{\prime}\right): \operatorname{element}\left(x^{\prime}, y^{\prime}\right) \neq 0} \operatorname{src}\left(x+x^{\prime}, y+y^{\prime}\right)
  • 函数使用
代码语言:javascript
复制
cv2.erode(
	src, 					# 源图像
	kernel[, 				# 腐蚀核
	dst[, 					# 输出图像
	anchor[, 				# 锚在元素中的位置,默认为 (-1, -1),表示锚点在核中心
	iterations[, 			# 腐蚀轮数
	borderType[, 			# 像素外推法
	borderValue]]]]]		# 如果使用常数外推的话需要配置该值
	) → dst

  • 示例代码
代码语言:javascript
复制
img = mt.cv_rgb_imread('img1.jpg', gray=False)
kernal = np.ones([1, 58])
res = cv2.erode(img, kernal)
PIS(img, res)

通用形态学函数

cv2.morphologyEx

包含了若干形态学操作的通用函数 官方文档

  • 函数使用
代码语言:javascript
复制
cv2.morphologyEx(
	src, 				# 源图像
	op, 				# 形态学操作
	kernel[, 			# 核
	dst[, 				# 输出图像
	anchor[, 			# 锚在元素中的位置,默认为 (-1, -1),表示锚点在核中心
	iterations[, 		# 操作轮数
	borderType[, 		# 像素外推法
	borderValue]]]]])	# 如果使用常数外推的话需要配置该值
    → dst

  • op 可选值

操作值

形态学操作

cv2.MORPH_ERODE

腐蚀操作

cv2.MORPH_DILATE

膨胀操作

cv2.MOP_OPEN

开操作

cv2.MOP_CLOSE

闭操作

cv2.MOP_GRADIENT

形态学梯度

cv2.MOP_TOPHAT

顶帽操作

cv2.MOP_BLACKHAT

底帽操作

cv2.MORPH_HITMISS

击中击不中操作

布尔图像上的开操作和闭操作

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

开运算
  • 开操作先将图像腐蚀,然后对腐蚀的结果膨胀。
闭运输
  • 闭操作先将图像进行膨胀,然后对膨胀的结果进行腐蚀
非布尔图像上的开操作和闭操作

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

开运算
闭运算
形态学梯度

接下来要叙述的操作是形态学梯度(Morphological Gradient),可以描述为膨胀与腐蚀的差值,用如下表达式描述:

\operatorname{gradient}(\mathrm{src})=\operatorname{dilate}(\mathrm{src})-\operatorname{erode}(\mathrm{src})

形态学梯度通常用于显示明亮区域的边界,然后便可以将他们看作目标或者目标的部分。用扩张的图像减去了收缩的图像,如此一来就找出了完整的边界。这与计算梯度不同,它不会关注某一个物体的周围。

顶帽和黑帽

最后两种操作是顶帽黑帽。这两种操作分别用于显示与其邻域相比更亮或更暗的部分。当试图根据物体的亮度变化分离依附于物体的某些部分时,就会用到这些方法。在生物体或细胞的显微镜图像上经常会用到这些方法。两种操作都是根据基础操作定义的,如下所示:

顶帽操作
黑帽操作
击中击不中操作

源图像仅支持二值图,会匹配模板,模板中的 1 对应源图的1,模板-1对应源图0,模板0忽略源图像素,按照当前规则匹配源图,匹配成功为1,失败为0,返回结果图

  • 示例代码
代码语言:javascript
复制
binary_array = (np.random.random([20, 20]) > 0.5).astype('uint8')
kernal = np.array([[1, -1, 1], [-1, 1, 1], [1, 1, 0]])
res = cv2.morphologyEx(binary_array, cv2.MORPH_HITMISS, kernal)
PIS(binary_array, res, kernal)

自定义核

OpenCV可以让你创建自己的核。在形态学上,核常常称为“构造元素”。因此供开发者创建自定义形态学核的函数叫cv2.getStructuringElement()

  • 函数使用
代码语言:javascript
复制
cv2.getStructuringElement(
	shape,		# 核形状 
	ksize, 		# 核尺寸
	anchor		# 锚点位置,默认(-1, -1),表示在核中心
	)

  • shape

形状值

元素

描述

cv2.MORPH_RECT

矩形

$\mathrm{E}_{i, j}=1, \forall i, j$

cv2.MORPH_ELLIPSE

椭圆形

以ksize.width和ksize.height为两个半径做椭圆

cv2.MORPH_CROSS

交叉

$\mathrm{E}_{i, j}=1, i=anchor.y \text{ or } j=anchor.x$

  • 示例代码
代码语言:javascript
复制
cross = cv2.getStructuringElement(cv2.MORPH_CROSS, [5,5])
rect = cv2.getStructuringElement(cv2.MORPH_RECT, [5,5])
ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, [5,5])

-->
cross
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)
       
rect
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]], dtype=uint8)
       
ellipse
array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)

汇总示例

  • 示例代码
代码语言:javascript
复制
img = mt.cv_rgb_imread('test.jpg', gray=True)
kernal_1d = cv2.getGaussianKernel(5, 1)
kernal_2d = kernal_1d* kernal_1d.T
erode = cv2.morphologyEx(img, cv2.MORPH_ERODE, kernal_2d)
dilate = cv2.morphologyEx(img, cv2.MORPH_DILATE, kernal_2d)
open = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernal_2d)
close = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernal_2d)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernal_2d)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernal_2d)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernal_2d)
PIS([img, 'origin'], [erode, 'erode'], [dilate, 'dilate'], [open, 'open'], [close, 'close'], [gradient, 'gradient'], [tophat, 'tophat'], [blackhat, 'blackhat'])

示例源码

参考资料

  • 《学习 OpenCV3》 第十章
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年3月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 形态学操作
    • 膨胀和腐蚀
      • 膨胀 / cv2.dilate
      • 腐蚀 / cv2.erode
  • 通用形态学函数
    • cv2.morphologyEx
      • 布尔图像上的开操作和闭操作
        • 开运算
        • 闭运输
      • 非布尔图像上的开操作和闭操作
        • 开运算
        • 闭运算
      • 形态学梯度
        • 顶帽和黑帽
          • 顶帽操作
          • 黑帽操作
        • 击中击不中操作
        • 自定义核
        • 汇总示例
        • 示例源码
        • 参考资料
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档