tflite
A Flutter plugin for accessing TensorFlow Lite API. Supports image classification, object detection (SSD and YOLO), Pix2Pix and Deeplab and PoseNet on both iOS and Android.
Table of Contents
Breaking changes
Since 1.1.0:
- iOS TensorFlow Lite library is upgraded from TensorFlowLite 1.x to TensorFlowLiteObjC 2.x. Changes to native code are denoted with
TFLITE2.
Since 1.0.0:
- Updated to TensorFlow Lite API v1.12.0.
- No longer accepts parameter
inputSize and numChannels. They will be retrieved from input tensor.
numThreads is moved to Tflite.loadModel.
Installation
Add tflite as a dependency in your pubspec.yaml file.
Android
In android/app/build.gradle, add the following setting in android block.
aaptOptions {
noCompress 'tflite'
noCompress 'lite'
}
iOS
Solutions to build errors on iOS:
-
'vector' file not found"
Open ios/Runner.xcworkspace in Xcode, click Runner > Tagets > Runner > Build Settings, search Compile Sources As, change the value to Objective-C++
-
'tensorflow/lite/kernels/register.h' file not found
The plugin assumes the tensorflow header files are located in path "tensorflow/lite/kernels".
However, for early versions of tensorflow the header path is "tensorflow/contrib/lite/kernels".
Use CONTRIB_PATH to toggle the path. Uncomment //#define CONTRIB_PATH from here:
https://github.com/shaqian/flutter_tflite/blob/master/ios/Classes/TflitePlugin.mm#L1
Usage
- Create a
assets folder and place your label file and model file in it. In pubspec.yaml add:
assets:
- assets/labels.txt
- assets/mobilenet_v1_1.0_224.tflite
- Import the library:
import 'package:tflite/tflite.dart';
- Load the model and labels:
String res = await Tflite.loadModel(
model: "assets/mobilenet_v1_1.0_224.tflite",
labels: "assets/labels.txt",
numThreads: 1,
isAsset: true,
useGpuDelegate: false
);
-
See the section for the respective model below.
-
Release resources:
await Tflite.close();
GPU Delegate
When using GPU delegate, refer to this step for release mode setting to get better performance.
Image Classification
{
index: 0,
label: "person",
confidence: 0.629
}
var recognitions = await Tflite.runModelOnImage(
path: filepath,
imageMean: 0.0,
imageStd: 255.0,
numResults: 2,
threshold: 0.2,
asynch: true
);
var recognitions = await Tflite.runModelOnBinary(
binary: imageToByteListFloat32(image, 224, 127.5, 127.5),
numResults: 6,
threshold: 0.05,
asynch: true
);
Uint8List imageToByteListFloat32(
img.Image image, int inputSize, double mean, double std) {
var convertedBytes = Float32List(1 * inputSize * inputSize * 3);
var buffer = Float32List.view(convertedBytes.buffer);
int pixelIndex = 0;
for (var i = 0; i < inputSize; i++) {
for (var j = 0; j < inputSize; j++) {
var pixel = image.getPixel(j, i);
buffer[pixelIndex++] = (img.getRed(pixel) - mean) / std;
buffer[pixelIndex++] = (img.getGreen(pixel) - mean) / std;
buffer[pixelIndex++] = (img.getBlue(pixel) - mean) / std;
}
}
return convertedBytes.buffer.asUint8List();
}
Uint8List imageToByteListUint8(img.Image image, int inputSize) {
var convertedBytes = Uint8List(1 * inputSize * inputSize * 3);
var buffer = Uint8List.view(convertedBytes.buffer);
int pixelIndex = 0;
for (var i = 0; i < inputSize; i++) {
for (var j = 0; j < inputSize; j++) {
var pixel = image.getPixel(j, i);
buffer[pixelIndex++] = img.getRed(pixel);
buffer[pixelIndex++] = img.getGreen(pixel);
buffer[pixelIndex++] = img.getBlue(pixel);
}
}
return convertedBytes.buffer.asUint8List();
}
- Run on image stream (video frame):
Works with camera plugin 4.0.0. Video format: (iOS) kCVPixelFormatType_32BGRA, (Android) YUV_420_888.
var recognitions = await Tflite.runModelOnFrame(
bytesList: img.planes.map((plane) {return plane.bytes;}).toList(),
imageHeight: img.height,
imageWidth: img.width,
imageMean: 127.5,
imageStd: 127.5,
rotation: 90,
numResults: 2,
threshold: 0.1,
asynch: true
);
Object Detection
x, y, w, h are between [0, 1]. You can scale x, w by the width and y, h by the height of the image.
{
detectedClass: "hot dog",
confidenceInClass: 0.123,
rect: {
x: 0.15,
y: 0.33,
w: 0.80,
h: 0.27
}
}
SSD MobileNet:
var recognitions = await Tflite.detectObjectOnImage(
path: filepath,
model: "SSDMobileNet",
imageMean: 127.5,
imageStd: 127.5,
threshold: 0.4,
numResultsPerClass: 2,
asynch: true
);
var recognitions = await Tflite.detectObjectOnBinary(
binary: imageToByteListUint8(resizedImage, 300),
model: "SSDMobileNet",
threshold: 0.4,
numResultsPerClass: 2,
asynch: true
);
- Run on image stream (video frame):
Works with camera plugin 4.0.0. Video format: (iOS) kCVPixelFormatType_32BGRA, (Android) YUV_420_888.
var recognitions = await Tflite.detectObjectOnFrame(
bytesList: img.planes.map((plane) {return plane.bytes;}).toList(),
model: "SSDMobileNet",
imageHeight: img.height,
imageWidth: img.width,
imageMean: 127.5,
imageStd: 127.5,
rotation: 90,
numResults: 2,
threshold: 0.1,
asynch: true
);
Tiny YOLOv2:
var recognitions = await Tflite.detectObjectOnImage(
path: filepath,
model: "YOLO",
imageMean: 0.0,
imageStd: 255.0,
threshold: 0.3,
numResultsPerClass: 2,
anchors: anchors,
blockSize: 32,
numBoxesPerBlock: 5,
asynch: true
);
var recognitions = await Tflite.detectObjectOnBinary(
binary: imageToByteListFloat32(resizedImage, 416, 0.0, 255.0),
model: "YOLO",
threshold: 0.3,
numResultsPerClass: 2,
anchors: anchors,
blockSize: 32,
numBoxesPerBlock: 5,
asynch: true
);
- Run on image stream (video frame):
Works with camera plugin 4.0.0. Video format: (iOS) kCVPixelFormatType_32BGRA, (Android) YUV_420_888.
var recognitions = await Tflite.detectObjectOnFrame(
bytesList: img.planes.map((plane) {return plane.bytes;}).toList(),
model: "YOLO",
imageHeight: img.height,
imageWidth: img.width,
imageMean: 0,
imageStd: 255.0,
numResults: 2,
threshold: 0.1,
numResultsPerClass: 2,
anchors: anchors,
blockSize: 32,
numBoxesPerBlock: 5,
asynch: true
);
Pix2Pix
Thanks to RP from Green Appers
var result = await runPix2PixOnImage(
path: filepath,
imageMean: 0.0,
imageStd: 255.0,
asynch: true
);
var result = await runPix2PixOnBinary(
binary: binary,
asynch: true
);
- Run on image stream (video frame):
var result = await runPix2PixOnFrame(
bytesList: img.planes.map((plane) {return plane.bytes;}).toList(),
imageHeight: img.height,
imageWidth: img.width,
imageMean: 127.5,
imageStd: 127.5,
rotation: 90,
asynch: true
);
Deeplab
Thanks to RP from see-- for Android implementation.
var result = await runSegmentationOnImage(
path: filepath,
imageMean: 0.0,
imageStd: 255.0,
labelColors: [...],
outputType: "png",
asynch: true
);
var result = await runSegmentationOnBinary(
binary: binary,
labelColors: [...],
outputType: "png",
asynch: true
);
- Run on image stream (video frame):
var result = await runSegmentationOnFrame(
bytesList: img.planes.map((plane) {return plane.bytes;}).toList(),
imageHeight: img.height,
imageWidth: img.width,
imageMean: 127.5,
imageStd: 127.5,
rotation: 90,
labelColors: [...],
outputType: "png",
asynch: true
);
PoseNet
Model is from StackOverflow thread.
x, y are between [0, 1]. You can scale x by the width and y by the height of the image.
[ // array of poses/persons
{ // pose
score: 0.6324902,
keypoints: {
0: {
x: 0.250,
y: 0.125,
part: nose,
score: 0.9971070
},
1: {
x: 0.230,
y: 0.105,
part: leftEye,
score: 0.9978438
}
......
}
},
{ // pose
score: 0.32534285,
keypoints: {
0: {
x: 0.402,
y: 0.538,
part: nose,
score: 0.8798978
},
1: {
x: 0.380,
y: 0.513,
part: leftEye,
score: 0.7090239
}
......
}
},
......
]
var result = await runPoseNetOnImage(
path: filepath,
imageMean: 125.0,
imageStd: 125.0,
numResults: 2,
threshold: 0.7,
nmsRadius: 10,
asynch: true
);
var result = await runPoseNetOnBinary(
binary: binary,
numResults: 2,
threshold: 0.7,
nmsRadius: 10,
asynch: true
);
- Run on image stream (video frame):
var result = await runPoseNetOnFrame(
bytesList: img.planes.map((plane) {return plane.bytes;}).toList(),
imageHeight: img.height,
imageWidth: img.width,
imageMean: 125.0,
imageStd: 125.0,
rotation: 90,
numResults: 2,
threshold: 0.7,
nmsRadius: 10,
asynch: true
);
Example
Prediction in Static Images
Refer to the example.
Real-time detection
Refer to flutter_realtime_Detection.
Run test cases
flutter test test/tflite_test.dart