---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[3], line 61
     59 X = np.array(X)
     60 Y = np.array(Y)
---> 61 X, Y = shuffle(X, Y, random_state=100)
     63 # Normalizing and reshaping the mask set (Y)
     64 Y = (Y >= 100).astype('int').reshape(-1, 256, 320, 1)

File /opt/conda/lib/python3.10/site-packages/sklearn/utils/__init__.py:683, in shuffle(random_state, n_samples, *arrays)
    617 def shuffle(*arrays, random_state=None, n_samples=None):
    618     """Shuffle arrays or sparse matrices in a consistent way.
    619 
    620     This is a convenience alias to ``resample(*arrays, replace=False)`` to do
   (...)
    681       array([0, 1])
    682     """
--> 683     return resample(
    684         *arrays, replace=False, n_samples=n_samples, random_state=random_state
    685     )

File /opt/conda/lib/python3.10/site-packages/sklearn/utils/__init__.py:569, in resample(replace, n_samples, random_state, stratify, *arrays)
    563 elif (max_n_samples > n_samples) and (not replace):
    564     raise ValueError(
    565         "Cannot sample %d out of arrays with dim %d when replace is False"
    566         % (max_n_samples, n_samples)
    567     )
--> 569 check_consistent_length(*arrays)
    571 if stratify is None:
    572     if replace:

File /opt/conda/lib/python3.10/site-packages/sklearn/utils/validation.py:397, in check_consistent_length(*arrays)
    395 uniques = np.unique(lengths)
    396 if len(uniques) > 1:
--> 397     raise ValueError(
    398         "Found input variables with inconsistent numbers of samples: %r"
    399         % [int(l) for l in lengths]
    400     )

ValueError: Found input variables with inconsistent numbers of samples: [7252, 0]

import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D, Concatenate, Dropout
from tensorflow.keras import Model
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
from tensorflow.keras.callbacks import ModelCheckpoint, TensorBoard

# Google Colab import, if available
try:
    from google.colab import files
except ImportError:
    pass

# Setting up Kaggle API credentials
os.environ['KAGGLE_USERNAME'] = 'saisai6567'
os.environ['KAGGLE_KEY'] = 'a26b5bb35240ac0aa00506ef1db25bb9'

# Downloading the dataset from Kaggle
!kaggle datasets download -d rangalamahesh/preprocessed-1 --unzip

# Dataset directory paths
train_path = '/kaggle/input/preprocessed-1/training'

# Creating a generator and retrieving images from the directory
img_generator = tf.keras.preprocessing.image.ImageDataGenerator()
seed = 10
images_set = img_generator.flow_from_directory(
    train_path,
    shuffle=False,
    batch_size=64,
    class_mode='binary',
    target_size=(256, 320)
)

# Loading Images and Masks
num_images = 7252
num_batches = num_images // 64 + 1
X = []
Y = []

# Looping over the batches and extracting the images
for i in range(num_batches):
    batch = next(images_set)
    batch_images = batch[0]
    batch_labels = batch[1]
    for ind, lb in enumerate(batch_labels):
        if lb == 0:
            X.append(batch_images[ind])
        else:
            Y.append(np.mean(batch_images[ind], axis=2))
    if i % 10 == 0:
        print(f'Batch {i}')

# Converting the lists to numpy arrays
X = np.array(X)
Y = np.array(Y)
X, Y = shuffle(X, Y, random_state=100)

# Normalizing and reshaping the mask set (Y)
Y = (Y >= 100).astype('int').reshape(-1, 256, 320, 1)

# Splitting the dataset into train and validation sets
X_train, X_val, Y_train, Y_val = train_test_split(X, Y, test_size=.1, random_state=100)
print("Shape of X_train:", X_train.shape)
print("Shape of X_val:", X_val.shape)
print("Shape of Y_train:", Y_train.shape)
print("Shape of Y_val:", Y_val.shape)

