After running this code: import os
import cv2
import numpy as np
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Input, Conv2D, MaxPooling2D, Flatten, LSTM, Dense, Embedding, Concatenate
from keras import Model
from keras.utils import to_categorical
from keras.layers import RepeatVector, TimeDistributed


# Constants for the image and sequence properties
IMAGE_HEIGHT = 256
IMAGE_WIDTH = 256
NUM_CHANNELS = 3
NUM_HTML_TOKENS = 10000  # Assuming 10,000 possible tokens in the HTML vocabulary
MAX_SEQUENCE_LENGTH = 500  # This should be set to the maximum sequence length after exploring your dataset
EPOCHS = 10

def resize_image_with_padding(img, target_width, target_height):
    old_width, old_height = img.shape[1], img.shape[0]
    aspect_ratio = old_width / old_height

    # Determine new width and height, preserving aspect ratio
    if old_width > old_height:
        new_width = target_width
        new_height = int(target_width / aspect_ratio)
    else:
        new_height = target_height
        new_width = int(target_height * aspect_ratio)

    # Resize the image
    img_resized = cv2.resize(img, (new_width, new_height))

    # Padding calculations
    delta_w = target_width - new_width
    delta_h = target_height - new_height
    top, bottom = delta_h // 2, delta_h - (delta_h // 2)
    left, right = delta_w // 2, delta_w - (delta_w // 2)

    # Add padding to the resized image
    color = [0, 0, 0]  # Padding color (black)
    img_padded = cv2.copyMakeBorder(img_resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)

    return img_padded


# Load and preprocess your images and HTML
# Function to load images and corresponding HTML
def load_and_preprocess_data(screenshots_dir, html_dir, image_height, image_width):
    images = []
    all_html_sources = []

    for filename in sorted(os.listdir(screenshots_dir)):
        if filename.endswith(".png"):
            # Load and preprocess each image
            img_path = os.path.join(screenshots_dir, filename)
            img = cv2.imread(img_path)
            img = resize_image_with_padding(img, image_width, image_height)
            img = img / 255.0  # Normalize pixel values to [0, 1]
            images.append(img)
            
            # Find corresponding HTML file with the same base name
        base_name = os.path.splitext(filename)[0]
        html_filename = base_name.replace("screen", "html") + ".html"  # Changes here
        html_path = os.path.join(html_dir, html_filename)
        if os.path.isfile(html_path):
            with open(html_path, "r", encoding="utf-8") as file:
                html_content = file.read()
                all_html_sources.append(html_content)
    
    return np.array(images), all_html_sources

# Paths to your data directories
screenshots_dir = "C:/Users/Dell-PC/Desktop/Projets/Img-2-Code/screenshots"
html_dir = "C:/Users/Dell-PC/Desktop/Projets/Img-2-Code/html"
images, all_html_sources = load_and_preprocess_data(screenshots_dir, html_dir, IMAGE_HEIGHT, IMAGE_WIDTH)

# Tokenize the HTML content
tokenizer = Tokenizer(num_words=NUM_HTML_TOKENS)
tokenizer.fit_on_texts(all_html_sources)

# Convert text to a sequence of integers
sequences = tokenizer.texts_to_sequences(all_html_sources)

# Pad the sequences so they all have the same length
html_sequences = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH, padding="post")

# Convert html_sequences to one-hot-encoded for use with categorical crossentropy
html_sequences_one_hot = to_categorical(html_sequences, num_classes=NUM_HTML_TOKENS)

# Step 1: Create the CNN model to extract features from the image
input_image = Input(shape=(IMAGE_HEIGHT, IMAGE_WIDTH, NUM_CHANNELS))
cnn = Conv2D(filters=32, kernel_size=(3,3), activation="relu")(input_image)
cnn = MaxPooling2D(pool_size=(2,2))(cnn)
cnn = Conv2D(filters=64, kernel_size=(3,3), activation="relu")(cnn)
cnn = MaxPooling2D(pool_size=(2,2))(cnn)
cnn = Flatten()(cnn)
cnn = Dense(units=512)(cnn)  # Ensure the CNN output size matches the LSTM input
cnn_out_repeated = RepeatVector(MAX_SEQUENCE_LENGTH)(cnn)


# Step 2: Create an embedding layer for the HTML input sequence
decoder_input_sequence = Input(shape=(MAX_SEQUENCE_LENGTH,))
embedding_layer = Embedding(NUM_HTML_TOKENS, 256)(decoder_input_sequence)
lstm = LSTM(units=512, return_sequences=True)(embedding_layer)

# Instead of the Concatenate layer, combine CNN and LSTM outputs with a TimeDistributed layer
# We can stack the CNN’s output on top of the LSTM by using a concatenate layer with axis=-1
combined_outputs = Concatenate(axis=-1)([cnn_out_repeated, lstm])
# Step 3: Apply a TimeDistributed Dense layer to generate a probability over the vocabulary for each time step
decoder_output = TimeDistributed(Dense(NUM_HTML_TOKENS, activation="softmax"))(combined_outputs)
model = Model([input_image, decoder_input_sequence], decoder_output)

# Compile the model with a loss and an optimizer
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")

# Shift html_sequences to the right by one place for the decoder input
decoder_input_sequences = np.pad(html_sequences[:, :-1], ((0, 0), (1, 0)), "constant", constant_values=(0, 0))

print(f"html_sequences_one_hot.shape: {html_sequences_one_hot.shape}")  # should print (num_samples, MAX_SEQUENCE_LENGTH, NUM_HTML_TOKENS)

print(f"Images shape: {images.shape}")
print(f"Decoder input sequences shape: {decoder_input_sequences.shape}")


# For using with sparse_categorical_crossentropy
targets = html_sequences[:, 1:]  # targets are shifted by 1 position
targets = np.expand_dims(targets, -1)  # add an extra dimension

print(f"Targets shape: {targets.shape}")

# Train the model accordingly
# model.fit([images, decoder_input_sequences], targets, epochs=EPOCHS)

# Save or evaluate your model
# model.save("Image_to_html.keras")     i got this error: html_sequences_one_hot.shape: (15, 500, 10000)
Images shape: (15, 256, 256, 3)
Decoder input sequences shape: (15, 500)
Targets shape: (15, 499, 1)