import cv2
import numpy as np
import matplotlib.pyplot as plt

def preprocess_image(image_path):
    image = cv2.imread(image_path)
    return image

def display_image_with_segments(image, segments, title):
    output = image.copy()
    for (x, y, w, h) in segments:
        cv2.rectangle(output, (x, y), (x + w, y + h), (0, 255, 0), 2)
    plt.imshow(output)
    plt.title(title)
    plt.show()

def segment_lines_chars(image):
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    _, binary_image = cv2.threshold(gray_image, 150, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

    # Encontra os contornos das linhas
    contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    lines = [cv2.boundingRect(c) for c in contours]
    lines = sorted(lines, key = lambda x: x[1])

    display_image_with_segments(image, lines, "Segmentação de Linhas")

    # Segmenta os caracteres de cada linha
    segments = []
    for (x, y, w, h) in lines:
        line_img = image[y:y + h, x:x + w]
        line_gray = binary_image[y:y + h, x:x + w]
        char_contours, _ = cv2.findContours(line_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        chars = [cv2.boundingRect(c) for c in char_contours]
        chars = sorted(chars, key = lambda x: x[0])

        line_segment = [line_img[char_y:char_y + char_h, char_x:char_x + char_w] for (char_x, char_y, char_w, char_h) in chars]
        segments.append(line_segment)
    
    return segments

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense

# Configurações do dataset
img_height, img_width = 28, 28
batch_size = 32
dataset_path = r"C:\Users\kidda\Documents\Code\csv\dataset"

# Preparação dos dados
datagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)

train_generator = datagen.flow_from_directory(
    dataset_path,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    color_mode="grayscale",
    class_mode="categorical",
    subset="training"
)

validation_generator = datagen.flow_from_directory(
    dataset_path,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    color_mode="grayscale",
    class_mode="categorical",
    subset="validation"
)

num_classes = len(train_generator.class_indices)

# Construção do modelo
model = Sequential([
    Conv2D(32, (3, 3), activation="relu", input_shape=(img_height, img_width, 1)),
    MaxPooling2D((2, 2)),
    Conv2D(64, (3, 3), activation="relu"),
    MaxPooling2D((2, 2)),
    Flatten(),
    Dense(128, activation="relu"),
    Dense(num_classes, activation="softmax")
])

model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"])

# Treinamento do modelo
epochs = 10
history = model.fit(
    train_generator,
    epochs=epochs
)

model.save("ocr_model.h5")

from tensorflow.keras.models import load_model

model = load_model("ocr_model.h5")

def predict_character(image_segment, model):
    img = cv2.resize(image_segment, (img_height, img_width))
    img = img.astype("float32") / 255.0
    img = np.expand_dims(img, axis=-1)
    img = np.expand_dims(img, axis=0)
    prediction = model.predict(img)
    class_idx = np.argmax(prediction, axis=1)[0]
    class_labels = {v: k for k, v in train_generator.class_indices.items()}
    return class_labels[class_idx]

def extract_text_from_image(image_path):
    preprocessed_image = preprocess_image(image_path)
    lines_segments = segment_lines_chars(preprocessed_image)
    
    text = ""
    for line in lines_segments:
        for char_img in line:
            char = predict_character(char_img, model)
            text += char
        text += "\n"
    
    return text.strip()

# Exemplo de uso
image_path = r"C:\Users\kidda\Documents\Code\csv\test.jpg"
extracted_text = extract_text_from_image(image_path)
print(extracted_text)

esse é meu código, mas estou tendo o erro:

Input 0 of layer "conv2d" is incompatible with the layer: expected axis -1 of input shape to have value 1, but received input with shape (1, 28, 28, 3)

Arguments received by Sequential.call():
  • inputs=tf.Tensor(shape=(1, 28, 28, 3, 1), dtype=float32)
  • training=False
  • mask=None