Advertisement

形态学图像处理(Morphological Image Processing)

阅读量:

形态学图像处理(Morphological Image Processing)

前言

个人博客专门用于记录数字图像处理课程的学习内容,并提供进一步的知识拓展以及相关的演示代码。

写博客类似做 checkpoint ,毕竟个人还无法做到游刃有余的水平,在遗忘的时候就必须重新从零开始训练,这让作者感到有些棘手。

题外话说完,开始吧。

Note:

  • 笔者使用的是 Ubuntu 24.04 LTS
  • 沿续以往的写作风格,在这里我会以自己的话来进行理解而不是简单直接地贴上原本的概念。(目的不是撰写学术论文),因此尽量选择通俗易懂的语言。(除非我是语言贫乏的人已经没有更多的表达方式)
  • 令人感到惋惜的是,在学习数字图像处理课程时(教材中)缺乏这类相关内容(实际上我也很少运用相关知识),因此不得不参考一些参考资料(尤其是英文版资料)。


目录

文章目录

  • 形态学图像处理(Morphological Image Processing)

  • 前言

  • 目录

  • 什么是形态学图像处理(Morphological Image Processing)

  • 需了解的基础集合论公式

  • 结构元素(structuring element)

    • 简要介绍
    • 邻域窗口运算符(Neighborhood window operator)及其与结构元素的关系
    • 结构元素的三大基本属性及其影响
  • 算子是如何定义的

  • 二值形态学的主要操作有哪些

    • 腐蚀(Erosion)及其作用原理
    • 数学公式B
    • 腐蚀的基本概念
    • 腐蚀的操作步骤
  • 腐蚀在实际中的应用领域有哪些

    • 常见的应用场景举例
  • 如何通过实例演示腐蝕操作的具体流程

    复制代码
    * 膨胀(Dilation)
    * * 膨胀的解释与公式
    • 膨胀的应用

    • 膨胀操作的demo实现

      • 膨胀与腐蚀的关系
      • 开运算(Opening)
        • 开运算的简介
    • 开运算的demo实现

      • 闭运算(Closing)
        • 闭运算的简介
    • 闭运算的demo实现

      • 开闭运算的侧重
      • 顶帽运算(Top Hat)
        • 顶帽运算的简介
    • 顶帽运算的demo实现

      • 黑帽运算(Black Hat)
        • 黑帽运算的简介
    • 黑帽运算的demo实现

      • 梯度运算(Gradient)
        • 梯度运算的简介
    • 梯度运算的demo实现

  • 击中-未击中的滤波器(Hit-Miss Filter)

    • 对该方法进行详细阐述及其相关的数学表达式
  • 该方法在实际中的应用

  • 灰度形态学的核心操作

    • 灰度图像
    • 常规的腐蚀运算符(Flat erosion operator)
    • 常规的膨胀运算符(Flat dilation operator)
    • Flat腐蚀与传统的腐蚀对比分析(Flat erosion vs. traditional erosion)
  • 形态学边界探测(Morphological boundary detectors)

    • 概述性介绍

    • 针对二进制图像

    • 针对灰度级图像

      • 参考资料
        • data
        • blog and related sources


什么叫形态学图像处理(Morphological Image Processing)

什么是形态学图像处理呢?

为了便于理解起见,在讲解这一概念时我们可以将其形象地比喻为表层结构(即图像的形态),而支撑起这一表层结构的核心则是骨骼系统(即所谓的骨)。具体来说,在形态学处理中我们指的是对其中的骨骼进行调整以期达到预期效果。

如何更换骨骼?采用预先定制的骨骼组件,并根据预先设定的标准进行替换。

简而言之,就是侧重于图像”皮肉“下的”骨头“的处理。

下面是正式一点的介绍:

形态学图像处理对于图像分析而言具有核心地位,在这一过程中其中主要涉及计算机视觉、图像分割以及特征提取等技术分支。

其主要操作涉及扩张、侵蚀、开闭处理以及边缘识别等;这些操作均基于集合论原理,并通过设定结构元素对图像进行处理;从而能有效地提取出图像的形状特征及其结构信息;为其后续分析与理解提供可靠依据。


集合论须知的公式

概念,如无必要,就直接上公式

  1. 集合的并(Union):