# Defining the U-Net model architecture
def unet(input_size=(256,320,3)):
    inputs = Input(input_size)
    rescale = tf.keras.layers.Rescaling(1./255)(inputs)
    
    # Encoder
    conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(rescale)
    conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv1)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
    
    conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool1)
    conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv2)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
    
    conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool2)
    conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv3)
    pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
    
    conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool3)
    conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv4)
    pool4 = MaxPooling2D(pool_size=(2, 2))(conv4)
    
    # Decoder
    conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool4)
    conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv5)
    drop5 = Dropout(0.5)(conv5)
    
    up6 = Conv2D(512, 2, activation='relu', padding='same', kernel_initializer='he_normal')(UpSampling2D(size=(2,2))(drop5))
    merge6 = Concatenate(axis=3)([conv4, up6])
    conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge6)
    conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv6)
    
    up7 = Conv2D(256, 2, activation='relu', padding='same', kernel_initializer='he_normal')(UpSampling2D(size=(2,2))(conv6))
    merge7 = Concatenate(axis=3)([conv3, up7])
    conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge7)
    conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv7)
    
    up8 = Conv2D(128, 2, activation='relu', padding='same', kernel_initializer='he_normal')(UpSampling2D(size=(2,2))(conv7))
    merge8 = Concatenate(axis=3)([conv2, up8])
    conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge8)
    conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv8)
    
    up9 = Conv2D(64, 2, activation='relu', padding='same', kernel_initializer='he_normal')(UpSampling2D(size=(2,2))(conv8))
    merge9 = Concatenate(axis=3)([conv1, up9])
    conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge9)
    conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv9)
    
    outputs = Conv2D(1, 1, activation='sigmoid')(conv9)
    
    model = Model(inputs=inputs, outputs=outputs)
    return model

# Compiling the model
model = unet()
model.compile(optimizer='adam', loss=tf.keras.losses.BinaryFocalCrossentropy(), metrics=['accuracy'])
model.summary()

# Defining callbacks
tensorboard_log_dir = './logs'
tensorboard_callback = TensorBoard(log_dir=tensorboard_log_dir, histogram_freq=1)
callbacks = [
    ModelCheckpoint("save_at_{epoch}.h5"),
    tensorboard_callback,
]

# Training the model
history = model.fit(
    X_train,
    Y_train,
    epochs=32,
    callbacks=callbacks,
    validation_data=(X_val, Y_val),
    batch_size=8
)

# Evaluating the model and visualizing results
preds = model.predict(X_val)

# Preparing predictions
preds = (preds >= .5).astype('int')

# Displaying some results
plt.figure(figsize=(10, 45))
s, e = 0, 8
index = 1

for i, j, k in zip(X_val[s:e], preds[s:e], Y_val[s:e]):
    cv2.imwrite(f'./out/img-{index}.jpg', i)
    cv2.imwrite(f'./out/pred-{index}.jpg', j*255.)
    cv2.imwrite(f'./out/ground-{index}.jpg', k*255.)
    
    plt.subplot(10, 2, index)
    plt.imshow(i / 255.)
    plt.title('Ground truth image')
    
    plt.subplot(10, 2, index + 1)
    plt.imshow(j, cmap='gray')
    plt.title('Pred mask')
    index += 2

# Function to dehaze the image
def dehaze_image(image):
    def retinex_ssr(img, sigma):
        img = img.astype(np.float32) + 1.0
        retinex = np.log10(img) - np.log10(cv2.GaussianBlur(img, (0, 0), sigma))
        return retinex

    def retinex_msr(img, sigma_list):
        msr = np.zeros_like(img, dtype=np.float32)
        for sigma in sigma_list:
            msr += retinex_ssr(img, sigma)
        msr = msr / len(sigma_list)
        return msr

    sigma_list = [15, 80, 250]
    img_msr = retinex_msr(image, sigma_list)
    img_msr = np.uint8(cv2.normalize(img_msr, None, 0, 255, cv2.NORM_MINMAX))

    gray = cv2.cvtColor(img_msr, cv2.COLOR_BGR2GRAY)
    hessian = cv2.cornerHarris(gray, 2, 3, 0.04)
    hessian = cv2.dilate(hessian, None)
    img_msr[hessian > 0.01 * hessian.max()] = [0, 0, 255]

    return img_msr

