Help us measure site usage?

With your permission, we use self-hosted analytics to understand page usage. It is optional and does not affect the Service. Learn more.

DartadvancedaiAI generated

On-Device Image Classifier

Build a Flutter app that classifies photos entirely on the device, with no server and no internet needed. The user picks an image from the gallery or takes one with the camera. The app runs it through a bundled TensorFlow Lite model (MobileNet) and shows the top 5 predicted labels, each with its confidence as a percentage. You'll learn how to load and run an ML model in Dart, how to convert an image into the exact input format a model expects, how to manage async state with Riverpod, and how to handle real failures: unsupported files, denied permissions, a model that won't load. When you're done, you'll have a working app plus unit tests for the parts that don't need a device.

Estimate
~16h
Steps
8
Completed by
0
Proposed by
codeseed.app

Flutter · Riverpod

Project roadmap

  1. 01

    Set up the project and bundle the model

    ~1.5h

    Create a new Flutter project and add these dependencies: flutter_riverpod, tflite_flutter, image_picker, image. Download a MobileNet .tflite model and its labels file (for example from the TensorFlow Lite model zoo). Put both in assets/models/ and register them in pubspec.yaml under flutter → assets. Done when: the app builds and runs, and pubspec.yaml lists the four packages and both asset files.

  2. 02

    Load the model and labels

    ~2h

    Create lib/classifier/classifier.dart with a Classifier class. It loads the .tflite file with Interpreter.fromAsset and reads the labels file into a List<String>, one label per line. It exposes the model's input shape (e.g. 224×224×3), read from the interpreter rather than hard-coded. Loading must be async and throw a clear custom exception if the model or labels file is missing. Done when: a Classifier can be created and reports its input shape and label count.

  3. 03

    Convert an image into model input

    ~2.5h

    Write a function that takes raw image bytes and returns exactly what the model expects. Decode the bytes with the image package, resize to the model's input width and height, and convert the pixels into a [1, height, width, 3] list. Normalize values the way your model needs: 0–1 or -1 to 1 for float models, raw 0–255 integers for quantized ones. Keep this function pure (no Flutter imports) so it can be unit tested. Done when: any JPG or PNG produces a correctly shaped input.

  4. 04

    Run the model and rank the results

    ~2h

    Add a classify(bytes) method to Classifier. It preprocesses the image, runs the interpreter, pairs each output score with its label, sorts by confidence from highest to lowest, and returns the top 5 as (label, confidence) objects. Keep confidence as 0–1 in the data; the UI formats it as a percentage. Put the sort-and-take-top-5 logic in its own pure function so it can be tested without the model. Done when: classifying a photo returns 5 labels in descending order of confidence.

  5. 05

    Pick an image and manage state with Riverpod

    ~2.5h

    Use image_picker to let the user choose a photo from the gallery or take one with the camera. Create two Riverpod providers: one that loads the Classifier once at startup, and one (e.g. an AsyncNotifier) that holds the current state: idle, loading, results, or error. Picking a new image triggers classification and moves through those states. Done when: selecting an image moves the state from loading to results without freezing the UI.

  6. 06

    Build the results screen

    ~2h

    The main screen needs two buttons (Gallery and Camera), a preview of the selected image, and the top 5 predictions. Each prediction shows its label, its confidence as a percentage (e.g. 87.3%), and a progress bar sized to match. Show a spinner while classifying and a short hint before any image is picked. Done when: the whole flow works end to end on a device or emulator.

  7. 07

    Handle failures clearly

    ~1.5h

    Each of these cases should show a readable message, not a crash or a blank screen. If the user cancels the picker, the app simply returns to its previous state. The other cases each get a message: camera or gallery permission denied, a file that can't be decoded as an image, and a model that fails to load. Add the required camera and photo permission entries to AndroidManifest.xml and Info.plist. Done when: every one of these cases is handled and the app stays usable afterwards.

  8. 08

    Write unit tests

    ~2h

    In test/, write unit tests for the parts that don't need a device. Cover the preprocessing function (output shape and value range, using a small test image) and label file parsing. Also test the ranking logic with a fake list of scores rather than the real model: it should return the top 5, in order, with the correct labels matched to their scores. Done when: flutter test passes and covers all three areas.

Ready to build this?

Get a GitHub repo and start building. Your AI reviewer checks each step as you go.

~16h · 8 steps

Tech stack

FlutterRiverpod