• OpenCV-Python快速入门(十三):形态学操作


    前言

    • 本文是个人快速入门OpenCV-Python的电子笔记,由于水平有限,难免出现错漏,敬请批评改正。
    • 更多精彩内容,可点击进入
      OpenCV-Python快速入门
      专栏或我的个人主页查看

    前提条件

    实验环境

    • Python 3.x (面向对象的高级语言)
    • OpenCV 4.0(python第三方库)pip3 install opencv-python

    形态学操作

    • 形态学,即数学形态学(Mathematical Morphology),是图像处理过程中一个非常重要的研究方向。
    • 形态学主要从图像内提取分量信息,该分量信息通常对于表达和描绘图像的形状具有重要意义,通常是图像理解时所使用的最本质的形状特征。例如,在识别手写数字时,能够通过形态学运算得到其骨架信息,在具体识别时,仅针对其骨架进行运算即可。形态学处理在视觉检测、文字识别、医学图像处理、图像压缩编码等领域都有非常重要的应用。
    • 形态学操作主要包含:腐蚀、膨胀、开运算、闭运算、形态学梯度(Morphological Gradient)运算、顶帽运算(礼帽运算)、黑帽运算等操作。腐蚀操作和膨胀操作是形态学运算的基础,将腐蚀和膨胀操作进行结合,就可以实现开运算、闭运算、形态学梯度运算、顶帽运算、黑帽
      运算、击中击不中等不同形式的运算。

    腐蚀(cv2.erode())

    • 腐蚀是最基本的形态学操作之一,它能够将图像的边界点消除,使图像沿着边界向内收缩,也可以将小于指定结构体元素的部分去除。
    • 腐蚀基本思路:在 kernel 完全位于前景图象中时,将其中心点所对应的 rst 中像素点的值置为 1;当 kernel 不完全位于前景图像中时,将其中心点对应的 rst 中像素点的值置为 0。
      在这里插入图片描述
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    # 读取图片
    img = cv2.imread('1.jpg')
    # BGR -> RGB
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    plt.figure(figsize=(20, 20))
    plt.subplot(2, 2, 1)
    plt.title("Original")
    plt.imshow(image)
    
    # 灰度图
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 二值化
    ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    '''
    dst = cv2.erode( src, kernel[, anchor[, iterations[, borderType[, borderValue]]]] )
    参数:
        src 是需要进行腐蚀的原始图像,图像的通道数可以是任意的。
            但是要求图像的深度必须是 CV_8U、CV_16U、CV_16S、CV_32F、CV_64F 中的一种。
        kernel 代表腐蚀操作时所采用的结构类型。它可以自定义生成,也可以通过函数cv2.getStructuringElement()生成。
        anchor 代表 element 结构中锚点的位置。该值默认为(-1,-1),在核的中心位置。
        iterations 是腐蚀操作迭代的次数,该值默认为 1,即只进行一次腐蚀操作。
        borderType 代表边界样式,一般采用其默认值 BORDER_CONSTANT。
        borderValue 是边界值,一般采用默认值。
    返回值:
        dst 是腐蚀后所输出的目标图像,该图像和原始图像具有同样的类型和大小。
    '''
    # kernel = np.ones((90,90),np.uint8) # 自定义生成
    '''
    kernel = cv2.getStructuringElement(shape, ksize) 
    参数:
        shape:代表形状类型
            cv2.MORPH_RECT:矩形结构元素,所有元素值都是1
            cv2.MORPH_CROSS:十字形结构元素,对角线元素值都是1
            cv2.MORPH_ELLIPSE:椭圆形结构元素
        ksize:代表形状元素的大小
    返回值:
        kernel ksize大小的核
    '''
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(90,90))
    # 腐蚀
    erosion = cv2.erode(binary,kernel)
    
    plt.subplot(2, 2, 2)
    plt.title("Gray")
    plt.imshow(gray,cmap="gray")
    
    plt.subplot(2, 2, 3)
    plt.title("Binary")
    plt.imshow(binary,cmap="gray")
    
    plt.subplot(2, 2, 4)
    plt.title("Erosion")
    plt.imshow(erosion,cmap="gray")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    在这里插入图片描述

    膨胀(cv2.dilate())

    • 膨胀操作是形态学中另外一种基本的操作。膨胀操作和腐蚀操作的作用是相反的,膨胀操作能对图像的边界进行扩张。膨胀操作将与当前对象(前景)接触到的背景点合并到当前对象内,从而实现将图像的边界点向外扩张。
    • 如果图像内两个对象的距离较近,那么在膨胀的过程中,两个对象可能会连通在一起。膨胀操作对填补图像分割后图像内所存在的空白相当有帮助。
    • 膨胀基本思路:在 kernel 内,当任意一个像素点与前景对象重合时,其中心点所对应的膨胀结果图像内的像素点值的为 1;当 kernel 与前景对象完全无重合时,其中心点对应的膨胀结果图像内像素点的值为 0。
      在这里插入图片描述
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    # 读取图片
    img = cv2.imread('1.jpg')
    # BGR -> RGB
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    plt.figure(figsize=(20, 20))
    plt.subplot(2, 2, 1)
    plt.title("Original")
    plt.imshow(image)
    
    # 灰度图
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 二值化
    ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    '''
    dst = cv2.dilate( src, kernel[, anchor[, iterations[, borderType[, borderValue]]]] )
    参数:
        src 代表需要进行膨胀操作的原始图像。图像的通道数可以是任意的,
            但是要求图像的深度必须是 CV_8U、CV_16U、CV_16S、CV_32F、CV_64F 中的一种。
        kernel 代表膨胀操作时所采用的结构类型。它可以自定义生成,也可以通过函数cv2.getStructuringElement()生成。
        anchor 代表 element 结构中锚点的位置。该值默认为(-1,-1),在核的中心位置。
        iterations 是膨胀操作迭代的次数,该值默认为 1,即只进行一次膨胀操作。
        borderType 代表边界样式,一般采用其默认值 BORDER_CONSTANT。
        borderValue 是边界值,一般采用默认值。
    返回值:
        dst 是代表膨胀后所输出的目标图像,该图像和原始图像具有同样的类型和大小。
    '''
    # kernel = np.ones((90,90),np.uint8) # 自定义生成
    '''
    kernel = cv2.getStructuringElement(shape, ksize) 
    参数:
        shape:代表形状类型
            cv2.MORPH_RECT:矩形结构元素,所有元素值都是1
            cv2.MORPH_CROSS:十字形结构元素,对角线元素值都是1
            cv2.MORPH_ELLIPSE:椭圆形结构元素
        ksize:代表形状元素的大小
    返回值:
        kernel ksize大小的核
    '''
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(90,90))
    # 膨胀
    dilate = cv2.dilate(binary,kernel)
    
    plt.subplot(2, 2, 2)
    plt.title("Gray")
    plt.imshow(gray,cmap="gray")
    
    plt.subplot(2, 2, 3)
    plt.title("Binary")
    plt.imshow(binary,cmap="gray")
    
    plt.subplot(2, 2, 4)
    plt.title("Dilate")
    plt.imshow(dilate,cmap="gray")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    在这里插入图片描述

    通用形态学函数(cv2.morphologyEx())

    • 腐蚀操作和膨胀操作是形态学运算的基础,将腐蚀和膨胀操作进行组合,就可以实现开运算、闭运算(关运算)、形态学梯度(Morphological Gradient)运算、礼帽运算(顶帽运算)、黑帽运算、击中击不中等多种不同形式的运算。
    • OpenCV 提供了函数 cv2.morphologyEx()来实现上述形态学运算,其语法结构如下:
      • dst = cv2.morphologyEx( src, op, kernel[, anchor[, iterations[, borderType[, borderValue]]]]] )
    • dst 代表经过形态学处理后所输出的目标图像,该图像和原始图像具有同样的类型和大小。
    • src 代表需要进行形态学操作的原始图像。图像的通道数可以是任意的,但是要求图像的深度必须是 CV_8U、CV_16U、CV_16S、CV_32F、CV_64F 中的一种。
    • op 代表操作类型,如表所示。各种形态学运算的操作规则均是将腐蚀和膨胀操作进行组合而得到的。
      在这里插入图片描述
    • kernel 代表膨胀操作时所采用的结构类型。它可以自定义生成,也可以通过函数cv2.getStructuringElement()生成。
    • anchor 代表 element 结构中锚点的位置。该值默认为(-1,-1),在核的中心位置。
    • iterations 是膨胀操作迭代的次数,该值默认为 1,即只进行一次膨胀操作。
    • borderType 代表边界样式,一般采用其默认值 BORDER_CONSTANT。
      在这里插入图片描述
    • borderValue 是边界值,一般采用默认值。

    开运算(cv2.MORPH_OPEN)

    • 开运算进行的操作是先将图像腐蚀,再对腐蚀的结果进行膨胀。开运算可以用于去噪、计数等。
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    # 读取图片
    img = cv2.imread('1.jpg')
    # BGR -> RGB
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    plt.figure(figsize=(20, 20))
    plt.subplot(2, 2, 1)
    plt.title("Original")
    plt.imshow(image)
    
    # 灰度图
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 二值化
    ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    
    # kernel = np.ones((90,90),np.uint8) # 自定义生成
    '''
    kernel = cv2.getStructuringElement(shape, ksize) 
    参数:
        shape:代表形状类型
            cv2.MORPH_RECT:矩形结构元素,所有元素值都是1
            cv2.MORPH_CROSS:十字形结构元素,对角线元素值都是1
            cv2.MORPH_ELLIPSE:椭圆形结构元素
        ksize:代表形状元素的大小
    返回值:
        kernel ksize大小的核
    '''
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(90,90))
    # 开运算:先将图像腐蚀,再对腐蚀的结果进行膨胀
    opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
    
    plt.subplot(2, 2, 2)
    plt.title("Gray")
    plt.imshow(gray,cmap="gray")
    
    plt.subplot(2, 2, 3)
    plt.title("Binary")
    plt.imshow(binary,cmap="gray")
    
    plt.subplot(2, 2, 4)
    plt.title("Opening")
    plt.imshow(opening,cmap="gray")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    闭运算(cv2.MORPH_CLOSE)

    • 闭运算是先膨胀、后腐蚀的运算,它有助于关闭前景物体内部的小孔,或去除物体上的小黑点,还可以将不同的前景图像进行连接。
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    # 读取图片
    img = cv2.imread('1.jpg')
    # BGR -> RGB
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    plt.figure(figsize=(20, 20))
    plt.subplot(2, 2, 1)
    plt.title("Original")
    plt.imshow(image)
    
    # 灰度图
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 二值化
    ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    
    # kernel = np.ones((90,90),np.uint8) # 自定义生成
    '''
    kernel = cv2.getStructuringElement(shape, ksize) 
    参数:
        shape:代表形状类型
            cv2.MORPH_RECT:矩形结构元素,所有元素值都是1
            cv2.MORPH_CROSS:十字形结构元素,对角线元素值都是1
            cv2.MORPH_ELLIPSE:椭圆形结构元素
        ksize:代表形状元素的大小
    返回值:
        kernel ksize大小的核
    '''
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(90,90))
    # 闭运算:先膨胀、后腐蚀
    closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
    
    plt.subplot(2, 2, 2)
    plt.title("Gray")
    plt.imshow(gray,cmap="gray")
    
    plt.subplot(2, 2, 3)
    plt.title("Binary")
    plt.imshow(binary,cmap="gray")
    
    plt.subplot(2, 2, 4)
    plt.title("Closing")
    plt.imshow(closing,cmap="gray")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    形态学梯度运算(cv2.MORPH_GRADIENT)

    形态学梯度运算是用膨胀图像减腐蚀图像的操作,该操作可以获取原始图像中前景图像的边缘。

    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    # 读取图片
    img = cv2.imread('1.jpg')
    # BGR -> RGB
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    plt.figure(figsize=(20, 20))
    plt.subplot(2, 2, 1)
    plt.title("Original")
    plt.imshow(image)
    
    # 灰度图
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 二值化
    ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    
    # kernel = np.ones((90,90),np.uint8) # 自定义生成
    '''
    kernel = cv2.getStructuringElement(shape, ksize) 
    参数:
        shape:代表形状类型
            cv2.MORPH_RECT:矩形结构元素,所有元素值都是1
            cv2.MORPH_CROSS:十字形结构元素,对角线元素值都是1
            cv2.MORPH_ELLIPSE:椭圆形结构元素
        ksize:代表形状元素的大小
    返回值:
        kernel ksize大小的核
    '''
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(90,90))
    # 形态学运算:用膨胀图像减腐蚀图像
    result = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel)
    
    plt.subplot(2, 2, 2)
    plt.title("Gray")
    plt.imshow(gray,cmap="gray")
    
    plt.subplot(2, 2, 3)
    plt.title("Binary")
    plt.imshow(binary,cmap="gray")
    
    plt.subplot(2, 2, 4)
    plt.title("Result")
    plt.imshow(result,cmap="gray")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    礼帽运算(cv2.MORPH_GRADIENT)

    礼帽运算是用原始图像减去其开运算图像的操作。礼帽运算能够获取图像的噪声信息,或者得到比原始图像的边缘更亮的边缘信息。

    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    # 读取图片
    img = cv2.imread('1.jpg')
    # BGR -> RGB
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    plt.figure(figsize=(20, 20))
    plt.subplot(2, 2, 1)
    plt.title("Original")
    plt.imshow(image)
    
    # 灰度图
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 二值化
    ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    
    # kernel = np.ones((90,90),np.uint8) # 自定义生成
    '''
    kernel = cv2.getStructuringElement(shape, ksize) 
    参数:
        shape:代表形状类型
            cv2.MORPH_RECT:矩形结构元素,所有元素值都是1
            cv2.MORPH_CROSS:十字形结构元素,对角线元素值都是1
            cv2.MORPH_ELLIPSE:椭圆形结构元素
        ksize:代表形状元素的大小
    返回值:
        kernel ksize大小的核
    '''
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(90,90))
    # 礼帽运算:用原始图像减去其开运算图像
    result = cv2.morphologyEx(binary, cv2.MORPH_TOPHAT, kernel)
    
    plt.subplot(2, 2, 2)
    plt.title("Gray")
    plt.imshow(gray,cmap="gray")
    
    plt.subplot(2, 2, 3)
    plt.title("Binary")
    plt.imshow(binary,cmap="gray")
    
    plt.subplot(2, 2, 4)
    plt.title("Result")
    plt.imshow(result,cmap="gray")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    黑帽运算(cv2.MORPH_BLACKHAT)

    黑帽运算是用闭运算图像减去原始图像的操作。黑帽运算能够获取图像内部的小孔,或前景色中的小黑点,或者得到比原始图像的边缘更暗的边缘部分。

    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    # 读取图片
    img = cv2.imread('1.jpg')
    # BGR -> RGB
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    plt.figure(figsize=(20, 20))
    plt.subplot(2, 2, 1)
    plt.title("Original")
    plt.imshow(image)
    
    # 灰度图
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 二值化
    ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
    
    # kernel = np.ones((90,90),np.uint8) # 自定义生成
    '''
    kernel = cv2.getStructuringElement(shape, ksize) 
    参数:
        shape:代表形状类型
            cv2.MORPH_RECT:矩形结构元素,所有元素值都是1
            cv2.MORPH_CROSS:十字形结构元素,对角线元素值都是1
            cv2.MORPH_ELLIPSE:椭圆形结构元素
        ksize:代表形状元素的大小
    返回值:
        kernel ksize大小的核
    '''
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(90,90))
    # 黑帽运算:用闭运算图像减去原始图像
    result = cv2.morphologyEx(binary, cv2.MORPH_BLACKHAT, kernel)
    
    plt.subplot(2, 2, 2)
    plt.title("Gray")
    plt.imshow(gray,cmap="gray")
    
    plt.subplot(2, 2, 3)
    plt.title("Binary")
    plt.imshow(binary,cmap="gray")
    
    plt.subplot(2, 2, 4)
    plt.title("Result")
    plt.imshow(result,cmap="gray")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述

    参考文献

    [1] https://opencv.org/
    [2] 李立宗. OpenCV轻松入门:面向Python. 北京: 电子工业出版社,2019

  • 相关阅读:
    进一步理解函数
    基于Redis的分布式锁安全吗?(上)
    2023年亚太杯数学建模思路 - 案例:最短时间生产计划安排
    Windows环境同时安装多个版本的Python解释器(python2和python3)(超详细)
    浅述数据中心供配电系统解决方案及产品选型
    编程小白如何成为大神?大学新生的最佳入门攻略
    07_sentinel—QPS—流控规则
    大数据ClickHouse进阶(八):ClickHouse的with子句
    web请求cookie中expires总结
    【毕业设计】机器视觉二维码识别检测 - python opencv
  • 原文地址:https://blog.csdn.net/FriendshipTang/article/details/127822970