Контекст

Бетонные поверхностные трещины являются основным дефектом строительных конструкций. Инспекция здания, которая проводится для оценки жесткости и прочности на растяжение здания. Обнаружение трещин играет важную роль в осмотре здания, обнаружении трещин и определении состояния здания.

Содержание

Наборы данных содержат изображения различных бетонных поверхностей с трещинами и без них. Данные изображения разделены на две части: негативные (без трещин) и позитивные (с трещинами) в отдельной папке для классификации изображений. Каждый класс имеет 20 000 изображений, всего 40 000 изображений размером 227 x 227 пикселей с каналами RGB. Набор данных создается из 458 изображений с высоким разрешением (4032x3024 пикселя) с помощью метода, предложенного Zhang et al (2016). Выяснилось, что изображения с высоким разрешением сильно различаются по качеству обработки поверхности и условиям освещения. Никакого увеличения данных с точки зрения случайного вращения, переворота или наклона не применяется.

Благодарности

Этот набор данных взят с веб-сайта Mendeley Data — Crack Detection, предоставленного Чагларом Фиратом Озгенелем.

Озгенель, Чаглар Фират (2019), Изображения бетонных трещин для классификации, данные Mendeley, v2 http://dx.doi.org/10.17632/5y9wdsg2zt.2

Научно-исследовательская работа

https://www.researchgate.net/publication/348389736_Image-Based_Surface_Defect_Detection_Using_Deep_Learning_A_Review

Ссылка на набор данных: - https://www.kaggle.com/arunrk7/surface-crack-detection

ИМПОРТ НЕОБХОДИМЫХ БИБЛИОТЕК

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
from sklearn.metrics import confusion_matrix, classification_report
import tensorflow as tf
from pathlib import Path
from sklearn.model_selection import train_test_split

СОЗДАНИЕ СПРАВОЧНИКОВ ДЛЯ ПОЛОЖИТЕЛЬНЫХ И НЕГАТИВНЫХ ИЗОБРАЖЕНИЙ

positive_dir = Path('../input/surface-crack-detection/Positive')
negative_dir = Path('../input/surface-crack-detection/Negative')

ФУНКЦИЯ ДОБАВЛЕНИЯ ЭТИКЕТОК К КАЖДОМУ ПУТИ ИЗОБРАЖЕНИЯ

def generate_df(image_dir, label):
    filepaths = pd.Series(list(image_dir.glob(r'*.jpg')), name='Filepath').astype(str)
    labels = pd.Series(label, name='Label', index=filepaths.index)
    df = pd.concat([filepaths, labels], axis=1)
    return df

СОЗДАНИЕ ОКОНЧАТЕЛЬНОГО ФРЕЙМА ДАННЫХ

positive_df = generate_df(positive_dir, label="POSITIVE")
negative_df = generate_df(negative_dir, label="NEGATIVE")

df = pd.concat([positive_df, negative_df], axis=0).sample(frac=1.0, random_state=1).reset_index(drop=True)
df

РАЗДЕЛЕНИЕ НАБОРА ДАННЫХ НА 70 % ОБУЧАЮЩЕГО НАБОРА И 30 % ТЕСТИРОВАНИЯ

train_df, test_df = train_test_split(df,train_size=0.7,shuffle=True,random_state=42)
Image Data Generator generates batches of tensor image data with real-time data augmentation.
For more insights check the tensorflow official documentation https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator
train_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255,validation_split=0.2)

test_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
flow_from_dataframe checks the path available on the dataframe and then automatically search for the image in train directory. Then it make the desired preprocessing steps available in ImageDataGenerator
More insights can be found from this article https://vijayabhaskar96.medium.com/tutorial-on-keras-imagedatagenerator-with-flow-from-dataframe-8bd5776e45c1
train_data = train_gen.flow_from_dataframe(
    train_df,
    x_col='Filepath',
    y_col='Label',
    target_size=(120, 120),
    color_mode='rgb',
    class_mode='binary',
    batch_size=32,
    shuffle=True,
    seed=42,
    subset='training')
Found 22400 validated image filenames belonging to 2 classes.
val_data = train_gen.flow_from_dataframe(
    train_df,
    x_col='Filepath',
    y_col='Label',
    target_size=(120, 120),
    color_mode='rgb',
    class_mode='binary',
    batch_size=32,
    shuffle=True,
    seed=42,
    subset='validation')