A \cup B = \{x \mid x \in A \text{ or } x \in B\}

  1. 集合的交(Intersection):

A \cap B = \{x \mid x \in A \text{ and } x \in B\}

  1. 集合的补(Complement):

\overline{A} = \{x \mid x \notin A\}

  1. 集合的差(Difference):

A - B = \{x \mid x \in A \text{ and } x \notin B\}

  1. 集合的反射(Reflection):

A^{'} = \{(-x, -y) \mid (x, y) \in A \}

  1. 集合的平移(Translation):

A + \mathbf{y} = \{ (x + y_1, y + y_2) \mid (x, y) \in A \}


结构元素(structuring element)

简要介绍

在进行图像形态学处理时,我们需要掌握的核心概念是结构元素 。其中被称为'核'或'模板'的结构元素是一种小尺寸的二值(binary)图形单位,在形态学中被用来作为工具对输入图象执行数学运算,在这一过程中我们关注的是通过对这些运算的操作来解析出图象所具有的特定形状特性。

什么是二值图像?它是一种大小较小(如3 \times 35 \times 5等)的二维数组(称为矩阵),仅由0(背景、黑色)和1(前景、白色)两种像素值组成。在灰度或彩色图像分析系统中作为中间层次的抽象结构,在进行阈值分割或其他图像属性判断时具有重要作用。例如,在文本识别、线条图形处理以及文档影像处理等方面都能见到它的身影。

结构元素有多种形状 ,常见的为 方形圆形十字形线形 等等。

在确定完结构元素的尺寸与形态之后

综上,结构元素有三大属性,大小形状原点


邻域“窗口”算子(Neighborhood “window” operator)与结构元素

邻域“窗口”算子,同结构元素密切相关,其公式表示为:

W\{f[x, y]\}=\left\{f\left[x-x', y-y'\right]:\left[x', y'\right] \in \prod_{x y}\right\}

在这里面(This is within),变量f[x,y]代表了图像中位于坐标(x,y)处的具体像素数值(specific pixel value)。符号\Pi_{xy}被定义为一个特定区域(set of specific regions)或位置(positions)的概念)。该区域(concept)或位置(positions)被用来决定,在对变量f[x,y]进行处理时所涉及的一组周边像素的位置与数量(number and positions of adjacent pixels involved in the processing operation)。

其区别在于它通过选择图像中的像素集合来进行运算,并不仅会基于不同的形态学操作对这些像素值进行运算组合。

简单来说, 比如使用印章。其实就是这个印章上的**图案**. 其操作步骤类似于在上面滴加一层印油。

该公式也包含两个变体;这两个变体将在后续的二值形态学的基本运算中被使用。

W^{-}(f(x, y)) 被定义为所有形如 f(x - x', y - y') 的值集合,并且其中 (x', y') 属于 x \times y

  1. 基于结构元素 \Pi_{xy} 的形态与尺寸定位图像 f 中心在坐标 (x, y) 的邻域区域。
  2. 遍历结构元素 \Pi_{xy} 上的所有坐标点 (x', y') ,计算对应位置的图像 f 像素坐标 (x - x', y - y')
  3. 提取对应位置处的像素强度值为 f[x - x',\,y'−y]
  4. 将所有提取到的像素强度值整合成一个数据集合 W^{(-)}\{f[x,\,y]\}

W^{+}\{f[x,y]\} = \text{{the set of all }} f[x + x', y + y'] \text{{ where }} [x', y'] \text{{ belongs to }} \prod_{xy}}

同理。


结构元素的三大属性的影响

在上文中提到

图像尺寸的变化程度越大,则会对图像产生越显著的影响;这种变化幅度大的情况下会影响范围也会相应增大;在形态学操作中这一效果会更加明显;同时会对图像原有的关键结构或轮廓产生更大的作用范围;而当尺寸相对较小的情况下则会减弱这种影响。

图像的不同形态在很大程度上直接影响着处理的效果与结果,在图像重建过程中,B的具体形态直接决定了重建后的图像其骨架的表现形式。

核心位置 即为我们的工作中心,在这个关键基准点上进行操作至关重要。核心位置在哪里将直接影响着处理结果的整体定位与落脚点所在的具体区域。由于原点的变化将导致最终形成的'骨架'走向不同的方向,并且这一过程中的细节处理与特征匹配将产生重要影响


