Opencv-Python学习笔记(五):图像形态学操作---腐蚀、膨胀、开/闭运算、梯度、礼帽与黑帽

  • 本篇记录学习不同的形态学操作,例如侵蚀,膨胀,开/闭运算,梯度、礼帽与黑帽。
  • 学习以下不同的函数,例如:cv2.erode()cv2.dilate()cv2.morphologyEx()等。

我们先来接上一篇文章的一个小尾巴,介绍一种图像滤波方式:边缘保留滤波(EPF)

常用的两种处理方法:

  • 高斯双边滤波
  • 均值迁移滤波

函数 cv2.bilateralFilter() 能在保持边界清晰的情况下有效的去除噪音。但是这种操作与其他滤波器相比会比较慢。我们已经知道高斯滤波器是求中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要。双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。

下面这张图是贾志刚老师课程里面截取的一张,关于他是如何操作的建议去看一下老师的课程:边缘保留滤波(EPF)
 

下面我们通过代码来看一下效果:


import cv2 as cv
import numpy as np


def bi_demo(image):  # bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)
    """
    同时考虑空间与信息和灰度相似性,达到保边去噪的目的
    双边滤波的核函数是空间域核与像素范围域核的综合结果:
    在图像的平坦区域,像素值变化很小,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊;
    在图像的边缘区域,像素值变化很大,像素范围域权重变大,从而保持了边缘的信息。
    """
    dst = cv.bilateralFilter(image, 0, 100, 15)  # 高斯双边
    cv.imshow("bi_demo", dst)


# pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None)
# @param src The source 8-bit, 3-channel image.
# @param dst The destination image of the same format and the same size as the source.
# @param sp The spatial window radius.
# @param sr The color window radius.
# @param maxLevel Maximum level of the pyramid for the segmentation.
# @param termcrit Termination criteria: when to stop meanshift iterations.
def shift_demo(image):  # 均值迁移
    dst = cv.pyrMeanShiftFiltering(image, 10, 50)
    cv.imshow("shift_demo", dst)


if __name__ == '__main__':
    src = cv.imread("../images/CrystalLiu1.jpg")  # 读入图片放进src中
    cv.namedWindow("Crystal Liu")  # 创建窗口
    cv.imshow("Crystal Liu", src)  # 将src图片放入该创建的窗口中
    bi_demo(src)
    shift_demo(src)
    cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()  # 关闭所有窗口

原图-->高斯双边-->均值迁移

以上,图像中经常用到的滤波方式已经学习完了,赶快去给自己P一张图吧!!!


接下来就是本篇主要内容了,图像的形态学操作。

形态学操作是根据图像形状进行的简单操作。一般情况下对二值化图像进行的操作。需要输入两个参数,一个是原始图像,第二个被称为结构化元素或核,它是用来决定操作的性质的。两个基本的形态学操作是腐蚀和膨胀。他们的变体构成了开运算,闭运算,梯度等。我们会以下图为例逐一介绍它们。

  • 腐蚀:

就像土壤侵蚀一样,这个操作会把前景物体的边界腐蚀掉(但是前景仍然是白色)。这是怎么做到的呢?卷积核沿着图像滑动,如果与卷积核对应的原图像的所有像素值都是 1,那么中心元素就保持原来的像素值,否则就变为零。这会产生什么影响呢?根据卷积核的大小靠近前景的所有像素都会被腐蚀掉(变为 0),所以前景物体会变小,整幅图像的白色区域会减少。这对于去除
白噪声很有用,也可以用来断开两个连在一块的物体等。这里我们有一个例子,使用一个 5x5 的卷积核,其中所有的值都是以。让我们看看他是如何工作的:
 

# -*- coding:utf-8 -*-
# Author : MMagicLoren
# @Email : [email protected]
# @Time : 2019/10/7 10:01
# @File : 图像形态学.py
# @Project : Workspace
import cv2 as cv
import numpy as np


def erosion_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    erosion = cv.erode(src, kernel, iterations=1)
    cv.imshow("erosion", erosion)


if __name__ == '__main__':

    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")  # 读入图片放进src中
    cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 创建窗口, 窗口尺寸自动调整
    cv.imshow("input image", src)
    erosion_demo(src)
    cv.waitKey(0)

    cv.destroyAllWindows()

  • 膨胀:

