"""
<h1>ASL Recognition using Keras CNN</h1>
<p>In this notebook, we will train a Keras Deep Learning model to recognize American Sign Language</p>
"""
"""
<img src="https://miro.medium.com/max/4800/1*DrbLUMbhtehEgEl8Kj5v9Q.png">
"""
from tensorflow import keras
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.metrics import f1_score,precision_score,recall_score
from sklearn.metrics import ConfusionMatrixDisplay
import matplotlib.pyplot as plt
import numpy as np
import glob
import cv2
features = []
labels = []
#reading file locations
#From the locations read, consider only 1100 out of 3000 to reduce dataset size
classes = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
for i in range(len(classes)):
    file_list = glob.glob("/kaggle/input/asl-alphabet/asl_alphabet_train/asl_alphabet_train/" + classes[i] + "/*.jpg")
    for item in range(1100):
        features.append(file_list[item])
        labels.append([i])
print("Dataset Feature size : ",len(features))
print("Dataset labels size : ",len(labels))
#Shuffle the array
features,labels = shuffle(features,labels,random_state=0)
train_features = []
train_labels = []
validation_features = []
validation_labels = []

for i in features:
    train_features.append(cv2.imread(i,cv2.IMREAD_COLOR))
    train_features[-1] = np.reshape(train_features[-1],[200,200,3])

for i in labels:
    train_labels.append(i)

train_features,validation_features,train_labels,validation_labels = train_test_split(train_features,train_labels,test_size=0.3)
print("Train data : ",len(train_features),len(train_labels))
print("Validation data : ",len(validation_features),len(validation_labels))
del features
del labels
del file_list
alpha = [chr(c) for c in range(65,91)]
un,count = np.unique(train_labels,return_counts=True)
j=1
plt.figure(figsize=(100,100))
for i in un:
    plt.subplot(7,4,j)
    plt.imshow(train_features[np.where(train_labels == np.array(i))[0][0]])
    plt.axis('off')
    plt.title(alpha[i],fontdict=dict({'fontsize' : 100}))
    j=j+1
model = keras.Sequential()

model.add(keras.layers.Conv2D(32,(3,3),activation="relu",padding="same",input_shape=(200,200,3)))
model.add(keras.layers.Conv2D(32,(3,3),activation="relu",padding="same"))
model.add(keras.layers.MaxPooling2D(3,3))

model.add(keras.layers.Conv2D(64,(3,3),activation="relu",padding="same"))
model.add(keras.layers.Conv2D(64,(3,3),activation="relu",padding="same"))
model.add(keras.layers.MaxPooling2D(3,3))

model.add(keras.layers.Conv2D(128,(3,3),activation="relu",padding="same"))
model.add(keras.layers.Conv2D(128,(3,3),activation="relu",padding="same"))
model.add(keras.layers.MaxPooling2D(3,3))

model.add(keras.layers.Conv2D(256,(3,3),activation="relu",padding="same"))
model.add(keras.layers.Conv2D(256,(3,3),activation="relu",padding="same"))

model.add(keras.layers.Flatten())

model.add(keras.layers.Dense(1568,activation="relu"))
model.add(keras.layers.Dropout(0.5))

model.add(keras.layers.Dense(26,activation="softmax"))

opt = keras.optimizers.Adam(learning_rate=0.0001)
model.compile(optimizer=opt,loss="sparse_categorical_crossentropy",metrics=['accuracy'])
model.summary()
train_features = np.array(train_features)
train_labels = np.array(train_labels) 
validation_features = np.array(validation_features)
validation_labels = np.array(validation_labels)
history = model.fit(train_features,
          train_labels,
          epochs=10, 
          validation_data = (validation_features,validation_labels))
# Get training and test loss histories
training_loss = history.history['loss']
test_loss = history.history['val_loss']
train_acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

#Create count of the number of epochs
epoch_count = range(1, len(training_loss) + 1)

# Visualize metrics
plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
plt.plot(epoch_count, training_loss)
plt.plot(epoch_count, test_loss)
plt.legend(['Train Loss', 'Test Loss'])
plt.xlabel('Epoch')
plt.ylabel('Loss')

plt.subplot(1,2,2)
plt.plot(epoch_count, train_acc)
plt.plot(epoch_count, val_acc)
plt.legend(['Train Accuracy', 'Validation Accuracy'])
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.show()
del train_features
del train_labels
"""
<h1>Model Evaluation</h1>
"""
y_pred = np.argmax(model.predict(validation_features),1)
print("Precision : {:.2f} %".format(precision_score(y_pred,validation_labels,average='macro')))
print("Recall    : {:.2f} %".format(precision_score(y_pred,validation_labels,average='macro')))
print("F1 Score  : {:.2f} %".format(precision_score(y_pred,validation_labels,average='macro')))
"""
<h1>Confusion Matrix</h1>
"""
plt.figure(figsize=(50,50))
cm = confusion_matrix(validation_labels, y_pred.reshape(-1,1))
disp = ConfusionMatrixDisplay(confusion_matrix=cm,
                               display_labels=alpha)
fig, ax = plt.subplots(figsize=(15,15))
disp.plot(ax=ax)