From 55e04ba25a9a8b8b96a04ec4c516c55d30fe4ad0 Mon Sep 17 00:00:00 2001 From: Duy Mai M Date: Wed, 7 Feb 2024 11:23:58 +0700 Subject: [PATCH] add readme --- example/movinet/README.md | 26 ++++--- example/movinet/assets/images/tfl_logo.png | Bin 0 -> 7839 bytes example/movinet/ios/Runner/Info.plist | 2 + example/movinet/lib/main.dart | 5 +- example/movinet/pubspec.yaml | 3 +- lib/src/interpreter.dart | 80 ++++++++------------- 6 files changed, 55 insertions(+), 61 deletions(-) create mode 100644 example/movinet/assets/images/tfl_logo.png diff --git a/example/movinet/README.md b/example/movinet/README.md index 5e82f8c..64d2f3e 100644 --- a/example/movinet/README.md +++ b/example/movinet/README.md @@ -1,16 +1,22 @@ -# movinet +# Action Recognition Movinet -A new Flutter project. +| | Android | iOS | Linux | Mac | Windows | Web | +|------|---------|-----|-------|-----|---------|-----| +| live | ✅ | ✅ | | | | | -## Getting Started +This project is a sample of how to perform action recognition using +TensorFlow Lite in Flutter. It includes support for both Android and IOS. -This project is a starting point for a Flutter application. +## Download model and labels -A few resources to get you started if this is your first Flutter project: +To build the project, you must first download the Movinet TensorFlow Lite +model. You can do this by access https://www.kaggle.com/models/google/movinet +and download movinet model. After downloading the model, you must copy the model +into the `assets` folder. -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) +## About the sample -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +- You can use Flutter-supported IDEs such as Android Studio or Visual Studio. + This project has been tested on Android Studio Flamingo. +- Before building, ensure that you have downloaded the model and the labels by + following a set of instructions. diff --git a/example/movinet/assets/images/tfl_logo.png b/example/movinet/assets/images/tfl_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2bdcd9ab2120786edd9623a3920055d6ea88b523 GIT binary patch literal 7839 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 UILaunchStoryboardName LaunchScreen + NSCameraUsageDescription + Camera Permission UIMainStoryboardFile Main UISupportedInterfaceOrientations diff --git a/example/movinet/lib/main.dart b/example/movinet/lib/main.dart index 39cc2f5..bfe192b 100644 --- a/example/movinet/lib/main.dart +++ b/example/movinet/lib/main.dart @@ -160,7 +160,10 @@ class _MyHomePageState extends State with WidgetsBindingObserver { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Center(child: Text(widget.title)), + title: Image.asset( + 'assets/images/tfl_logo.png', + fit: BoxFit.contain, + ), backgroundColor: Colors.black.withOpacity(0.5), ), body: resultWidget(context), diff --git a/example/movinet/pubspec.yaml b/example/movinet/pubspec.yaml index 5b031ab..6a288ff 100644 --- a/example/movinet/pubspec.yaml +++ b/example/movinet/pubspec.yaml @@ -63,8 +63,9 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - - assets/movinet_int8.tflite + - assets/ - assets/label/kinetics600_label_map.txt + - assets/images/tfl_logo.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware diff --git a/lib/src/interpreter.dart b/lib/src/interpreter.dart index a37ff00..bb6a8e2 100644 --- a/lib/src/interpreter.dart +++ b/lib/src/interpreter.dart @@ -212,10 +212,14 @@ class Interpreter { inputTensors.elementAt(i).setTo(inputs[i]); } - var inferenceStartNanos = DateTime.now().microsecondsSinceEpoch; + var inferenceStartNanos = DateTime + .now() + .microsecondsSinceEpoch; invoke(); _lastNativeInferenceDurationMicroSeconds = - DateTime.now().microsecondsSinceEpoch - inferenceStartNanos; + DateTime + .now() + .microsecondsSinceEpoch - inferenceStartNanos; } /// Gets all input tensors associated with the model. @@ -226,8 +230,9 @@ class Interpreter { var tensors = List.generate( tfliteBinding.TfLiteInterpreterGetInputTensorCount(_interpreter), - (i) => Tensor( - tfliteBinding.TfLiteInterpreterGetInputTensor(_interpreter, i)), + (i) => + Tensor( + tfliteBinding.TfLiteInterpreterGetInputTensor(_interpreter, i)), growable: false); return tensors; @@ -241,8 +246,10 @@ class Interpreter { var tensors = List.generate( tfliteBinding.TfLiteInterpreterGetOutputTensorCount(_interpreter), - (i) => Tensor( - tfliteBinding.TfLiteInterpreterGetOutputTensor(_interpreter, i)), + (i) => + Tensor( + tfliteBinding.TfLiteInterpreterGetOutputTensor( + _interpreter, i)), growable: false); return tensors; @@ -253,7 +260,7 @@ class Interpreter { final dimensionSize = shape.length; final dimensions = calloc(dimensionSize); final externalTypedData = - dimensions.cast().asTypedList(dimensionSize); + dimensions.cast().asTypedList(dimensionSize); externalTypedData.setRange(0, dimensionSize, shape); final status = tfliteBinding.TfLiteInterpreterResizeInputTensor( _interpreter, tensorIndex, dimensions, dimensionSize); @@ -341,7 +348,7 @@ class Interpreter { // check if signature key exists if (!_signatureRunners.containsKey(signatureKey)) { Pointer signatureKeyPointer = - signatureKey.toNativeUtf8() as Pointer; + signatureKey.toNativeUtf8() as Pointer; final signatureRunner = tfliteBinding.TfLiteInterpreterGetSignatureRunner( _interpreter, signatureKeyPointer); _signatureRunners[signatureKey] = signatureRunner; @@ -355,7 +362,7 @@ class Interpreter { int getSignatureInputCount(String signatureKey) { final signatureRunner = _getSignatureRunner(signatureKey); final subGraphIndex = - tfliteBinding.TfLiteSignatureRunnerGetInputCount(signatureRunner); + tfliteBinding.TfLiteSignatureRunnerGetInputCount(signatureRunner); return subGraphIndex; } @@ -363,7 +370,7 @@ class Interpreter { int getSignatureOutputCount(String signatureKey) { final signatureRunner = _getSignatureRunner(signatureKey); final subGraphIndex = - tfliteBinding.TfLiteSignatureRunnerGetOutputCount(signatureRunner); + tfliteBinding.TfLiteSignatureRunnerGetOutputCount(signatureRunner); return subGraphIndex; } @@ -371,7 +378,7 @@ class Interpreter { String getSignatureInputName(String signatureKey, int index) { final signatureRunner = _getSignatureRunner(signatureKey); final inputName = - tfliteBinding.TfLiteSignatureRunnerGetInputName(signatureRunner, index); + tfliteBinding.TfLiteSignatureRunnerGetInputName(signatureRunner, index); return inputName.cast().toDartString(); } @@ -383,8 +390,8 @@ class Interpreter { return outputName.cast().toDartString(); } - List getSignatureInputTensorShape( - String signatureKey, String inputName) { + List getSignatureInputTensorShape(String signatureKey, + String inputName) { final signatureRunner = _getSignatureRunner(signatureKey); final inputTensor = Tensor( tfliteBinding.TfLiteSignatureRunnerGetInputTensor( @@ -393,8 +400,8 @@ class Interpreter { return shape; } - List getSignatureOutputTensorShape( - String signatureKey, String outputName) { + List getSignatureOutputTensorShape(String signatureKey, + String outputName) { final signatureRunner = _getSignatureRunner(signatureKey); final outputTensor = Tensor( tfliteBinding.TfLiteSignatureRunnerGetOutputTensor( @@ -403,32 +410,6 @@ class Interpreter { return shape; } - /// get signature input tensor - Map getSignatureInputTensors( - String signatureKey, List keys) { - final signatureRunner = _getSignatureRunner(signatureKey); - Map tensors = HashMap(); - keys.forEach((key) { - tensors[key] = Tensor(tfliteBinding.TfLiteSignatureRunnerGetInputTensor( - signatureRunner, key.toNativeUtf8().cast())); - }); - - return tensors; - } - - /// get signature output tensor - Map getSignatureOutputTensors( - String signatureKey, List keys) { - final signatureRunner = _getSignatureRunner(signatureKey); - Map tensors = HashMap(); - keys.forEach((key) { - tensors[key] = Tensor(tfliteBinding.TfLiteSignatureRunnerGetOutputTensor( - signatureRunner, key.toNativeUtf8().cast())); - }); - - return tensors; - } - /// Run for single input and output void runSignature(Map inputs, Map outputs, String signatureKey) { @@ -440,21 +421,22 @@ class Interpreter { } final Pointer signatureRunner = - _getSignatureRunner(signatureKey); - - var inputTensor = - getSignatureInputTensors(signatureKey, inputs.keys.toList()); + _getSignatureRunner(signatureKey); inputs.forEach((key, value) { - inputTensor[key]?.setTo(value); + Tensor inputTensor = Tensor( + tfliteBinding.TfLiteSignatureRunnerGetInputTensor( + signatureRunner, key.toNativeUtf8().cast())); + inputTensor.setTo(value); }); tfliteBinding.TfLiteSignatureRunnerInvoke(signatureRunner); - var outputTensor = - getSignatureOutputTensors(signatureKey, outputs.keys.toList()); outputs.forEach((key, value) { - outputTensor[key]?.copyTo(value); + Tensor outputTensor = Tensor( + tfliteBinding.TfLiteSignatureRunnerGetOutputTensor( + signatureRunner, key.toNativeUtf8().cast())); + outputTensor.copyTo(value); }); }