import os
import cv2
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from google.colab import drive

# Mount Google Drive to access the dataset
drive.mount('/content/drive')

# Create directories if they don't exist
os.makedirs('/content/dataset/detection_train/license_plates_detection_train', exist_ok=True)
os.makedirs('/content/dataset/recognition_train/license_plates_recognition_train', exist_ok=True)
os.makedirs('/content/dataset/test', exist_ok=True)

# Unzip the images
!unzip -o /content/drive/MyDrive/DATA\ SCIENTIST_ASSIGNMENT/Licplatesdetection_train.zip -d /content/dataset/detection_train
!unzip -o /content/drive/MyDrive/DATA\ SCIENTIST_ASSIGNMENT/Licplatesrecognition_train.zip -d /content/dataset/recognition_train
!unzip -o /content/drive/MyDrive/DATA\ SCIENTIST_ASSIGNMENT/test.zip -d /content/dataset/test

# Function to load images and bounding box annotations from CSV
def load_detection_data(image_dir, annotation_file):
    annotations = pd.read_csv(annotation_file)
    images = []
    bboxes = []
    for index, row in annotations.iterrows():
        image_path = os.path.join(image_dir, row['img_id'])
        image = cv2.imread(image_path)
        if image is None:
            print(f"Warning: Image at {image_path} could not be loaded.")
            continue
        bbox = [row['ymin'], row['xmin'], row['ymax'], row['xmax']]
        images.append(image)
        bboxes.append(bbox)
    return images, bboxes

# Function to load images and text annotations for recognition
def load_recognition_data(image_dir, annotation_file):
    annotations = pd.read_csv(annotation_file)
    images = []
    texts = []
    for index, row in annotations.iterrows():
        image_path = os.path.join(image_dir, row['img_id'])
        image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
        if image is None:
            print(f"Warning: Image at {image_path} could not be loaded.")
            continue
        text = row['text']
        images.append(image)
        texts.append(text)
    return images, texts

# Function to preprocess images
def preprocess_images(images, target_size):
    preprocessed_images = []
    for img in images:
        if img is not None:
            img = cv2.resize(img, target_size)
            img = img / 255.0
            preprocessed_images.append(img)
    return np.array(preprocessed_images)

# Load and preprocess training data for detection
detection_image_dir = '/content/dataset/detection_train/license_plates_detection_train'
detection_annotation_file = '/content/drive/MyDrive/DATA SCIENTIST_ASSIGNMENT/Licplatesdetection_train.csv'
train_detection_images, train_detection_bboxes = load_detection_data(detection_image_dir, detection_annotation_file)
train_detection_images = preprocess_images(train_detection_images, (224, 224))

# Load and preprocess training data for recognition
recognition_image_dir = '/content/dataset/recognition_train/license_plates_recognition_train'
recognition_annotation_file = '/content/drive/MyDrive/DATA SCIENTIST_ASSIGNMENT/Licplatesrecognition_train.csv'
train_recognition_images, train_recognition_texts = load_recognition_data(recognition_image_dir, recognition_annotation_file)
train_recognition_images = preprocess_images(train_recognition_images, (100, 32))  # Assuming (100, 32) is a reasonable size for character recognition

# Ensure bounding boxes have the correct shape
train_detection_bboxes = np.array(train_detection_bboxes)

# Data augmentation for detection
detection_datagen = ImageDataGenerator(rotation_range=20, zoom_range=0.2, horizontal_flip=True)
detection_datagen.fit(train_detection_images)

print(f"Detection images shape: {train_detection_images.shape}")
print(f"Detection bounding boxes shape: {train_detection_bboxes.shape}")
print(f"Recognition images shape: {train_recognition_images.shape}")
print(f"Recognition texts shape: {len(train_recognition_texts)}")

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense

# Simple CNN model for license plate detection
def create_detection_model(input_shape):
    model = Sequential()
    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
    model.add(MaxPooling2D((2, 2)))
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2)))
    model.add(Conv2D(128, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2)))
    model.add(Flatten())
    model.add(Dense(512, activation='relu'))
    model.add(Dense(4))  # Bounding box coordinates (ymin, xmin, ymax, xmax)
    return model

input_shape = (224, 224, 3)
detection_model = create_detection_model(input_shape)
detection_model.compile(optimizer='adam', loss='mse')
detection_model.summary()

# Train the model
detection_model.fit(detection_datagen.flow(train_detection_images, train_detection_bboxes, batch_size=32), epochs=10)

import numpy as np
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, LSTM, Dense, TimeDistributed
from tensorflow.keras.utils import to_categorical

# Encode text labels for character recognition with padding
def encode_labels(texts, vocab, max_length):
    encoded_texts = []
    for text in texts:
        encoded_text = [vocab.index(char) for char in text]
        # Pad the sequence with a special character (e.g., space) index
        padded_encoded_text = encoded_text + [vocab.index(' ')] * (max_length - len(encoded_text))
        encoded_texts.append(padded_encoded_text)
    return np.array(encoded_texts)

# Define the character recognition model
def create_recognition_model(input_shape, vocab_size):
    inputs = Input(shape=input_shape)
    x = LSTM(128, return_sequences=True)(inputs)
    x = LSTM(128, return_sequences=True)(x)
    outputs = TimeDistributed(Dense(vocab_size, activation='softmax'))(x)
    model = Model(inputs, outputs)
    return model

