数字图像处理——第九章 形态学图像处理

数字图像处理——第9章 形态学图像处理

1 基础知识

1.1 形态学图像

形态学通常指的是生物学的某个分支,常用来处理动物和植物的形状和结构。现在,我们也将这个词用于图像处理中。形态学图像处理就是使用数学形态学的基本运算,由计算机对图像进行分析,以达到所需结果的一种技术。通俗理解,形态学操作其实就是改变物体的形态

1.2 二值图像

为啥会形态学会提到二值图像,因为形态学操作一般作用于二值图像。所以继续复习下二值图像。二值图像(Binary Image)是指将图像上的每一个像素只有两种可能的取值或灰度等级状态。具体来说,二值图像是指在图像中,灰度等级只有两种,也就是说,图像中的任何像素点的灰度值均为0或者255,分别代表黑色和白色。举个例子,首先我们需要读取一张灰度图,然后将设定一个全1的矩阵,然后设定阈值,即二值化的阈值,例如177,则原图像素值大于177的置为1,小于177则置为0。
在这里插入图片描述

代码如下:

import cv2
import numpy as np 
import matplotlib.pyplot as plt

img = cv2.imread('  ',0)
param = 177
img_2 = np.ones(img.shape[0:2])
img_2[img<177] = 0
plt.figure(dpi = 150)
plt.subplot(121)
plt.title("Gray Scale Image")
plt.imshow(img, cmap = 'gray')
plt.subplot(122)
plt.title("Binary Image")
plt.imshow(img_2, cmap = 'gray')
plt.tight_layout()
plt.show()

2 腐蚀和膨胀

现有一个结构元素的概念

  • 设有两幅图象B,X。若X是被处理的对象,而B是用来处理X的,则称B为结构元素(structure element),又被形象地称做刷子。结构元素通常都是一些比较小的图象。

2.1 腐蚀

把结构元素B平移a后得到Ba,若Ba包含于X,我们记下这个a点,所有满足上述条件的a点组成的集合称做X被B腐蚀(Erosion)的结果。如下图所示:

在这里插入图片描述

其中X是被处理的对象,B是结构元素。对于任意一个在阴影部分的点a,Ba 包含于X,所以X被B腐蚀的结果就是那个阴影部分。阴影部分在X的范围之内,可以看出比之前的X要小了,被撕了一层似的,是将图像中的目标进行细化的操作。opencv中已有现成的腐蚀库供调用,实验效果如下:

在这里插入图片描述

实验分析:腐蚀之后的图像通俗理解会变细,且随着滤波器的大小改变。当滤波器的尺寸越大,则腐蚀效果越强,图像就变得越细;弱滤波器的大小较小,则腐蚀效果较弱。腐蚀将图像中的高亮区域或白色部分进行缩减细化,其运行结果图比原图的高亮区域更小。

代码如下:

import cv2
import numpy as np 
import matplotlib.pyplot as plt

# 将图片转成二值图像
def img2binary_img(img):
    param = 177
    binary_img = np.ones(img.shape[0:2])
    binary_img[img<177] = 0
    return binary_img
# 执行腐蚀操作
def img_erode(binary, kernel_size):
    #可以修改卷积核大小来增加腐蚀效果,越大腐蚀越强
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(kernel_size,kernel_size))
    dst = cv2.erode(binary,kernel)
    return dst
img = cv2.imread('  ',0)
binary_img = img2binary_img(img)
erode_img_5 = img_erode(binary_img, 5)
erode_img_7 = img_erode(binary_img, 7)
erode_img_9 = img_erode(binary_img, 9)

plt.figure(dpi = 120)
plt.subplot(221)
plt.title("Binary Image")
plt.imshow(binary_img, cmap = 'gray')
plt.subplot(222)
plt.title("Erode Image(kernel_size = 5)")
plt.imshow(erode_img_5, cmap = 'gray')
plt.subplot(223)
plt.title("Erode Image(kernel_size = 7)")
plt.imshow(erode_img_7, cmap = 'gray')
plt.subplot(224)
plt.title("Erode Image(kernel_size = 9)")
plt.imshow(erode_img_9, cmap = 'gray')
plt.tight_layout()
plt.show()

2.2 膨胀

