基于 U-net 的裂缝检测

简介: 基于 U-net 的裂缝检测

使用人工智能将结构检测带入 21 世纪!


问题陈述


虽然新技术几乎改变了我们生活的方方面面,但建筑领域似乎正在努力迎头赶上。目前,建筑物的结构状况仍主要由人工检查。简单来说,即使现在需要检查结构是否有任何损坏,工程师也会手动检查所有表面并拍摄一堆照片,同时记录任何裂缝的位置。然后需要在办公室再花几个小时来整理所有照片和笔记,试图从中做出有意义的报告。显然,这是一个费力、昂贵且主观的过程。最重要的是,由于结构的某些部分存在访问限制且难以到达,因此会引起安全问题。举个例子,金门大桥需要定期检查。换句话说,直到最近,还会有受过专门训练的人爬过这座风景如画的建筑,检查它的每一个位置。


幸运的是,可以部署无人驾驶飞机(例如无人机)来拍照,但仍然需要一个人花费数小时和数小时来检查拍摄的每张照片是否有损坏迹象。


这就是我们想要彻底改变检查过程的工作。更具体地说,深度学习通过训练我们的模型能够代替人类完成检测结构照片裂缝的繁琐任务。


根据照片进行裂纹检测分为三个步骤:


  • 图像被分成多个 patches,每个 patch 被分配一个 crack 或 non-crack 标签
  • 在任何检测到的裂纹周围绘制一个矩形
  • 每个图像都标有裂纹或非裂纹


使用图像块分类(左)、边界框回归(中)和像素分割(右)进行裂缝检测(Dais 等人,2021 年)


虽然用于裂缝检测的深度学习方法已针对混凝土表面或沥青进行了广泛研究,但在基于视觉的评估方面以及专门用于砖砌体表面缺陷检测方面的研究很少。我们工作的重点是检测砖石表面照片上的裂缝,包括补丁和像素级别。


数据集准备


训练深度学习模型最重要的部分是数据;模型的准确性在很大程度上取决于数据的质量和数量。真实世界的表现越好,模型在真实结构上“工作”的机会就越高。毫无疑问,与混凝土或沥青相比,砖石表面的均匀度较低,噪音也明显较大。此外,没有可用的砖石表面裂缝照片数据集。为了解决数据不足的问题,我在网上查找了相关的照片,同时我拿着相机把格罗宁根市中心的所有裂缝都拍了下来!


已开发的深度学习方法的一个普遍缺陷是,它们在单调背景上进行测试时取得了显著的效果,但在复杂背景的图像上进行测试时,它们的准确性会严重下降。窗户、门、装饰品、标签、灯、电缆、植被等物体在裂缝检测过程中可以被表征为噪声,网络需要学习消除它们以准确检测裂缝。因此,在拍照时也有意包括了这些物体。

因此,根据包含复杂背景的砖石结构照片准备了一个广泛的数据集,现在我们已准备好进行下一步:训练深度学习模型。


有裂缝和无裂缝的结构图像(Dais 等人,2021 年)


可以在结构立面上找到的物体(Dais 等人,2021 年)


训练模型


关于裂纹检测,本文检查了使用不同CNN将砖石表面图像分类为裂纹和非裂纹的基于 ImageNet 预训练模型效果。考虑的网络是:VGG16、MobileNet、MobileNetV2、InceptionV3、DenseNet121、DenseNet169、ResNet34 和 ResNet50。最好的结果是使用 MobileNet 的预训练模型,MobileNet 是一种轻量级网络,注定要在计算有限的平台上运行。特别注意的是,经过预训练的 MobileNet 获得了 95.3% 的准确率,而当不使用预训练模型时,准确率下降到 89.0%。


使用 MobileNet 获得的混淆矩阵(Dais 等人,2021 年)


对于裂缝分割 U-net 和特征金字塔网络(FPN),一种通用的金字塔表示,并将其与不同的 CNN 相结合,一起作为训练的主干网络。


