Note: Scroll to the bottom to see algorithm classifying images. Below is the script for 5 different models. Model 2 was used to classify images

In [1]:
pip install Augmentor
In [2]:
from google.colab import drive
import os
import random
import shutil
from tensorflow import keras
from tensorflow.keras import layers
import tensorflow as tf
import glob
import warnings
warnings.filterwarnings("ignore")
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from keras.applications import VGG16
from keras.applications.vgg16 import VGG16
from keras.models import Model
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from keras.applications.vgg16 import VGG16, decode_predictions
import imgaug.augmenters as iaa
import Augmentor
In [3]:

Data Augmentation¶

In [10]:
# Data Augmentation for every car

# Hatchback
train_directory = "/content/train/Hatchback"

# Create an Augmentor pipeline
p = Augmentor.Pipeline(train_directory)

# Adding augmentation operations
# Flip horizontally with a probability of 0.5
p.flip_left_right(probability=0.5)
# Example: Rotate by a random angle between -10 and 10 degrees
p.rotate(probability=0.7, max_left_rotation=10, max_right_rotation=10)
# Add more augmentation operations as needed

# Set the number of augmented images you want to generate
p.sample(971)

output_dir = "/content/train/Hatchback/output"
suv_dir = "/content/train/Hatchback"

# Move all files from output to Hatchback
for filename in os.listdir(output_dir):
    src = os.path.join(output_dir, filename)
    dst = os.path.join(suv_dir, filename)
    shutil.move(src, dst)
os.rmdir(output_dir)


# SUV
train_directory = "/content/train/SUV"

p = Augmentor.Pipeline(train_directory)
p.flip_left_right(probability=0.5)
p.rotate(probability=0.7, max_left_rotation=10, max_right_rotation=10)
p.sample(207)

output_dir = "/content/train/SUV/output"
suv_dir = "/content/train/SUV"

for filename in os.listdir(output_dir):
    src = os.path.join(output_dir, filename)
    dst = os.path.join(suv_dir, filename)
    shutil.move(src, dst)
os.rmdir(output_dir)


# Pickup_Truck
train_directory = "/content/train/Pickup_Truck"

p = Augmentor.Pipeline(train_directory)
p.flip_left_right(probability=0.5)
p.rotate(probability=0.7, max_left_rotation=10, max_right_rotation=10)
p.sample(31)

output_dir = "/content/train/Pickup_Truck/output"
suv_dir = "/content/train/Pickup_Truck"

for filename in os.listdir(output_dir):
    src = os.path.join(output_dir, filename)
    dst = os.path.join(suv_dir, filename)
    shutil.move(src, dst)
os.rmdir(output_dir)


# Sedan
train_directory = "/content/train/Sedan"

p = Augmentor.Pipeline(train_directory)
p.flip_left_right(probability=0.5)
p.rotate(probability=0.7, max_left_rotation=10, max_right_rotation=10)
p.sample(478)

output_dir = "/content/train/Sedan/output"
suv_dir = "/content/train/Sedan"

# Move all files from output to SUV
for filename in os.listdir(output_dir):
    src = os.path.join(output_dir, filename)
    dst = os.path.join(suv_dir, filename)
    shutil.move(src, dst)
os.rmdir(output_dir)


# Sports_Car
train_directory = "/content/train/Sports_Car"

p = Augmentor.Pipeline(train_directory)
p.flip_left_right(probability=0.5)
p.rotate(probability=0.7, max_left_rotation=10, max_right_rotation=10)
p.sample(974)

output_dir = "/content/train/Sports_Car/output"
suv_dir = "/content/train/Sports_Car"

# Move all files from output to SUV
for filename in os.listdir(output_dir):
    src = os.path.join(output_dir, filename)
    dst = os.path.join(suv_dir, filename)
    shutil.move(src, dst)
os.rmdir(output_dir)
Initialised with 329 image(s) found.
Output directory set to /content/train/Hatchback/output.
Processing <PIL.Image.Image image mode=RGB size=116x106 at 0x781F6C4E3250>: 100%|██████████| 971/971 [00:15<00:00, 63.30 Samples/s]
Initialised with 1087 image(s) found.
Output directory set to /content/train/SUV/output.
Processing <PIL.Image.Image image mode=RGB size=466x360 at 0x781F6C458520>: 100%|██████████| 207/207 [00:02<00:00, 99.84 Samples/s] 
Initialised with 1299 image(s) found.
Output directory set to /content/train/Pickup_Truck/output.
Processing <PIL.Image.Image image mode=RGB size=334x220 at 0x78200EE13A60>: 100%|██████████| 31/31 [00:00<00:00, 100.05 Samples/s]
Initialised with 822 image(s) found.
Output directory set to /content/train/Sedan/output.
Processing <PIL.Image.Image image mode=RGB size=529x328 at 0x781F6E9CAE90>: 100%|██████████| 478/478 [00:08<00:00, 56.43 Samples/s]
Initialised with 326 image(s) found.
Output directory set to /content/train/Sports_Car/output.
Processing <PIL.Image.Image image mode=RGB size=300x168 at 0x781F6C2FF970>: 100%|██████████| 974/974 [01:34<00:00, 10.32 Samples/s]