Found 5600 validated image filenames belonging to 2 classes.
test_data = train_gen.flow_from_dataframe(
    test_df,
    x_col='Filepath',
    y_col='Label',
    target_size=(120, 120),
    color_mode='rgb',
    class_mode='binary',
    batch_size=32,
    shuffle=False,
    seed=42)
Found 12000 validated image filenames belonging to 2 classes.

Обучение модели

inputs = tf.keras.Input(shape=(120, 120, 3))
x = tf.keras.layers.Conv2D(filters=16, kernel_size=(3, 3), activation='relu')(inputs)
x = tf.keras.layers.MaxPool2D(pool_size=(2, 2))(x)
x = tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu')(x)
x = tf.keras.layers.MaxPool2D(pool_size=(2, 2))(x)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)

model = tf.keras.Model(inputs=inputs, outputs=outputs)

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['accuracy'])
print(model.summary())
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 120, 120, 3)]     0         
_________________________________________________________________
conv2d (Conv2D)              (None, 118, 118, 16)      448       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 59, 59, 16)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 57, 57, 32)        4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 28, 28, 32)        0         
_________________________________________________________________
global_average_pooling2d (Gl (None, 32)                0         
_________________________________________________________________
dense (Dense)                (None, 1)                 33        
=================================================================
Total params: 5,121
Trainable params: 5,121
Non-trainable params: 0
_________________________________________________________________

Подгонка модели

history = model.fit(train_data,validation_data=val_data,epochs=10,
            callbacks=[tf.keras.callbacks.EarlyStopping(
            monitor='val_loss',
            patience=3,
            restore_best_weights=True)])
At the end of 10th epoch we are getting an accuracy of 0.9793 and validation accuracy of 0.9759.

Потери при обучении и валидации с течением времени

fig = px.line(
    history.history,
    y=['loss', 'val_loss'],
    labels={'index': "Epoch", 'value': "Loss"},
    title="Training and Validation Loss Over Time")
fig.show()

Обучение и проверка точности с течением времени

fig = px.line(
    history.history,
    y=['accuracy', 'val_accuracy'],
    labels={'index': "Epoch", 'value': "Accuracy"},
    title="Training and Validation Accuracy Over Time")
fig.show()

Оценка модели на тестовом наборе

def evaluate_model(model, test_data):
    
    results = model.evaluate(test_data, verbose=0)
    loss = results[0]
    acc = results[1]
    
    print("    Test Loss: {:.5f}".format(loss))
    print("Test Accuracy: {:.2f}%".format(acc * 100))
evaluate_model(model, test_data)

Потеря теста: 0,05720
Точность теста: 97,91%

Точность теста составляет 97,91 %, а потеря при тестировании — 0,05720, что очень хорошо.

Матрица путаницы

y_pred = np.squeeze((model.predict(test_data) >= 0.5).astype(np.int))
cm = confusion_matrix(test_data.labels, y_pred)
clr = classification_report(test_data.labels, y_pred, target_names=["NEGATIVE", "POSITIVE"])
    
plt.figure(figsize=(6, 6))
sns.heatmap(cm, annot=True, fmt='g', vmin=0, cmap='viridis', cbar=False)
plt.xticks(ticks=np.arange(2) + 0.5, labels=["NEGATIVE", "POSITIVE"])
plt.yticks(ticks=np.arange(2) + 0.5, labels=["NEGATIVE", "POSITIVE"])
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.title("Confusion Matrix")
plt.show()

Мы получили 11 749 правильных прогнозов из 12 000 записей в тестовом наборе.

Отчет о классификации

print("Classification Report:\n----------------------\n", clr)
Classification Report:
----------------------
               precision    recall  f1-score   support

    NEGATIVE       0.97      0.99      0.98      5991
    POSITIVE       0.99      0.97      0.98      6009

    accuracy                           0.98     12000
   macro avg       0.98      0.98      0.98     12000
weighted avg       0.98      0.98      0.98     12000

Вы можете подписаться на меня в Linkedin, Github и Kaggle.

Ссылка на гитхаб



Ссылка на Kaggle

https://www.kaggle.com/ratul6/surface-crack-image-detection-acc-97-91

LinkedIn Ссылка

https://www.linkedin.com/in/ratul-ghosh-8048a8148/