膨胀(dilation)可以看做是腐蚀的对偶运算,其定义是:把结构元素B平移a后得到Ba,若Ba击中X,我们记下这个a点。所有满足上述条件的a点组成的集合称做X被B膨胀的结果。如下图所示。

在这里插入图片描述

其中X是被处理的对象,B是结构元素,不难知道,对于任意一个在阴影部分的点a,Ba击中X,所以X被B膨胀的结果就是那个阴影部分。阴影部分包括X的所有范围,就象X膨胀了一圈似的。同样用python-opencv处理。

在这里插入图片描述

代码如下:

import cv2
import numpy as np 
import matplotlib.pyplot as plt

# 将图片转成二值图像
def img2binary_img(img):
    param = 177
    binary_img = np.ones(img.shape[0:2])
    binary_img[img<177] = 0
    return binary_img
# 执行膨胀操作
def img_dilate(binary, kernel_size):
    #可以修改卷积核大小来增加膨胀效果,越大膨胀越强
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(kernel_size,kernel_size))
    dst = cv2.dilate(binary,kernel)
    return dst
img = cv2.imread('  ',0)
binary_img = img2binary_img(img)
erode_img_5 = img_dilate(binary_img, 5)
erode_img_7 = img_dilate(binary_img, 7)
erode_img_9 = img_dilate(binary_img, 9)

plt.figure(dpi = 120)
plt.subplot(221)
plt.title("Binary Image")
plt.imshow(binary_img, cmap = 'gray')
plt.subplot(222)
plt.title("Dilate Image(kernel_size = 5)")
plt.imshow(erode_img_5, cmap = 'gray')
plt.subplot(223)
plt.title("Dilate Image(kernel_size = 7)")
plt.imshow(erode_img_7, cmap = 'gray')
plt.subplot(224)
plt.title("Dilate Image(kernel_size = 9)")
plt.imshow(erode_img_9, cmap = 'gray')
plt.tight_layout()
plt.show()

实验分析:图像膨胀是腐蚀操作的逆操作,类似于“领域扩张”,将图像中的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更大,线条变粗了,主要用于去噪。同时图像被腐蚀后,去除了噪声,但是会压缩图像。且对腐蚀过的图像,进行膨胀处理,可以去除噪声,并且保持原有形状。

3 开操作与闭操作

开操作闭操作简称开闭运算,即开操作=开运算;闭操作=闭运算。说白了就是打腐蚀和膨胀的组合拳。 **为什么有了膨胀、腐蚀还要开运算闭运算呢?**其实开闭运算最重要的一点就是,可以保持物体原有大小。然后一个是消除物体外部噪声(开运算)的另一个是增强物体之间连接点(闭运算)的。

3.1 开操作

开运算 = 先腐蚀运算,再膨胀运算

开运算如下图所示:

在这里插入图片描述

3.2 闭操作

闭运算 = 先膨胀运算,再腐蚀运算

闭运算如下图所示:

在这里插入图片描述

3.3 实验对比

可用opencv中cv2.morphologyEx函数实现开闭运算,cv2.morphologyEx(src, op, kernel) 可进行各类形态学的变化。参数说明:

  • src传入的图片
  • op进行变化的方式
  • kernel表示方框的大小

op = cv2.MORPH_OPEN 进行开运算,指的是先进行腐蚀操作,再进行膨胀操作

op = cv2.MORPH_CLOSE 进行闭运算, 指的是先进行膨胀操作,再进行腐蚀操作

实验效果如下:

在这里插入图片描述

实验总结(开运算):
(1)开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不便。
(2)开运算是一个基于几何运算的滤波器。
(3)结构元素大小的不同将导致滤波效果的不同。
(4)不同的结构元素的选择导致了不同的分割,即提取出不同的特征。

代码如下:

import cv2
import numpy as np 
import matplotlib.pyplot as plt
# 将图片转成二值图像
def img2binary_img(img):
    param = 177
    binary_img = np.ones(img.shape[0:2])
    binary_img[img<177] = 0
    return binary_img
