zoukankan      html  css  js  c++  java
  • opencv之膨胀与腐蚀

    腐蚀和膨胀 Erosion/Dilation

    erosion/dilation,用白话说,就是让图像亮的区域收缩和扩张.

    原理

    • 我们定义一个卷积核矩阵.这个矩阵可以是任何形状的,但通常而言,是矩形或者圆形的.同时要定义一个锚点位置.
    • 用这个卷积核矩阵挨个地划过原始图像矩阵,同时更改锚点位置的像素值.
    • 锚点位置的像素值更改为卷积核矩阵覆盖的有效像素值中的最大值/最小值(分别对应膨胀/腐蚀).
      什么叫"有效"像素值呢?就是卷积核中不为0的那些位置.用公式表达的话,即:

    膨胀和腐蚀,说白了就是个求"卷积核所表示的局部"的最大值最小值的过程.

    我们来看一个例子:

    import cv2
    import numpy as np
    def test1():
        img = np.zeros((10,10,1),np.uint8)
        img[3:7,3:7,:] = 255
        img[4:6,4:6,:] = 200
        
        kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
        erosion_dst = cv2.erode(img, kernel1)
        print(erosion_dst)
    

    首先我们创建一个10 x 10的图像,像素如下:

    [[  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0 255 255 255 255   0   0   0]
     [  0   0   0 255 200 200 255   0   0   0]
     [  0   0   0 255 200 200 255   0   0   0]
     [  0   0   0 255 255 255 255   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]]
    

    我们创建一个卷积核:

    kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
    

    getStructuringElement api

    三个参数分别为卷积核的形状/大小/锚点位置. 默认锚点在矩阵的中心位置.

    形状有三种

    上面代码中我们创建的3 x 3矩形卷积核如下

    用这个卷积核对原始图像做腐蚀后得到的矩阵如下

    即矩阵有如下变化:

    [[  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0 255 255 255 255   0   0   0]
     [  0   0   0 255 200 200 255   0   0   0]
     [  0   0   0 255 200 200 255   0   0   0]
     [  0   0   0 255 255 255 255   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]]
     
    -->
    
    [[  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0 200 200   0   0   0   0]
     [  0   0   0   0 200 200   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]]
    

    我们考虑第三行第四列img[2,3,:]这个像素.当我们的卷积核矩阵的锚点位置与该像素重合时,我们取周边所有像素的最小值.最小值为0.所以该位置的像素值变为0. 其余位置的像素值同理可求.

    我们稍微改一下我们的代码,然后再看一下不同卷积核作用下的不同结果,会理解的更清楚

    import cv2
    import numpy as np
    def test1():
        img = np.zeros((10,10,1),np.uint8)
        img[3:7,3:7,:] = 255
        img[4:6,4:6,:] = 200
        
        kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
        print(kernel1)
        erosion_dst = cv2.erode(img, kernel1)
        print(erosion_dst)
    
    def test2():
        img = np.zeros((10,10,1),np.uint8)
        img[3:7,3:7,:] = 255
        img[4:6,4:6,:] = 200
        img[2,4,:] = 100
        
        kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
        erosion_dst = cv2.erode(img, kernel1)
        print(erosion_dst)
        
        kernel2 = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
        erosion_dst2 = cv2.erode(img, kernel2)
        print(erosion_dst2)
    
    test2()
    
    

    我们把原始图像矩阵改为

    [[  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0 100   0   0   0   0   0]
     [  0   0   0 255 255 255 255   0   0   0]
     [  0   0   0 255 200 200 255   0   0   0]
     [  0   0   0 255 200 200 255   0   0   0]
     [  0   0   0 255 255 255 255   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]
     [  0   0   0   0   0   0   0   0   0   0]]
    

    用kernal1时,kernal1如下:

    以第四行,第五列的像素为例,用卷积核的锚点与之对应,此时计算的是其周围八个像素的最小值,最小值为0.
    所以我们得到的矩阵为

    当我们用kernal2时,kernal2如下:

    对第四行,第五列的像素,用卷积核的锚点与之对应,此时计算的不再是周围八个像素的最小值,而是其正上方,正下方,正左边,正右边的四个像素的最小值.该值为100.
    所以我们得到的矩阵为

    opencv示例

    from __future__ import print_function
    import cv2 as cv
    import numpy as np
    import argparse
    
    erosion_size = 0
    max_elem = 2
    max_kernel_size = 21
    
    title_trackbar_element_type = 'Element:
     0: Rect 
     1: Cross 
     2: Ellipse'
    title_trackbar_kernel_size = 'Kernel size:
     2n +1'
    title_erosion_window = 'Erosion Demo'
    title_dilatation_window = 'Dilation Demo'
    
    def erosion(val):
        erosion_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_erosion_window)
        erosion_type = 0
        val_type = cv.getTrackbarPos(title_trackbar_element_type, title_erosion_window)
        if val_type == 0:
            erosion_type = cv.MORPH_RECT
        elif val_type == 1:
            erosion_type = cv.MORPH_CROSS
        elif val_type == 2:
            erosion_type = cv.MORPH_ELLIPSE
        element = cv.getStructuringElement(erosion_type, (2*erosion_size + 1, 2*erosion_size+1), (erosion_size, erosion_size))
        erosion_dst = cv.erode(src, element)
        cv.imshow(title_erosion_window, erosion_dst)
        
    def dilatation(val):
        dilatation_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_dilatation_window)
        dilatation_type = 0
        val_type = cv.getTrackbarPos(title_trackbar_element_type, title_dilatation_window)
        if val_type == 0:
            dilatation_type = cv.MORPH_RECT
        elif val_type == 1:
            dilatation_type = cv.MORPH_CROSS
        elif val_type == 2:
            dilatation_type = cv.MORPH_ELLIPSE
        element = cv.getStructuringElement(dilatation_type, (2*dilatation_size + 1, 2*dilatation_size+1), (dilatation_size, dilatation_size))
        dilatation_dst = cv.dilate(src, element)
        cv.imshow(title_dilatation_window, dilatation_dst)
    
    src = cv.imread("/home/sc/disk/keepgoing/opencv_test/j.png")
    cv.namedWindow(title_erosion_window)
    cv.createTrackbar(title_trackbar_element_type, title_erosion_window , 0, max_elem, erosion)
    cv.createTrackbar(title_trackbar_kernel_size, title_erosion_window , 0, max_kernel_size, erosion)
    
    cv.namedWindow(title_dilatation_window)
    cv.createTrackbar(title_trackbar_element_type, title_dilatation_window , 0, max_elem, dilatation)
    cv.createTrackbar(title_trackbar_kernel_size, title_dilatation_window , 0, max_kernel_size, dilatation)
    
    erosion(0)
    dilatation(0)
    cv.waitKey()
    

    通过createTrackbar在窗口上创建两个bar,方便我们看不同种类不同大小的卷积核的影响.

    cv.createTrackbar(title_trackbar_element_type, title_erosion_window , 0, max_elem, erosion)
    cv.createTrackbar(title_trackbar_kernel_size, title_erosion_window , 0, max_kernel_size, erosion)
    

    原始图片:

    处理效果:

    opencv实现

    https://github.com/opencv/opencv/blob/master/modules/imgproc/src/morph.dispatch.cpp

  • 相关阅读:
    List集合
    ArrayList_toArray
    Collection集合基础知识
    Array类的使用
    16.10
    16.9
    16.8
    16.7
    16.6
    16.5
  • 原文地址:https://www.cnblogs.com/sdu20112013/p/11644684.html
Copyright © 2011-2022 走看看