• OpenCV4【9】-图像形态学处理


    形态学处理 主要针对残缺图像、有斑点图像,不同区域有粘连的图像,使其变得丰满,或者去除多余的像素,也有类似去噪的作用;

    形态学处理 的方法有 腐蚀、膨胀、开运算、闭运算、顶帽、底帽、形态学梯度;

    形态学处理 通常针对 灰度图,确切的说是二值图,最好是 黑底 白景

    腐蚀

    腐蚀逻辑:和滤波一样,也存在一个,只是这个核不是进行卷积运算,而是取核中像素最小值代替锚点的像素值,    【类似 最小 池化】

    如果图像为 黑底白景,那么核中都是黑底或者白景时,保持不变,如果核中有黑有白,那锚点就会被替换成黑色,

    这样黑色区域就变大了,白色区域就变小了,就像被腐蚀了一样,

    反之就是膨胀了

    先看个实例吧

    img = cv.imread('imgs/fs3.jpg')
    img_cvt = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    ret, img_thr = cv.threshold(img_cvt, 200, 255, cv.THRESH_BINARY)
    kernel = cv.getStructuringElement(cv.MORPH_CROSS, (3, 3))        # MORPH_CROSS  MORPH_RECT  MORPH_ELLIPSE
    dst = cv.erode(img_thr, kernel, iterations=1)
    
    cv.imshow("img",img)
    cv.imshow("img_thr",img_thr)
    cv.imshow("dst",dst)
    cv.waitKey(0)
    cv.destroyAllWindows()

    效果图

    可以看到 字体 模糊了,像腐蚀了一样

    可以看到 字体变小了,且模糊了,像腐蚀了一样

    创建 核

    前面提到 腐蚀操作 需要一个 核,opencv 提供 getStructuringElement() 函数来创建核;

    可以创建 矩形核,十字核,椭圆核

    kernel=cv2.getStructuringElement(shape,ksize,anchor)
            shape:核的形状
                    cv2.MORPH_RECT: 矩形
                    cv2.MORPH_CROSS: 十字形(以矩形的锚点为中心的十字架)
                    cv2.MORPH_ELLIPSE:椭圆(矩形的内切椭圆)
                    
            ksize: 核的大小,矩形的宽,高格式为(width,height)
            anchor: 核的锚点,默认值为(-1,-1),即核的中心点

    示例

    k = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))     # 矩形核
    print(k)
    # [[1 1 1 1 1]
    #  [1 1 1 1 1]
    #  [1 1 1 1 1]
    #  [1 1 1 1 1]
    #  [1 1 1 1 1]]
    k = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))    # 椭圆核
    print(k)
    # [[0 0 1 0 0]
    #  [1 1 1 1 1]
    #  [1 1 1 1 1]
    #  [1 1 1 1 1]
    #  [0 0 1 0 0]]
    k = cv.getStructuringElement(cv.MORPH_CROSS, (5, 5))      # 十字核
    print(k)
    # [[0 0 1 0 0]
    #  [0 0 1 0 0]
    #  [1 1 1 1 1]
    #  [0 0 1 0 0]
    #  [0 0 1 0 0]]

    腐蚀函数

    dst=cv2.erode(src,kernel,anchor,iterations,borderType,borderValue):
            src: 输入图像对象矩阵,为二值化图像
            kernel:进行腐蚀操作的核,可以通过函数getStructuringElement()获得
            anchor:锚点,默认为(-1,-1)
            iterations:腐蚀操作的次数,默认为1
            borderType: 边界种类,有默认值
            borderValue:边界值,有默认值

    膨胀

    膨胀逻辑:与腐蚀相反,也存在一个核,只是取核中最大的像素值替代锚点的像素值,      【类似 最大 池化】

    如果是 黑底白景,那么 黑色区域 会变小,白色区域 会变大,相当于膨胀了

    膨胀函数

    dst = cv2.dilate(src,kernel,anchor,iterations,borderType,borderValue)
            src: 输入图像对象矩阵,为二值化图像
            kernel:进行腐蚀操作的核,可以通过函数getStructuringElement()获得
            anchor:锚点,默认为(-1,-1)
            iterations:腐蚀操作的次数,默认为1
            borderType: 边界种类
            borderValue:边界值

    示例

    img = cv.imread('imgs/fs3.jpg')
    img_cvt = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    ret, img_thr = cv.threshold(img_cvt, 200, 255,cv.THRESH_BINARY)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (2, 2))
    dst = cv.dilate(img_thr, kernel, iterations=3)          # 膨胀 3 次看看效果,很明显
    
    cv.imshow("img",img)
    cv.imshow("img_thr",img_thr)
    cv.imshow("dst",dst)
    cv.waitKey(0)
    cv.destroyAllWindows()

    效果图

    可以看到 字体变粗了,膨胀 3 次,效果明显

    开运算、闭运算、顶帽、底帽、形态学梯度

    • 开运算:先进行腐蚀操作,后进行膨胀操作,主要用来去除一些较亮的部分,即先腐蚀掉不要的部分,再进行膨胀。
    • 闭运算:先进行膨胀操作,后进行腐蚀操作,主要用来去除一些较暗的部分。
    • 形态学梯度:膨胀运算结果减去腐蚀运算结果,可以拿到轮廓信息
    • 顶帽运算:原图像减去开运算结果。
    • 底帽运算:原图像减去闭运算结果。

    函数

    dst = cv2.morphologyEx(src,op,kernel,anchor,iterations,borderType,borderValue)
            src: 输入图像对象矩阵,为二值化图像
            op: 形态学操作类型
                cv2.MORPH_OPEN    开运算
                cv2.MORPH_CLOSE   闭运算
                cv2.MORPH_GRADIENT 形态梯度
                cv2.MORPH_TOPHAT   顶帽运算
                cv2.MORPH_BLACKHAT  底帽运算
                
            kernel:进行腐蚀操作的核,可以通过函数getStructuringElement()获得
            anchor:锚点,默认为(-1,-1)
            iterations:腐蚀操作的次数,默认为1
            borderType: 边界种类
            borderValue:边界值

    示例

    img = cv.imread('imgs/fs3.jpg')
    img_cvt = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    ret, img_thr = cv.threshold(img_cvt, 200, 255, cv.THRESH_BINARY)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (2, 2))
    open = cv.morphologyEx(img_thr, cv.MORPH_OPEN, kernel, iterations=1)            # 开运算
    close = cv.morphologyEx(img_thr, cv.MORPH_CLOSE, kernel, iterations=1)          # 闭运算
    gradient = cv.morphologyEx(img_thr, cv.MORPH_GRADIENT, kernel, iterations=1)    # 形态学梯度
    tophat = cv.morphologyEx(img_thr, cv.MORPH_TOPHAT, kernel, iterations=1)        # 顶帽
    blackhat = cv.morphologyEx(img_thr, cv.MORPH_BLACKHAT, kernel, iterations=1)    # 底帽
    
    images = [img_thr, open, close, gradient, tophat, blackhat]
    titles = ["img_thr", "open", "close", "gradient", "tophat", "blackhat"]
    for i in range(6):
        plt.subplot(2, 3, i+1), plt.imshow(images[i], "gray")
        plt.title(titles[i]), plt.xticks([]), plt.yticks([])
    plt.show()

    效果图

    应用案例

    有如下一张中文图片,当我们进行字符切割时,常需要知道其中的汉字是否带下划线,方便进行后续处理。

    我们首先想到的可能是使用霍夫直线检测算法,但是直接检测时,会有很多干扰。

    我们可以通过采用一个横向的矩阵核,来腐蚀字体,使图片中只剩下下划线,然后再进行霍夫直线检测,这样干扰小,准确度会高很多

    代码如下

    img = cv.imread('imgs/fs.png')
    img_cvt = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    # 膨胀
    # ret, img_thr = cv.threshold(img_cvt, 100, 255, cv.THRESH_BINARY)
    # # 由于是1*30的矩阵,字体会被横向空隙的白色腐蚀掉,而下划线横向都是黑色,不会腐蚀
    # kernel = cv.getStructuringElement(cv.MORPH_RECT, (30, 1))
    # dst = cv.dilate(img_thr, kernel, iterations=1)  # 由于是白底黑字,所有进行膨胀操作来去除黑色字体
    
    # 腐蚀
    ret, img_thr = cv.threshold(img_cvt, 100, 255, cv.THRESH_BINARY_INV)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (30, 1))
    dst = cv.erode(img_thr, kernel, iterations=1)
    cv.imshow("img_thr", img_thr)
    cv.imshow("dst", dst)
    cv.waitKey(0)
    cv.destroyAllWindows()

    效果图

    参考资料:

    https://www.cnblogs.com/silence-cho/p/11069903.html  OpenCV-Python学习—形态学处理

  • 相关阅读:
    通过模板类简单实现Spark的JobServer
    aggregate 和 treeAggregate 的对比
    IntelliJ Idea 常用快捷键列表
    dataframe 数据统计可视化---spark scala 应用
    用java api读取HDFS文件
    .net Core 简单中间件使用
    .Net Core Ocelot网关使用熔断、限流 二
    .Net Core Ocelot网关使用 一
    Docker 问题处理
    CentOS 创建用户
  • 原文地址:https://www.cnblogs.com/yanshw/p/15406030.html
Copyright © 2020-2023  润新知