简述算子是什么

我想,很多同我一样的初学者会有一个疑问,什么是算子?

我们了解了函数的概念。简单地说,函数由输入组成,并遵循特定的法则进行操作以产生结果。

算子由输入函数、具体规则以及将输入函数通过具体规则转换生成另一个函数的方式构成。

换而言之,算子处理的对象,是函数


二值形态学的基本运算

二值形态学的核心操作涉及腐蚀(erosion)、膨胀(dilation)、开运算(opening)以及闭运算(closing)。这些操作在图像处理中被广泛应用于提取图像的形状特性,并具体地帮助识别边界、区域以及连通性等关键属性。

二值图像中像素由 0 组成(代表背景区域),以及 1 组成(代表目标区域),处于灰度与彩色图像分析体系之间的基础层次

值得特别注意的是,在形态学运算中使用了不同的结构元素进行处理,并且通过不断优化参数设置以达到最佳效果。

因此,在二值形态学与灰度形态学的框架内进行的形态学运算中,则只需主要关注腐蚀与膨胀操作之间的差异即可;而其他组合运算则无需过多讨论


腐蚀(Erosion)

腐蚀的解释与公式

首先我们得回答一个问题,为什么叫腐蚀?

从字面上看,在实现某种功能时会涉及对一个对象进行缩减的操作;这种缩减的效果类似于'变细'或者'变瘦'。在我们讨论的二值图像处理场景中,则是以将前景物体(即像素值为 1 的区域)缩减为其基础形态来体现这一操作的效果。

把公式先端上来:

g[x,y]=AND[W^{(+)}\{f[x,y]\}]:=erode(f,W)

其定义是针对每一个像素点 (x,y) 处理。具体而言,在此操作中,在每一时刻只有当目标图像中的某个特定位置 (x,y) 处有一个特定亮度等级时才执行以下步骤:首先确定该结构元素覆盖的所有像素点;然后提取这些点对应的灰度值;接着将这些灰度值与目标图像在相同位置处对应的原始灰度值进行逐位逻辑与运算(即按位与操作)。随后将结果作为新的当前亮度等级赋回目标图像中的对应位置 (x,y)

在图像滑动过程中(即滑动窗口)中包含特定模式的情况下

我想,得画图才能表示地更加清晰。

QQ20241113-142008

如图所示,为了更直观地说,腐蚀操作的工作原理是:使用结构元素逐像素扫描目标图像.对于每一个像素位置,只有当结构元素与该区域完全吻合时,则该位置的输出结果设为 1;其余位置设为 0.

对于上面的公式,我们可能比较陌生,我们更熟悉的可能是下面这个公式:

A \ominus B = \{ x \mid (B)_{y} \subseteq A \}

其中:

  • A:表示基础二值图像,在此框架中将像素划分为目标区域(标记为1)与背景区域(标记为0)两类。
  • B:指定了一个较小尺寸的结构元素,在形态学运算中被用来提取或分析目标区域的具体形态特征。
  • \ominus :代表基本形态学运算中的腐蚀过程。
  • (B)_{y}:描述了将结构元素B的位置参数化至坐标系中的位置坐标点y的过程。

(B)_y仍然属于集合A时,则这些点的集合被称为A被B腐蚀的结果。


腐蚀的应用

  1. 去除噪音:针对单个噪音点进行消除
  2. 图像细化处理:生成骨架形态
  3. 区别开连接的目标
  4. 特征识别过程:识别物体边缘信息

腐蚀操作的demo实现

复制代码
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def save_pair_imgs(imgs,original_title,processed_title):
    plt.figure(figsize=(10, 8))
    
    plt.subplot(1, 2, 1)
    plt.imshow(imgs[0],'gray')
    plt.title(original_title)
    plt.xticks([]), plt.yticks([])
    
    plt.subplot(1, 2, 2)
    plt.imshow(imgs[1],'gray')
    plt.title(processed_title)
    plt.xticks([]), plt.yticks([])
    
    title = original_title + '_' + processed_title
    
    plt.savefig(f'../imgs/{title}.png', bbox_inches='tight')
    plt.show()
    
    # 读取图像
    image = cv2.imread('../data/Lena.bmp', 0)  # 0表示以灰度模式读取
    
    # 定义结构元素
    kernel = np.ones((5,5), np.uint8)
    
    # 腐蚀操作
    erosion = cv2.erode(image, kernel, iterations = 1)
    save_pair_imgs([image,erosion],'Original Image','Erosion')

