• zhang-suen算法提取裂缝图骨架


    一、算法介绍

    zhang-suen是一种应用较广的细化算法,也是骨架提取算法常用的算法。

    初始条件: 输入是一个二值化图像,零点表示背景,非零值表示前景。算法的目标是细化前景物体的边缘。

    迭代条件:Zhang-Suen 算法包含两个迭代步骤,通常会交替执行直到不再发生任何改变。这两个步骤是:

    第一步,算法会遍历图像的每个像素,对于前景色将会检查是否满足一下条件。

    • 当前像素为白色
    • 当前像素P的 8 邻域上下、左右、左上、左下、右上、右下中至少有一个黑色像素
    • 当前像素的 8 邻域中,白色像素数量在2到6之间

    如果以上条件全部满足,那么将当前像素标记为黑色

    第二步中,算法再次遍历图像的每个像素,对于前景色将会检查其是否满足以下条件:

    • 当前像素为白色
    • 当前像素的 8 邻域中,至少有一个是黑色
    • 当前像素的 8 邻域中,白色像素数量在2到6之间
    • 当前像素的 8 邻域的黑色像素不是连通的(即不是一个连通分量)

    如果以上条件全部满足,那么将当前像素标记为黑色(背景)。

    迭代终止条件: 迭代步骤1和步骤2将交替执行,直到不再有像素可以被删除。如果经过一轮迭代后,没有像素被删除,那么算法终止,否则继续下一轮迭代。

    结果: 经过多轮迭代后,Zhang-Suen 算法将细化图像中白色目标对象的边缘,最终得到一个具有一像素宽度的骨架。

    具体的实现可能因编程语言和图像处理库的不同而有所不同,但上述描述了 Zhang-Suen 算法的基本原理和步骤。

    如果想要选择手写算法,可以参考下面两篇

    激光条纹中心提取——Zhang-Suen法python

    视觉组学习内容:Zhang-Suen骨架提取算法

    二、skimage实现骨架提取

    原先我也使用过手写的,但大多还是有逻辑错误,运行超时等情况,后面调研发现在skimage的morphology模块中实现了zhang-suen算法,我们需要保证我们的图像是二值图,这里用的是Otsu阈值方法来自动选择阈值,然后将图像二值化,将图像分成前景和背景。

    1. from skimage.filters import threshold_otsu,median
    2. from skimage.morphology import skeletonize,dilation,disk
    3. from skimage import io, morphology
    4. import matplotlib.pyplot as plt
    5. plt.switch_backend('TkAgg')
    6. # 使用Otsu阈值方法进行二值化处理
    7. path = r"D:\PythonProject\RoadCrack\dimension2_data\num\001.png"
    8. image = io.imread(path, as_gray=True)
    9. thresh = threshold_otsu(image)
    10. binary = image > thresh
    11. skeleton = skeletonize(binary)
    12. io.imshow(skeleton)
    13. # io.imsave('output.png', skeleton)
    14. io.show()

    原图:

    运行效果: 

    可以看见图片上面还有一点瑕疵,可以使用一些图像预处理,帮助减小图像中的毛刺或噪声,同时改善图像的质量。

    根据我对我自己数据集的测试,采用膨胀、中值滤波和闭运算等算法可以有效的减小图像中的瑕疵。

    我使用的是裂缝森林数据集,你可以尝试其他的一些形态学方法,尽量早到适用于自己数据集的组合,下面是我经过测试获得的组合,大家可以借鉴。

    1. from skimage.filters import threshold_otsu,median
    2. from skimage.morphology import skeletonize,dilation,disk
    3. from skimage import io, morphology
    4. import matplotlib.pyplot as plt
    5. plt.switch_backend('TkAgg')
    6. # 使用Otsu阈值方法进行二值化处理
    7. path = r"D:\PythonProject\RoadCrack\dimension2_data\num\001.png"
    8. image = io.imread(path, as_gray=True)
    9. thresh = threshold_otsu(image)
    10. binary = image > thresh
    11. binary = dilation(binary, disk(3))
    12. binary = median(binary, selem=morphology.disk(5))
    13. binary = dilation(binary, disk(2))
    14. binary = median(binary, selem=morphology.disk(5))
    15. # 添加闭运算
    16. selem = morphology.disk(3)
    17. binary = morphology.closing(binary, selem)
    18. skeleton = skeletonize(binary)
    19. io.imshow(skeleton)
    20. # io.imsave('output.png', skeleton)
    21. io.show()

    三、数据集问题

    你可以从网上可以找到开源数据集进行测试,我这里采用的是裂缝森林的数据集,你可以从Kaggle上找到crackforest | Kaggle。如果你下载的数据集是mat后缀的,可以使用下面这个脚本进行转换。

    1. # Mat2png.py
    2. from os.path import isdir
    3. from scipy import io
    4. import os, sys
    5. import numpy as np
    6. from PIL import Image
    7. if __name__ == '__main__':
    8. file_path = './groundTruth/'
    9. png_img_dir = './groundTruthPngImg/'
    10. if not isdir(png_img_dir):
    11. os.makedirs(png_img_dir)
    12. image_path_lists = os.listdir(file_path)
    13. images_path = []
    14. for index in range(len(image_path_lists)):
    15. image_file = os.path.join(file_path, image_path_lists[index])
    16. # print(image_file)#./CrackForest-dataset-master/groundTruth/001.mat
    17. images_path.append(image_file)
    18. image_mat = io.loadmat(image_file)
    19. segmentation_image = image_mat['groundTruth']['Segmentation'][0]
    20. segmentation_image_array = np.array(segmentation_image[0])
    21. image = Image.fromarray((segmentation_image_array - 1) * 255)
    22. png_image_path = os.path.join(png_img_dir, "%s.png" % image_path_lists[index][0:3])
    23. image.save(png_image_path)

    转换后的图片可能还存在下面的问题,我获得的裂缝森林数据集不是标准的二值图,如果不是细心,真没发现它的标签存在问题

     远看没有任何的问题,如果你使用图片查看器或ps放大查看就会看到下面的情况:

    这种图片是有问题的,所以必须要进行二值化操作。当然这里也可以转灰度后使用阈值法:

    1. std = 127.5
    2. mask[mask > std] = 255
    3. mask[mask < std] = 0
    4. mask = mask.astype("uint8")
  • 相关阅读:
    CSS的盒子模型:掌握网页设计的基石!
    Java使用joml计算机图形学库,将3D坐标旋转正交投影转为2D坐标
    2013年12月12日 Go生态洞察:深入Go Playground的内部实现
    Java List 树形结构数据构造
    基于SpringBoot+Vue的旅游管理系统
    play() failed because the user didn‘t interact with the document优化媒体不能自动播放
    Java笔记13—控制语句(分支、循环、转向)
    java项目_第168期ssm二手车交易网站-_计算机毕业设计
    2024年华为OD机试真题-生成哈夫曼树-Java-OD统一考试(C卷)
    云原生技术盛会KubeCon即将召开!亚马逊云科技作为钻石赞助商参会
  • 原文地址:https://blog.csdn.net/m0_62919535/article/details/133211055