img = cv2.imread('  ',0)
binary_img = img2binary_img(img)
kernel = np.ones((5,5),np.uint8)
open_img = cv2.morphologyEx(binary_img, cv2.MORPH_OPEN, kernel)
close_img = cv2.morphologyEx(binary_img, cv2.MORPH_CLOSE, kernel) 
plt.figure(dpi = 190)
plt.subplot(131)
plt.title("Binary Image")
plt.imshow(binary_img, cmap = 'gray')
plt.subplot(132)
plt.title("Opened Image")
plt.imshow(open_img, cmap = 'gray')
plt.subplot(133)
plt.title("Closed Image")
plt.imshow(close_img, cmap = 'gray')
plt.tight_layout()
plt.show()

在这里插入图片描述

实验总结(闭运算):
(1)闭运算能够填平小湖(即小孔),弥合小裂缝,而总的位置和形状不变。
(2)闭运算是通过填充图像的凹角来滤波图像的。
(3)结构元素大小的不同将导致滤波效果的不同。
(4)不同结构元素的选择导致了不同的分割。

4 一些基本的形态学算法

当处理二值图像时,形态学的主要应用是提取表示和描述形状的有用成分。特别是用形态学方法提取某一区域边界线,连接成分,骨骼,凸壳的算法是十分有效的。此外,区域填充,细化,加粗,裁剪等处理方法也经常与上述算法相结合在预处理和后处理中使用。

4.1 边界提取

这类似于边缘检测,之前学过的Canny边缘检测算法,使用opencv函数cv2.Canny可轻松实现边缘提取:

在这里插入图片描述

代码如下:

import cv2
img = cv2.imread("  ",0)
blurred = cv2.GaussianBlur(img,(11,11),0)
gaussImg = cv2.Canny(blurred, 10, 70)

plt.figure(dpi = 130)
plt.subplot(121)
plt.title("Origin Image")
plt.imshow(img, cmap = 'gray')
plt.subplot(122)
plt.title("Canny Image")
plt.imshow(gaussImg, cmap = 'gray')
plt.tight_layout()
plt.show()

4.2 空洞填充

使用空洞填充,可以对图像进行填充。使用函数为泛洪函数。原型为:cv2.floodFill(img, mask, seed, newvalue(BGR), (loDiff1, loDiff2, loDiff3), (upDiff1, upDiff2, upDiff3), flag)

  • img:为待使用泛洪算法的图像
  • mask:为掩码层,使用掩码可以规定是在哪个区域使用该算法,如果是对于完整图像都要使用,则掩码层大小为原图行数+2,列数+2.是一个二维的0矩阵,边缘一圈会在使用算法是置为1。而只有对于掩码层上对应为0的位置才能泛洪,所以掩码层初始化为0矩阵。【dtype:np.uint8】
  • seed:为泛洪算法的种子点,也是根据该点的像素判断决定和其相近颜色的像素点,是否被泛洪处理。
  • newvalue:是对于泛洪区域新赋的值(B,G,R)
  • (loDiff1,loDiff2,loDiff3):是相对于seed种子点像素可以往下的像素值,即seed(B0,G0,R0),泛洪区域下界为(B0-loDiff1,G0-loDiff2,R0-loDiff3)
  • (upDiff1,upDiff2,upDiff3):是相对于seed种子点像素可以往上的像素值,即seed(B0,G0,R0),泛洪区域上界为(B0+upDiff1,G0+upDiff2,R0+upDiff3)
  • flag:为泛洪算法的处理模式。

如下图所示使用泛洪函数简单对彩色图像进行填充:

在这里插入图片描述

代码如下:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('  ')
im_floodfill = img.copy()
h, w = img.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
cv2.floodFill(im_floodfill, mask, (220, 250), (0, 255, 255), (100, 100, 100), (50, 50 ,50), cv2.FLOODFILL_FIXED_RANGE)
plt.figure(dpi = 190)
plt.subplot(131)
plt.title("Origin Image")
plt.imshow(img)
plt.subplot(132)
plt.title("FillHole Image")
plt.imshow(im_floodfill)
plt.tight_layout()
plt.show()

4.3 凸壳

凸壳在平面中是一种形状,类比三个点的三角形,四个点的常见四边形,橡皮筋的比喻很容易让人认为凸壳是皮筋,实际是皮筋围起来的区域。而且,凸壳通常被称为最小凸多边形(MCP,the minimum convex polygon)。二值图像的凸壳指的是包围输入二值图像白色区域的最小的凸多边形的像素集合。可使用skimage库实现。实现效果如下图所示,有点外接多边形的意思。
在这里插入图片描述

  • 5
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值