效果图如下:

Original Image_Erosion


膨胀(Dilation)

膨胀的解释与公式

该过程主要表现为将图像中的物体进行扩展处理,并与腐蚀作用形成对比关系;在二值图像中,则是将前景区域进行扩展处理。

端上公式:

g[x,y]=OR[W^{(-)}\{f[x,y]\}]:=dilate(f,W)

每当结构元素 W^{(-)} 移动至图像上某处时,在经过膨胀运算后生成的新图像中对应的中心位置坐标点处会设置该结构元素中心点对应的灰度值也为零;如果该区域中的任何一个像素点灰度值达到一,则新生成图像中相应位置处的灰度值也会被设置为一。仅在所有覆盖区域内的像素点灰度值均为零的情况下

继续上图:

QQ20241113-171552

简单来说,在膨胀操作中,通过结构核作用于图像的每个像素点。如果该结构核与当前像素所在区域存在重叠区域,则该位置的像素会被标记为1;反之,则标记为0。

同样地,我们通常看到的是下面的公式:

A \oplus B = \{ x \mid (B)_{y}\cap A \neq \emptyset \}

其中:

  • A:代表基础二值图像,在此框架中包含了目标区域(标记为1像素)与背景区域(标记为0像素)。
  • B:代表结构元素单元,在图像处理中通常采用较小尺寸的设计以实现特定形态学效果。
  • \oplus :标识膨胀运算过程。
  • (B)_{y}:指通过位置变换将结构元素 B 的基元原点转移至空间坐标系中的位置坐标 y

直观地阐述这一公式:当集合(B)_{y}与集合A存在非空交集时,则由所有满足条件的点y所构成的集合被定义为由集合B膨胀后覆盖的所有点。


膨胀的应用

  • 图像预处理:填补空隙, 缝合断开区域
  • 目标增强: 增强边界细节, 扩展目标范围
  • 形态学梯度计算用于提取边缘特征


膨胀操作的demo实现

复制代码
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def save_pair_imgs(imgs,original_title,processed_title):
    plt.figure(figsize=(10, 8))
    
    plt.subplot(1, 2, 1)
    plt.imshow(imgs[0],'gray')
    plt.title(original_title)
    plt.xticks([]), plt.yticks([])
    
    plt.subplot(1, 2, 2)
    plt.imshow(imgs[1],'gray')
    plt.title(processed_title)
    plt.xticks([]), plt.yticks([])
    
    title = original_title + '_' + processed_title
    
    plt.savefig(f'../imgs/{title}.png', bbox_inches='tight')
    plt.show()
    
    # 读取图像
    image = cv2.imread('../data/Lena.bmp', 0)  # 0表示以灰度模式读取
    
    # 定义结构元素
    kernel = np.ones((5,5), np.uint8)
    
    # 膨胀操作
    dilation = cv2.dilate(image, kernel, iterations=1)
    save_pair_imgs([image, dilation], 'Original Image', 'Dilation')

效果图如下:

Original Image_Dilation


膨胀与腐蚀的关系

对偶性

dilate(f,W)=NOT[erode(NOT[f],W)]

erode(f,W)=NOT[dilate(NOT[f],W)]

换句话说,在图像处理中将前景进行膨胀操作相当于执行背景的腐蚀操作;反之亦然。

但腐蚀不是膨胀的逆运算

f[x,y]\neq erode(dilate(f,W),W)\neq dilate(erode(f,W),W)


开运算(Opening)

开运算的简介

开运算是先腐蚀后膨胀的组合操作:

open(f,W)=dilate(erode(f,W),W)

我们更常见的公式如下:

A \circ B = (A \ominus B) \oplus B

其中,A 是原始图像,B 是结构元素。

前面我们已经知道,在图像处理中使用腐蚀操作能够去除表面的物质并露出内部结构‘骨架’。然而,在这个过程中可能会丢失一些细节信息。因此我们可以采用膨胀操作将这些被去除的部分重新恢复回去。这样就能既去除了噪声污染又能尽可能地保持物体原本的轮廓特征了(需要注意的是由于腐蚀与膨胀操作并没有严格的逆运算性质所以这种方法只能说是近似地保留住了原有的轮廓)