All car types have 1300-1330 images in training, 200 in validation, and 200 in testing

Assigning classes to images in training, validation, and testing set¶

In [11]:
image_size = (180, 180)
batch_size = 32

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    "/content/train",
    labels='inferred',
    seed=1337,
    image_size=image_size,
    batch_size=batch_size,
)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    "/content/validation",
    labels='inferred',
    seed=1337,
    image_size=image_size,
    batch_size=batch_size,
)

test_ds = tf.keras.preprocessing.image_dataset_from_directory(
    "/content/test",
    labels='inferred',
    #subset="testing",
    seed=1337,
    image_size=image_size,
    batch_size=batch_size,
    shuffle=True, # Not really sure what this does
)
Found 6524 files belonging to 5 classes.
Found 1000 files belonging to 5 classes.
Found 1000 files belonging to 5 classes.

Models¶

VGG16 Sequential¶

In [12]:
# (Model 1)

model1 = VGG16(include_top=False, input_shape=(180, 180, 3)) # we'll replace the "top" with our own layers
for layer in model1.layers:
    layer.trainable = False

# Add new classifier layers
flat = layers.Flatten()(model1.layers[-1].output) # connect to last layer of VGG
drop1 = layers.Dropout(0.5)(flat)
cls = layers.Dense(128, activation='relu')(drop1)
drop2 = layers.Dropout(0.5)(cls)
output = layers.Dense(5, activation='softmax')(drop2) #


# Define new model
model1 = Model(inputs=model1.inputs, outputs=output)