与腐蚀相反,与卷积核对应的原图像的像素值中只要有一个是 1,中心元素的像素值就是 1。所以这个操作会增加图像中的白色区域(前景)。一般在去噪声时先用腐蚀再用膨胀。因为腐蚀在去掉白噪声的同时,也会使前景对象变小。所以我们再对他进行膨胀。这时噪声已经被去除了,不会再回来了,但是前景还在并会增加。膨胀也可以用来连接两个分开的物体。
 

def dilation_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    dilation = cv.dilate(src, kernel, iterations=1)
    cv.imshow("dilation", dilation)

  • 开运算:

先进性腐蚀再进行膨胀就叫做开运算。就像我们上面介绍的那样,它被用来去除噪声。这里我们用到的函数是cv2.morphologyEx()
 

def opening_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    opening = cv.morphologyEx(src, cv.MORPH_OPEN, kernel)
    cv.imshow("opening", opening)

  • 闭运算:

先膨胀再腐蚀。它经常被用来填充前景物体中的小洞,或者前景物体上的小黑点。
 

def closing_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    closing = cv.morphologyEx(src, cv.MORPH_CLOSE, kernel)
    cv.imshow("closing", closing)

这张图的效果不是很好,学习是参考官方文档看一下。

  • 形态学梯度:

梯度=膨胀-腐蚀。结果看上去就像前景物体的轮廓。

def morphological_gradient_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    morphological_gradient = cv.morphologyEx(src, cv.MORPH_GRADIENT, kernel)
    cv.imshow("morphological_gradient", morphological_gradient)


  • 礼帽:

礼貌=原始图像-开运算结果。下面的例子是用一个 9x9 的核进行礼帽操作的结果。
 

def top_hat_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((9, 9), np.uint8)
    top_hat = cv.morphologyEx(src, cv.MORPH_TOPHAT, kernel)
    cv.imshow("top_hat", top_hat)

  • 黑帽:

黑帽=闭运算-原始输入。

def black_hat_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((9, 9), np.uint8)
    black_hat_demo = cv.morphologyEx(src, cv.MORPH_BLACKHAT, kernel)
    cv.imshow("black_hat_demo", black_hat_demo)

以上就是图像形态学的基本操作。

完整工程代码:

# -*- coding:utf-8 -*-
# Author : MMagicLoren
# @Email : [email protected]
# @Time : 2019/10/7 10:01
# @File : 图像形态学.py
# @Project : Workspace
import cv2 as cv
import numpy as np


def erosion_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    erosion = cv.erode(src, kernel, iterations=1)
    cv.imshow("erosion", erosion)


def dilation_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    dilation = cv.dilate(src, kernel, iterations=1)
    cv.imshow("dilation", dilation)


def opening_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    opening = cv.morphologyEx(src, cv.MORPH_OPEN, kernel)
    cv.imshow("opening", opening)


def closing_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    closing = cv.morphologyEx(src, cv.MORPH_CLOSE, kernel)
    cv.imshow("closing", closing)


def morphological_gradient_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    morphological_gradient = cv.morphologyEx(src, cv.MORPH_GRADIENT, kernel)
    cv.imshow("morphological_gradient", morphological_gradient)


def top_hat_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((9, 9), np.uint8)
    top_hat = cv.morphologyEx(src, cv.MORPH_TOPHAT, kernel)
    cv.imshow("top_hat", top_hat)


def black_hat_demo(image):
    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")
    kernel = np.ones((5, 5), np.uint8)
    black_hat_demo = cv.morphologyEx(src, cv.MORPH_BLACKHAT, kernel)
    cv.imshow("black_hat_demo", black_hat_demo)


if __name__ == '__main__':

    src = cv.imread(
        "F:/Pycharm/opencv_exercises-master/images/01.jpg")  # 读入图片放进src中
    cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 创建窗口, 窗口尺寸自动调整
    cv.imshow("input image", src)
    # erosion_demo(src)
    # dilation_demo(src)
    # opening_demo(src)
    # closing_demo(src)
    # morphological_gradient_demo(src)
    # top_hat_demo(src)
    black_hat_demo(src)
    cv.waitKey(0)

    cv.destroyAllWindows()
发布了29 篇原创文章 · 获赞 83 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/l59565455/article/details/102289457