其基本原理是通过去除数值为1的小区域来实现对微小物体的消除。这相当于去除了微小的突出物和连接处,并且去除了微小的噪声斑块。然而,在这一过程中,我们成功地保留了物体的本质结构。


开运算的demo实现

复制代码
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def save_pair_imgs(imgs,original_title,processed_title):
    plt.figure(figsize=(10, 8))
    
    plt.subplot(1, 2, 1)
    plt.imshow(imgs[0],'gray')
    plt.title(original_title)
    plt.xticks([]), plt.yticks([])
    
    plt.subplot(1, 2, 2)
    plt.imshow(imgs[1],'gray')
    plt.title(processed_title)
    plt.xticks([]), plt.yticks([])
    
    title = original_title + '_' + processed_title
    
    plt.savefig(f'../imgs/{title}.png', bbox_inches='tight')
    plt.show()
    
    # 读取图像
    image = cv2.imread('../data/Lena.bmp', 0)  # 0表示以灰度模式读取
    
    # 定义结构元素
    kernel = np.ones((5,5), np.uint8)
    
    # 开运算操作
    opening = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
    save_pair_imgs([image, opening], 'Original Image', 'Opening')

效果图如下:

Original Image_Opening


闭运算(Closing)

闭运算的简介

闭运算是先膨胀后腐蚀的组合操作:

close(f,W)=erode(dilate(f,W),W)

我们更常见的公式如下:

A \bullet B = (A \oplus B) \ominus B

其中,A 是原始图像,B 是结构元素。

为什么要采用闭运算这一方法?它通常会先进行膨胀操作以消除边界处的凹陷,并进一步去除背景噪声的影响。随后通过填充孔洞和连接相邻区域的操作步骤,在完成腐蚀过程后就能够有效消除这些干扰,并且能够保持物体的主要形态特征。

闭运算去除的是小的背景部分(数值为0)。


闭运算的demo实现

复制代码
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def save_pair_imgs(imgs,original_title,processed_title):
    plt.figure(figsize=(10, 8))
    
    plt.subplot(1, 2, 1)
    plt.imshow(imgs[0],'gray')
    plt.title(original_title)
    plt.xticks([]), plt.yticks([])
    
    plt.subplot(1, 2, 2)
    plt.imshow(imgs[1],'gray')
    plt.title(processed_title)
    plt.xticks([]), plt.yticks([])
    
    title = original_title + '_' + processed_title
    
    plt.savefig(f'../imgs/{title}.png', bbox_inches='tight')
    plt.show()
    
    # 读取图像
    image = cv2.imread('../data/Lena.bmp', 0)  # 0表示以灰度模式读取
    
    # 定义结构元素
    kernel = np.ones((5,5), np.uint8)
    
    # 闭运算操作
    closing = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
    save_pair_imgs([image, closing], 'Original Image', 'Closing')

效果图如下:

Original Image_Closing


开闭运算的侧重

闭运算的侧重点,是去除小的背景部分保留主要 ​**特征 **。

开运算的侧重点,是去除小的前景部分保留主要 ​**轮廓 **。


顶帽运算(Top Hat)

顶帽运算的简介

顶帽运算也称为礼帽运算,它是原图像与开运算结果的差值。

其公式定义如下:

T = f - (f \circ b)

顶帽运算能够识别出图像中比周围结构元素尺寸范围内背景更明亮的部分;它主要用作区分图像中较明亮的物体或噪声与其周围的背景。

也就是,分离出噪声信息或者比元素图像更亮的边缘信息。


顶帽运算的demo实现

复制代码
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def save_pair_imgs(imgs,original_title,processed_title):
    plt.figure(figsize=(10, 8))
    
    plt.subplot(1, 2, 1)
    plt.imshow(imgs[0],'gray')
    plt.title(original_title)
    plt.xticks([]), plt.yticks([])
    
    plt.subplot(1, 2, 2)
    plt.imshow(imgs[1],'gray')
    plt.title(processed_title)
    plt.xticks([]), plt.yticks([])
    
    title = original_title + '_' + processed_title
    
    plt.savefig(f'../imgs/{title}.png', bbox_inches='tight')
    plt.show()
    
    # 读取图像
    image = cv2.imread('../data/Lena.bmp', 0)  # 0表示以灰度模式读取
    
    # 定义结构元素
    kernel = np.ones((5,5), np.uint8)
    
    # Top Hat 操作
    tophat = cv2.morphologyEx(image, cv2.MORPH_TOPHAT, kernel)
    save_pair_imgs([image, tophat], 'Original Image', 'Top Hat')

