Surface crack detection¶
Credit: AITS Cainvas Community
Photo by Tevis Godfrey on Dribbble
Concrete surface cracks are major defects in civil structures. Identifying them is an important part of the building inspection process where the rigidity and tensile strength of the building are evaluated.
Automating this process involves using a mobile bot with a camera input that scans the surfaces of the building for cracks and logs the locations for the same.
In order to make predictions on a larger surface, the camera is to be moved over the surface, covering it in small sections. The trained model is then applied to the image of this smaller section.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
from keras import layers, optimizers, models, preprocessing, losses, callbacks, Input, Model, applications
import os
import random
from PIL import Image
import keras
import tensorflow as tf
!wget https://cainvas-static.s3.amazonaws.com/media/user_data/AyishaR0/surface.zip
!unzip -qo -d surface surface.zip
!rm surface.zip
The dataset has two folders - negative and positive, each with their respective images.
Using 80-20 (train-test) split on the images.
# Loading the dataset
path = 'surface'
batch_size = 256
train_df = preprocessing.image_dataset_from_directory(path, label_mode = 'binary', validation_split = 0.2, seed = 113, subset='training', batch_size = batch_size)
test_df = preprocessing.image_dataset_from_directory(path, label_mode = 'binary', validation_split = 0.2, seed = 113, subset='validation', batch_size = batch_size)
# Looking into the class labels
class_names = train_df.class_names
print("Train class names: ", train_df.class_names)
print("Test class names: ", test_df.class_names)
Visualization¶
num_samples = 4 # the number of samples to be displayed in each class
for x in class_names:
plt.figure(figsize=(20, 20))
filenames = os.listdir(path + '/' + x)
for i in range(num_samples):
ax = plt.subplot(1, num_samples, i + 1)
img = Image.open(path +'/' + x + '/' + filenames[i])
plt.imshow(img)
plt.title(x)
plt.axis("off")
# Normalizing the pixel values for faster convergence
normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)
train_df = train_df.map(lambda x, y: (normalization_layer(x), y))
test_df = test_df.map(lambda x, y: (normalization_layer(x), y))
The model¶
model = models.Sequential([
layers.Conv2D(8, 2, activation='relu', input_shape=(256,256,3)),
layers.Conv2D(16, 2, activation='relu'),
layers.MaxPool2D(pool_size=(2, 2)),
layers.Conv2D(16, 2, activation='relu'),
layers.Conv2D(32, 2, activation='relu'),
layers.MaxPool2D(pool_size=(2, 2)),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(32, activation='relu'),
layers.Dense(1, activation='sigmoid')
])
cb = [callbacks.EarlyStopping(monitor = 'val_loss', patience = 5, restore_best_weights = True)]
model.compile(loss=losses.BinaryCrossentropy(), optimizer=optimizers.Adam(0.0001), metrics=['accuracy'])
history = model.fit(train_df, validation_data = test_df, epochs=32, callbacks = cb)
model.evaluate(test_df)
Plotting the metrics¶
def plot(history, variable1, variable2):
plt.plot(range(len(history[variable1])), history[variable1])
plt.plot(range(len(history[variable2])), history[variable2])
plt.legend([variable1, variable2])
plt.title(variable1)
plot(history.history, "accuracy", 'val_accuracy')
plot(history.history, "loss", 'val_loss')
Prediction¶
# pick random test data sample from one batch
x = random.randint(0, 32 - 1) # default batch size is 32
for i in test_df.as_numpy_iterator():
img, label = i
plt.axis('off') # remove axes
plt.imshow(img[x]) # shape from (32, 256, 256, 3) --> (256, 256, 3)
output = model.predict(np.expand_dims(img[x],0))[0][0] # getting output; input shape (256, 256, 3) --> (1, 256, 256, 3)
pred = (output > 0.5).astype('int')
print("Predicted: ", class_names[pred], '(', output, '-->', pred, ')') # Picking the label from class_names base don the model output
print("True: ", class_names[label[x][0].astype('int')])
break
deepC¶
model.save('surface.h5')
!deepCC surface.h5