[Python] Flutter TFLite Model Predictions Wrong Despite Matching Python Preprocessing (Works...

Discussão em 'Python' iniciado por Stack, Abril 27, 2025.

  1. Stack

    Stack Membro Participativo

    I'm struggling with a Flutter + TFLite integration.

    I have a trained TFLite model (EMNIST-like for handwritten letters), and it works perfectly when I test it in Python — but in Flutter, the predictions are wrong or way off.

    Here's what happens:
    ✅ In Python, I preprocess the image → predict → works very accurately.

    ❌ In Flutter, I apply the same preprocessing steps → but predictions are wrong. (example: I draw "A" → it predicts "B", or draw "I" → it predicts "Q".)

    Here's the python code I used to test my TFLITE file before moving to Flutter.


    import tensorflow as tf
    import numpy as np
    from PIL import Image
    import matplotlib.pyplot as plt

    #LOAD THE MODELS
    def load_labels(label_file='labels.txt'):
    with open(label_file, 'r') as f:
    labels_list = f.read().splitlines()
    return labels_list

    # LOAD THE TFLITE MODELLLL
    def load_tflite_model(model_path='emnist_model_finetuned.tflite'):
    interpreter = tf.lite.Interpreter(model_path=model_path)
    interpreter.allocate_tensors()
    return interpreter

    #PREPRCOSSES THE IMAGES
    def preprocess_image(image_path):
    """
    So that we won't get lost in the future lol
    1. Convert to grayscale
    2. Resize to (28, 28)
    3. Normalize pixel values
    4. Expand dims to (1, 28, 28, 1)
    5. Rotate 90° clockwise (k=-1)
    6. Transpose width/height
    """
    # Load and convert to grayscale
    img = Image.open(image_path).convert('L')
    # Resize
    img = img.resize((28, 28))
    # Convert to numpy array and normalize
    img_array = np.array(img).astype('float32') / 255.0

    # Expand dimensions: (28,28) -> (28,28,1) -> (1,28,28,1)
    img_array = np.expand_dims(img_array, axis=-1)
    img_array = np.expand_dims(img_array, axis=0)

    # Rotate 90° clockwise
    img_array = np.rot90(img_array, k=-1, axes=(1, 2))
    # Transpose
    img_array = np.transpose(img_array, (0, 2, 1, 3))

    return img_array

    #RUUUUUN
    def run_inference(image_path, interpreter, labels_list):
    # Preprocess the image
    image = preprocess_image(image_path)

    # Get input & output details
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()

    # Set the input tensor
    interpreter.set_tensor(input_details[0]['index'], image)
    # Invoke the model
    interpreter.invoke()

    # Get the output predictions
    output = interpreter.get_tensor(output_details[0]['index'])
    predicted_class = np.argmax(output, axis=1)[0]
    predicted_label = labels_list[predicted_class]

    return predicted_label

    # ======================
    # Main
    # ======================
    if __name__ == '__main__':
    # 1. Load TFLite model and labels
    interpreter = load_tflite_model('emnist_model.tflite')
    labels_list = load_labels('labels.txt')

    image_path = 'test_letter.png' # Replace with your own image file

    predicted_label = run_inference(image_path, interpreter, labels_list)
    print(f"Predicted Label: {predicted_label}")

    # 4. (Optional) Display the image
    img = Image.open(image_path)
    plt.imshow(img, cmap='gray')
    plt.title(f"Predicted: {predicted_label}")
    plt.axis('off')
    plt.show()


    In Flutter, I tried to mimic the same steps:

    • Capture canvas drawing.
    • Resize to 28x28.
    • Rotate 90° clockwise.
    • Transpose (swap width and height).
    • Normalize pixel values (0–1).
    • Expand dimensions to [1,28,28,1].
    • Pass to the TFLite model. My Flutter (Dart) preprocessing code:

    Future<String?> runModelOnImageBytes(Uint8List bytes) async {
    final img.Image? baseImage = img.decodeImage(bytes);
    if (baseImage == null) return null;

    // Resize to 28x28
    img.Image resized = img.copyResize(baseImage, width: 28, height: 28);

    // Rotate 90 degrees clockwise
    img.Image rotated = img.copyRotate(resized, angle: -90);

    // Transpose (swap width and height)
    img.Image transposed = img.copyTranspose(rotated);

    // Normalize and prepare input
    Float32List input = Float32List(28 * 28);
    int idx = 0;
    for (int y = 0; y < 28; y++) {
    for (int x = 0; x < 28; x++) {
    final pixel = transposed.getPixel(x, y);
    final gray = img.getLuminance(pixel) / 255.0;
    input[idx++] = gray;
    }
    }

    // Run inference
    var output = List.filled(1 * 62, 0.0).reshape([1, 62]);
    interpreter!.run(input.reshape([1, 28, 28, 1]), output);
    int predIndex = output[0].indexWhere((e) => e == output[0].reduce(max));
    return labels[predIndex];
    }


    Environment:

    Flutter 3.7.0
    tflite_flutter: ^0.11.0
    image: ^4.5.3


    The 28x28 preview looks wrong or white (probably bad pre-processing?). I tried multiple versions of rotation, resizing, grayscale, luminance, and nothing fixes it. I'll provide images of what it looks like:

    [​IMG]

    Is my Flutter preprocessing truly equivalent to the Python preprocessing?

    How can I accurately preview what image I'm feeding into the model (the true 28x28 processed one)?

    Am I misunderstanding how Flutter's image package handles pixel channels (RGBA vs grayscale)?

    Could my input shape normalization or pixel interpretation be slightly off causing all this?

    Continue reading...

Compartilhe esta Página