效果图如下:

Original Image_Top Hat


黑帽运算(Black Hat)

黑帽运算的简介

其主要作用与其对应的是相反的;它能够从图像中提取出那些在局部结构元素尺寸范围内显得更为暗淡的区域;这些区域通常用于分离出图像中的阴影或其他较暗细节,并将其与其他较为明亮的部分区分开来

具体来说,在图像中提取以下三个部分:首先是图像内部的孔洞;其次是前景区域中的黑色颗粒;最后是边缘区域中亮度较低的部分。

黑帽运算是闭运算结果与原图像的差值。

其公式定义如下:

B=(f \cdot b) - f


黑帽运算的demo实现

复制代码
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def save_pair_imgs(imgs,original_title,processed_title):
    plt.figure(figsize=(10, 8))
    
    plt.subplot(1, 2, 1)
    plt.imshow(imgs[0],'gray')
    plt.title(original_title)
    plt.xticks([]), plt.yticks([])
    
    plt.subplot(1, 2, 2)
    plt.imshow(imgs[1],'gray')
    plt.title(processed_title)
    plt.xticks([]), plt.yticks([])
    
    title = original_title + '_' + processed_title
    
    plt.savefig(f'../imgs/{title}.png', bbox_inches='tight')
    plt.show()
    
    # 读取图像
    image = cv2.imread('../data/Lena.bmp', 0)  # 0表示以灰度模式读取
    
    # 定义结构元素
    kernel = np.ones((5,5), np.uint8)
    
    # Black Hat 操作
    blackhat = cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, kernel)
    save_pair_imgs([image, blackhat], 'Original Image', 'Black Hat')

效果图如下:

Original Image_Black Hat


梯度运算(Gradient)

梯度运算的简介

什么是梯度运算,梯度,我们下意识可以想到高数中的梯度。

梯度向量地呈现着一个空间中的变化趋势,在场域中各点的梯度方向均指向函数值上升最陡峭的方向。从数学意义上讲,在任一点处的梯度大小不仅反映了该点处函数值沿最陡上升方向的变化速度,在物理意义上这一特性也对应着场强的概念。

边缘通常位于图像中物体与背景之间像素值变化显著的位置,在此区域应用梯度运算能够有效提取出图像中的边缘信息(包括位置和强度)

梯度运算的公式很多,常见的基本差分梯度公式 如下:

对于二维离散图像 f(x,y)

  • 水平方向梯度:G_x = f(x+1, y) - f(x, y) 反映了图像横向相邻像素值的变化。
  • 垂直方向梯度:G_y = f(x, y+1) - f(x, y) 用于检测图像纵向像素值的变化情况。
  • 总的梯度幅值 G = \sqrt{G_x^2 + G_y^2} 综合考虑了水平与垂直两个方向的梯度变化情况。


梯度运算的demo实现

复制代码
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    def save_pair_imgs(imgs,original_title,processed_title):
    plt.figure(figsize=(10, 8))
    
    plt.subplot(1, 2, 1)
    plt.imshow(imgs[0],'gray')
    plt.title(original_title)
    plt.xticks([]), plt.yticks([])
    
    plt.subplot(1, 2, 2)
    plt.imshow(imgs[1],'gray')
    plt.title(processed_title)
    plt.xticks([]), plt.yticks([])
    
    title = original_title + '_' + processed_title
    
    plt.savefig(f'../imgs/{title}.png', bbox_inches='tight')
    plt.show()
    
    # 读取图像
    image = cv2.imread('../data/Lena.bmp', 0)  # 0表示以灰度模式读取
    
    # 定义结构元素
    kernel = np.ones((5,5), np.uint8)
    
    # 梯度操作
    gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel)
    save_pair_imgs([image, gradient], 'Original Image', 'Gradient')

效果图如下:

Original Image_Gradient


击中击不中变换(Hit - miss filter)