# Preprocessing the image for segmentation
def preprocess_image_segmentation(image):
    image = cv2.resize(image, (256, 320))
    image = image.astype('float32') / 255.0
    image = np.expand_dims(image, axis=0)
    return image

# Performing road segmentation using U-Net
def segment_road(image, model):
    image = preprocess_image_segmentation(image)
    mask = model.predict(image)
    mask = (mask[0] > 0.5).astype('uint8') * 255
    return mask

# Combining the original image with the segmentation mask
def highlight_road(image, mask):
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    highlighted_image = cv2.drawContours(image.copy(), contours, -1, (0, 255, 0), 3)
    return highlighted_image

# Uploading the image
uploaded = files.upload()
image_path = list(uploaded.keys())[0]
image = cv2.imread(image_path)
original_height, original_width = image.shape[:2]

# Dehazing the image and performing segmentation
dehazed_image = dehaze_image(image)
road_mask = segment_road(dehazed_image, model)
highlighted_image = highlight_road(dehazed_image, road_mask)

# Displaying the result
plt.figure(figsize=(15, 15))
plt.subplot(1, 3, 1)
plt.title("Original Image")
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.axis('off')

plt.subplot(1, 3, 2)
plt.title("Dehazed Image")
plt.imshow(cv2.cvtColor(dehazed_image, cv2.COLOR_BGR2RGB))
plt.axis('off')

plt.subplot(1, 3, 3)
plt.title("Road Highlighted")
plt.imshow(cv2.cvtColor(highlighted_image, cv2.COLOR_BGR2RGB))
plt.axis('off')

plt.show()

# Creating metrics
accuracy = tf.keras.metrics.Accuracy()
precision = tf.keras.metrics.Precision()
recal = tf.keras.metrics.Recall()
iou = tf.keras.metrics.IoU(num_classes=2, target_class_ids=[1])

# Evaluating metrics
accuracy.update_state(Y_val, preds)
accuracy_value = accuracy.result().numpy()
precision.update_state(Y_val, preds)
precision_value = precision.result().numpy()
recal.update_state(Y_val, preds)
recal_value = recal.result().numpy()
f1_score = 2 / ((1 / precision_value) + (1 / recal_value))
iou.update_state(Y_val, preds)
iou_value = iou.result().numpy()

print("Accuracy:", accuracy_value)
print("Precision:", precision_value)
print("Recall:", recal_value)
print('F1 Score: ', f1_score)
print('IoU: ', iou_value)

# Calculating MSE and RMSE
from sklearn.metrics import mean_squared_error
import math
mse_value = mean_squared_error(Y_val.flatten(), preds.flatten())
rmse_value = math.sqrt(mse_value)

print("Mean Squared Error (MSE):", mse_value)
print("Root Mean Squared Error (RMSE):", rmse_value)

# Plotting training and validation metrics
plt.figure(figsize=(12, 12))

# Plotting Training and Validation Loss
plt.subplot(2, 1, 1)
plt.plot(history.history['loss'], label='Training Loss', marker='o')
plt.plot(history.history['val_loss'], label='Validation Loss', marker='o')
plt.title('Training and Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.ylim(-0.1, 1.1)

# Plotting Training and Validation Accuracy
plt.subplot(2, 1, 2)
plt.plot(history.history['accuracy'], label='Training Accuracy', marker='o')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy', marker='o')
plt.title('Training and Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.ylim(-0.1, 1.1)

plt.tight_layout()
plt.show()