• opencv之形态变换


    形态变换

    opencv之膨胀与腐蚀中介绍了Dilation/Erosion的原理.建议先读这一篇,搞懂原理. 这样就可以很轻松地理解为什么本文的这些形态变换可以取得相应的效果.
    基于此,我们可以组合出更多的形态变换以达到不同的目的.
    有以下几种:

    • Opening
    • Closing
    • Morphological Gradient
    • Top Hat
    • Black Hat

    Opening


    先腐蚀再膨胀,可以把较小的目标去除.比如:

    Closing


    可以把物体内的小黑洞消除.比如:

    Morphological Gradient


    可以提取出物体的轮廓.
    比如下图,腐蚀和膨胀对物体内部的像素影响不大,(内部的局部最大值和最小值差不多),所以做完插值以后,边缘的像素值差比较大,内部像素差值变为0,从而提取出物体轮廓.

    Top Hat


    Black Hat


    from __future__ import print_function
    import cv2 as cv
    import numpy as np
    import argparse
    morph_size = 0
    max_operator = 4
    max_elem = 2
    max_kernel_size = 21
    title_trackbar_operator_type = 'Operator:
     0: Opening - 1: Closing  
     2: Gradient - 3: Top Hat 
     4: Black Hat'
    title_trackbar_element_type = 'Element:
     0: Rect - 1: Cross - 2: Ellipse'
    title_trackbar_kernel_size = 'Kernel size:
     2n + 1'
    title_window = 'Morphology Transformations Demo'
    morph_op_dic = {0: cv.MORPH_OPEN, 1: cv.MORPH_CLOSE, 2: cv.MORPH_GRADIENT, 3: cv.MORPH_TOPHAT, 4: cv.MORPH_BLACKHAT}
    def morphology_operations(val):
        morph_operator = cv.getTrackbarPos(title_trackbar_operator_type, title_window)
        morph_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_window)
        morph_elem = 0
        val_type = cv.getTrackbarPos(title_trackbar_element_type, title_window)
        if val_type == 0:
            morph_elem = cv.MORPH_RECT
        elif val_type == 1:
            morph_elem = cv.MORPH_CROSS
        elif val_type == 2:
            morph_elem = cv.MORPH_ELLIPSE
        element = cv.getStructuringElement(morph_elem, (2*morph_size + 1, 2*morph_size+1), (morph_size, morph_size))
        operation = morph_op_dic[morph_operator]
        dst = cv.morphologyEx(src, operation, element)
        cv.imshow(title_window, dst)
    
    src = cv.imread("/home/sc/disk/keepgoing/opencv_test/j.png")
    if src is None:
        print('Could not open or find the image: ', args.input)
        exit(0)
        
    cv.namedWindow(title_window)
    cv.createTrackbar(title_trackbar_operator_type, title_window , 0, max_operator, morphology_operations)
    cv.createTrackbar(title_trackbar_element_type, title_window , 0, max_elem, morphology_operations)
    cv.createTrackbar(title_trackbar_kernel_size, title_window , 0, max_kernel_size, morphology_operations)
    morphology_operations(0)
    cv.waitKey()
    
    

    可以用上述代码感受一下对不同图片,采用不同操作,不同参数,得到的结果是怎样的.


    利用形态变换提取图像中的水平线

    看一个具体的例子
    我们想从下图中提取出水平线出来.

    前面讲过,膨胀和腐蚀都是通过卷积核去定义一个要从什么样的区域去取局部极大值或局部极小值. 那为了完成水平线的提取,我们可以定义自己的特定形状的卷积核去完成这个功能.

    # 形态变换实现水平线和音符提取
    import cv2 as cv
    import numpy as np
    
    def test():
        src = cv.imread("/home/sc/disk/keepgoing/opencv_test/music.png",cv.IMREAD_COLOR)
        gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
        gray = cv.bitwise_not(gray)
         cv.imshow("gray",gray)
    
        horizontal = np.copy(gray)
        vertical = np.copy(gray)
        
        ##设计特定形状卷积核
        cols = horizontal.shape[1]
        horizontal_size = cols // 30
        horizontalStructure = cv.getStructuringElement(cv.MORPH_RECT, (horizontal_size, 1))
        print(horizontalStructure)
        
        horizontal1 = cv.erode(horizontal, horizontalStructure)
        cv.imshow("h1",horizontal1)
    
        horizontal2 = cv.dilate(horizontal1, horizontalStructure)
        cv.imshow("h2",horizontal2)
        
        ##设计特定形状卷积核
        rows = vertical.shape[0]
        verticalsize = rows // 30
        verticalStructure = cv.getStructuringElement(cv.MORPH_RECT, (1, verticalsize))
        
        vertical = cv.erode(vertical, verticalStructure)
        vertical = cv.dilate(vertical, verticalStructure)
        cv.imshow("v",vertical)
        
    test()
    if 27 == cv.waitKey(0):
        cv.destroyAllWindows()
    

    首先我们完成将图像的预处理.

    这里用了cv.bitwise_not(gray)将我们关注的部分变为亮的.不关注的变为暗的. 因为膨胀和腐蚀都是针对亮的区域而言的.指亮的区域的扩张或收缩.

    接下来就是如何定义我们的卷积核呢?
    以音符的提取为例,我们希望把水平方向的白色横线去除,即我们更关注垂直方向的像素点. 水平方向的白色横线的上下位置基本是黑色的背景. 所以我们需要的卷积核是一个如下:

    这样对白色横线上的像素点,通过取该像素点上下方若干个点的最小值,把该像素点灰度值变为0.从而达到去除白色横线的目的.
    最终得到如下:

  • 相关阅读:
    root用户javac可以执行sudo后command not found问题
    机器学习 KNN算法实现 (鸢尾花)
    机器学习 KNN分类算法简单介绍+数据集拆分
    机器学习的一般流程
    机器学习算法的性能评价
    Opencv 自带函数(Haar)的人脸检测
    Opencv 的基础认识
    labelme 的学习
    天梯赛总结CCCC
    VScode配置c,c++编译环境
  • 原文地址:https://www.cnblogs.com/sdu20112013/p/11672634.html
Copyright © 2020-2023  润新知