击中击不中变换的解释与公式

该变换用以在二值图像中检测特定形状和结构,并依据结构元素与图像像素之间的对应关系来确定目标形状或结构的位置。

二值图像处理中的击中-非击中变换涉及两个关键的结构模板:模板V(用于目标区域匹配)和模板W(用于背景区域匹配)。在图像中的每一个像素点上,在以该像素为中心的区域与模板V在目标部分完全吻合的同时,在其背景部分也与模板W完全对应时,则标记该像素为目标形状或结构的位置。

令二值图像定义为 f ,经由冲积侵蚀变换处理后得到的图像是 g ,则冲积侵蚀变换可被表征为:

g = f \circledast (V,W)

其中 \circledast 表示击中击不中变换操作。

在具体计算过程中(或者步骤中),首先会对图像 f 执行腐蚀操作(或者运算),所使用的结构元素为 V ,从而得到一个中间输出结果(或者变量)f_V

对图像 f 的背景区域实施腐蚀操作,并使用结构元素 W 进行腐蚀处理后会生成一个中间结果记为f_{W}^{C};随后将两个中间结果f_{V}f_{W}^{C}结合使用逻辑与运算符进行处理后会得到一种称为击中-击不中变换的结果记为:

g = (f \ominus V) \cap (f^C \ominus W)

其中 \ominus 表示腐蚀操作,f^C 表示 f 的补集。

我们可以理解为完全匹配,前景和背景元素需要跟设定的完全一致。

上图:

image

Note:在击中击不中变换的结构元中,-1表示背景,1表示前景,0表示不关心


击中击不中变换的应用

  • 形状检测与识别技术:在工业检测领域中应用广泛,在此系统中用于检测产品表面特定形状的缺陷或标记信息等关键特征点。通过设计合适的结构元素来匹配正常焊点的形状特征,并利用击中击不中变换方法能够快速准确地筛选出不符合标准要求的关键缺陷点信息实现产品质量检测与控制的目的。
  • 纹理分析技术:在纹理图像分析过程中某些特定类型的纹理特征具有独特的形态或结构模式特性,在此过程中击中击不中变换方法可以帮助提取这些关键的纹理特征进而用于图像分类分割等任务例如在纺织品质量评估过程中可以通过对纺织品织物图案进行分析提取其中特殊的编织图案或纹理结构信息以此判断纺织品的质量等级以及具体的类型。
  • 字符识别预处理技术:在光学字符识别(OCR)系统设计过程中可将其作为预处理步骤用于提取字符的具体形态组成特征如字母中的孔洞(如字母“o”“p”等中的圆形孔洞)笔画端点以及交叉点等关键特征信息这些形态学特征数据为后续阶段的字符分类与识别工作提供了重要的参数依据从而有效提高整体系统的字符辨识准确率和效率。


灰度形态学的基本运算

灰度图像

灰度图像与二值图像在特性上存在显著差异,在其像素值分布上具有明确的定义域特点:x\in[0,255]x属于整数集合\mathbb{Z}。这种定义域特点使其能够有效刻画图像的明暗变化以及纹理等细节特征。

在处理灰度图像时,我们可以通过建立基于阈值的集合 T_{θ}(f[x,y]) = \{[x, y] : f[x, y] \geq θ\}, -∞ < θ < +∞ 来实现对图像的分解。原始图像则可通过取上确界的方式由所有满足条件的θ值得到。

阈值集合被定义为图像中gray-level values exceeding or equal to θ的所有pixel set。当θ设为128时,则T₁₂₈(f[x,y])就代表图像中gray-level values exceeding or equal to 128的所有pixel set构成的集合。

简而言之,在处理灰度图像时, 我们能够通过一种称为阈值化的技术来分解图像. 随后, 我们可以利用supremum过程来重建图像.


Flat/一般腐蚀算子

灰度形态学中,Flat腐蚀算子 定义如下:

g[x,y]=\min\{W^{(+)}\{f[x,y]\}\}:=erode(f,W)

其中:

f[x, y] 表示原始灰度图像在位置 (x, y) 的像素值。
W^{(+)} 被称为与结构元素相关联的领域运算器。
g[x, y] 代表经过腐蚀处理后得到的新图像在位置 (x, y) 的像素值。

