Traffic Sign Classification with 47 Classes: A Deep Learning Journey

Share this post

[Introduction]

Traffic signs are everywhere on our roads, ensuring safety and efficient traffic flow. But what if we could teach a computer to understand and interpret these signs, just like humans do? That’s exactly what we’re going to explore in this video.

[Project Overview]

In this project, we trained a deep learning model to classify traffic signs from a dataset containing a whopping 47 different classes. That’s right, we’re taking on the challenge of recognizing everything from speed limits to no entry signs.

[Training Process]

We started by collecting and preprocessing a vast dataset of traffic sign images. Then, using the power of Convolutional Neural Networks (CNNs), we built a robust model capable of identifying these signs with high accuracy.

Our training process involved fine-tuning hyperparameters, optimizing the model, and ensuring it could handle the diverse set of signs efficiently.

[GUI for Model Testing]

But the fun doesn’t stop there! We didn’t want to keep this amazing model locked away in the coding world. So, we created a user-friendly Graphical User Interface (GUI) using Python’s Tkinter library.

Now, anyone can upload an image of a traffic sign, and our model will instantly classify it. It’s a practical application of AI that can have a real impact on road safety and traffic management.

The provided code is for training a deep-learning model to classify traffic signs using the TensorFlow and Keras libraries. I’ll break down the code and explain each part:

Importing Libraries:

import numpy as np
import os
from PIL import Image
from sklearn.model_selection import train_test_split
from keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPool2D, Dropout, Flatten, Dense, BatchNormalization, GlobalAveragePooling2D


# Function to load and preprocess images
def load_images_from_directory(path, image_size=(30, 30)):
    images = os.listdir(path)
    data = []
    labels = []
    class_id = int(path.split('/')[-1])

    for image_filename in images:
        try:
            image = Image.open(os.path.join(path, image_filename))
            image = image.resize(image_size)
            image = np.array(image)
            data.append(image)
            labels.append(class_id)
        except:
            print(f"Error loading image: {os.path.join(path, image_filename)}")

    return data, labels

# Retrieving the images and their labels
data = []
labels = []
num_classes = 43
current_path = os.getcwd()

for class_id in range(num_classes):
    path = os.path.join(current_path, 'data/Train', str(class_id))
    class_data, class_labels = load_images_from_directory(path)
    data.extend(class_data)
    labels.extend(class_labels)

# Converting lists into numpy arrays
data = np.array(data)
labels = np.array(labels)

print(data.shape, labels.shape)

# Splitting training and testing dataset
X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=42)

print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

# Converting the labels into one hot encoding
y_train_one_hot = to_categorical(y_train, num_classes)
y_test_one_hot = to_categorical(y_test, num_classes)

# Building the model
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(5, 5), activation='relu', input_shape=X_train.shape[1:]))
model.add(Conv2D(filters=32, kernel_size=(5, 5), activation='relu'))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Dropout(rate=0.25))

model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Dropout(rate=0.25))

# Replace the Flatten layer with GlobalAveragePooling2D
model.add(GlobalAveragePooling2D())

