flutter_tflite_image_classification_engine 0.0.3
flutter_tflite_image_classification_engine: ^0.0.3 copied to clipboard
A lightweight Flutter package for running **TensorFlow Lite image classification** with custom `.tflite` models and label files.
flutter_tflite_image_classification_engine #
A lightweight, flexible, and UI-free Flutter engine for running TensorFlow Lite image classification with custom .tflite models and custom label files.
flutter_tflite_image_classification_engine helps Flutter developers add on-device image classification to their apps without forcing any camera, gallery, picker, or UI dependency into the core package.
Classify from File, Path, Bytes, Image Stream, or Camera Frame Stream.
π± Demo Preview #
Normal Image Classification | Realtime Stream Classification
β¨ Features #
- β TensorFlow Lite image classification
- β
Custom
.tflitemodel support - β
Custom
labels.txtsupport - β Model loading from asset, file, path, or bytes
- β Label loading from asset, file, path, raw text, or list
- β
Image classification from
File - β Image classification from image path
- β Image classification from image bytes
- β Single image classification mode
- β Realtime image stream classification mode
- β Realtime frame stream classification mode
- β Auto input tensor shape detection
- β RGB, BGRA8888, YUV420, and grayscale support
- β Configurable top-K predictions
- β Configurable confidence threshold
- β Configurable normalization
- β Output activation support: none, softmax, sigmoid
- β Resize strategy support: stretch, center crop, fit contain, letterbox
- β Optional model validation
- β Optional isolate-based image preprocessing
- β Structured result with predictions, timing, FPS, and JSON support
- β No camera dependency in core package
- β No gallery picker dependency in core package
- β No file picker dependency in core package
π Supported Modes #
| Mode | Description |
|---|---|
| Normal Classification | Classify a single image from file, path, or bytes |
| Image Stream Classification | Classify a stream of image inputs |
| Frame Stream Classification | Classify realtime camera frames from your own camera layer |
| Dynamic Model Mode | Load model from asset, file, path, or bytes |
| Dynamic Label Mode | Load labels from asset, file, path, text, or list |
π¦ Installation #
Add this package to your pubspec.yaml:
dependencies:
flutter_tflite_image_classification_engine: ^0.0.3
Then run:
flutter pub get
π Assets Setup #
Add your model and labels file:
assets/
models/
model.tflite
labels.txt
Register assets in your pubspec.yaml:
flutter:
assets:
- assets/models/model.tflite
- assets/models/labels.txt
β‘ Quick Start #
1. Import package #
import 'dart:io';
import 'package:flutter_tflite_image_classification_engine/flutter_tflite_image_classification_engine.dart';
2. Create engine from assets #
final FlutterTfliteImageClassificationEngine engine =
await FlutterTfliteImageClassificationEngine.fromAssets(
modelAssetPath: 'assets/models/model.tflite',
labelsAssetPath: 'assets/models/labels.txt',
options: TfliteClassifierOptions.mobileNet(
topK: 5,
minConfidence: 0.40,
),
);
Alternative classic API:
final FlutterTfliteImageClassificationEngine engine =
await FlutterTfliteImageClassificationEngine.create(
model: TfliteModel.asset('assets/models/model.tflite'),
labels: TfliteLabels.asset('assets/models/labels.txt'),
options: const TfliteClassifierOptions(
topK: 5,
minConfidence: 0.40,
),
);
3. Classify image #
final ClassificationResult result = await engine.classifyFile(
File('/storage/emulated/0/Pictures/image.jpg'),
);
print('Best Label: ${result.bestLabel}');
print('Confidence: ${result.bestConfidencePercent}');
engine.close();
π§ Normal Image Classification #
Use classifyFile(), classifyPath(), classifyBytes(), or classifyImage() for single image classification.
Future<void> runNormalClassification(File imageFile) async {
final engine = await FlutterTfliteImageClassificationEngine.fromAssets(
modelAssetPath: 'assets/models/model.tflite',
labelsAssetPath: 'assets/models/labels.txt',
options: const TfliteClassifierOptions(
mode: ClassificationMode.normal,
topK: 3,
minConfidence: 0.40,
threads: 4,
normalizationType: NormalizationType.zeroToOne,
outputActivation: OutputActivation.none,
resizeStrategy: ResizeStrategy.stretch,
channelOrder: ChannelOrder.rgb,
interpolation: ResizeInterpolation.linear,
unknownLabel: 'Unknown',
runPreprocessInIsolate: true,
),
);
final ClassificationResult result = await engine.classifyFile(imageFile);
if (result.isSuccess && !result.isUnknown) {
print('Best: ${result.bestLabel}');
print('Confidence: ${result.bestConfidencePercent}');
for (final TflitePrediction prediction in result.predictions) {
print('${prediction.label}: ${prediction.confidencePercent}');
}
} else {
print(result.error ?? result.message ?? 'Classification failed');
}
engine.close();
}
πΌοΈ Classify from Different Image Sources #
await engine.classifyFile(File('/storage/emulated/0/image.jpg'));
await engine.classifyPath('/storage/emulated/0/image.jpg');
await engine.classifyBytes(imageBytes);
await engine.classifyImage(ImageInput.file(imageFile));
β‘ Realtime Image Stream Classification #
This package does not open the camera directly. You can use any camera package or any custom stream and pass image/frame input to this engine.
Future<void> runRealtimeImageStream(
Stream<ImageInput> imageStream,
) async {
final engine = await FlutterTfliteImageClassificationEngine.fromAssets(
modelAssetPath: 'assets/models/model.tflite',
labelsAssetPath: 'assets/models/labels.txt',
options: const TfliteClassifierOptions(
mode: ClassificationMode.realtimeStream,
topK: 3,
minConfidence: 0.40,
realtimeOptions: RealtimeClassifierOptions(
frameIntervalMs: 300,
skipBusyFrames: true,
emitSkippedFrames: false,
maxStreamErrors: 5,
),
),
);
engine.classifyImageStream(imageStream).listen((ClassificationResult result) {
if (result.isSkipped) return;
if (result.isSuccess && !result.isUnknown) {
print('${result.bestLabel}: ${result.bestConfidencePercent}');
print('FPS: ${result.fps}');
print('Inference: ${result.inferenceTimeMs} ms');
} else {
print(result.error ?? result.message ?? 'Unknown result');
}
});
}
π₯ Realtime Camera Frame Classification #
For camera stream integration, convert your camera frame into FrameInput, then pass it to classifyFrameStream().
Stream<ClassificationResult> runFrameStream(
FlutterTfliteImageClassificationEngine engine,
Stream<FrameInput> frameStream,
) {
return engine.classifyFrameStream(frameStream);
}
Example frame input:
final FrameInput frame = FrameInput.rgb(
bytes: rgbBytes,
width: width,
height: height,
rotation: 90,
);
YUV420 input:
final FrameInput frame = FrameInput.yuv420(
width: width,
height: height,
rotation: 90,
planes: <FramePlane>[
FramePlane(
bytes: yPlaneBytes,
bytesPerRow: yBytesPerRow,
bytesPerPixel: 1,
),
FramePlane(
bytes: uPlaneBytes,
bytesPerRow: uBytesPerRow,
bytesPerPixel: uBytesPerPixel,
),
FramePlane(
bytes: vPlaneBytes,
bytesPerRow: vBytesPerRow,
bytesPerPixel: vBytesPerPixel,
),
],
);
π§ Dynamic Model Sources #
You can load your .tflite model in multiple ways:
TfliteModel.asset('assets/models/model.tflite');
TfliteModel.file(File('/storage/emulated/0/model.tflite'));
TfliteModel.path('/storage/emulated/0/model.tflite');
TfliteModel.bytes(modelBytes);
π·οΈ Dynamic Label Sources #
TfliteLabels.asset('assets/models/labels.txt');
TfliteLabels.file(File('/storage/emulated/0/labels.txt'));
TfliteLabels.path('/storage/emulated/0/labels.txt');
TfliteLabels.text('cat\ndog\nbird');
TfliteLabels.list(<String>['cat', 'dog', 'bird']);
βοΈ Configuration Options #
const TfliteClassifierOptions(
mode: ClassificationMode.normal,
topK: 3,
minConfidence: 0.40,
threads: 4,
normalizationType: NormalizationType.zeroToOne,
outputActivation: OutputActivation.none,
resizeStrategy: ResizeStrategy.stretch,
channelOrder: ChannelOrder.rgb,
interpolation: ResizeInterpolation.linear,
inputLayout: InputTensorLayout.nhwc,
unknownLabel: 'Unknown',
runPreprocessInIsolate: true,
modelValidationMode: ModelValidationMode.warning,
errorHandlingMode: ErrorHandlingMode.returnResult,
realtimeOptions: RealtimeClassifierOptions(
frameIntervalMs: 300,
skipBusyFrames: true,
emitSkippedFrames: false,
maxStreamErrors: 5,
),
);
π― Preset Options #
Use presets for common model types.
TfliteClassifierOptions.mobileNet(
topK: 5,
minConfidence: 0.40,
);
TfliteClassifierOptions.efficientNetLite(
topK: 5,
minConfidence: 0.40,
);
TfliteClassifierOptions.custom(
topK: 3,
minConfidence: 0.50,
normalizationType: NormalizationType.minusOneToOne,
);
π’ Normalization Types #
| Type | Formula |
|---|---|
NormalizationType.zeroToOne |
value = pixel / 255.0 |
NormalizationType.minusOneToOne |
value = (pixel - 127.5) / 127.5 |
NormalizationType.none |
value = raw pixel value 0..255 |
π Output Activation #
| Activation | Best For |
|---|---|
OutputActivation.none |
Model already returns probabilities |
OutputActivation.softmax |
Single-label classifier with logits |
OutputActivation.sigmoid |
Multi-label classifier with independent scores |
Example:
const TfliteClassifierOptions(
outputActivation: OutputActivation.softmax,
);
π§© Resize Strategy #
| Strategy | Description |
|---|---|
ResizeStrategy.stretch |
Resize directly to model input size |
ResizeStrategy.centerCrop |
Crop center area while preserving aspect ratio |
ResizeStrategy.fitContain |
Fit image inside input size |
ResizeStrategy.letterbox |
Preserve aspect ratio and add padding |
Example:
const TfliteClassifierOptions(
resizeStrategy: ResizeStrategy.centerCrop,
);
π Classification Result #
The engine returns a structured ClassificationResult.
final ClassificationResult result = await engine.classifyPath(imagePath);
print(result.isSuccess);
print(result.isUnknown);
print(result.isSkipped);
print(result.bestLabel);
print(result.bestConfidence);
print(result.bestConfidencePercent);
print(result.predictions);
print(result.rawScores);
print(result.inferenceTimeMs);
print(result.preprocessTimeMs);
print(result.totalTimeMs);
print(result.fps);
print(result.processedFrameCount);
print(result.skippedFrameCount);
print(result.toJson());
π Prediction Data #
Each prediction contains index, label, and confidence.
for (final TflitePrediction prediction in result.predictions) {
print('${prediction.index}');
print('${prediction.label}');
print('${prediction.confidence}');
print('${prediction.confidencePercent}');
}
π Useful Result Helpers #
result.bestLabel;
result.bestConfidence;
result.bestConfidencePercent;
result.top(3);
result.predictionByLabel('cat');
result.labelConfidenceMap;
result.toJson();
π Full Usage Example #
import 'dart:io';
import 'package:flutter_tflite_image_classification_engine/flutter_tflite_image_classification_engine.dart';
class ClassificationService {
FlutterTfliteImageClassificationEngine? _engine;
Future<void> load() async {
_engine = await FlutterTfliteImageClassificationEngine.fromAssets(
modelAssetPath: 'assets/models/model.tflite',
labelsAssetPath: 'assets/models/labels.txt',
options: TfliteClassifierOptions.mobileNet(
topK: 3,
minConfidence: 0.40,
),
);
}
Future<ClassificationResult> classify(File imageFile) async {
final engine = _engine;
if (engine == null) {
throw StateError('Classification engine is not loaded');
}
return engine.classifyFile(imageFile);
}
void dispose() {
_engine?.close();
}
}
π‘οΈ Performance Tips #
For realtime image classification, follow these rules:
- Load the model once and reuse the same engine
- Do not process every camera frame
- Use frame throttling
- Use
skipBusyFrames: true - Use low or medium camera resolution
- Do not call classification inside
build() - Stop image stream before disposing camera controller
- Close the engine when the screen is disposed
- Use isolate-based preprocessing for large images
Recommended realtime options:
const RealtimeClassifierOptions(
frameIntervalMs: 300,
skipBusyFrames: true,
emitSkippedFrames: false,
maxStreamErrors: 5,
);
π§ͺ Example App #
Run the example project:
cd example
flutter clean
flutter pub get
flutter run
The example app can show:
- Normal image classification
- Realtime stream classification
- Camera preview integration
- Classification result overlay
- Top prediction display
- Inference timing and FPS display
π§± Platform Support #
| Platform | Status |
|---|---|
| Android | β Supported |
| iOS | β Supported |
| Web | β Not supported |
| Windows | β Not supported |
| macOS | β Not supported |
| Linux | β Not supported |
β οΈ Important Note About Bounding Boxes #
This package is for image classification.
Image classification models return:
label + confidence
They do not return object position or bounding boxes.
So this package cannot draw a real moving rectangle around objects like object detection models.
For moving object rectangles, use an object detection model such as:
- SSD MobileNet
- YOLO
- EfficientDet
β Best For #
- Fruit classification
- Product category classification
- Plant classification
- Food classification
- Document image classification
- Realtime category classification
- Custom TFLite classifier integration
- Lightweight AI feature integration in Flutter apps
- Offline AI classification features
π« Not Included #
This package does not include:
- Camera UI
- Gallery picker
- File picker
- Object detection bounding box parser
- Model training
- Dataset annotation tools
This keeps the package lightweight, clean, and flexible.
πΊοΈ Roadmap #
- β Normal image classification
- β Realtime stream classification
- β Dynamic model source
- β Dynamic label source
- β Dynamic image source
- β Structured classification result
- β Isolate-based preprocessing
- β Easy asset/path shortcut constructors
- β Output activation options
- β Resize strategy options
- β More polished example apps
- β Camera helper example
- β Ready-made result widgets
- β Metadata-based model loading
- β More iOS optimization examples
β Troubleshooting #
Model file not found #
Make sure your model path is correct:
TfliteModel.asset('assets/models/model.tflite');
And make sure the asset is registered:
flutter:
assets:
- assets/models/model.tflite
Labels file not found #
Make sure your labels path is correct:
TfliteLabels.asset('assets/models/labels.txt');
And make sure the labels file is registered:
flutter:
assets:
- assets/models/labels.txt
Labels and output size mismatch #
Make sure your labels.txt order and count match the model output.
For strict validation:
const TfliteClassifierOptions(
modelValidationMode: ModelValidationMode.strict,
);
Wrong prediction result #
Try changing normalization type:
normalizationType: NormalizationType.zeroToOne,
or:
normalizationType: NormalizationType.minusOneToOne,
If your model returns logits, try:
outputActivation: OutputActivation.softmax,
Also make sure your labels order matches your model output order.
App is slow in realtime mode #
Use these settings:
const TfliteClassifierOptions(
runPreprocessInIsolate: true,
realtimeOptions: RealtimeClassifierOptions(
frameIntervalMs: 300,
skipBusyFrames: true,
),
);
Also use low or medium camera resolution in your app.
π€ Contributing #
Contributions are welcome.
You can help by adding:
- More example apps
- Better camera frame examples
- Ready-made UI widgets
- iOS optimization examples
- Documentation improvements
- More model preset examples
π License #
See the LICENSE file for details.
π¨βπ» Author #
Created by Nafim Ahmed.( https://github.com/NafimAhmed )
Flutter developer focused on AI vision, automation, ERP integrations, and realtime mobile applications.