其基本含义是,在图像的所有像素点中被确定为其新值的是那些位于结构元素窗口 W 内部并具有最低灰度值的像素点。

那么,在图像中阴影区的面积将增大,并且亮区的面积将减小(因为数值降低至更小值时会显得更暗)。

也就是,暗大明小。

灰度形态学中,一般腐蚀算子 定义如下:

g[x,y]=\inf_{\alpha,\beta}\{f[x+\alpha,y+\beta]-w[\alpha,\beta]\}=erode(f,w)

这里 inf​ 表示取下确界(类似最小值)。

其基本原理是:对于图像中的每一个像元点 (x, y),我们关注其周围区域。具体而言,在结构元素 w 在位置 (α, β) 的影响范围内进行运算。我们需要计算 f(x+α, y+β)(即图像在平移 (α, β) 后的位置上的像素值)与 w 在位置 (α, β) 处对应的数值之间的差异。将这些差异中的最小下限作为经过腐蚀后的新的像元值 g(x, y)。


Flat/一般膨胀算子

灰度形态学中,Flat膨胀算子 定义如下:

g[x,y]=\max\{W^{(-)}\{f[x,y]\}\}:=dilate(f,W)

与Flat腐蚀算子不同,在图像的所有像素点上进行处理,并将每个像素的新值设置为其所在区域的最大值

那么,在图像中被识别为明亮区域的面积会增大(亮度值提升意味着亮度等级提高),而被识别为暗区域的面积则会减小。

也就是,明大暗小。

灰度形态学中,一般膨胀算子 定义如下:

g(x,y)等于\text{sup}_{\alpha,\beta}\{\ f(x - \alpha, y - β) + w(α, β)\ \};即\text{sup}_{\α,β}\{\ w(x - α, y - β) + f(α, β)\ \}

在该处,sup 被定义为上确界(如同最大值一样)。考虑图像 f[x,y] 中的所有像素点 (x,y)。在结构元素 w[\alpha,\beta] 所确定的邻域范围内,在每一个位置计算出对应位置上的新数值:即对所有可能的位置 (x−α, y−β) 来说,在平移后的图像中对应的像素值与其对应权重之总和,并从中选取最大的那个总和作为新的输出 pixel 值。


Flat腐蚀和膨胀算子和一般腐蚀和膨胀算子

从名字上可以猜到,Flat算子其实是一般算子的特殊情况。

用途上即为,在无特殊需求或精度要求时使用Flat运算较为简便即可;而若非如此,则需采用更为复杂的通用运算来进行处理。


形态学边缘检测(Morphological edge detectors)

简要介绍

我们都知道腐蚀会使肉皮去除而留下骨,并使骨再生出肉;那么如果我们对比膨胀后与腐蚀后的结果是否能够直接得到外层皮肤(或表皮)的轮廓呢?

正式一点地说,在形态学运算中将腐蚀作用于原始图像会缩小前景对象的范围;反之将图像进行膨胀操作则会使前景对象的范围增大;因此这两种运算结果之间的差异就反映了物体的边界轮廓。

但是有个前提如下:

  • erode(f,W)\neq f \space AND \space dilate(f,W)\neq erode(f,W)

在图像中进行边缘检测可用于突出物体轮廓并辅助后续目标识别、图像分割等相关任务。例如,在图像中识别出物体的边界线就可以完成上述一系列后续任务。

  • 优点:该方法能够有效维持图像中的边缘完整性,在抗噪声能力方面表现良好。
  • 缺点:该方法在边缘定位精确度上存在一定的局限性,并且其性能高度依赖于所选择的结构元素。


对于二值图像

g_{edge}[x,y] = g_{dilate}[x,y] \space XOR \space g_{erode}[x,y]

在二值图像中仅包含 \left\lbrace0,1\right\rbrace 两个数值特征值,在这种情况下我们可以通过对膨胀运算结果与腐蚀运算结果执行逻辑异或操作来准确识别边缘像素的位置从而清晰地展现物体的轮廓边界


对于灰度图像

g_{edge}[x,y] = g_{dilate}[x,y] - g_{erode}[x,y]


参考资料

data

Lena图等: http://www.eecs.qmul.ac.uk/~phao/IP/Images/

检索到的出处: <>

全部评论 (0)

还没有任何评论哟~