# Optionally, you can add more Dense layers with BatchNormalization and Dropout
model.add(Dense(256, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(rate=0.5))

# Make sure num_classes is defined properly for your specific problem
model.add(Dense(num_classes, activation='softmax'))

# Compilation of the model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

epochs = 15
history = model.fit(X_train, y_train_one_hot, batch_size=32, epochs=epochs, validation_data=(X_test, y_test_one_hot))
#model.save("model.h5")

Plot Results:

import matplotlib.pyplot as plt

def plot_accuracy(history):
    plt.figure(figsize=(8, 6))
    plt.plot(history.history['accuracy'], label='Training Accuracy')
    plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
    plt.title('Accuracy')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')
    plt.legend()
    plt.grid(True)
    plt.show()

def plot_loss(history):
    plt.figure(figsize=(8, 6))
    plt.plot(history.history['loss'], label='Training Loss')
    plt.plot(history.history['val_loss'], label='Validation Loss')
    plt.title('Loss')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend()
    plt.grid(True)
    plt.show()

# Plotting graphs for accuracy and loss
plot_accuracy(history)
plot_loss(history)
#testing accuracy on test dataset
from sklearn.metrics import accuracy_score
import pandas as pd

y_test = pd.read_csv('data/Test.csv')

labels = y_test["ClassId"].values
imgs = y_test["Path"].values
data=[]

for img in imgs:
    image = Image.open("data/"+img)
    image = image.resize((30,30))
    data.append(np.array(image))

X_test=np.array(data)

# Make predictions on the test data
pred_probs = model.predict(X_test)
pred = np.argmax(pred_probs, axis=1)

#Accuracy with the test data
from sklearn.metrics import accuracy_score
print(accuracy_score(labels, pred))

model.save('traffic_classifier_model.h5')

GUI CODE:

import tkinter as tk
from tkinter import filedialog
from tkinter import Label, Button
from PIL import ImageTk, Image
import numpy as np


from tensorflow.keras.models import load_model

# Load the trained model to classify signs
def load_traffic_classifier():
    model = load_model('traffic_classifier_model.h5')

    # Dictionary to label all traffic signs class

    classes = { 1:'Speed limit (20km/h)',
                2:'Speed limit (30km/h)', 
                3:'Speed limit (50km/h)', 
                4:'Speed limit (60km/h)', 
                5:'Speed limit (70km/h)', 
                6:'Speed limit (80km/h)', 
                7:'End of speed limit (80km/h)', 
                8:'Speed limit (100km/h)', 
                9:'Speed limit (120km/h)', 
                10:'No passing', 
                11:'No passing veh over 3.5 tons', 
                12:'Right-of-way at intersection', 
                13:'Priority road', 
                14:'Yield', 
                15:'Stop', 
                16:'No vehicles', 
                17:'Veh > 3.5 tons prohibited', 
                18:'No entry', 
                19:'General caution', 
                20:'Dangerous curve left', 
                21:'Dangerous curve right', 
                22:'Double curve', 
                23:'Bumpy road', 
                24:'Slippery road', 
                25:'Road narrows on the right', 
                26:'Road work', 
                27:'Traffic signals', 
                28:'Pedestrians', 
                29:'Children crossing', 
                30:'Bicycles crossing', 
                31:'Beware of ice/snow',
                32:'Wild animals crossing', 
                33:'End speed + passing limits', 
                34:'Turn right ahead', 
                35:'Turn left ahead', 
                36:'Ahead only', 
                37:'Go straight or right', 
                38:'Go straight or left', 
                39:'Keep right', 
                40:'Keep left', 
                41:'Roundabout mandatory', 
                42:'End of no passing', 
                43:'End no passing veh > 3.5 tons' }
    
    return model, classes

# Initialize GUI
def init_gui():
    top = tk.Tk()
    top.geometry('800x600')
    top.title('Traffic sign classification')
    top.configure(background='#CDCDCD')

    label = Label(top, background='#CDCDCD', font=('arial', 15, 'bold'))
    sign_image = Label(top)
    heading = Label(top, text="Predict Traffic Sign", pady=20, font=('arial', 20, 'bold'))
    heading.configure(background='#CDCDCD', foreground='#364156')
    
    upload = Button(top, text="Upload an image", command=upload_image, padx=10, pady=5)
    upload.configure(background='#364156', foreground='white', font=('arial', 10, 'bold'))

    upload.pack(side=tk.BOTTOM, pady=50)
    sign_image.pack(side=tk.BOTTOM, expand=True)
    label.pack(side=tk.BOTTOM, expand=True)
    heading.pack()
    
        
    exit_app = Button(top, text="Exit App", command=top.destroy, padx=10, pady=5)
    exit_app.configure(background='#364156', foreground='white', font=('arial', 10, 'bold'))
    exit_app.pack(side=tk.BOTTOM)

    return top, label, sign_image


    
def classify(file_path, model, classes, label):
    image = Image.open(file_path)
    image = image.resize((30, 30))  # Resize the image to exactly (30, 30)
    image = np.array(image)
    image = np.expand_dims(image, axis=0)

    pred_probs = model.predict(image)
    pred = np.argmax(pred_probs, axis=1)

    sign = classes[pred[0] + 1]  # Changed pred + 1 to pred[0] + 1
    print(sign)
    label.configure(foreground='#011638', text=sign)
    

def show_classify_button(file_path, model, classes):
    classify_b = Button(top, text="Classify Image", command=lambda: classify(file_path, model, classes, label), padx=10, pady=5)
    classify_b.configure(background='#364156', foreground='white', font=('arial', 10, 'bold'))
    classify_b.place(relx=0.79, rely=0.46)

def upload_image():
    try:
        file_path = filedialog.askopenfilename()
        uploaded = Image.open(file_path)
        uploaded.thumbnail(((top.winfo_width() / 2.25), (top.winfo_height() / 2.25)))
        im = ImageTk.PhotoImage(uploaded)

        sign_image.configure(image=im)
        sign_image.image = im
        label.configure(text='')
        show_classify_button(file_path, model, classes)
    except:
        pass

if __name__ == "__main__":
    model, classes = load_traffic_classifier()
    top, label, sign_image = init_gui()
    top.mainloop()

Complete Project Link:

Dataset link:

Code link:


Share this post

1 thought on “Traffic Sign Classification with 47 Classes: A Deep Learning Journey”

Leave a Comment

Your email address will not be published. Required fields are marked *