# Compile model
model1.compile(optimizer="adam", loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model1.fit(train_ds, epochs=7,validation_data=val_ds)
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg16/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
58889256/58889256 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
Epoch 1/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 53s 195ms/step - accuracy: 0.5275 - loss: 8.6005 - val_accuracy: 0.8130 - val_loss: 0.5980
Epoch 2/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 55s 120ms/step - accuracy: 0.7278 - loss: 0.7983 - val_accuracy: 0.8620 - val_loss: 0.4833
Epoch 3/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 39s 113ms/step - accuracy: 0.7627 - loss: 0.7025 - val_accuracy: 0.9060 - val_loss: 0.3403
Epoch 4/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 25s 121ms/step - accuracy: 0.8107 - loss: 0.5571 - val_accuracy: 0.9050 - val_loss: 0.3141
Epoch 5/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 26s 126ms/step - accuracy: 0.8285 - loss: 0.5475 - val_accuracy: 0.9360 - val_loss: 0.2422
Epoch 6/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 23s 112ms/step - accuracy: 0.8368 - loss: 0.4611 - val_accuracy: 0.9590 - val_loss: 0.2229
Epoch 7/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 41s 112ms/step - accuracy: 0.8618 - loss: 0.4056 - val_accuracy: 0.9590 - val_loss: 0.1858
Out[12]:
<keras.src.callbacks.history.History at 0x781f6c4a98a0>
In [13]:
# Model 1 testing set accuracy and loss

loss, accuracy = model1.evaluate(test_ds)
loss = round((loss),2)
accuracy = round((accuracy * 100),2)
print("Test Loss:", loss)
print("Test Accuracy:", accuracy,"%")
32/32 ━━━━━━━━━━━━━━━━━━━━ 3s 93ms/step - accuracy: 0.9579 - loss: 0.5890
Test Loss: 0.39
Test Accuracy: 95.9 %
In [14]:
# (Model 2)

# Pulling pretrained classes from VGG16
model_vgg16 = VGG16(weights='imagenet', include_top=True)  # Include top layers for classification

# Get the class labels for ImageNet
class_labels = decode_predictions(np.zeros((1, 1000)), top=1000)
class_names = [label[1] for label in class_labels[0]]

# After looking through list of pretrained classes, we only found sports_car and pickup
# Find the indices of 'pickup' and 'sports_car' in class_names
pickup_index = class_names.index('pickup')
sports_car_index = class_names.index('sports_car')

# Create your model based on VGG16
model_base = VGG16(include_top=False, input_shape=(180, 180, 3))

# Freeze the layers of the base model
for layer in model_base.layers:
    layer.trainable = False

# Adding my model to pretrained classes of VGG
flat = layers.Flatten()(model_base.layers[-1].output)
drop1 = layers.Dropout(0.5)(flat)
cls = layers.Dense(128, activation='relu')(drop1)
drop2 = layers.Dropout(0.5)(cls)

# Adjust the number of classes in the output layer
new_class_names = class_names[:pickup_index] + ['Pickup_Truck'] + class_names[pickup_index+1:sports_car_index] + ['Sports_Car'] + class_names[sports_car_index+1:]
output = layers.Dense(len(new_class_names), activation='softmax')(drop2)

# Defining model
model2 = Model(inputs=model_base.inputs, outputs=output)

# Compile the final model
model2.compile(optimizer="adam", loss='sparse_categorical_crossentropy', metrics=['accuracy'])

# Now you can train your final model
model2.fit(train_ds, epochs=7, validation_data=val_ds)
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg16/vgg16_weights_tf_dim_ordering_tf_kernels.h5
553467096/553467096 ━━━━━━━━━━━━━━━━━━━━ 7s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/imagenet_class_index.json
35363/35363 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
Epoch 1/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 32s 143ms/step - accuracy: 0.5620 - loss: 3.8843 - val_accuracy: 0.9310 - val_loss: 0.2302
Epoch 2/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 26s 127ms/step - accuracy: 0.8433 - loss: 0.5129 - val_accuracy: 0.9510 - val_loss: 0.1920
Epoch 3/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 40s 122ms/step - accuracy: 0.8844 - loss: 0.3703 - val_accuracy: 0.9690 - val_loss: 0.1113
Epoch 4/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 40s 117ms/step - accuracy: 0.9040 - loss: 0.3333 - val_accuracy: 0.9640 - val_loss: 0.1481
Epoch 5/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 43s 126ms/step - accuracy: 0.9141 - loss: 0.2662 - val_accuracy: 0.9530 - val_loss: 0.2251
Epoch 6/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 41s 125ms/step - accuracy: 0.9282 - loss: 0.2312 - val_accuracy: 0.9620 - val_loss: 0.1731
Epoch 7/7
204/204 ━━━━━━━━━━━━━━━━━━━━ 41s 126ms/step - accuracy: 0.9329 - loss: 0.2347 - val_accuracy: 0.9750 - val_loss: 0.1261
Out[14]:

Passing through external image to test model¶

Using model with highest accuracy and lowest loss (Model 2)¶

Images are not in any set (train, validation, test)¶

In [23]:
# Function to preprocess the image
def preprocess_image(image_path, target_size):
    # Open the image
    img = Image.open(image_path)
    # Resize the image to match the input size of your model
    img = img.resize(target_size)
    # Convert the image to a numpy array and normalize the pixel values
    img_array = np.array(img) / 255.0
    # Add batch dimension as your model expects batches of images
    img_array = np.expand_dims(img_array, axis=0)
    return img_array

# Function to predict the class of the image
def predict_image(model, image_path, target_size, class_names):
    # Preprocess the image
    img = preprocess_image(image_path, target_size)
    # Make predictions using the model
    predictions = model.predict(img)
    # Get the predicted class index
    predicted_class_index = np.argmax(predictions[0])
    # Get the class label
    predicted_class = class_names[predicted_class_index]
    # Get the confidence score
    confidence_score = predictions[0][predicted_class_index]
    return predicted_class, confidence_score

# Path to the uploaded image
uploaded_image_path = "McLaren_Sports.jpg"

# Using model 2

# Define the target size (same as the input size of your model)
target_size = (180, 180)

# Define the class names
class_names = ['SUV', 'Sedan', 'Pickup_Truck', 'Hatchback', 'Sports_Car']

# Predict the class of the uploaded image
predicted_class, confidence_score = predict_image(model2, uploaded_image_path, target_size, class_names)


# Visualize the uploaded image
img = Image.open(uploaded_image_path)
plt.imshow(img)
plt.axis('off')
plt.title(f"Predicted Class: {predicted_class}")
plt.show()


# Second Test
uploaded_image_path2 = "Honda_Hatchback.jpg"

# Predict the class of the uploaded image
predicted_class2, confidence_score2 = predict_image(model2, uploaded_image_path2, target_size, class_names)



# Visualize the uploaded image
img = Image.open(uploaded_image_path2)
plt.imshow(img)
plt.axis('off')
plt.title(f"Predicted Class: {predicted_class2}")
plt.show()


# Third Test
uploaded_image_path2 = "GMC_Pickup.jpg"

# Predict the class of the uploaded image
predicted_class2, confidence_score2 = predict_image(model2, uploaded_image_path2, target_size, class_names)


# Visualize the uploaded image
img = Image.open(uploaded_image_path2)
plt.imshow(img)
plt.axis('off')
plt.title(f"Predicted Class: {predicted_class2}")
plt.show()
1/1 ━━━━━━━━━━━━━━━━━━━━ 2s 2s/step
No description has been provided for this image
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 23ms/step
No description has been provided for this image
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 18ms/step
No description has been provided for this image