# Assuming each license plate has a fixed length of 10 characters
max_plate_length = 10
vocab = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ '  # Digits, uppercase letters, and space
vocab_size = len(vocab)

# Sample data (replace these with your actual data)
train_recognition_texts = [['A', 'B', 'C', 'D', '1', '2', '3', '4', '5', '6'], 
                           ['1', '2', '3', '4', 'A', 'B', 'C', 'D', 'E', 'F']]
train_recognition_images = np.random.rand(2, 100, 32)  # Dummy image data

# Convert each list of characters to a string if needed
train_recognition_texts = [''.join(text) if isinstance(text, list) else text for text in train_recognition_texts]

# Encode the labels for recognition
encoded_texts = encode_labels(train_recognition_texts, vocab, max_plate_length)

# Resize the images to (100, 32) if necessary (assuming it's already done)
# preprocess_images function is assumed to be implemented elsewhere
# train_recognition_images = preprocess_images(train_recognition_images, (100, 32))

# Flatten the images to create sequences
train_recognition_images = train_recognition_images.reshape(train_recognition_images.shape[0], -1)

# Reshape the images to match the LSTM expected input shape (batch_size, max_plate_length, feature_dim)
input_shape = (max_plate_length, train_recognition_images.shape[1] // max_plate_length)
train_recognition_images = train_recognition_images.reshape(-1, max_plate_length, input_shape[1])

# One-hot encode the labels
train_recognition_texts = to_categorical(encoded_texts, num_classes=vocab_size)

# Define the model input shape
recognition_model = create_recognition_model(input_shape, vocab_size)
recognition_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
recognition_model.summary()

# Train the recognition model
recognition_model.fit(train_recognition_images, train_recognition_texts, batch_size=32, epochs=10)
import numpy as np
import cv2
from tensorflow.keras.models import load_model

# Assuming the detection and recognition models are already loaded
# detection_model = load_model('path_to_detection_model')
# recognition_model = load_model('path_to_recognition_model')

# Function to preprocess images (you need to define this function)
def preprocess_images(images, target_size):
    preprocessed_images = [cv2.resize(image, target_size) / 255.0 for image in images]
    return np.array(preprocessed_images)

# Function to detect license plates in an image
def detect_license_plates(image, detection_model):
    preprocessed_image = preprocess_images([image], (224, 224))
    if preprocessed_image.size == 0:
        raise ValueError("Preprocessed image is empty.")
    bbox = detection_model.predict(preprocessed_image)[0]
    ymin, xmin, ymax, xmax = bbox
    return int(ymin), int(xmin), int(ymax), int(xmax)

# Function to recognize characters in a license plate
def recognize_characters(plate_image, recognition_model):
    preprocessed_plate = cv2.resize(plate_image, (100, 32)) / 255.0
    preprocessed_plate = np.expand_dims(preprocessed_plate, axis=0)
    preprocessed_plate = np.expand_dims(preprocessed_plate, axis=-1)
    if preprocessed_plate.size == 0:
        raise ValueError("Preprocessed plate image is empty.")
    prediction = recognition_model.predict(preprocessed_plate)
    predicted_text = ''.join([vocab[np.argmax(char)] for char in prediction[0]])
    return predicted_text

# Test the models on a new image
test_image_path = '/content/dataset/test/test/test/933.jpg'
test_image = cv2.imread(test_image_path)

# Check if the image is loaded properly
if test_image is None:
    raise ValueError(f"Failed to load image from {test_image_path}")

try:
    ymin, xmin, ymax, xmax = detect_license_plates(test_image, detection_model)
    plate_image = test_image[ymin:ymax, xmin:xmax]
    predicted_text = recognize_characters(plate_image, recognition_model)
    print('Predicted License Plate Text:', predicted_text)
except Exception as e:
    print(f"Error during license plate detection or recognition: {e}")



full code

error:
1/1 [==============================] - 0s 76ms/step
Error during license plate detection or recognition: in user code:

    File "/usr/local/lib/python3.10/dist-packages/keras/src/engine/training.py", line 2440, in predict_function  *
        return step_function(self, iterator)
    File "/usr/local/lib/python3.10/dist-packages/keras/src/engine/training.py", line 2425, in step_function  **
        outputs = model.distribute_strategy.run(run_step, args=(data,))
    File "/usr/local/lib/python3.10/dist-packages/keras/src/engine/training.py", line 2413, in run_step  **
        outputs = model.predict_step(data)
    File "/usr/local/lib/python3.10/dist-packages/keras/src/engine/training.py", line 2381, in predict_step
        return self(x, training=False)
    File "/usr/local/lib/python3.10/dist-packages/keras/src/utils/traceback_utils.py", line 70, in error_handler
        raise e.with_traceback(filtered_tb) from None
    File "/usr/local/lib/python3.10/dist-packages/keras/src/engine/input_spec.py", line 298, in assert_input_compatibility
        raise ValueError(

    ValueError: Input 0 of layer "model_2" is incompatible with the layer: expected shape=(None, 10, 320), found shape=(None, 32, 100, 3, 1)
expand_more