U-net-MobileNet(U-Net as base-model with MobileNet as backbone)和 FPN-InceptionV3(FPN as base-model with InceptionV3 as backbone)获得了最高的 F1 分数,即 79.6%。未加载预训练的 U-net 和 U-net-MobileNet 的获得了相似的 F1 分数,分别为 75.7% 和 75.4%。因此,使用预训练网络作为主干网络可将 F1 分数提高约 4%。同样,迁移学习似乎可以解决我们很大问题!


用于裂纹分割的数据集的特点是存在严重的类别不平衡,即背景类占据照片的最大部分,而裂纹只存在于有限的像素。由于这种不平衡,如果不采取特殊措施,网络在预测背景类别时往往会变得过于自信,这可能导致裂缝的错误分类和大量的假阴性。为了克服这个问题,研究了不同的损失函数。加权交叉熵损失函数允许网络通过增加正错误成本的权重来关注正类,其表现优于其他函数。


原始图像、ground truth 和使用 U-net-MobileNet 的预测(Dais 等人,2021)

Code

    import os
    folder = {}
    # Use this to easily run the code in different directories/devices
    folder['initial'] = 'C:/Users/jimar/Dimitris/python/'
    # The path where the repository is stored
    folder['main'] = folder['initial'] + 'crack_detection_CNN_masonry/'
    # if folder['main'] == '', then the current working directory will be used
    if folder['main'] == '':
        folder['main'] = os.getcwd()
    import sys
    sys.path.append(folder['main'])
    from config_class import Config
    cnf = Config(folder['main'])
    args = cnf.set_repository()
    # Set some parameters
    IMAGE_DIMS = cnf.IMAGE_DIMS
    BS = cnf.BS
    epochs = cnf.epochs
    INIT_LR = cnf.INIT_LR
    N_FILTERS = cnf.N_FILTERS
    info = cnf.info
    mode = cnf.mode
    # When using DeepCrack, eager execution needs to be enabled
    if args["model"] == 'DeepCrack':
        import tensorflow as tf
        tf.enable_eager_execution()
    from subroutines.HDF5 import HDF5DatasetGeneratorMask
    #%%
    if mode == 'train':
        from keras.preprocessing.image import ImageDataGenerator
        from keras.callbacks import ModelCheckpoint
        from keras.callbacks import CSVLogger
        from subroutines.callbacks import EpochCheckpoint
        from subroutines.callbacks import TrainingMonitor
        from subroutines.visualize_model import visualize_model
        #%%  
        # Prepare model for training
        #
        # Define metrics
        from metrics_class import Metrics
        metrics = Metrics(args).define_Metrics()
        # Define loss
        from loss_class import Loss
        loss = Loss(args).define_Loss()
        # Define optimizer
        from optimizer_class import Optimizer
        opt = Optimizer(args, INIT_LR).define_Optimizer()
        # Define Network and compile model
        from network_class import Network
        model = Network(args, IMAGE_DIMS, N_FILTERS, BS, INIT_LR, opt, loss, metrics).define_Network()
        # Visualize model
        try:
            visualize_model(model, args['architecture'], args['summary'])
        except:
            from subroutines.visualize_model import visualize_model_tf
            visualize_model_tf(model, args['architecture'], args['summary'])
        #%%
        # Data augmentation for training and validation sets
        if args['aug'] == True:
            aug = ImageDataGenerator(rotation_range=20, zoom_range=0.15,
                width_shift_range=0.2, height_shift_range=0.2, shear_range=0.15,
                horizontal_flip=True, fill_mode='nearest')
        else:
            aug = None
        # Load data generators
        trainGen = HDF5DatasetGeneratorMask(args['TRAIN_HDF5'], BS, aug=aug, shuffle=False, binarize=args['binarize'])
        valGen = HDF5DatasetGeneratorMask(args['VAL_HDF5'], BS, aug=aug, shuffle=False, binarize=args['binarize'])
        #%%
        # Callback that streams epoch results to a CSV file
        # https://keras.io/api/callbacks/csv_logger/
        csv_logger = CSVLogger(args['CSV_PATH'], append=True, separator=';')
        # serialize model to JSON
        try:
            model_json = model.to_json()
            with open(args['model_json'], 'w') as json_file:
                json_file.write(model_json)
        except:
            pass
        # Define whether the whole model or the weights only will be saved from the ModelCheckpoint
        # Refer to the documentation of ModelCheckpoint for extra details
        # https://keras.io/api/callbacks/model_checkpoint/
        temp = '{}_{}'.format(info, args['counter']) + "_epoch_{epoch}_" + \
                args['metric_to_plot'] + "_{val_" + args['metric_to_plot'] +":.3f}.h5"
        if args['save_model_weights'] == 'model':
            ModelCheckpoint_file = args["checkpoints"] + temp
            save_weights_only = False
        elif args['save_model_weights'] == 'weights':
            ModelCheckpoint_file = args['weights'] + temp
            save_weights_only = True
        epoch_checkpoint = EpochCheckpoint(args['checkpoints'], args['weights'], args['save_model_weights'],
                            every=args['every'], startAt=args['start_epoch'], info=info, counter=args['counter'])
        training_monitor = TrainingMonitor(args['FIG_PATH'], jsonPath=args['JSON_PATH'], 
                                           startAt=args['start_epoch'], metric=args['metric_to_plot'])
        model_checkpoint = ModelCheckpoint(ModelCheckpoint_file, monitor='val_{}'.format(args['metric_to_plot']), 
                                          verbose=1, save_best_only=True, mode='max', save_weights_only=save_weights_only)
        # Construct the set of callbacks
        callbacks = [csv_logger,
                     epoch_checkpoint,
                     training_monitor,
                     model_checkpoint]   
        #%%  
        # Train the network
        #
        H = model.fit_generator(
            trainGen.generator(),
            steps_per_epoch=trainGen.numImages // BS,
            validation_data=valGen.generator(),
            validation_steps=valGen.numImages // BS,
            epochs=epochs,
            max_queue_size=BS * 2,
            callbacks=callbacks, verbose=1)
    #%%
    elif mode == 'evaluate':
        # load pretrained model/weights
        from evaluate_class import LoadModel
        model = LoadModel(args, IMAGE_DIMS, BS).load_pretrained_model()
        # Do not use data augmentation when evaluating model: aug=None
        evalGen = HDF5DatasetGeneratorMask(args['EVAL_HDF5'], BS, aug=None, shuffle=False, binarize=args['binarize'])
        # Use the pretrained model to fenerate predictions for the input samples from a data generator
        predictions = model.predict_generator(evalGen.generator(),
                                              steps=evalGen.numImages // BS+1, max_queue_size=BS * 2, verbose=1)
        # Define folder where predictions will be stored
        predictions_folder = '{}{}/'.format(args['predictions'], args['pretrained_filename'])
        # Create folder where predictions will be stored
        cnf.check_folder_exists(predictions_folder)
        # Visualize  predictions
        # Create a plot with original image, ground truth and prediction
        # Show the metrics for the prediction
        # Output will be stored in a subfolder of the predictions folder (args['predictions_subfolder'])
        from subroutines.visualize_predictions import Visualize_Predictions
        Visualize_Predictions(args, predictions)

    结论


    通过我们的研究,我们展示了建筑行业的现代化,特别是检查过程的现代化是可行的。当然,这些新技术有着无限的可能性,只有通过进一步的研究才能揭示出来。

    使用 3D 场景重建进行裂缝检测


    相关文章
    |
    5月前
    云效静态代码检测可以检测.net吗?
    云效静态代码检测可以检测.net吗?
    29 1
    |
    8月前
    |
    存储 开发框架 .NET
    ASP.NET检测实验室LIMS系统源码
    分析业务流程,包括任务下达、采样、分样、预处理、样品登录、分析项目分配、结果输入(自动采集与手工录入)、自动计算、报警提示、数据审核(多级审核)、报告生成、数据传送与发布等全过程。
    |
    12月前
    |
    传感器 机器学习/深度学习 编解码
    将点云与RGB图像结合,谷歌&Waymo提出的4D-Net,成功检测远距离目标
    将点云与RGB图像结合,谷歌&Waymo提出的4D-Net,成功检测远距离目标
    165 0
    |
    12月前
    |
    机器学习/深度学习 人工智能 算法
    R2AU-Net: 基于循环残差注意力和半监督学习范式的道路裂缝分割算法
    R2AU-Net: 基于循环残差注意力和半监督学习范式的道路裂缝分割算法
    145 0
    |
    机器学习/深度学习 编解码 人工智能
    诺亚最新!AOP-Net:一体式3D检测和全景分割的感知网络
    本文提出了一种基于LiDAR的多任务框架——一体感知网络(AOP-Net),该框架结合了3D检测和全景分割。论文开发了双任务3D主干,以从输入的LiDAR点云中提取全景和检测级特征。此外,还设计了一个新的2D主干,将多层感知器(MLP)和卷积层交织在一起,以进一步提高检测任务性能。最后提出了一种新的模块,通过恢复在3D主干中的下采样操作期间丢弃的有用特征来引导检测头。该模块利用估计的实例分割掩码从每个候选目标中恢复详细信息。AOP-Net在nuScenes基准上为3D目标检测和全景分割任务实现了最先进的性能。此外,实验表明,论文的方法很容易适应任何基于BEV的3D目标检测方法,并显著提高了其性
    诺亚最新!AOP-Net:一体式3D检测和全景分割的感知网络
    |
    Linux C# Docker
    推荐基于.NetCore一款高性能敏感词检测开源库
    一款基于.Net开发的、高性能敏感词工具箱,支持繁简互换、全角半角互换,拼音模糊搜索等功能。功能强大、高性能,秒级检测亿级别的文章。
    277 0
    推荐基于.NetCore一款高性能敏感词检测开源库
    |
    机器学习/深度学习 人工智能 计算机视觉
    YOLOv7 在 ML.NET 中使用 ONNX 检测对象
    本文介绍如何在 ML.NET 中使用 YOLOv7 的 ONNX 模型来检测图像中的对象。
    286 0
    YOLOv7 在 ML.NET 中使用 ONNX 检测对象
    通过JavaScript或PHP检测Andro“.NET研究”id设备
      随着乔布斯的回归,iPad2的发布,看来移动端的开发话题越来越火热了。在此列出一些能够在iOS的最大竞争者——安卓(Android)系统的检测方法。   JavaScript判断方法   搜索user agent字符串中的Android单词是最省事儿的方法: 1.
    903 0
    在.NetCore中使用Myrmec检测文件真实格式
    Myrmec 是什么? Myrmec 是一个用于检测文件格式的库,Myrmec不同于其它库或者手写检测代码,Myrmec不依赖文件扩展名(在实际使用中,你的用户很可能使用虚假的扩展名欺骗你的应用程序),Myrmec会检测文件的二进制头,并在其元数据库中匹配来获得文件的格式。
    1127 0
    |
    Windows
    控制台安装跟检测Microsoft.Net Framework
    1、检测 每一个版本的.Net Framework的安装过程都会在Windows目录下的\Microsoft.NET\Framework目录中生成一个子目录(安装目录)。 比如说,假设Windows目录在C盘且不曾在安装OS时重命名过Windows目录,那么.Net Framework 3.5的安装目录应该是: C:\Windows\Microsoft.NET\Framework\v3.5 在这个目录下应该有一个该版本的MSBuild.exe,我们执行 MSBuild /version 应该能得到版本信息。
    1432 0