├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── hiennv │ │ │ │ └── flutter_realtime_object_detection │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── fonts │ ├── Roboto-Bold.ttf │ ├── Roboto-Medium.ttf │ └── Roboto-Regular.ttf ├── images │ ├── 2.0x │ │ └── logo.png │ ├── 3.0x │ │ └── logo.png │ └── logo.png └── models │ ├── mobilenet_v1.tflite │ ├── mobilenet_v1.txt │ ├── posenet_mv1_checkpoints.tflite │ ├── ssd_mobilenet.tflite │ ├── ssd_mobilenet.txt │ ├── yolov2_tiny.tflite │ └── yolov2_tiny.txt ├── images ├── image1.jpg ├── image2.jpg ├── image3.jpg ├── image4.jpg ├── image5.jpg └── image6.jpg ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── README.md │ │ ├── logo.png │ │ ├── logo@2x.png │ │ └── logo@3x.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── app │ ├── app_listener.dart │ ├── app_resources.dart │ ├── app_router.dart │ └── base │ │ ├── base_stateful.dart │ │ └── base_view_model.dart ├── main.dart ├── models │ └── recognition.dart ├── pages │ ├── home_screen.dart │ ├── local_screen.dart │ └── splash_screen.dart ├── services │ ├── navigation_service.dart │ └── tensorflow_service.dart ├── view_models │ ├── home_view_model.dart │ └── local_view_model.dart ├── view_states │ ├── home_view_state.dart │ └── local_view_state.dart └── widgets │ ├── aperture │ ├── aperture_leaf.dart │ ├── aperture_leaf_painter.dart │ └── aperture_widget.dart │ └── confidence_widget.dart ├── pubspec.lock └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f4abaa0735eba4dfd8f33f73363911d63931fe03 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Hien Nguyen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter realtime object detection with Tensorflow Lite 2 | 3 | Flutter realtime object detection with Tensorflow Lite 4 | 5 | ## Info 6 | 7 | An app made with Flutter and TensorFlow Lite for realtime object detection using model YOLO, SSD, MobileNet, PoseNet. 8 | 9 | 10 | 11 | ## :star: Features 12 | 13 | * Realtime object detection on the live camera 14 | * Using Model: YOLOv2-Tiny, SSDMobileNet, MobileNet, PoseNet 15 | * Save image has been detected 16 | * MVVM architecture 17 | 18 |
19 | 20 | ## 🚀  Installation 21 | 22 | 1. Install Packages 23 | ``` 24 | camera: get the streaming image buffers 25 | https://pub.dev/packages/camera 26 | ``` 27 | * https://pub.dev/packages/camera 28 | ``` 29 | tflite: run model TensorFlow Lite 30 | https://pub.dev/packages/tflite 31 | ``` 32 | * https://pub.dev/packages/tflite 33 | ``` 34 | provider: state management 35 | https://pub.dev/packages/provider 36 | ``` 37 | * https://pub.dev/packages/provider 38 | 39 |
40 | 2. Configure Project 41 | 42 | * Android 43 | ``` 44 | android/app/build.gradle 45 | 46 | android { 47 | ... 48 | aaptOptions { 49 | noCompress 'tflite' 50 | noCompress 'lite' 51 | } 52 | ... 53 | } 54 | 55 | 56 | minSdkVersion 21 57 | ``` 58 |
59 | 3. Load model 60 | 61 | ``` 62 | loadModel() async { 63 | Tflite.close(); 64 | await Tflite.loadModel( 65 | model: "assets/models/yolov2_tiny.tflite", 66 | //ssd_mobilenet.tflite, mobilenet_v1.tflite, posenet_mv1_checkpoints.tflite 67 | labels: "assets/models/yolov2_tiny.txt", 68 | //ssd_mobilenet.txt, mobilenet_v1.txt 69 | //numThreads: 1, // defaults to 1 70 | //isAsset: true, // defaults: true, set to false to load resources outside assets 71 | //useGpuDelegate: false // defaults: false, use GPU delegate 72 | ); 73 | } 74 | ``` 75 |
76 | 4. Run model 77 | 78 | For Realtime Camera 79 | ``` 80 | //YOLOv2-Tiny 81 | Future?> runModelOnFrame(CameraImage image) async { 82 | var recognitions = await Tflite.detectObjectOnFrame( 83 | bytesList: image.planes.map((plane) { 84 | return plane.bytes; 85 | }).toList(), 86 | model: "YOLO", 87 | imageHeight: image.height, 88 | imageWidth: image.width, 89 | imageMean: 0, // defaults to 127.5 90 | imageStd: 255.0, // defaults to 127.5 91 | threshold: 0.2, // defaults to 0.1 92 | numResultsPerClass: 1, 93 | ); 94 | return recognitions; 95 | } 96 | 97 | //SSDMobileNet 98 | Future?> runModelOnFrame(CameraImage image) async { 99 | var recognitions = await Tflite.detectObjectOnFrame( 100 | bytesList: image.planes.map((plane) { 101 | return plane.bytes; 102 | }).toList(), 103 | model: "SSDMobileNet", 104 | imageHeight: image.height, 105 | imageWidth: image.width, 106 | imageMean: 127.5, 107 | imageStd: 127.5, 108 | threshold: 0.4, 109 | numResultsPerClass: 1, 110 | ); 111 | return recognitions; 112 | } 113 | 114 | //MobileNet 115 | Future?> runModelOnFrame(CameraImage image) async { 116 | var recognitions = await Tflite.runModelOnFrame( 117 | bytesList: image.planes.map((plane) { 118 | return plane.bytes; 119 | }).toList(), 120 | imageHeight: image.height, 121 | imageWidth: image.width, 122 | numResults: 5 123 | ); 124 | return recognitions; 125 | } 126 | 127 | //PoseNet 128 | Future?> runModelOnFrame(CameraImage image) async { 129 | var recognitions = await Tflite.runPoseNetOnFrame( 130 | bytesList: image.planes.map((plane) { 131 | return plane.bytes; 132 | }).toList(), 133 | imageHeight: image.height, 134 | imageWidth: image.width, 135 | numResults: 5 136 | ); 137 | return recognitions; 138 | } 139 | ``` 140 | For Image 141 | ``` 142 | Future?> runModelOnImage(File image) async { 143 | var recognitions = await Tflite.detectObjectOnImage( 144 | path: image.path, 145 | model: "YOLO", 146 | threshold: 0.3, 147 | imageMean: 0.0, 148 | imageStd: 127.5, 149 | numResultsPerClass: 1 150 | ); 151 | return recognitions; 152 | } 153 | ``` 154 | ``` 155 | Output format: 156 | 157 | YOLO,SSDMobileNet 158 | [{ 159 | detectedClass: "dog", 160 | confidenceInClass: 0.989, 161 | rect: { 162 | x: 0.0, 163 | y: 0.0, 164 | w: 100.0, 165 | h: 100.0 166 | } 167 | },...] 168 | 169 | MobileNet 170 | [{ 171 | index: 0, 172 | label: "WithMask", 173 | confidence: 0.989 174 | },...] 175 | 176 | PoseNet 177 | [{ 178 | score: 0.5, 179 | keypoints: { 180 | 0: { 181 | x: 0.2, 182 | y: 0.12, 183 | part: nose, 184 | score: 0.803 185 | }, 186 | 1: { 187 | x: 0.2, 188 | y: 0.1, 189 | part: leftEye, 190 | score: 0.8666 191 | }, 192 | ... 193 | } 194 | },...] 195 | 196 | ``` 197 |
198 | 5. Issue 199 | 200 | ``` 201 | * IOS 202 | Downgrading TensorFlowLiteC to 2.2.0 203 | 204 | Downgrade your TensorFlowLiteC in /ios/Podfile.lock to 2.2.0 205 | run pod install in your /ios folder 206 | ``` 207 |
208 | 6. Source code 209 | 210 | ``` 211 | please checkout repo github 212 | https://github.com/hiennguyen92/flutter_realtime_object_detection 213 | ``` 214 | * https://github.com/hiennguyen92/flutter_realtime_object_detection 215 | ## :bulb: Demo 216 | 217 | 1. Demo Illustration: https://www.youtube.com/watch?v=__i7PRmz5kY&ab_channel=HienNguyen 218 | 2. Image 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 |
233 | 234 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.hiennv.flutter_realtime_object_detection" 38 | minSdkVersion 21 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | 52 | aaptOptions { 53 | noCompress 'tflite' 54 | noCompress 'lite' 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | } 65 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 14 | 18 | 22 | 27 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hiennv/flutter_realtime_object_detection/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hiennv.flutter_realtime_object_detection 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /assets/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /assets/images/2.0x/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/images/2.0x/logo.png -------------------------------------------------------------------------------- /assets/images/3.0x/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/images/3.0x/logo.png -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/images/logo.png -------------------------------------------------------------------------------- /assets/models/mobilenet_v1.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/models/mobilenet_v1.tflite -------------------------------------------------------------------------------- /assets/models/mobilenet_v1.txt: -------------------------------------------------------------------------------- 1 | background 2 | tench 3 | goldfish 4 | great white shark 5 | tiger shark 6 | hammerhead 7 | electric ray 8 | stingray 9 | cock 10 | hen 11 | ostrich 12 | brambling 13 | goldfinch 14 | house finch 15 | junco 16 | indigo bunting 17 | robin 18 | bulbul 19 | jay 20 | magpie 21 | chickadee 22 | water ouzel 23 | kite 24 | bald eagle 25 | vulture 26 | great grey owl 27 | European fire salamander 28 | common newt 29 | eft 30 | spotted salamander 31 | axolotl 32 | bullfrog 33 | tree frog 34 | tailed frog 35 | loggerhead 36 | leatherback turtle 37 | mud turtle 38 | terrapin 39 | box turtle 40 | banded gecko 41 | common iguana 42 | American chameleon 43 | whiptail 44 | agama 45 | frilled lizard 46 | alligator lizard 47 | Gila monster 48 | green lizard 49 | African chameleon 50 | Komodo dragon 51 | African crocodile 52 | American alligator 53 | triceratops 54 | thunder snake 55 | ringneck snake 56 | hognose snake 57 | green snake 58 | king snake 59 | garter snake 60 | water snake 61 | vine snake 62 | night snake 63 | boa constrictor 64 | rock python 65 | Indian cobra 66 | green mamba 67 | sea snake 68 | horned viper 69 | diamondback 70 | sidewinder 71 | trilobite 72 | harvestman 73 | scorpion 74 | black and gold garden spider 75 | barn spider 76 | garden spider 77 | black widow 78 | tarantula 79 | wolf spider 80 | tick 81 | centipede 82 | black grouse 83 | ptarmigan 84 | ruffed grouse 85 | prairie chicken 86 | peacock 87 | quail 88 | partridge 89 | African grey 90 | macaw 91 | sulphur-crested cockatoo 92 | lorikeet 93 | coucal 94 | bee eater 95 | hornbill 96 | hummingbird 97 | jacamar 98 | toucan 99 | drake 100 | red-breasted merganser 101 | goose 102 | black swan 103 | tusker 104 | echidna 105 | platypus 106 | wallaby 107 | koala 108 | wombat 109 | jellyfish 110 | sea anemone 111 | brain coral 112 | flatworm 113 | nematode 114 | conch 115 | snail 116 | slug 117 | sea slug 118 | chiton 119 | chambered nautilus 120 | Dungeness crab 121 | rock crab 122 | fiddler crab 123 | king crab 124 | American lobster 125 | spiny lobster 126 | crayfish 127 | hermit crab 128 | isopod 129 | white stork 130 | black stork 131 | spoonbill 132 | flamingo 133 | little blue heron 134 | American egret 135 | bittern 136 | crane 137 | limpkin 138 | European gallinule 139 | American coot 140 | bustard 141 | ruddy turnstone 142 | red-backed sandpiper 143 | redshank 144 | dowitcher 145 | oystercatcher 146 | pelican 147 | king penguin 148 | albatross 149 | grey whale 150 | killer whale 151 | dugong 152 | sea lion 153 | Chihuahua 154 | Japanese spaniel 155 | Maltese dog 156 | Pekinese 157 | Shih-Tzu 158 | Blenheim spaniel 159 | papillon 160 | toy terrier 161 | Rhodesian ridgeback 162 | Afghan hound 163 | basset 164 | beagle 165 | bloodhound 166 | bluetick 167 | black-and-tan coonhound 168 | Walker hound 169 | English foxhound 170 | redbone 171 | borzoi 172 | Irish wolfhound 173 | Italian greyhound 174 | whippet 175 | Ibizan hound 176 | Norwegian elkhound 177 | otterhound 178 | Saluki 179 | Scottish deerhound 180 | Weimaraner 181 | Staffordshire bullterrier 182 | American Staffordshire terrier 183 | Bedlington terrier 184 | Border terrier 185 | Kerry blue terrier 186 | Irish terrier 187 | Norfolk terrier 188 | Norwich terrier 189 | Yorkshire terrier 190 | wire-haired fox terrier 191 | Lakeland terrier 192 | Sealyham terrier 193 | Airedale 194 | cairn 195 | Australian terrier 196 | Dandie Dinmont 197 | Boston bull 198 | miniature schnauzer 199 | giant schnauzer 200 | standard schnauzer 201 | Scotch terrier 202 | Tibetan terrier 203 | silky terrier 204 | soft-coated wheaten terrier 205 | West Highland white terrier 206 | Lhasa 207 | flat-coated retriever 208 | curly-coated retriever 209 | golden retriever 210 | Labrador retriever 211 | Chesapeake Bay retriever 212 | German short-haired pointer 213 | vizsla 214 | English setter 215 | Irish setter 216 | Gordon setter 217 | Brittany spaniel 218 | clumber 219 | English springer 220 | Welsh springer spaniel 221 | cocker spaniel 222 | Sussex spaniel 223 | Irish water spaniel 224 | kuvasz 225 | schipperke 226 | groenendael 227 | malinois 228 | briard 229 | kelpie 230 | komondor 231 | Old English sheepdog 232 | Shetland sheepdog 233 | collie 234 | Border collie 235 | Bouvier des Flandres 236 | Rottweiler 237 | German shepherd 238 | Doberman 239 | miniature pinscher 240 | Greater Swiss Mountain dog 241 | Bernese mountain dog 242 | Appenzeller 243 | EntleBucher 244 | boxer 245 | bull mastiff 246 | Tibetan mastiff 247 | French bulldog 248 | Great Dane 249 | Saint Bernard 250 | Eskimo dog 251 | malamute 252 | Siberian husky 253 | dalmatian 254 | affenpinscher 255 | basenji 256 | pug 257 | Leonberg 258 | Newfoundland 259 | Great Pyrenees 260 | Samoyed 261 | Pomeranian 262 | chow 263 | keeshond 264 | Brabancon griffon 265 | Pembroke 266 | Cardigan 267 | toy poodle 268 | miniature poodle 269 | standard poodle 270 | Mexican hairless 271 | timber wolf 272 | white wolf 273 | red wolf 274 | coyote 275 | dingo 276 | dhole 277 | African hunting dog 278 | hyena 279 | red fox 280 | kit fox 281 | Arctic fox 282 | grey fox 283 | tabby 284 | tiger cat 285 | Persian cat 286 | Siamese cat 287 | Egyptian cat 288 | cougar 289 | lynx 290 | leopard 291 | snow leopard 292 | jaguar 293 | lion 294 | tiger 295 | cheetah 296 | brown bear 297 | American black bear 298 | ice bear 299 | sloth bear 300 | mongoose 301 | meerkat 302 | tiger beetle 303 | ladybug 304 | ground beetle 305 | long-horned beetle 306 | leaf beetle 307 | dung beetle 308 | rhinoceros beetle 309 | weevil 310 | fly 311 | bee 312 | ant 313 | grasshopper 314 | cricket 315 | walking stick 316 | cockroach 317 | mantis 318 | cicada 319 | leafhopper 320 | lacewing 321 | dragonfly 322 | damselfly 323 | admiral 324 | ringlet 325 | monarch 326 | cabbage butterfly 327 | sulphur butterfly 328 | lycaenid 329 | starfish 330 | sea urchin 331 | sea cucumber 332 | wood rabbit 333 | hare 334 | Angora 335 | hamster 336 | porcupine 337 | fox squirrel 338 | marmot 339 | beaver 340 | guinea pig 341 | sorrel 342 | zebra 343 | hog 344 | wild boar 345 | warthog 346 | hippopotamus 347 | ox 348 | water buffalo 349 | bison 350 | ram 351 | bighorn 352 | ibex 353 | hartebeest 354 | impala 355 | gazelle 356 | Arabian camel 357 | llama 358 | weasel 359 | mink 360 | polecat 361 | black-footed ferret 362 | otter 363 | skunk 364 | badger 365 | armadillo 366 | three-toed sloth 367 | orangutan 368 | gorilla 369 | chimpanzee 370 | gibbon 371 | siamang 372 | guenon 373 | patas 374 | baboon 375 | macaque 376 | langur 377 | colobus 378 | proboscis monkey 379 | marmoset 380 | capuchin 381 | howler monkey 382 | titi 383 | spider monkey 384 | squirrel monkey 385 | Madagascar cat 386 | indri 387 | Indian elephant 388 | African elephant 389 | lesser panda 390 | giant panda 391 | barracouta 392 | eel 393 | coho 394 | rock beauty 395 | anemone fish 396 | sturgeon 397 | gar 398 | lionfish 399 | puffer 400 | abacus 401 | abaya 402 | academic gown 403 | accordion 404 | acoustic guitar 405 | aircraft carrier 406 | airliner 407 | airship 408 | altar 409 | ambulance 410 | amphibian 411 | analog clock 412 | apiary 413 | apron 414 | ashcan 415 | assault rifle 416 | backpack 417 | bakery 418 | balance beam 419 | balloon 420 | ballpoint 421 | Band Aid 422 | banjo 423 | bannister 424 | barbell 425 | barber chair 426 | barbershop 427 | barn 428 | barometer 429 | barrel 430 | barrow 431 | baseball 432 | basketball 433 | bassinet 434 | bassoon 435 | bathing cap 436 | bath towel 437 | bathtub 438 | beach wagon 439 | beacon 440 | beaker 441 | bearskin 442 | beer bottle 443 | beer glass 444 | bell cote 445 | bib 446 | bicycle-built-for-two 447 | bikini 448 | binder 449 | binoculars 450 | birdhouse 451 | boathouse 452 | bobsled 453 | bolo tie 454 | bonnet 455 | bookcase 456 | bookshop 457 | bottlecap 458 | bow 459 | bow tie 460 | brass 461 | brassiere 462 | breakwater 463 | breastplate 464 | broom 465 | bucket 466 | buckle 467 | bulletproof vest 468 | bullet train 469 | butcher shop 470 | cab 471 | caldron 472 | candle 473 | cannon 474 | canoe 475 | can opener 476 | cardigan 477 | car mirror 478 | carousel 479 | carpenter's kit 480 | carton 481 | car wheel 482 | cash machine 483 | cassette 484 | cassette player 485 | castle 486 | catamaran 487 | CD player 488 | cello 489 | cellular telephone 490 | chain 491 | chainlink fence 492 | chain mail 493 | chain saw 494 | chest 495 | chiffonier 496 | chime 497 | china cabinet 498 | Christmas stocking 499 | church 500 | cinema 501 | cleaver 502 | cliff dwelling 503 | cloak 504 | clog 505 | cocktail shaker 506 | coffee mug 507 | coffeepot 508 | coil 509 | combination lock 510 | computer keyboard 511 | confectionery 512 | container ship 513 | convertible 514 | corkscrew 515 | cornet 516 | cowboy boot 517 | cowboy hat 518 | cradle 519 | crane 520 | crash helmet 521 | crate 522 | crib 523 | Crock Pot 524 | croquet ball 525 | crutch 526 | cuirass 527 | dam 528 | desk 529 | desktop computer 530 | dial telephone 531 | diaper 532 | digital clock 533 | digital watch 534 | dining table 535 | dishrag 536 | dishwasher 537 | disk brake 538 | dock 539 | dogsled 540 | dome 541 | doormat 542 | drilling platform 543 | drum 544 | drumstick 545 | dumbbell 546 | Dutch oven 547 | electric fan 548 | electric guitar 549 | electric locomotive 550 | entertainment center 551 | envelope 552 | espresso maker 553 | face powder 554 | feather boa 555 | file 556 | fireboat 557 | fire engine 558 | fire screen 559 | flagpole 560 | flute 561 | folding chair 562 | football helmet 563 | forklift 564 | fountain 565 | fountain pen 566 | four-poster 567 | freight car 568 | French horn 569 | frying pan 570 | fur coat 571 | garbage truck 572 | gasmask 573 | gas pump 574 | goblet 575 | go-kart 576 | golf ball 577 | golfcart 578 | gondola 579 | gong 580 | gown 581 | grand piano 582 | greenhouse 583 | grille 584 | grocery store 585 | guillotine 586 | hair slide 587 | hair spray 588 | half track 589 | hammer 590 | hamper 591 | hand blower 592 | hand-held computer 593 | handkerchief 594 | hard disc 595 | harmonica 596 | harp 597 | harvester 598 | hatchet 599 | holster 600 | home theater 601 | honeycomb 602 | hook 603 | hoopskirt 604 | horizontal bar 605 | horse cart 606 | hourglass 607 | iPod 608 | iron 609 | jack-o'-lantern 610 | jean 611 | jeep 612 | jersey 613 | jigsaw puzzle 614 | jinrikisha 615 | joystick 616 | kimono 617 | knee pad 618 | knot 619 | lab coat 620 | ladle 621 | lampshade 622 | laptop 623 | lawn mower 624 | lens cap 625 | letter opener 626 | library 627 | lifeboat 628 | lighter 629 | limousine 630 | liner 631 | lipstick 632 | Loafer 633 | lotion 634 | loudspeaker 635 | loupe 636 | lumbermill 637 | magnetic compass 638 | mailbag 639 | mailbox 640 | maillot 641 | maillot 642 | manhole cover 643 | maraca 644 | marimba 645 | mask 646 | matchstick 647 | maypole 648 | maze 649 | measuring cup 650 | medicine chest 651 | megalith 652 | microphone 653 | microwave 654 | military uniform 655 | milk can 656 | minibus 657 | miniskirt 658 | minivan 659 | missile 660 | mitten 661 | mixing bowl 662 | mobile home 663 | Model T 664 | modem 665 | monastery 666 | monitor 667 | moped 668 | mortar 669 | mortarboard 670 | mosque 671 | mosquito net 672 | motor scooter 673 | mountain bike 674 | mountain tent 675 | mouse 676 | mousetrap 677 | moving van 678 | muzzle 679 | nail 680 | neck brace 681 | necklace 682 | nipple 683 | notebook 684 | obelisk 685 | oboe 686 | ocarina 687 | odometer 688 | oil filter 689 | organ 690 | oscilloscope 691 | overskirt 692 | oxcart 693 | oxygen mask 694 | packet 695 | paddle 696 | paddlewheel 697 | padlock 698 | paintbrush 699 | pajama 700 | palace 701 | panpipe 702 | paper towel 703 | parachute 704 | parallel bars 705 | park bench 706 | parking meter 707 | passenger car 708 | patio 709 | pay-phone 710 | pedestal 711 | pencil box 712 | pencil sharpener 713 | perfume 714 | Petri dish 715 | photocopier 716 | pick 717 | pickelhaube 718 | picket fence 719 | pickup 720 | pier 721 | piggy bank 722 | pill bottle 723 | pillow 724 | ping-pong ball 725 | pinwheel 726 | pirate 727 | pitcher 728 | plane 729 | planetarium 730 | plastic bag 731 | plate rack 732 | plow 733 | plunger 734 | Polaroid camera 735 | pole 736 | police van 737 | poncho 738 | pool table 739 | pop bottle 740 | pot 741 | potter's wheel 742 | power drill 743 | prayer rug 744 | printer 745 | prison 746 | projectile 747 | projector 748 | puck 749 | punching bag 750 | purse 751 | quill 752 | quilt 753 | racer 754 | racket 755 | radiator 756 | radio 757 | radio telescope 758 | rain barrel 759 | recreational vehicle 760 | reel 761 | reflex camera 762 | refrigerator 763 | remote control 764 | restaurant 765 | revolver 766 | rifle 767 | rocking chair 768 | rotisserie 769 | rubber eraser 770 | rugby ball 771 | rule 772 | running shoe 773 | safe 774 | safety pin 775 | saltshaker 776 | sandal 777 | sarong 778 | sax 779 | scabbard 780 | scale 781 | school bus 782 | schooner 783 | scoreboard 784 | screen 785 | screw 786 | screwdriver 787 | seat belt 788 | sewing machine 789 | shield 790 | shoe shop 791 | shoji 792 | shopping basket 793 | shopping cart 794 | shovel 795 | shower cap 796 | shower curtain 797 | ski 798 | ski mask 799 | sleeping bag 800 | slide rule 801 | sliding door 802 | slot 803 | snorkel 804 | snowmobile 805 | snowplow 806 | soap dispenser 807 | soccer ball 808 | sock 809 | solar dish 810 | sombrero 811 | soup bowl 812 | space bar 813 | space heater 814 | space shuttle 815 | spatula 816 | speedboat 817 | spider web 818 | spindle 819 | sports car 820 | spotlight 821 | stage 822 | steam locomotive 823 | steel arch bridge 824 | steel drum 825 | stethoscope 826 | stole 827 | stone wall 828 | stopwatch 829 | stove 830 | strainer 831 | streetcar 832 | stretcher 833 | studio couch 834 | stupa 835 | submarine 836 | suit 837 | sundial 838 | sunglass 839 | sunglasses 840 | sunscreen 841 | suspension bridge 842 | swab 843 | sweatshirt 844 | swimming trunks 845 | swing 846 | switch 847 | syringe 848 | table lamp 849 | tank 850 | tape player 851 | teapot 852 | teddy 853 | television 854 | tennis ball 855 | thatch 856 | theater curtain 857 | thimble 858 | thresher 859 | throne 860 | tile roof 861 | toaster 862 | tobacco shop 863 | toilet seat 864 | torch 865 | totem pole 866 | tow truck 867 | toyshop 868 | tractor 869 | trailer truck 870 | tray 871 | trench coat 872 | tricycle 873 | trimaran 874 | tripod 875 | triumphal arch 876 | trolleybus 877 | trombone 878 | tub 879 | turnstile 880 | typewriter keyboard 881 | umbrella 882 | unicycle 883 | upright 884 | vacuum 885 | vase 886 | vault 887 | velvet 888 | vending machine 889 | vestment 890 | viaduct 891 | violin 892 | volleyball 893 | waffle iron 894 | wall clock 895 | wallet 896 | wardrobe 897 | warplane 898 | washbasin 899 | washer 900 | water bottle 901 | water jug 902 | water tower 903 | whiskey jug 904 | whistle 905 | wig 906 | window screen 907 | window shade 908 | Windsor tie 909 | wine bottle 910 | wing 911 | wok 912 | wooden spoon 913 | wool 914 | worm fence 915 | wreck 916 | yawl 917 | yurt 918 | web site 919 | comic book 920 | crossword puzzle 921 | street sign 922 | traffic light 923 | book jacket 924 | menu 925 | plate 926 | guacamole 927 | consomme 928 | hot pot 929 | trifle 930 | ice cream 931 | ice lolly 932 | French loaf 933 | bagel 934 | pretzel 935 | cheeseburger 936 | hotdog 937 | mashed potato 938 | head cabbage 939 | broccoli 940 | cauliflower 941 | zucchini 942 | spaghetti squash 943 | acorn squash 944 | butternut squash 945 | cucumber 946 | artichoke 947 | bell pepper 948 | cardoon 949 | mushroom 950 | Granny Smith 951 | strawberry 952 | orange 953 | lemon 954 | fig 955 | pineapple 956 | banana 957 | jackfruit 958 | custard apple 959 | pomegranate 960 | hay 961 | carbonara 962 | chocolate sauce 963 | dough 964 | meat loaf 965 | pizza 966 | potpie 967 | burrito 968 | red wine 969 | espresso 970 | cup 971 | eggnog 972 | alp 973 | bubble 974 | cliff 975 | coral reef 976 | geyser 977 | lakeside 978 | promontory 979 | sandbar 980 | seashore 981 | valley 982 | volcano 983 | ballplayer 984 | groom 985 | scuba diver 986 | rapeseed 987 | daisy 988 | yellow lady's slipper 989 | corn 990 | acorn 991 | hip 992 | buckeye 993 | coral fungus 994 | agaric 995 | gyromitra 996 | stinkhorn 997 | earthstar 998 | hen-of-the-woods 999 | bolete 1000 | ear 1001 | toilet tissue 1002 | -------------------------------------------------------------------------------- /assets/models/posenet_mv1_checkpoints.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/models/posenet_mv1_checkpoints.tflite -------------------------------------------------------------------------------- /assets/models/ssd_mobilenet.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/models/ssd_mobilenet.tflite -------------------------------------------------------------------------------- /assets/models/ssd_mobilenet.txt: -------------------------------------------------------------------------------- 1 | ??? 2 | person 3 | bicycle 4 | car 5 | motorcycle 6 | airplane 7 | bus 8 | train 9 | truck 10 | boat 11 | traffic light 12 | fire hydrant 13 | ??? 14 | stop sign 15 | parking meter 16 | bench 17 | bird 18 | cat 19 | dog 20 | horse 21 | sheep 22 | cow 23 | elephant 24 | bear 25 | zebra 26 | giraffe 27 | ??? 28 | backpack 29 | umbrella 30 | ??? 31 | ??? 32 | handbag 33 | tie 34 | suitcase 35 | frisbee 36 | skis 37 | snowboard 38 | sports ball 39 | kite 40 | baseball bat 41 | baseball glove 42 | skateboard 43 | surfboard 44 | tennis racket 45 | bottle 46 | ??? 47 | wine glass 48 | cup 49 | fork 50 | knife 51 | spoon 52 | bowl 53 | banana 54 | apple 55 | sandwich 56 | orange 57 | broccoli 58 | carrot 59 | hot dog 60 | pizza 61 | donut 62 | cake 63 | chair 64 | couch 65 | potted plant 66 | bed 67 | ??? 68 | dining table 69 | ??? 70 | ??? 71 | toilet 72 | ??? 73 | tv 74 | laptop 75 | mouse 76 | remote 77 | keyboard 78 | cell phone 79 | microwave 80 | oven 81 | toaster 82 | sink 83 | refrigerator 84 | ??? 85 | book 86 | clock 87 | vase 88 | scissors 89 | teddy bear 90 | hair drier 91 | toothbrush 92 | -------------------------------------------------------------------------------- /assets/models/yolov2_tiny.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/assets/models/yolov2_tiny.tflite -------------------------------------------------------------------------------- /assets/models/yolov2_tiny.txt: -------------------------------------------------------------------------------- 1 | person 2 | bicycle 3 | car 4 | motorbike 5 | aeroplane 6 | bus 7 | train 8 | truck 9 | boat 10 | traffic light 11 | fire hydrant 12 | stop sign 13 | parking meter 14 | bench 15 | bird 16 | cat 17 | dog 18 | horse 19 | sheep 20 | cow 21 | elephant 22 | bear 23 | zebra 24 | giraffe 25 | backpack 26 | umbrella 27 | handbag 28 | tie 29 | suitcase 30 | frisbee 31 | skis 32 | snowboard 33 | sports ball 34 | kite 35 | baseball bat 36 | baseball glove 37 | skateboard 38 | surfboard 39 | tennis racket 40 | bottle 41 | wine glass 42 | cup 43 | fork 44 | knife 45 | spoon 46 | bowl 47 | banana 48 | apple 49 | sandwich 50 | orange 51 | broccoli 52 | carrot 53 | hot dog 54 | pizza 55 | donut 56 | cake 57 | chair 58 | sofa 59 | pottedplant 60 | bed 61 | diningtable 62 | toilet 63 | tvmonitor 64 | laptop 65 | mouse 66 | remote 67 | keyboard 68 | cell phone 69 | microwave 70 | oven 71 | toaster 72 | sink 73 | refrigerator 74 | book 75 | clock 76 | vase 77 | scissors 78 | teddy bear 79 | hair drier 80 | toothbrush 81 | -------------------------------------------------------------------------------- /images/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/images/image1.jpg -------------------------------------------------------------------------------- /images/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/images/image2.jpg -------------------------------------------------------------------------------- /images/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/images/image3.jpg -------------------------------------------------------------------------------- /images/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/images/image4.jpg -------------------------------------------------------------------------------- /images/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/images/image5.jpg -------------------------------------------------------------------------------- /images/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/images/image6.jpg -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - camera (0.0.1): 3 | - Flutter 4 | - Flutter (1.0.0) 5 | - image_gallery_saver (1.5.0): 6 | - Flutter 7 | - image_picker (0.0.1): 8 | - Flutter 9 | - TensorFlowLiteC (2.2.0) 10 | - tflite (1.1.2): 11 | - Flutter 12 | - TensorFlowLiteC 13 | - url_launcher (0.0.1): 14 | - Flutter 15 | 16 | DEPENDENCIES: 17 | - camera (from `.symlinks/plugins/camera/ios`) 18 | - Flutter (from `Flutter`) 19 | - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`) 20 | - image_picker (from `.symlinks/plugins/image_picker/ios`) 21 | - tflite (from `.symlinks/plugins/tflite/ios`) 22 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`) 23 | 24 | SPEC REPOS: 25 | trunk: 26 | - TensorFlowLiteC 27 | 28 | EXTERNAL SOURCES: 29 | camera: 30 | :path: ".symlinks/plugins/camera/ios" 31 | Flutter: 32 | :path: Flutter 33 | image_gallery_saver: 34 | :path: ".symlinks/plugins/image_gallery_saver/ios" 35 | image_picker: 36 | :path: ".symlinks/plugins/image_picker/ios" 37 | tflite: 38 | :path: ".symlinks/plugins/tflite/ios" 39 | url_launcher: 40 | :path: ".symlinks/plugins/url_launcher/ios" 41 | 42 | SPEC CHECKSUMS: 43 | camera: 3164201dc344383e62282964016528c4f5a9ad50 44 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c 45 | image_gallery_saver: 259eab68fb271cfd57d599904f7acdc7832e7ef2 46 | image_picker: e06f7a68f000bd36f552c1847e33cda96ed31f1f 47 | TensorFlowLiteC: b3ab9e867b0b71052ca102a32a786555b330b02e 48 | tflite: 7acd11db0915e2d90ab90474413068568eb605f0 49 | url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef 50 | 51 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 52 | 53 | COCOAPODS: 1.10.1 54 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 931B7663E5750EA93E4164BB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE79A235869A4F3567D16BED /* Pods_Runner.framework */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 35 | 3B0A0860FC559D9DCBB767F6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 37 | 621842E2FE5E78F19599B868 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 38 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 39 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 40 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 41 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 42 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 43 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 46 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 47 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | D4CD9338F6EB7D51F2CA5C19 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 49 | DE79A235869A4F3567D16BED /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 931B7663E5750EA93E4164BB /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 55EF2BCEC80394B32FD0B7E4 /* Pods */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 3B0A0860FC559D9DCBB767F6 /* Pods-Runner.debug.xcconfig */, 68 | 621842E2FE5E78F19599B868 /* Pods-Runner.release.xcconfig */, 69 | D4CD9338F6EB7D51F2CA5C19 /* Pods-Runner.profile.xcconfig */, 70 | ); 71 | path = Pods; 72 | sourceTree = ""; 73 | }; 74 | 5AE14FE4C5406962649D8943 /* Frameworks */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | DE79A235869A4F3567D16BED /* Pods_Runner.framework */, 78 | ); 79 | name = Frameworks; 80 | sourceTree = ""; 81 | }; 82 | 9740EEB11CF90186004384FC /* Flutter */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 86 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 87 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 88 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 89 | ); 90 | name = Flutter; 91 | sourceTree = ""; 92 | }; 93 | 97C146E51CF9000F007C117D = { 94 | isa = PBXGroup; 95 | children = ( 96 | 9740EEB11CF90186004384FC /* Flutter */, 97 | 97C146F01CF9000F007C117D /* Runner */, 98 | 97C146EF1CF9000F007C117D /* Products */, 99 | 55EF2BCEC80394B32FD0B7E4 /* Pods */, 100 | 5AE14FE4C5406962649D8943 /* Frameworks */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | 97C146EF1CF9000F007C117D /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 97C146EE1CF9000F007C117D /* Runner.app */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 97C146F01CF9000F007C117D /* Runner */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 116 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 117 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 118 | 97C147021CF9000F007C117D /* Info.plist */, 119 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 120 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 121 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 122 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 123 | ); 124 | path = Runner; 125 | sourceTree = ""; 126 | }; 127 | /* End PBXGroup section */ 128 | 129 | /* Begin PBXNativeTarget section */ 130 | 97C146ED1CF9000F007C117D /* Runner */ = { 131 | isa = PBXNativeTarget; 132 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 133 | buildPhases = ( 134 | 622D5F5AD13988F83F5BA1BA /* [CP] Check Pods Manifest.lock */, 135 | 9740EEB61CF901F6004384FC /* Run Script */, 136 | 97C146EA1CF9000F007C117D /* Sources */, 137 | 97C146EB1CF9000F007C117D /* Frameworks */, 138 | 97C146EC1CF9000F007C117D /* Resources */, 139 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 140 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 141 | 083E61A3BD1DF1F64CFBCDF1 /* [CP] Embed Pods Frameworks */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = Runner; 148 | productName = Runner; 149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 150 | productType = "com.apple.product-type.application"; 151 | }; 152 | /* End PBXNativeTarget section */ 153 | 154 | /* Begin PBXProject section */ 155 | 97C146E61CF9000F007C117D /* Project object */ = { 156 | isa = PBXProject; 157 | attributes = { 158 | LastUpgradeCheck = 1020; 159 | ORGANIZATIONNAME = ""; 160 | TargetAttributes = { 161 | 97C146ED1CF9000F007C117D = { 162 | CreatedOnToolsVersion = 7.3.1; 163 | LastSwiftMigration = 1100; 164 | }; 165 | }; 166 | }; 167 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 168 | compatibilityVersion = "Xcode 9.3"; 169 | developmentRegion = en; 170 | hasScannedForEncodings = 0; 171 | knownRegions = ( 172 | en, 173 | Base, 174 | ); 175 | mainGroup = 97C146E51CF9000F007C117D; 176 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 177 | projectDirPath = ""; 178 | projectRoot = ""; 179 | targets = ( 180 | 97C146ED1CF9000F007C117D /* Runner */, 181 | ); 182 | }; 183 | /* End PBXProject section */ 184 | 185 | /* Begin PBXResourcesBuildPhase section */ 186 | 97C146EC1CF9000F007C117D /* Resources */ = { 187 | isa = PBXResourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 191 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 193 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | }; 197 | /* End PBXResourcesBuildPhase section */ 198 | 199 | /* Begin PBXShellScriptBuildPhase section */ 200 | 083E61A3BD1DF1F64CFBCDF1 /* [CP] Embed Pods Frameworks */ = { 201 | isa = PBXShellScriptBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | ); 205 | inputFileListPaths = ( 206 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 207 | ); 208 | name = "[CP] Embed Pods Frameworks"; 209 | outputFileListPaths = ( 210 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | shellPath = /bin/sh; 214 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 215 | showEnvVarsInLog = 0; 216 | }; 217 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 218 | isa = PBXShellScriptBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | ); 222 | inputPaths = ( 223 | ); 224 | name = "Thin Binary"; 225 | outputPaths = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | shellPath = /bin/sh; 229 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 230 | }; 231 | 622D5F5AD13988F83F5BA1BA /* [CP] Check Pods Manifest.lock */ = { 232 | isa = PBXShellScriptBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | ); 236 | inputFileListPaths = ( 237 | ); 238 | inputPaths = ( 239 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 240 | "${PODS_ROOT}/Manifest.lock", 241 | ); 242 | name = "[CP] Check Pods Manifest.lock"; 243 | outputFileListPaths = ( 244 | ); 245 | outputPaths = ( 246 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | shellPath = /bin/sh; 250 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 251 | showEnvVarsInLog = 0; 252 | }; 253 | 9740EEB61CF901F6004384FC /* Run Script */ = { 254 | isa = PBXShellScriptBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | ); 258 | inputPaths = ( 259 | ); 260 | name = "Run Script"; 261 | outputPaths = ( 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | shellPath = /bin/sh; 265 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 266 | }; 267 | /* End PBXShellScriptBuildPhase section */ 268 | 269 | /* Begin PBXSourcesBuildPhase section */ 270 | 97C146EA1CF9000F007C117D /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 275 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 276 | ); 277 | runOnlyForDeploymentPostprocessing = 0; 278 | }; 279 | /* End PBXSourcesBuildPhase section */ 280 | 281 | /* Begin PBXVariantGroup section */ 282 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 283 | isa = PBXVariantGroup; 284 | children = ( 285 | 97C146FB1CF9000F007C117D /* Base */, 286 | ); 287 | name = Main.storyboard; 288 | sourceTree = ""; 289 | }; 290 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 291 | isa = PBXVariantGroup; 292 | children = ( 293 | 97C147001CF9000F007C117D /* Base */, 294 | ); 295 | name = LaunchScreen.storyboard; 296 | sourceTree = ""; 297 | }; 298 | /* End PBXVariantGroup section */ 299 | 300 | /* Begin XCBuildConfiguration section */ 301 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ALWAYS_SEARCH_USER_PATHS = NO; 305 | CLANG_ANALYZER_NONNULL = YES; 306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 307 | CLANG_CXX_LIBRARY = "libc++"; 308 | CLANG_ENABLE_MODULES = YES; 309 | CLANG_ENABLE_OBJC_ARC = YES; 310 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 311 | CLANG_WARN_BOOL_CONVERSION = YES; 312 | CLANG_WARN_COMMA = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 325 | CLANG_WARN_STRICT_PROTOTYPES = YES; 326 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 327 | CLANG_WARN_UNREACHABLE_CODE = YES; 328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 330 | COPY_PHASE_STRIP = NO; 331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 332 | ENABLE_NS_ASSERTIONS = NO; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | GCC_C_LANGUAGE_STANDARD = gnu99; 335 | GCC_NO_COMMON_BLOCKS = YES; 336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 338 | GCC_WARN_UNDECLARED_SELECTOR = YES; 339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 340 | GCC_WARN_UNUSED_FUNCTION = YES; 341 | GCC_WARN_UNUSED_VARIABLE = YES; 342 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 343 | MTL_ENABLE_DEBUG_INFO = NO; 344 | SDKROOT = iphoneos; 345 | SUPPORTED_PLATFORMS = iphoneos; 346 | TARGETED_DEVICE_FAMILY = "1,2"; 347 | VALIDATE_PRODUCT = YES; 348 | }; 349 | name = Profile; 350 | }; 351 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 352 | isa = XCBuildConfiguration; 353 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 354 | buildSettings = { 355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 356 | CLANG_ENABLE_MODULES = YES; 357 | CODE_SIGN_STYLE = Manual; 358 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 359 | DEVELOPMENT_TEAM = U6ZMTZ5S22; 360 | ENABLE_BITCODE = NO; 361 | INFOPLIST_FILE = Runner/Info.plist; 362 | LD_RUNPATH_SEARCH_PATHS = ( 363 | "$(inherited)", 364 | "@executable_path/Frameworks", 365 | ); 366 | PRODUCT_BUNDLE_IDENTIFIER = com.hiennv.test; 367 | PRODUCT_NAME = "$(TARGET_NAME)"; 368 | PROVISIONING_PROFILE_SPECIFIER = "HienNV test profile"; 369 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 370 | SWIFT_VERSION = 5.0; 371 | VERSIONING_SYSTEM = "apple-generic"; 372 | }; 373 | name = Profile; 374 | }; 375 | 97C147031CF9000F007C117D /* Debug */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_ANALYZER_NONNULL = YES; 380 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 381 | CLANG_CXX_LIBRARY = "libc++"; 382 | CLANG_ENABLE_MODULES = YES; 383 | CLANG_ENABLE_OBJC_ARC = YES; 384 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 385 | CLANG_WARN_BOOL_CONVERSION = YES; 386 | CLANG_WARN_COMMA = YES; 387 | CLANG_WARN_CONSTANT_CONVERSION = YES; 388 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INFINITE_RECURSION = YES; 393 | CLANG_WARN_INT_CONVERSION = YES; 394 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 395 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 396 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 397 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 398 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 399 | CLANG_WARN_STRICT_PROTOTYPES = YES; 400 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 401 | CLANG_WARN_UNREACHABLE_CODE = YES; 402 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 403 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 404 | COPY_PHASE_STRIP = NO; 405 | DEBUG_INFORMATION_FORMAT = dwarf; 406 | ENABLE_STRICT_OBJC_MSGSEND = YES; 407 | ENABLE_TESTABILITY = YES; 408 | GCC_C_LANGUAGE_STANDARD = gnu99; 409 | GCC_DYNAMIC_NO_PIC = NO; 410 | GCC_NO_COMMON_BLOCKS = YES; 411 | GCC_OPTIMIZATION_LEVEL = 0; 412 | GCC_PREPROCESSOR_DEFINITIONS = ( 413 | "DEBUG=1", 414 | "$(inherited)", 415 | ); 416 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 417 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 418 | GCC_WARN_UNDECLARED_SELECTOR = YES; 419 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 420 | GCC_WARN_UNUSED_FUNCTION = YES; 421 | GCC_WARN_UNUSED_VARIABLE = YES; 422 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 423 | MTL_ENABLE_DEBUG_INFO = YES; 424 | ONLY_ACTIVE_ARCH = YES; 425 | SDKROOT = iphoneos; 426 | TARGETED_DEVICE_FAMILY = "1,2"; 427 | }; 428 | name = Debug; 429 | }; 430 | 97C147041CF9000F007C117D /* Release */ = { 431 | isa = XCBuildConfiguration; 432 | buildSettings = { 433 | ALWAYS_SEARCH_USER_PATHS = NO; 434 | CLANG_ANALYZER_NONNULL = YES; 435 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 436 | CLANG_CXX_LIBRARY = "libc++"; 437 | CLANG_ENABLE_MODULES = YES; 438 | CLANG_ENABLE_OBJC_ARC = YES; 439 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 440 | CLANG_WARN_BOOL_CONVERSION = YES; 441 | CLANG_WARN_COMMA = YES; 442 | CLANG_WARN_CONSTANT_CONVERSION = YES; 443 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 444 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 445 | CLANG_WARN_EMPTY_BODY = YES; 446 | CLANG_WARN_ENUM_CONVERSION = YES; 447 | CLANG_WARN_INFINITE_RECURSION = YES; 448 | CLANG_WARN_INT_CONVERSION = YES; 449 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 450 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 451 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 452 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 453 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 454 | CLANG_WARN_STRICT_PROTOTYPES = YES; 455 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 456 | CLANG_WARN_UNREACHABLE_CODE = YES; 457 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 458 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 459 | COPY_PHASE_STRIP = NO; 460 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 461 | ENABLE_NS_ASSERTIONS = NO; 462 | ENABLE_STRICT_OBJC_MSGSEND = YES; 463 | GCC_C_LANGUAGE_STANDARD = gnu99; 464 | GCC_NO_COMMON_BLOCKS = YES; 465 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 466 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 467 | GCC_WARN_UNDECLARED_SELECTOR = YES; 468 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 469 | GCC_WARN_UNUSED_FUNCTION = YES; 470 | GCC_WARN_UNUSED_VARIABLE = YES; 471 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 472 | MTL_ENABLE_DEBUG_INFO = NO; 473 | SDKROOT = iphoneos; 474 | SUPPORTED_PLATFORMS = iphoneos; 475 | SWIFT_COMPILATION_MODE = wholemodule; 476 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 477 | TARGETED_DEVICE_FAMILY = "1,2"; 478 | VALIDATE_PRODUCT = YES; 479 | }; 480 | name = Release; 481 | }; 482 | 97C147061CF9000F007C117D /* Debug */ = { 483 | isa = XCBuildConfiguration; 484 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 485 | buildSettings = { 486 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 487 | CLANG_ENABLE_MODULES = YES; 488 | CODE_SIGN_STYLE = Manual; 489 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 490 | DEVELOPMENT_TEAM = U6ZMTZ5S22; 491 | ENABLE_BITCODE = NO; 492 | INFOPLIST_FILE = Runner/Info.plist; 493 | LD_RUNPATH_SEARCH_PATHS = ( 494 | "$(inherited)", 495 | "@executable_path/Frameworks", 496 | ); 497 | PRODUCT_BUNDLE_IDENTIFIER = com.hiennv.test; 498 | PRODUCT_NAME = "$(TARGET_NAME)"; 499 | PROVISIONING_PROFILE_SPECIFIER = "HienNV test profile"; 500 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 501 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 502 | SWIFT_VERSION = 5.0; 503 | VERSIONING_SYSTEM = "apple-generic"; 504 | }; 505 | name = Debug; 506 | }; 507 | 97C147071CF9000F007C117D /* Release */ = { 508 | isa = XCBuildConfiguration; 509 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 510 | buildSettings = { 511 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 512 | CLANG_ENABLE_MODULES = YES; 513 | CODE_SIGN_STYLE = Manual; 514 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 515 | DEVELOPMENT_TEAM = U6ZMTZ5S22; 516 | ENABLE_BITCODE = NO; 517 | INFOPLIST_FILE = Runner/Info.plist; 518 | LD_RUNPATH_SEARCH_PATHS = ( 519 | "$(inherited)", 520 | "@executable_path/Frameworks", 521 | ); 522 | PRODUCT_BUNDLE_IDENTIFIER = com.hiennv.test; 523 | PRODUCT_NAME = "$(TARGET_NAME)"; 524 | PROVISIONING_PROFILE_SPECIFIER = "HienNV test profile"; 525 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 526 | SWIFT_VERSION = 5.0; 527 | VERSIONING_SYSTEM = "apple-generic"; 528 | }; 529 | name = Release; 530 | }; 531 | /* End XCBuildConfiguration section */ 532 | 533 | /* Begin XCConfigurationList section */ 534 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 535 | isa = XCConfigurationList; 536 | buildConfigurations = ( 537 | 97C147031CF9000F007C117D /* Debug */, 538 | 97C147041CF9000F007C117D /* Release */, 539 | 249021D3217E4FDB00AE95B9 /* Profile */, 540 | ); 541 | defaultConfigurationIsVisible = 0; 542 | defaultConfigurationName = Release; 543 | }; 544 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 545 | isa = XCConfigurationList; 546 | buildConfigurations = ( 547 | 97C147061CF9000F007C117D /* Debug */, 548 | 97C147071CF9000F007C117D /* Release */, 549 | 249021D4217E4FDB00AE95B9 /* Profile */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | /* End XCConfigurationList section */ 555 | }; 556 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 557 | } 558 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "logo@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "logo@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/LaunchImage.imageset/logo.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/LaunchImage.imageset/logo@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiennguyen92/flutter_realtime_object_detection/00e785330c8993d8cb1a17129f354b5aa230d6a6/ios/Runner/Assets.xcassets/LaunchImage.imageset/logo@3x.png -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Realtime Object Detection 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | flutter_realtime_object_detection 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | NSBonjourServices 47 | 48 | _dartobservatory._tcp 49 | 50 | NSCameraUsageDescription 51 | Realtime Object Detection camera use 52 | NSPhotoLibraryUsageDescription 53 | Realtime Object Detection photo use 54 | NSMicrophoneUsageDescription 55 | Realtime Object Detection microphone use 56 | LSApplicationQueriesSchemes 57 | 58 | https 59 | http 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/app/app_listener.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:async'; 3 | 4 | class AppListener { 5 | static StreamController _appManageListener = StreamController.broadcast(); 6 | 7 | static Map listeners = {}; 8 | 9 | static void addListener(void onFunc(dynamic data)) { 10 | listeners[onFunc] = _appManageListener.stream.listen(onFunc); 11 | } 12 | 13 | static void removeListener(void onFunc(dynamic data)) { 14 | StreamSubscription? listener = listeners[onFunc]; 15 | if(listener == null) return; 16 | listener.cancel(); 17 | listeners.remove(onFunc); 18 | } 19 | 20 | static void close() { 21 | _appManageListener.close(); 22 | } 23 | 24 | 25 | 26 | /// 27 | //登录成功广播 28 | static void test(dynamic data){ 29 | _appManageListener.add(data); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /lib/app/app_resources.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppIcons { 4 | AppIcons._(); 5 | 6 | static const IconData cameraFront = Icons.camera_front; 7 | static const IconData cameraBack = Icons.camera_rear; 8 | static const IconData linkOption = Icons.format_quote; 9 | static const IconData option = Icons.more_vert; 10 | static const IconData plus = Icons.add; 11 | } 12 | 13 | class AppColors { 14 | AppColors._(); 15 | 16 | static const Color black = Colors.black; 17 | static const Color white = Colors.white; 18 | static const Color blue = Colors.blue; 19 | static const Color grey = Colors.grey; 20 | } 21 | 22 | class AppFonts { 23 | AppFonts._(); 24 | 25 | static const String fontRoboto = 'Roboto'; 26 | } 27 | 28 | class AppFontSizes { 29 | AppFontSizes._(); 30 | 31 | static const double extraExtraSmall = 10.0; 32 | static const double extraSmall = 12.0; 33 | static const double small = 14.0; 34 | static const double medium = 16.0; 35 | static const double large = 18.0; 36 | } 37 | 38 | class AppTextStyles { 39 | AppTextStyles._(); 40 | 41 | //Regular 42 | static TextStyle regularTextStyle( 43 | {double? fontSize, Color? color, double? height, Color? backgroundColor}) => 44 | TextStyle( 45 | fontFamily: AppFonts.fontRoboto, 46 | fontWeight: FontWeight.w300, 47 | fontSize: fontSize ?? AppFontSizes.medium, 48 | color: color ?? AppColors.black, 49 | backgroundColor: backgroundColor ?? null, 50 | height: height); 51 | 52 | //Medium 53 | static TextStyle mediumTextStyle( 54 | {double? fontSize, Color? color, double? height, Color? backgroundColor}) => 55 | TextStyle( 56 | fontFamily: AppFonts.fontRoboto, 57 | fontSize: fontSize ?? AppFontSizes.medium, 58 | fontWeight: FontWeight.w500, 59 | color: color ?? AppColors.black, 60 | backgroundColor: backgroundColor ?? null, 61 | height: height); 62 | 63 | //Bold 64 | static TextStyle boldTextStyle( 65 | {double? fontSize, Color? color, double? height, Color? backgroundColor}) => 66 | TextStyle( 67 | fontFamily: AppFonts.fontRoboto, 68 | fontSize: fontSize ?? AppFontSizes.medium, 69 | fontWeight: FontWeight.w700, 70 | color: color ?? AppColors.black, 71 | backgroundColor: backgroundColor ?? null, 72 | height: height); 73 | } 74 | 75 | class AppImages { 76 | AppImages._(); 77 | 78 | // 79 | } 80 | 81 | class AppStrings { 82 | AppStrings._(); 83 | 84 | static const title = 'Realtime Object Detection'; 85 | static const urlRepo = 'https://github.com/hiennguyen92/flutter_realtime_object_detection'; 86 | } 87 | -------------------------------------------------------------------------------- /lib/app/app_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_realtime_object_detection/pages/home_screen.dart'; 3 | import 'package:flutter_realtime_object_detection/pages/local_screen.dart'; 4 | import 'package:flutter_realtime_object_detection/pages/splash_screen.dart'; 5 | import 'package:flutter_realtime_object_detection/services/navigation_service.dart'; 6 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 7 | import 'package:flutter_realtime_object_detection/view_models/home_view_model.dart'; 8 | import 'package:flutter_realtime_object_detection/view_models/local_view_model.dart'; 9 | import 'package:provider/provider.dart'; 10 | 11 | class AppRoute { 12 | static const splashScreen = '/splashScreen'; 13 | static const homeScreen = '/homeScreen'; 14 | static const localScreen = '/localScreen'; 15 | 16 | static final AppRoute _instance = AppRoute._private(); 17 | factory AppRoute() { 18 | return _instance; 19 | } 20 | AppRoute._private(); 21 | 22 | static AppRoute get instance => _instance; 23 | 24 | static Widget createProvider

( 25 | P Function(BuildContext context) provider, 26 | Widget child, 27 | ) { 28 | return ChangeNotifierProvider

( 29 | create: provider, 30 | builder: (_, __) { 31 | return child; 32 | }, 33 | ); 34 | } 35 | 36 | Route? generateRoute(RouteSettings settings) { 37 | switch (settings.name) { 38 | case splashScreen: 39 | return AppPageRoute(builder: (_) => SplashScreen()); 40 | case homeScreen: 41 | Duration? duration; 42 | if (settings.arguments != null) { 43 | final args = settings.arguments as Map; 44 | if ((args['isWithoutAnimation'] as bool)) { 45 | duration = Duration.zero; 46 | } 47 | } 48 | return AppPageRoute( 49 | appTransitionDuration: duration, 50 | appSettings: settings, 51 | builder: (_) => ChangeNotifierProvider( 52 | create: (context) => HomeViewModel(context, 53 | Provider.of(context, listen: false)), 54 | builder: (_, __) => HomeScreen())); 55 | case localScreen: 56 | return AppPageRoute( 57 | appSettings: settings, 58 | builder: (_) => ChangeNotifierProvider( 59 | create: (context) => LocalViewModel(context, 60 | Provider.of(context, listen: false)), 61 | builder: (_, __) => LocalScreen())); 62 | default: 63 | return null; 64 | } 65 | } 66 | } 67 | 68 | class AppPageRoute extends MaterialPageRoute { 69 | Duration? appTransitionDuration; 70 | 71 | RouteSettings? appSettings; 72 | 73 | AppPageRoute( 74 | {required WidgetBuilder builder, 75 | this.appSettings, 76 | this.appTransitionDuration}) 77 | : super(builder: builder); 78 | 79 | @override 80 | Duration get transitionDuration => 81 | appTransitionDuration ?? super.transitionDuration; 82 | 83 | @override 84 | RouteSettings get settings => appSettings ?? super.settings; 85 | } 86 | -------------------------------------------------------------------------------- /lib/app/base/base_stateful.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_realtime_object_detection/app/base/base_view_model.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | abstract class BaseStateful 6 | extends State with AutomaticKeepAliveClientMixin { 7 | late E viewModel = Provider.of(context, listen: false); 8 | 9 | @override 10 | bool get wantKeepAlive => false; 11 | 12 | @mustCallSuper 13 | @override 14 | void initState() { 15 | super.initState(); 16 | WidgetsBinding.instance?.addPostFrameCallback((_) { 17 | if (mounted) { 18 | afterFirstBuild(context); 19 | } 20 | }); 21 | } 22 | 23 | @protected 24 | void afterFirstBuild(BuildContext context) {} 25 | 26 | @override 27 | void setState(VoidCallback fn) { 28 | if (mounted) { 29 | super.setState(fn); 30 | } 31 | } 32 | 33 | @mustCallSuper 34 | @override 35 | Widget build(BuildContext context) { 36 | super.build(context); 37 | return ChangeNotifierProvider.value( 38 | value: viewModel, child: buildPageWidget(context)); 39 | } 40 | 41 | @protected 42 | Widget buildPageWidget(BuildContext context) { 43 | return Scaffold( 44 | appBar: buildAppBarWidget(context), 45 | body: buildBodyWidget(context), 46 | ); 47 | } 48 | 49 | @protected 50 | AppBar buildAppBarWidget(BuildContext context); 51 | 52 | @protected 53 | Widget buildBodyWidget(BuildContext context); 54 | 55 | Widget loadingWidget() { 56 | return Container( 57 | height: MediaQuery.of(context).size.height, 58 | width: double.infinity, 59 | child: Center(child: CircularProgressIndicator(color: Colors.blue))); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/app/base/base_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | abstract class BaseViewModel with ChangeNotifier { 4 | 5 | bool _mounted = true; 6 | 7 | BuildContext _context; 8 | 9 | T _state; 10 | 11 | bool get mounted => _mounted; 12 | 13 | bool _isLoading = false; 14 | 15 | bool get isLoading => _isLoading; 16 | 17 | T get state => _state; 18 | 19 | set isLoading(bool isLoading) { 20 | if(_isLoading != isLoading){ 21 | _isLoading = isLoading; 22 | this.notifyListeners(); 23 | } 24 | } 25 | 26 | BaseViewModel(this._context, this._state); 27 | 28 | @override 29 | void dispose() { 30 | super.dispose(); 31 | _mounted = false; 32 | } 33 | } -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:camera/camera.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_realtime_object_detection/app/app_router.dart'; 4 | import 'package:flutter_realtime_object_detection/services/navigation_service.dart'; 5 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 6 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:provider/single_child_widget.dart'; 9 | 10 | late List cameras; 11 | 12 | Future main() async { 13 | WidgetsFlutterBinding.ensureInitialized(); 14 | cameras = await availableCameras(); 15 | runApp(MultiProvider( 16 | providers: [ 17 | Provider(create: (_) => AppRoute()), 18 | Provider(create: (_) => NavigationService()), 19 | Provider(create: (_) => TensorFlowService()) 20 | ], 21 | child: Application(), 22 | )); 23 | } 24 | 25 | class Application extends StatelessWidget { 26 | @override 27 | Widget build(BuildContext context) { 28 | final AppRoute appRoute = Provider.of(context, listen: false); 29 | return ScreenUtilInit( 30 | designSize: Size(375, 812), 31 | builder: () { 32 | return MaterialApp( 33 | debugShowCheckedModeBanner: false, 34 | theme: ThemeData.dark(), 35 | onGenerateRoute: appRoute.generateRoute, 36 | initialRoute: AppRoute.splashScreen, 37 | navigatorKey: NavigationService.navigationKey, 38 | navigatorObservers: [ 39 | NavigationService.routeObserver 40 | ], 41 | ); 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/models/recognition.dart: -------------------------------------------------------------------------------- 1 | class Recognition { 2 | double? confidenceInClass; 3 | 4 | String? detectedClass; 5 | 6 | Rect? rect; 7 | 8 | /// 9 | int? index; 10 | 11 | String? label; 12 | 13 | double? confidence; 14 | 15 | ///PoseNet 16 | double? score; 17 | 18 | List? keypoints; 19 | 20 | Recognition( 21 | {this.detectedClass, 22 | this.confidenceInClass, 23 | this.rect, 24 | this.index, 25 | this.label, 26 | this.confidence, 27 | this.score, 28 | this.keypoints}); 29 | 30 | Map toJson() => { 31 | 'detectedClass': detectedClass, 32 | 'confidenceInClass': confidenceInClass, 33 | 'rect': rect?.toJson(), 34 | 'index': index, 35 | 'label': label, 36 | 'confidence': confidence, 37 | 'score': score, 38 | 'keypoints': keypoints 39 | }; 40 | 41 | factory Recognition.fromJson(Map json) => Recognition( 42 | detectedClass: json['detectedClass'] as String?, 43 | confidenceInClass: json['confidenceInClass'] as double?, 44 | rect: Rect.fromJson(json['rect'] as Map?), 45 | index: json['index'] as int?, 46 | label: json['label'] as String?, 47 | confidence: json['confidence'] as double?, 48 | score: json['score'] as double?, 49 | keypoints: json['keypoints'] != null ? (json['keypoints'] as Map?)! 50 | .values 51 | .map((e) => Keypoint.fromJson(e as Map?)) 52 | .toList(): [] ); 53 | 54 | @override 55 | String toString() { 56 | return 'Recognition{x: $confidenceInClass, detectedClass: $detectedClass, rect: $rect, index: $index, label: $label, confidence: $confidence}'; 57 | } 58 | } 59 | 60 | class Rect { 61 | double x = 0.0; 62 | double y = 0.0; 63 | double w = 0.0; 64 | double h = 0.0; 65 | 66 | Rect({required this.x, required this.y, required this.w, required this.h}); 67 | 68 | Map toJson() => 69 | {'x': x, 'y': y, 'w': w, 'h': h}; 70 | 71 | factory Rect.fromJson(Map? json) => Rect( 72 | x: json != null ? json['x'] as double : 0.0, 73 | y: json != null ? json['y'] as double : 0.0, 74 | w: json != null ? json['w'] as double : 0.0, 75 | h: json != null ? json['h'] as double : 0.0); 76 | 77 | @override 78 | String toString() { 79 | return 'Rect{x: $x, y: $y, w: $w, h: $h}'; 80 | } 81 | } 82 | 83 | class Keypoint { 84 | double x = 0.0; 85 | double y = 0.0; 86 | double score = 0.0; 87 | String part = ''; 88 | 89 | Keypoint( 90 | {required this.x, 91 | required this.y, 92 | required this.score, 93 | required this.part}); 94 | 95 | Map toJson() => 96 | {'x': x, 'y': y, 'score': score, 'part': part}; 97 | 98 | factory Keypoint.fromJson(Map? json) => Keypoint( 99 | x: json != null ? json['x'] as double : 0.0, 100 | y: json != null ? json['y'] as double : 0.0, 101 | score: json != null ? json['score'] as double : 0.0, 102 | part: json != null ? json['part'] as String : ''); 103 | 104 | @override 105 | String toString() { 106 | return 'Rect{x: $x, y: $y, w: $score, h: $part}'; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /lib/pages/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:math'; 3 | import 'dart:typed_data'; 4 | import 'dart:ui' as UI; 5 | 6 | import 'package:camera/camera.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter/widgets.dart'; 9 | import 'package:flutter_realtime_object_detection/app/app_resources.dart'; 10 | import 'package:flutter_realtime_object_detection/app/app_router.dart'; 11 | import 'package:flutter_realtime_object_detection/app/base/base_stateful.dart'; 12 | import 'package:flutter_realtime_object_detection/main.dart'; 13 | import 'package:flutter_realtime_object_detection/services/navigation_service.dart'; 14 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 15 | import 'package:flutter_realtime_object_detection/view_models/home_view_model.dart'; 16 | import 'package:flutter_realtime_object_detection/widgets/aperture/aperture_widget.dart'; 17 | import 'package:flutter_realtime_object_detection/widgets/confidence_widget.dart'; 18 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 19 | import 'package:image_gallery_saver/image_gallery_saver.dart'; 20 | import 'package:provider/provider.dart'; 21 | import 'package:screenshot/screenshot.dart'; 22 | import 'package:url_launcher/url_launcher.dart'; 23 | 24 | class HomeScreen extends StatefulWidget { 25 | @override 26 | State createState() { 27 | return _HomeScreenState(); 28 | } 29 | } 30 | 31 | class _HomeScreenState extends BaseStateful 32 | with WidgetsBindingObserver { 33 | late CameraController _cameraController; 34 | late Future _initializeControllerFuture; 35 | 36 | late StreamController apertureController; 37 | 38 | late ScreenshotController screenshotController; 39 | 40 | late Uint8List _imageFile; 41 | 42 | @override 43 | bool get wantKeepAlive => true; 44 | 45 | @override 46 | void afterFirstBuild(BuildContext context) { 47 | super.afterFirstBuild(context); 48 | WidgetsBinding.instance?.addObserver(this); 49 | } 50 | 51 | @override 52 | void initState() { 53 | super.initState(); 54 | loadModel(viewModel.state.type); 55 | initCamera(); 56 | 57 | apertureController = StreamController.broadcast(); 58 | screenshotController = ScreenshotController(); 59 | } 60 | 61 | void initCamera() { 62 | _cameraController = CameraController( 63 | cameras[viewModel.state.cameraIndex], ResolutionPreset.high); 64 | _initializeControllerFuture = _cameraController.initialize().then((_) { 65 | if (!mounted) { 66 | return; 67 | } 68 | _cameraController.setFlashMode(FlashMode.off); 69 | /// TODO: Run Model 70 | setState(() {}); 71 | _cameraController.startImageStream((image) async { 72 | if (!mounted) { 73 | return; 74 | } 75 | await viewModel.runModel(image); 76 | }); 77 | }); 78 | } 79 | 80 | void loadModel(ModelType type) async { 81 | await viewModel.loadModel(type); 82 | } 83 | 84 | Future runModel(CameraImage image) async { 85 | if (mounted) { 86 | await viewModel.runModel(image); 87 | } 88 | } 89 | 90 | @override 91 | void dispose() { 92 | super.dispose(); 93 | WidgetsBinding.instance?.removeObserver(this); 94 | viewModel.close(); 95 | apertureController.close(); 96 | } 97 | 98 | @override 99 | void didChangeAppLifecycleState(AppLifecycleState state) { 100 | super.didChangeAppLifecycleState(state); 101 | 102 | /// TODO: Check Camera 103 | if (!_cameraController.value.isInitialized) return; 104 | if (state == AppLifecycleState.inactive) { 105 | _cameraController.dispose(); 106 | } else { 107 | initCamera(); 108 | } 109 | } 110 | 111 | @override 112 | Widget buildPageWidget(BuildContext context) { 113 | return Scaffold( 114 | extendBodyBehindAppBar: false, 115 | appBar: buildAppBarWidget(context), 116 | body: buildBodyWidget(context), 117 | floatingActionButton: buildFloatingActionButton(context), 118 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat); 119 | } 120 | 121 | Widget buildFloatingActionButton(BuildContext context) { 122 | return Container( 123 | padding: EdgeInsets.symmetric(vertical: 0, horizontal: 10.0), 124 | child: Row( 125 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 126 | children: [ 127 | FloatingActionButton( 128 | heroTag: null, 129 | onPressed: handleCaptureClick, 130 | tooltip: "Capture", 131 | backgroundColor: AppColors.white, 132 | child: Icon( 133 | Icons.cut_outlined, 134 | color: AppColors.blue, 135 | ), 136 | ), 137 | FloatingActionButton( 138 | heroTag: null, 139 | onPressed: handleSwitchCameraClick, 140 | tooltip: "Switch Camera", 141 | backgroundColor: AppColors.white, 142 | child: Icon( 143 | viewModel.state.isBackCamera() 144 | ? Icons.camera_front 145 | : Icons.camera_rear, 146 | color: AppColors.blue, 147 | ), 148 | ), 149 | ], 150 | ), 151 | ); 152 | } 153 | 154 | Future handleSwitchCameraClick() async { 155 | apertureController.sink.add({}); 156 | viewModel.switchCamera(); 157 | initCamera(); 158 | return true; 159 | } 160 | 161 | handleSwitchSource(ModelType item) { 162 | viewModel.dispose(); 163 | viewModel.updateTypeTfLite(item); 164 | Provider.of(context, listen: false).pushReplacementNamed( 165 | AppRoute.homeScreen, 166 | args: {'isWithoutAnimation': true}); 167 | } 168 | 169 | Future handleCaptureClick() async { 170 | screenshotController.capture().then((value) async { 171 | if (value != null) { 172 | final cameraImage = await _cameraController.takePicture(); 173 | await renderedAndSaveImage(value, cameraImage); 174 | } 175 | }); 176 | return true; 177 | } 178 | 179 | Future renderedAndSaveImage(Uint8List draw, XFile camera) async { 180 | UI.Image cameraImage = await decodeImageFromList(await camera.readAsBytes()); 181 | 182 | UI.Codec codec = await UI.instantiateImageCodec(draw); 183 | var detectionImage = (await codec.getNextFrame()).image; 184 | 185 | var cameraRatio = cameraImage.height / cameraImage.width; 186 | var previewRatio = detectionImage.height / detectionImage.width; 187 | 188 | double scaleWidth, scaleHeight; 189 | if (cameraRatio > previewRatio) { 190 | scaleWidth = cameraImage.width.toDouble(); 191 | scaleHeight = cameraImage.width * previewRatio; 192 | } else { 193 | scaleWidth = cameraImage.height.toDouble() / previewRatio; 194 | scaleHeight = cameraImage.height.toDouble(); 195 | } 196 | var difW = (scaleWidth - cameraImage.width) / 2; 197 | var difH = (scaleHeight - cameraImage.height) / 2; 198 | 199 | final recorder = UI.PictureRecorder(); 200 | final canvas = new Canvas( 201 | recorder, 202 | Rect.fromPoints( 203 | new Offset(0.0, 0.0), 204 | new Offset(cameraImage.width.toDouble(), 205 | cameraImage.height.toDouble()))); 206 | 207 | canvas.drawImage(cameraImage, Offset.zero, Paint()); 208 | 209 | codec = await UI.instantiateImageCodec(draw, targetWidth: scaleWidth.toInt(), targetHeight: scaleHeight.toInt()); 210 | detectionImage = (await codec.getNextFrame()).image; 211 | 212 | canvas.drawImage(detectionImage, Offset(difW.abs(), difH.abs()), Paint()); 213 | 214 | canvas.save(); 215 | canvas.restore(); 216 | 217 | final picture = recorder.endRecording(); 218 | 219 | var img = await picture.toImage(scaleWidth.toInt(), scaleHeight.toInt()); 220 | 221 | final pngBytes = await img.toByteData(format: UI.ImageByteFormat.png); 222 | 223 | final result2 = await ImageGallerySaver.saveImage(Uint8List.view(pngBytes!.buffer), 224 | quality: 100, 225 | name: 'realtime_object_detection_${DateTime.now()}'); 226 | print(result2); 227 | return true; 228 | } 229 | 230 | _gotoRepo() async { 231 | if (await canLaunch(AppStrings.urlRepo)) { 232 | await launch(AppStrings.urlRepo); 233 | } else {} 234 | } 235 | 236 | @override 237 | AppBar buildAppBarWidget(BuildContext context) { 238 | return AppBar( 239 | elevation: 0.0, 240 | centerTitle: true, 241 | actions: [ 242 | IconButton( 243 | onPressed: () { 244 | _gotoRepo(); 245 | }, 246 | icon: Icon(AppIcons.linkOption, semanticLabel: 'Repo')), 247 | PopupMenuButton( 248 | onSelected: (item) => handleSwitchSource(item), 249 | color: AppColors.white, 250 | itemBuilder: (context) => [ 251 | PopupMenuItem( 252 | enabled: !viewModel.state.isYolo(), 253 | child: Row( 254 | children: [ 255 | Icon(Icons.api, 256 | color: !viewModel.state.isYolo() 257 | ? AppColors.black 258 | : AppColors.grey), 259 | Text(' YOLO', 260 | style: AppTextStyles.regularTextStyle( 261 | color: !viewModel.state.isYolo() 262 | ? AppColors.black 263 | : AppColors.grey)), 264 | ], 265 | ), 266 | value: ModelType.YOLO), 267 | PopupMenuItem( 268 | enabled: !viewModel.state.isSSDMobileNet(), 269 | child: Row( 270 | children: [ 271 | Icon(Icons.api, 272 | color: !viewModel.state.isSSDMobileNet() 273 | ? AppColors.black 274 | : AppColors.grey), 275 | Text(' SSD MobileNet', 276 | style: AppTextStyles.regularTextStyle( 277 | color: !viewModel.state.isSSDMobileNet() 278 | ? AppColors.black 279 | : AppColors.grey)), 280 | ], 281 | ), 282 | value: ModelType.SSDMobileNet), 283 | PopupMenuItem( 284 | enabled: !viewModel.state.isMobileNet(), 285 | child: Row( 286 | children: [ 287 | Icon(Icons.api, 288 | color: !viewModel.state.isMobileNet() 289 | ? AppColors.black 290 | : AppColors.grey), 291 | Text(' MobileNet', 292 | style: AppTextStyles.regularTextStyle( 293 | color: !viewModel.state.isMobileNet() 294 | ? AppColors.black 295 | : AppColors.grey)), 296 | ], 297 | ), 298 | value: ModelType.MobileNet), 299 | PopupMenuItem( 300 | enabled: !viewModel.state.isPoseNet(), 301 | child: Row( 302 | children: [ 303 | Icon(Icons.api, 304 | color: !viewModel.state.isPoseNet() 305 | ? AppColors.black 306 | : AppColors.grey), 307 | Text(' PoseNet', 308 | style: AppTextStyles.regularTextStyle( 309 | color: !viewModel.state.isPoseNet() 310 | ? AppColors.black 311 | : AppColors.grey)), 312 | ], 313 | ), 314 | value: ModelType.PoseNet), 315 | ]), 316 | ], 317 | backgroundColor: AppColors.blue, 318 | title: Text( 319 | AppStrings.title, 320 | style: AppTextStyles.boldTextStyle( 321 | color: AppColors.white, fontSize: AppFontSizes.large), 322 | ), 323 | ); 324 | } 325 | 326 | @override 327 | Widget buildBodyWidget(BuildContext context) { 328 | double heightAppBar = AppBar().preferredSize.height; 329 | 330 | bool isInitialized = _cameraController.value.isInitialized; 331 | 332 | final Size screen = MediaQuery.of(context).size; 333 | final double screenHeight = max(screen.height, screen.width); 334 | final double screenWidth = min(screen.height, screen.width); 335 | 336 | final Size previewSize = 337 | isInitialized ? _cameraController.value.previewSize! : Size(100, 100); 338 | final double previewHeight = max(previewSize.height, previewSize.width); 339 | final double previewWidth = min(previewSize.height, previewSize.width); 340 | 341 | final double screenRatio = screenHeight / screenWidth; 342 | final double previewRatio = previewHeight / previewWidth; 343 | final maxHeight = 344 | screenRatio > previewRatio ? screenHeight : screenWidth * previewRatio; 345 | final maxWidth = 346 | screenRatio > previewRatio ? screenHeight / previewRatio : screenWidth; 347 | 348 | return Container( 349 | height: MediaQuery.of(context).size.height, 350 | width: double.infinity, 351 | color: Colors.grey.shade900, 352 | child: Padding( 353 | padding: const EdgeInsets.all(10), 354 | child: Container( 355 | width: MediaQuery.of(context).size.width, 356 | child: Screenshot( 357 | controller: screenshotController, 358 | child: Stack( 359 | children: [ 360 | OverflowBox( 361 | maxHeight: maxHeight, 362 | maxWidth: maxWidth, 363 | child: FutureBuilder( 364 | future: _initializeControllerFuture, 365 | builder: (_, snapshot) { 366 | if (snapshot.connectionState == 367 | ConnectionState.done) { 368 | return CameraPreview(_cameraController); 369 | } else { 370 | return const Center( 371 | child: CircularProgressIndicator( 372 | color: AppColors.blue)); 373 | } 374 | }), 375 | ), 376 | Consumer(builder: (_, homeViewModel, __) { 377 | return ConfidenceWidget( 378 | heightAppBar: heightAppBar, 379 | entities: homeViewModel.state.recognitions, 380 | previewHeight: max(homeViewModel.state.heightImage, 381 | homeViewModel.state.widthImage), 382 | previewWidth: min(homeViewModel.state.heightImage, 383 | homeViewModel.state.widthImage), 384 | screenWidth: MediaQuery.of(context).size.width, 385 | screenHeight: MediaQuery.of(context).size.height, 386 | type: homeViewModel.state.type, 387 | ); 388 | }), 389 | OverflowBox( 390 | maxHeight: maxHeight, 391 | maxWidth: maxWidth, 392 | child: ApertureWidget( 393 | apertureController: apertureController, 394 | ), 395 | ), 396 | // Container( 397 | // decoration: BoxDecoration( 398 | // border: Border.all(color: Colors.red, width: 2) 399 | // ), 400 | // ) 401 | ], 402 | ))), 403 | )); 404 | } 405 | } 406 | -------------------------------------------------------------------------------- /lib/pages/local_screen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_realtime_object_detection/app/app_resources.dart'; 5 | import 'package:flutter_realtime_object_detection/app/base/base_stateful.dart'; 6 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 7 | import 'package:flutter_realtime_object_detection/view_models/local_view_model.dart'; 8 | import 'package:image_picker/image_picker.dart'; 9 | import 'package:provider/provider.dart'; 10 | import 'package:url_launcher/url_launcher.dart'; 11 | 12 | class LocalScreen extends StatefulWidget { 13 | @override 14 | State createState() { 15 | return _LocalScreenState(); 16 | } 17 | } 18 | 19 | class _LocalScreenState extends BaseStateful { 20 | ImagePicker _imagePicker = ImagePicker(); 21 | 22 | double _imageHeight = 0; 23 | double _imageWidth = 0; 24 | 25 | @override 26 | void afterFirstBuild(BuildContext context) { 27 | super.afterFirstBuild(context); 28 | } 29 | 30 | @override 31 | void initState() { 32 | super.initState(); 33 | loadModel(ModelType.YOLO); 34 | } 35 | 36 | void loadModel(ModelType type) async { 37 | await viewModel.loadModel(type); 38 | } 39 | 40 | void runModel(File image) async { 41 | if (mounted) { 42 | await viewModel.runModel(image); 43 | viewModel.isLoading = false; 44 | } 45 | } 46 | 47 | selectImage() async { 48 | viewModel.isLoading = true; 49 | XFile? _imageFile = 50 | await _imagePicker.pickImage(source: ImageSource.gallery); 51 | if (_imageFile == null) { 52 | viewModel.isLoading = false; 53 | return; 54 | } 55 | viewModel.updateImageSelected(File(_imageFile.path)); 56 | 57 | 58 | new FileImage(viewModel.state.imageSelected!) 59 | .resolve(new ImageConfiguration()) 60 | .addListener(ImageStreamListener((ImageInfo info, bool _) { 61 | setState(() { 62 | _imageHeight = info.image.height.toDouble(); 63 | _imageWidth = info.image.width.toDouble(); 64 | }); 65 | })); 66 | 67 | 68 | runModel(viewModel.state.imageSelected!); 69 | } 70 | 71 | _gotoRepo() async { 72 | if (await canLaunch(AppStrings.urlRepo)) { 73 | await launch(AppStrings.urlRepo); 74 | } else {} 75 | } 76 | 77 | @override 78 | AppBar buildAppBarWidget(BuildContext context) { 79 | return AppBar( 80 | elevation: 0.0, 81 | centerTitle: true, 82 | actions: [ 83 | IconButton( 84 | onPressed: () { 85 | _gotoRepo(); 86 | }, 87 | icon: Icon(AppIcons.linkOption, semanticLabel: 'Repo')) 88 | ], 89 | backgroundColor: AppColors.blue, 90 | title: Text( 91 | AppStrings.title, 92 | style: AppTextStyles.boldTextStyle( 93 | color: AppColors.white, fontSize: AppFontSizes.large), 94 | ), 95 | ); 96 | } 97 | 98 | @override 99 | Widget buildPageWidget(BuildContext context) { 100 | return Scaffold( 101 | extendBodyBehindAppBar: false, 102 | appBar: buildAppBarWidget(context), 103 | body: buildBodyWidget(context), 104 | floatingActionButton: buildFloatingActionButton(context) 105 | ); 106 | } 107 | 108 | Widget buildFloatingActionButton(BuildContext context) { 109 | return FloatingActionButton( 110 | child: Icon( 111 | AppIcons.plus, 112 | color: AppColors.blue, 113 | ), 114 | tooltip: "Pick From Gallery", 115 | backgroundColor: AppColors.white, 116 | onPressed: selectImage, 117 | ); 118 | } 119 | 120 | @override 121 | void dispose() { 122 | super.dispose(); 123 | viewModel.close(); 124 | } 125 | 126 | @override 127 | Widget buildBodyWidget(BuildContext context) { 128 | return Consumer(builder: (build, provide, _) { 129 | return viewModel.isLoading ? loadingWidget() : contentWidget(); 130 | }); 131 | } 132 | 133 | 134 | List renderBoxes(Size screen) { 135 | if (_imageHeight == 0 || _imageWidth == 0) return []; 136 | 137 | double factorX = screen.width; 138 | double factorY = _imageHeight / _imageWidth * screen.width; 139 | Color blue = Color.fromRGBO(37, 213, 253, 1.0); 140 | return viewModel.state.recognitions.map((re) { 141 | return Positioned( 142 | left: re["rect"]["x"] * factorX, 143 | top: re["rect"]["y"] * factorY, 144 | width: re["rect"]["w"] * factorX, 145 | height: re["rect"]["h"] * factorY, 146 | child: Container( 147 | decoration: BoxDecoration( 148 | borderRadius: BorderRadius.all(Radius.circular(8.0)), 149 | border: Border.all( 150 | color: blue, 151 | width: 2, 152 | ), 153 | ), 154 | child: Text( 155 | "${re["detectedClass"]} ${(re["confidenceInClass"] * 100).toStringAsFixed(0)}%", 156 | style: TextStyle( 157 | background: Paint()..color = blue, 158 | color: Colors.white, 159 | fontSize: 12.0, 160 | ), 161 | ), 162 | ), 163 | ); 164 | }).toList(); 165 | } 166 | 167 | Widget contentWidget() { 168 | List stackChildren = renderBoxes(MediaQuery.of(context).size); 169 | 170 | return Container( 171 | height: MediaQuery.of(context).size.height, 172 | width: double.infinity, 173 | decoration: BoxDecoration( 174 | color: AppColors.blue.withOpacity(0.4), 175 | border: Border.all(color: AppColors.blue, width: 2)), 176 | child: Padding( 177 | padding: const EdgeInsets.all(0), 178 | child: Stack( 179 | children: [ 180 | Positioned( 181 | top: 0.0, 182 | left: 0.0, 183 | width: MediaQuery.of(context).size.width, 184 | child: Image.file(viewModel.state.imageSelected!)), 185 | ...stackChildren 186 | ], 187 | ) 188 | ), 189 | ); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /lib/pages/splash_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/scheduler.dart'; 3 | import 'package:flutter_realtime_object_detection/app/app_resources.dart'; 4 | import 'package:flutter_realtime_object_detection/app/app_router.dart'; 5 | import 'package:flutter_realtime_object_detection/services/navigation_service.dart'; 6 | import 'package:provider/provider.dart'; 7 | 8 | class SplashScreen extends StatefulWidget { 9 | @override 10 | State createState() { 11 | return _SplashScreenState(); 12 | } 13 | } 14 | 15 | class _SplashScreenState extends State 16 | with SingleTickerProviderStateMixin { 17 | late AnimationController _controller; 18 | late Animation _animation; 19 | 20 | @override 21 | void initState() { 22 | super.initState(); 23 | _controller = AnimationController( 24 | duration: const Duration(milliseconds: 2000), vsync: this, value: 0.1); 25 | _animation = 26 | CurvedAnimation(parent: _controller, curve: Curves.bounceInOut); 27 | _controller.forward(); 28 | SchedulerBinding.instance?.addPostFrameCallback((timeStamp) { 29 | Future.delayed(Duration(seconds: 5), () { 30 | Provider.of(context, listen: false) 31 | .pushNamedAndRemoveUntil(AppRoute.homeScreen); 32 | }); 33 | }); 34 | } 35 | 36 | @override 37 | void dispose() { 38 | _controller.dispose(); 39 | super.dispose(); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return Container( 45 | alignment: Alignment.center, 46 | color: AppColors.white, 47 | padding: EdgeInsets.symmetric(vertical: 0.0, horizontal: 0.0), 48 | child: ScaleTransition( 49 | scale: _animation, 50 | alignment: Alignment.center, 51 | child: Image(image: AssetImage('assets/images/logo.png')), 52 | ), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/services/navigation_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class NavigationService { 5 | 6 | /// Global navigation key for whole application 7 | static GlobalKey navigationKey = GlobalKey(); 8 | 9 | /// Get app context 10 | static BuildContext? get appContext => navigationKey.currentContext; 11 | 12 | /// App route observer 13 | static RouteObserver> routeObserver = RouteObserver>(); 14 | 15 | /// Pushing new page into navigation stack 16 | /// 17 | /// `routeName` is page's route name defined in [AppRoute] 18 | /// `args` is optional data to be sent to new page 19 | Future pushNamed(String routeName, 20 | {Object? args}) async { 21 | return navigationKey.currentState?.pushNamed( 22 | routeName, 23 | arguments: args, 24 | ); 25 | } 26 | 27 | /// Pushing new page into navigation stack 28 | /// 29 | /// `route` is route generator 30 | Future push(Route route) async { 31 | return navigationKey.currentState?.push(route); 32 | } 33 | 34 | 35 | /// Replace the current route of the navigator by pushing the given route and 36 | /// then disposing the previous route once the new route has finished 37 | /// animating in. 38 | Future pushReplacementNamed( 39 | String routeName, 40 | {Object? args}) async { 41 | return navigationKey.currentState?.pushReplacementNamed( 42 | routeName, 43 | arguments: args, 44 | ); 45 | } 46 | 47 | 48 | 49 | 50 | 51 | 52 | /// Push the route with the given name onto the navigator, and then remove all 53 | /// the previous routes until the `predicate` returns true. 54 | Future pushNamedAndRemoveUntil( 55 | String routeName, { 56 | Object? args, 57 | bool Function(Route)? predicate, 58 | }) async { 59 | return navigationKey.currentState?.pushNamedAndRemoveUntil( 60 | routeName, 61 | predicate ?? (_) => false, 62 | arguments: args, 63 | ); 64 | } 65 | 66 | /// Push the given route onto the navigator, and then remove all the previous 67 | /// routes until the `predicate` returns true. 68 | Future pushAndRemoveUntil( 69 | Route route, { 70 | bool Function(Route)? predicate, 71 | }) async { 72 | return navigationKey.currentState?.pushAndRemoveUntil( 73 | route, 74 | predicate ?? (_) => false, 75 | ); 76 | } 77 | 78 | /// Consults the current route's [Route.willPop] method, and acts accordingly, 79 | /// potentially popping the route as a result; returns whether the pop request 80 | /// should be considered handled. 81 | Future maybePop([Object? args]) async { 82 | return navigationKey.currentState!.maybePop(args as T); 83 | } 84 | 85 | /// Whether the navigator can be popped. 86 | bool canPop() => navigationKey.currentState!.canPop(); 87 | 88 | /// Pop the top-most route off the navigator. 89 | void goBack({T? result}) { 90 | navigationKey.currentState?.pop(result); 91 | } 92 | 93 | /// Calls [pop] repeatedly until the predicate returns true. 94 | void popUntil(String route) { 95 | navigationKey.currentState!.popUntil(ModalRoute.withName(route)); 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /lib/services/tensorflow_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:camera/camera.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:tflite/tflite.dart'; 6 | 7 | enum ModelType { YOLO, SSDMobileNet, MobileNet, PoseNet } 8 | 9 | class TensorFlowService { 10 | ModelType _type = ModelType.YOLO; 11 | 12 | ModelType get type => _type; 13 | 14 | set type(type) { 15 | _type = type; 16 | } 17 | 18 | loadModel(ModelType type) async { 19 | try { 20 | Tflite.close(); 21 | String? res; 22 | switch (type) { 23 | case ModelType.YOLO: 24 | res = await Tflite.loadModel( 25 | model: 'assets/models/yolov2_tiny.tflite', 26 | labels: 'assets/models/yolov2_tiny.txt'); 27 | break; 28 | case ModelType.SSDMobileNet: 29 | res = await Tflite.loadModel( 30 | model: 'assets/models/ssd_mobilenet.tflite', 31 | labels: 'assets/models/ssd_mobilenet.txt'); 32 | break; 33 | case ModelType.MobileNet: 34 | res = await Tflite.loadModel( 35 | model: 'assets/models/mobilenet_v1.tflite', 36 | labels: 'assets/models/mobilenet_v1.txt'); 37 | break; 38 | case ModelType.PoseNet: 39 | res = await Tflite.loadModel( 40 | model: 'assets/models/posenet_mv1_checkpoints.tflite'); 41 | break; 42 | default: 43 | res = await Tflite.loadModel( 44 | model: 'assets/models/yolov2_tiny.tflite', 45 | labels: 'assets/models/yolov2_tiny.txt'); 46 | } 47 | print('loadModel: $res - $_type'); 48 | } on PlatformException { 49 | print('Failed to load model.'); 50 | } 51 | } 52 | 53 | close() async { 54 | await Tflite.close(); 55 | } 56 | 57 | Future?> runModelOnFrame(CameraImage image) async { 58 | List? recognitions = []; 59 | switch (_type) { 60 | case ModelType.YOLO: 61 | recognitions = await Tflite.detectObjectOnFrame( 62 | bytesList: image.planes.map((plane) { 63 | return plane.bytes; 64 | }).toList(), 65 | model: "YOLO", 66 | imageHeight: image.height, 67 | imageWidth: image.width, 68 | imageMean: 0, 69 | imageStd: 255.0, 70 | threshold: 0.2, 71 | numResultsPerClass: 1, 72 | ); 73 | break; 74 | case ModelType.SSDMobileNet: 75 | recognitions = await Tflite.detectObjectOnFrame( 76 | bytesList: image.planes.map((plane) { 77 | return plane.bytes; 78 | }).toList(), 79 | model: "SSDMobileNet", 80 | imageHeight: image.height, 81 | imageWidth: image.width, 82 | imageMean: 127.5, 83 | imageStd: 127.5, 84 | threshold: 0.4, 85 | numResultsPerClass: 1, 86 | ); 87 | break; 88 | case ModelType.MobileNet: 89 | recognitions = await Tflite.runModelOnFrame( 90 | bytesList: image.planes.map((plane) { 91 | return plane.bytes; 92 | }).toList(), 93 | imageHeight: image.height, 94 | imageWidth: image.width, 95 | numResults: 5 96 | ); 97 | break; 98 | case ModelType.PoseNet: 99 | recognitions = await Tflite.runPoseNetOnFrame( 100 | bytesList: image.planes.map((plane) { 101 | return plane.bytes; 102 | }).toList(), 103 | imageHeight: image.height, 104 | imageWidth: image.width, 105 | numResults: 5 106 | ); 107 | break; 108 | default: 109 | } 110 | print("recognitions: $recognitions"); 111 | return recognitions; 112 | } 113 | 114 | Future?> runModelOnImage(File image) async { 115 | var recognitions = await Tflite.detectObjectOnImage( 116 | path: image.path, 117 | model: "YOLO", 118 | threshold: 0.3, 119 | imageMean: 0.0, 120 | imageStd: 127.5, 121 | numResultsPerClass: 1); 122 | return recognitions; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /lib/view_models/home_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:camera/camera.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_realtime_object_detection/app/base/base_view_model.dart'; 4 | import '/models/recognition.dart'; 5 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 6 | import 'package:flutter_realtime_object_detection/view_states/home_view_state.dart'; 7 | 8 | class HomeViewModel extends BaseViewModel { 9 | bool _isLoadModel = false; 10 | bool _isDetecting = false; 11 | 12 | late TensorFlowService _tensorFlowService; 13 | 14 | HomeViewModel(BuildContext context, this._tensorFlowService) 15 | : super(context, HomeViewState(_tensorFlowService.type)); 16 | 17 | Future switchCamera() async { 18 | state.cameraIndex = state.cameraIndex == 0 ? 1 : 0; 19 | this.notifyListeners(); 20 | } 21 | 22 | Future loadModel(ModelType type) async { 23 | state.type = type; 24 | //if (type != this._tensorFlowService.type) { 25 | await this._tensorFlowService.loadModel(type); 26 | //} 27 | this._isLoadModel = true; 28 | } 29 | 30 | Future runModel(CameraImage cameraImage) async { 31 | if (_isLoadModel && mounted) { 32 | if (!this._isDetecting && mounted) { 33 | this._isDetecting = true; 34 | int startTime = new DateTime.now().millisecondsSinceEpoch; 35 | var recognitions = 36 | await this._tensorFlowService.runModelOnFrame(cameraImage); 37 | int endTime = new DateTime.now().millisecondsSinceEpoch; 38 | print('Time detection: ${endTime - startTime}'); 39 | if (recognitions != null && mounted) { 40 | state.recognitions = List.from( 41 | recognitions.map((model) => Recognition.fromJson(model))); 42 | state.widthImage = cameraImage.width; 43 | state.heightImage = cameraImage.height; 44 | notifyListeners(); 45 | } 46 | this._isDetecting = false; 47 | } 48 | } else { 49 | print('Please run `loadModel(type)` before running `runModel(cameraImage)`'); 50 | } 51 | } 52 | 53 | Future close() async { 54 | await this._tensorFlowService.close(); 55 | } 56 | 57 | void updateTypeTfLite(ModelType item) { 58 | this._tensorFlowService.type = item; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /lib/view_models/local_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_realtime_object_detection/app/base/base_view_model.dart'; 5 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 6 | import 'package:flutter_realtime_object_detection/view_states/local_view_state.dart'; 7 | 8 | class LocalViewModel extends BaseViewModel { 9 | 10 | bool _isLoadModel = false; 11 | 12 | late TensorFlowService _tensorFlowService; 13 | 14 | 15 | LocalViewModel(BuildContext context, this._tensorFlowService) : super(context, LocalViewState()); 16 | 17 | 18 | Future loadModel(ModelType type) async { 19 | await this._tensorFlowService.loadModel(type); 20 | this._isLoadModel = true; 21 | } 22 | 23 | Future runModel(File file) async { 24 | if(_isLoadModel) { 25 | var recognitions = await this._tensorFlowService.runModelOnImage(file); 26 | if (recognitions != null) { 27 | state.recognitions = recognitions; 28 | print('recognitions ${recognitions.toString()}'); 29 | notifyListeners(); 30 | } 31 | }else{ 32 | throw 'Please run `loadModel(type)` before running `runModelOnImage(file)`'; 33 | } 34 | } 35 | 36 | void close() { 37 | this._tensorFlowService.close(); 38 | } 39 | 40 | 41 | 42 | Future updateImageSelected(File file) async { 43 | state.imageSelected = file; 44 | this.notifyListeners(); 45 | } 46 | 47 | bool isHasPicked() { 48 | return state.imageSelected != null; 49 | } 50 | 51 | String getTextDetected() { 52 | return state.getTextDetected(); 53 | } 54 | 55 | 56 | 57 | } -------------------------------------------------------------------------------- /lib/view_states/home_view_state.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 3 | 4 | import '/models/recognition.dart'; 5 | 6 | class HomeViewState { 7 | 8 | ModelType type; 9 | 10 | late List recognitions = []; 11 | 12 | int widthImage = 0; 13 | 14 | int heightImage = 0; 15 | 16 | 17 | int cameraIndex = 0; 18 | 19 | HomeViewState(this.type); 20 | 21 | bool isFrontCamera() { 22 | return cameraIndex == 1; 23 | } 24 | 25 | bool isBackCamera() { 26 | return cameraIndex == 0; 27 | } 28 | 29 | bool isYolo() { 30 | return type == ModelType.YOLO; 31 | } 32 | 33 | bool isSSDMobileNet() { 34 | return type == ModelType.SSDMobileNet; 35 | } 36 | 37 | bool isMobileNet() { 38 | return type == ModelType.MobileNet; 39 | } 40 | 41 | bool isPoseNet() { 42 | return type == ModelType.PoseNet; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /lib/view_states/local_view_state.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:io'; 3 | 4 | class LocalViewState { 5 | 6 | late List recognitions = []; 7 | 8 | File? imageSelected; 9 | 10 | 11 | String getTextDetected() { 12 | return (recognitions.isNotEmpty) ? recognitions[0]['detectedClass'] : ''; 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /lib/widgets/aperture/aperture_leaf.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_realtime_object_detection/widgets/aperture/aperture_leaf_painter.dart'; 5 | 6 | class ApertureLeaf extends StatefulWidget { 7 | final double borderWidth; 8 | final AnimationController? animationController; 9 | final Animation? curvedAnimation; 10 | final bool startOpened; 11 | 12 | final double parentWidth; 13 | 14 | final Widget? child; 15 | 16 | final bool isShowChild; 17 | 18 | ApertureLeaf( 19 | {required this.borderWidth, 20 | required this.parentWidth, 21 | this.animationController, 22 | this.curvedAnimation, 23 | this.child, 24 | this.isShowChild = false, 25 | this.startOpened = true}); 26 | 27 | @override 28 | State createState() { 29 | return _ApertureLeafState(); 30 | } 31 | } 32 | 33 | class _ApertureLeafState extends State 34 | with SingleTickerProviderStateMixin { 35 | static const apertureBorderWidth = 2.0; 36 | static const open1 = 0.78; 37 | static const open2 = 0.33; 38 | 39 | late AnimationController animationController; 40 | late Animation curvedAnimation; 41 | 42 | late Animation _slide1; 43 | late Animation _slide2; 44 | late Animation _slide3; 45 | late Animation _slide4; 46 | late Animation _slide5; 47 | late Animation _slide6; 48 | 49 | @override 50 | void initState() { 51 | super.initState(); 52 | animationController = (widget.animationController != null 53 | ? widget.animationController 54 | : AnimationController( 55 | vsync: this, duration: Duration(milliseconds: 500)))!; 56 | 57 | curvedAnimation = (widget.curvedAnimation != null 58 | ? widget.curvedAnimation 59 | : CurvedAnimation( 60 | parent: animationController, curve: Curves.easeInOutBack))!; 61 | 62 | _slide1 = widget.startOpened 63 | ? Tween(begin: Offset(open1, 0.0), end: Offset(0.0, 0.0)) 64 | .animate(curvedAnimation) 65 | : Tween(begin: Offset(0.0, 0.0), end: Offset(open1, 0.0)) 66 | .animate(curvedAnimation); 67 | _slide2 = widget.startOpened 68 | ? Tween(begin: Offset(open2, open1), end: Offset(0.0, 0.0)) 69 | .animate(curvedAnimation) 70 | : Tween(begin: Offset(0.0, 0.0), end: Offset(open2, open1)) 71 | .animate(curvedAnimation); 72 | _slide3 = widget.startOpened 73 | ? Tween(begin: Offset(-open2, open1), end: Offset(0.0, 0.0)) 74 | .animate(curvedAnimation) 75 | : Tween(begin: Offset(0.0, 0.0), end: Offset(-open2, open1)) 76 | .animate(curvedAnimation); 77 | _slide4 = widget.startOpened 78 | ? Tween(begin: Offset(-open1, 0.0), end: Offset(0.0, 0.0)) 79 | .animate(curvedAnimation) 80 | : Tween(begin: Offset(0.0, 0.0), end: Offset(-open1, 0.0)) 81 | .animate(curvedAnimation); 82 | _slide5 = widget.startOpened 83 | ? Tween(begin: Offset(-open2, -open1), end: Offset(0.0, 0.0)) 84 | .animate(curvedAnimation) 85 | : Tween(begin: Offset(0.0, 0.0), end: Offset(-open2, -open1)) 86 | .animate(curvedAnimation); 87 | _slide6 = widget.startOpened 88 | ? Tween(begin: Offset(open2, -open1), end: Offset(0.0, 0.0)) 89 | .animate(curvedAnimation) 90 | : Tween(begin: Offset(0.0, 0.0), end: Offset(open2, -open1)) 91 | .animate(curvedAnimation); 92 | 93 | if (widget.animationController == null) { 94 | animationController.forward(); 95 | } 96 | } 97 | 98 | @override 99 | Widget build(BuildContext context) { 100 | final double boxWidth = widget.parentWidth; 101 | final bladeHeight = sqrt((pow(boxWidth, 2) - pow((boxWidth / 2), 2))); 102 | final heightDelta = boxWidth - bladeHeight; 103 | 104 | return LayoutBuilder(builder: (context, constraints) { 105 | final centerX = constraints.maxWidth / 2; 106 | final centerY = constraints.maxHeight / 2; 107 | 108 | return Stack( 109 | alignment: Alignment.center, 110 | children: [ 111 | if (widget.child != null && widget.isShowChild) 112 | Container( 113 | alignment: Alignment.center, 114 | width: constraints.maxWidth, 115 | height: constraints.maxHeight, 116 | child: widget.child, 117 | ), 118 | Container( 119 | decoration: BoxDecoration( 120 | border: Border.all(color: Colors.white, width: 0)), 121 | child: Stack( 122 | alignment: Alignment.center, 123 | children: [ 124 | Positioned( 125 | left: centerX + (boxWidth / 2), 126 | top: centerY + heightDelta, 127 | child: AnimatedBuilder( 128 | builder: (context, child) => 129 | SlideTransition(position: _slide1, child: child), 130 | animation: animationController, 131 | child: FittedBox( 132 | fit: BoxFit.none, 133 | child: SizedBox( 134 | width: boxWidth, 135 | height: boxWidth, 136 | child: CustomPaint( 137 | painter: ApertureLeafPainter( 138 | borderWidth: widget.borderWidth, 139 | rotationRadians: pi, 140 | fillColor: Colors.grey.shade900), 141 | ))), 142 | )), 143 | Positioned( 144 | left: centerX - apertureBorderWidth, 145 | top: centerY - 146 | (boxWidth - bladeHeight) - 147 | bladeHeight + 148 | (apertureBorderWidth / 2), 149 | child: AnimatedBuilder( 150 | builder: (context, child) => 151 | SlideTransition(position: _slide2, child: child), 152 | animation: animationController, 153 | child: FittedBox( 154 | fit: BoxFit.none, 155 | child: SizedBox( 156 | width: boxWidth, 157 | height: boxWidth, 158 | child: CustomPaint( 159 | painter: ApertureLeafPainter( 160 | borderWidth: widget.borderWidth, 161 | rotationRadians: 0, 162 | fillColor: Colors.grey.shade900), 163 | )), 164 | ), 165 | )), 166 | Positioned( 167 | left: centerX + boxWidth - apertureBorderWidth, 168 | top: centerY + heightDelta + bladeHeight, 169 | child: AnimatedBuilder( 170 | builder: (context, child) => 171 | SlideTransition(position: _slide3, child: child), 172 | animation: animationController, 173 | child: FittedBox( 174 | fit: BoxFit.none, 175 | child: SizedBox( 176 | width: boxWidth, 177 | height: boxWidth, 178 | child: CustomPaint( 179 | painter: ApertureLeafPainter( 180 | borderWidth: widget.borderWidth, 181 | rotationRadians: pi, 182 | fillColor: Colors.grey.shade900), 183 | )), 184 | ), 185 | )), 186 | Positioned( 187 | left: centerX - (boxWidth * 0.5), 188 | top: centerY - heightDelta, 189 | child: AnimatedBuilder( 190 | builder: (context, child) => 191 | SlideTransition(position: _slide4, child: child), 192 | animation: animationController, 193 | child: FittedBox( 194 | fit: BoxFit.none, 195 | child: SizedBox( 196 | width: boxWidth, 197 | height: boxWidth, 198 | child: CustomPaint( 199 | painter: ApertureLeafPainter( 200 | borderWidth: widget.borderWidth, 201 | rotationRadians: 0, 202 | fillColor: Colors.grey.shade900), 203 | )), 204 | ), 205 | )), 206 | Positioned( 207 | left: centerX + apertureBorderWidth, 208 | top: centerY + heightDelta + bladeHeight, 209 | child: AnimatedBuilder( 210 | builder: (context, child) => 211 | SlideTransition(position: _slide5, child: child), 212 | animation: animationController, 213 | child: FittedBox( 214 | fit: BoxFit.none, 215 | child: SizedBox( 216 | width: boxWidth, 217 | height: boxWidth, 218 | child: CustomPaint( 219 | painter: ApertureLeafPainter( 220 | borderWidth: widget.borderWidth, 221 | rotationRadians: pi, 222 | fillColor: Colors.grey.shade900), 223 | )), 224 | ), 225 | )), 226 | Positioned( 227 | left: centerX - boxWidth + apertureBorderWidth, 228 | top: centerY - 229 | heightDelta - 230 | bladeHeight + 231 | (apertureBorderWidth / 2), 232 | child: AnimatedBuilder( 233 | builder: (context, child) => 234 | SlideTransition(position: _slide6, child: child), 235 | animation: animationController, 236 | child: FittedBox( 237 | fit: BoxFit.none, 238 | child: SizedBox( 239 | width: boxWidth, 240 | height: boxWidth, 241 | child: CustomPaint( 242 | painter: ApertureLeafPainter( 243 | borderWidth: widget.borderWidth, 244 | rotationRadians: 0, 245 | fillColor: Colors.grey.shade900), 246 | )), 247 | ), 248 | )) 249 | ], 250 | ), 251 | ), 252 | ], 253 | ); 254 | }); 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /lib/widgets/aperture/aperture_leaf_painter.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'dart:math'; 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | class ApertureLeafPainter extends CustomPainter { 8 | 9 | final double rotationRadians; 10 | final double _borderWidth; 11 | final Color _borderColor; 12 | final Color _fillColor; 13 | 14 | final Paint _borderPaint = Paint(); 15 | final Paint _fillPaint = Paint(); 16 | 17 | 18 | 19 | ApertureLeafPainter({ 20 | required borderWidth, 21 | required this.rotationRadians, 22 | borderColor, 23 | fillColor 24 | }) : 25 | _borderWidth = borderWidth, 26 | _borderColor = borderColor ?? Colors.black, 27 | _fillColor = fillColor ?? Colors.grey.shade900; 28 | 29 | 30 | 31 | @override 32 | void paint(Canvas canvas, Size size) { 33 | _borderPaint.color = _borderColor; 34 | _fillPaint.color = _fillColor; 35 | 36 | final width = size.width; 37 | final height = sqrt((pow(width, 2) - pow((width / 2), 2))); 38 | 39 | canvas.save(); 40 | canvas.rotate(rotationRadians); 41 | 42 | Path borderPath = Path() 43 | ..moveTo(0, width) 44 | ..lineTo(width / 2, width - height) // top 45 | ..lineTo(width, width) 46 | ..close(); 47 | 48 | canvas.drawPath(borderPath, _borderPaint); 49 | 50 | Path fillPath = Path() 51 | ..moveTo(_borderWidth * 2, width - _borderWidth) 52 | ..lineTo(width / 2, width - height + (_borderWidth * 2)) 53 | ..lineTo(width - (_borderWidth * 2), width - _borderWidth) 54 | ..close(); 55 | 56 | canvas.drawPath(fillPath, _fillPaint); 57 | 58 | 59 | canvas.restore(); 60 | } 61 | 62 | @override 63 | bool shouldRepaint(covariant CustomPainter oldDelegate) { 64 | return false; 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /lib/widgets/aperture/aperture_widget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_realtime_object_detection/widgets/aperture/aperture_leaf.dart'; 5 | 6 | 7 | 8 | class ApertureWidget extends StatefulWidget { 9 | 10 | final StreamController apertureController; 11 | 12 | final Widget? child; 13 | 14 | ApertureWidget({required this.apertureController, this.child}); 15 | 16 | 17 | @override 18 | State createState() { 19 | return _ApertureWidgetState(); 20 | } 21 | } 22 | 23 | class _ApertureWidgetState extends State 24 | with SingleTickerProviderStateMixin { 25 | late AnimationController animationController; 26 | late StreamSubscription streamSubscription; 27 | 28 | bool _isShowChild = false; 29 | 30 | @override 31 | void initState() { 32 | super.initState(); 33 | streamSubscription = widget.apertureController.stream.asBroadcastStream().listen((event) { 34 | print(event); 35 | animationController.forward(); 36 | }); 37 | 38 | animationController = AnimationController( 39 | vsync: this, duration: Duration(milliseconds: 500)); 40 | 41 | animationController.addStatusListener((status) { 42 | if (status == AnimationStatus.completed) { 43 | Future.delayed(const Duration(milliseconds: 800), () { 44 | animationController.reverse(); 45 | }); 46 | } else if (status == AnimationStatus.dismissed) { 47 | } 48 | }); 49 | animationController.forward(); 50 | } 51 | 52 | 53 | @override 54 | void dispose() { 55 | animationController.dispose(); 56 | super.dispose(); 57 | streamSubscription.cancel(); 58 | } 59 | 60 | @override 61 | Widget build(BuildContext context) { 62 | return Container( 63 | alignment: Alignment.center, 64 | child: Center( 65 | child: Stack( 66 | alignment: Alignment.center, 67 | children: [ 68 | SizedBox( 69 | width: MediaQuery.of(context).size.width, 70 | height: MediaQuery.of(context).size.height, 71 | child: ApertureLeaf( 72 | parentWidth: MediaQuery.of(context).size.width + 100, 73 | animationController: animationController, 74 | borderWidth: 2.0, 75 | isShowChild: _isShowChild, 76 | child: widget.child, 77 | ), 78 | ), 79 | ], 80 | ), 81 | ), 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/widgets/confidence_widget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_realtime_object_detection/app/app_resources.dart'; 5 | import 'package:flutter_realtime_object_detection/models/recognition.dart'; 6 | import 'package:flutter_realtime_object_detection/services/tensorflow_service.dart'; 7 | 8 | class ConfidenceWidget extends StatelessWidget { 9 | final List entities; 10 | final int previewWidth; 11 | final int previewHeight; 12 | final double screenWidth; 13 | final double screenHeight; 14 | final ModelType type; 15 | 16 | final double heightAppBar; 17 | 18 | const ConfidenceWidget( 19 | {Key? key, 20 | required this.heightAppBar, 21 | required this.entities, 22 | required this.previewWidth, 23 | required this.previewHeight, 24 | required this.screenWidth, 25 | required this.screenHeight, 26 | required this.type}) 27 | : super(key: key); 28 | 29 | List _renderPoseNet() { 30 | var lists = []; 31 | this.entities.forEach((re) { 32 | var list = re.keypoints!.map((k) { 33 | var _x = k.x; 34 | var _y = k.y; 35 | var scaleWidth, scaleHeight, x, y; 36 | 37 | var screenRatio = this.screenHeight / this.screenWidth; 38 | var previewRatio = this.previewHeight / this.previewWidth; 39 | 40 | if (screenRatio > previewRatio) { 41 | scaleWidth = screenHeight / previewRatio; 42 | scaleHeight = screenHeight; 43 | var difW = (scaleWidth - screenWidth) / scaleWidth; 44 | x = (_x - difW / 2) * scaleWidth; 45 | y = _y * scaleHeight; 46 | } else { 47 | scaleHeight = screenWidth * previewRatio; 48 | scaleWidth = screenWidth; 49 | var difH = (scaleHeight - screenHeight) / scaleHeight; 50 | x = _x * scaleWidth; 51 | y = (_y - difH / 2) * scaleHeight; 52 | } 53 | return Positioned( 54 | left: x - 15, 55 | top: y - heightAppBar, 56 | width: 100, 57 | height: 15, 58 | child: Row(children: [ 59 | Icon(Icons.api, size: AppFontSizes.small, color: AppColors.blue), 60 | Text(" ${k.part}", 61 | style: AppTextStyles.regularTextStyle( 62 | color: Colors.red, 63 | fontSize: AppFontSizes.extraExtraSmall, 64 | backgroundColor: AppColors.white)) 65 | ])); 66 | }).toList(); 67 | lists..addAll(list); 68 | }); 69 | return lists; 70 | } 71 | 72 | List _renderStringEntities() { 73 | List results = []; 74 | double offset = 0; 75 | results = this.entities.map((entity) { 76 | offset = offset + 20; 77 | print(entity); 78 | return Positioned( 79 | left: 10, 80 | top: offset, 81 | width: this.screenWidth, 82 | height: this.screenHeight, 83 | child: Text( 84 | '${entity.label ?? ''} ${((entity.confidence ?? 0) * 100).toStringAsFixed(0)}%', 85 | style: AppTextStyles.regularTextStyle( 86 | color: Colors.red, 87 | fontSize: AppFontSizes.extraExtraSmall, 88 | backgroundColor: AppColors.white), 89 | )); 90 | }).toList(); 91 | 92 | return results; 93 | } 94 | 95 | List _renderHeightLineEntities() { 96 | List results = []; 97 | results = this.entities.map((entity) { 98 | var _x = entity.rect!.x; 99 | var _y = entity.rect!.y; 100 | var _w = entity.rect!.w; 101 | var _h = entity.rect!.h; 102 | 103 | var screenRatio = this.screenHeight / this.screenWidth; 104 | var previewRatio = this.previewHeight / this.previewWidth; 105 | 106 | var scaleWidth, scaleHeight, x, y, w, h; 107 | if (screenRatio > previewRatio) { 108 | scaleHeight = screenHeight; 109 | scaleWidth = screenHeight / previewRatio; 110 | var difW = (scaleWidth - screenWidth) / scaleWidth; 111 | x = (_x - difW / 2) * scaleWidth; 112 | w = _w * scaleWidth; 113 | if (_x < difW / 2) { 114 | w -= (difW / 2 - _x) * scaleWidth; 115 | } 116 | y = _y * scaleHeight; 117 | h = _h * scaleHeight; 118 | } else { 119 | scaleHeight = screenWidth * previewRatio; 120 | scaleWidth = screenWidth; 121 | var difH = (scaleHeight - screenHeight) / scaleHeight; 122 | x = _x * scaleWidth; 123 | w = _w * scaleWidth; 124 | y = (_y - difH / 2) * scaleHeight; 125 | h = _h * scaleHeight; 126 | if (_y < difH / 2) { 127 | h -= (difH / 2 - _y) * scaleHeight; 128 | } 129 | } 130 | return Positioned( 131 | left: max(0, x), 132 | top: max(0, y), 133 | width: w, 134 | height: h, 135 | child: Container( 136 | padding: EdgeInsets.all(0.0), 137 | decoration: BoxDecoration( 138 | border: Border.all(color: Colors.red, width: 2.0), 139 | ), 140 | child: Text( 141 | '${entity.detectedClass ?? ''} ${((entity.confidenceInClass ?? 0) * 100).toStringAsFixed(0)}%', 142 | overflow: TextOverflow.ellipsis, 143 | style: AppTextStyles.regularTextStyle( 144 | color: Colors.red, 145 | fontSize: AppFontSizes.extraExtraSmall, 146 | backgroundColor: AppColors.white), 147 | ), 148 | ), 149 | ); 150 | }).toList(); 151 | return results; 152 | } 153 | 154 | @override 155 | Widget build(BuildContext context) { 156 | List childes = []; 157 | switch (type) { 158 | case ModelType.YOLO: 159 | case ModelType.SSDMobileNet: 160 | childes = _renderHeightLineEntities(); 161 | break; 162 | case ModelType.MobileNet: 163 | childes = _renderStringEntities(); 164 | break; 165 | case ModelType.PoseNet: 166 | childes = _renderPoseNet(); 167 | break; 168 | default: 169 | childes = []; 170 | } 171 | return Stack( 172 | children: childes, 173 | ); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.6.1" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | camera: 19 | dependency: "direct main" 20 | description: 21 | name: camera 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "0.8.1+7" 25 | camera_platform_interface: 26 | dependency: transitive 27 | description: 28 | name: camera_platform_interface 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.1.0" 32 | characters: 33 | dependency: transitive 34 | description: 35 | name: characters 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | charcode: 40 | dependency: transitive 41 | description: 42 | name: charcode 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.2.0" 46 | clock: 47 | dependency: transitive 48 | description: 49 | name: clock 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.1.0" 53 | collection: 54 | dependency: transitive 55 | description: 56 | name: collection 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.15.0" 60 | cross_file: 61 | dependency: transitive 62 | description: 63 | name: cross_file 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "0.3.1+4" 67 | cupertino_icons: 68 | dependency: "direct main" 69 | description: 70 | name: cupertino_icons 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.0.3" 74 | fake_async: 75 | dependency: transitive 76 | description: 77 | name: fake_async 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "1.2.0" 81 | flutter: 82 | dependency: "direct main" 83 | description: flutter 84 | source: sdk 85 | version: "0.0.0" 86 | flutter_plugin_android_lifecycle: 87 | dependency: transitive 88 | description: 89 | name: flutter_plugin_android_lifecycle 90 | url: "https://pub.dartlang.org" 91 | source: hosted 92 | version: "2.0.2" 93 | flutter_screenutil: 94 | dependency: "direct main" 95 | description: 96 | name: flutter_screenutil 97 | url: "https://pub.dartlang.org" 98 | source: hosted 99 | version: "5.0.0+2" 100 | flutter_test: 101 | dependency: "direct dev" 102 | description: flutter 103 | source: sdk 104 | version: "0.0.0" 105 | flutter_web_plugins: 106 | dependency: transitive 107 | description: flutter 108 | source: sdk 109 | version: "0.0.0" 110 | http: 111 | dependency: transitive 112 | description: 113 | name: http 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "0.13.3" 117 | http_parser: 118 | dependency: transitive 119 | description: 120 | name: http_parser 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "4.0.0" 124 | image_gallery_saver: 125 | dependency: "direct main" 126 | description: 127 | name: image_gallery_saver 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.6.9" 131 | image_picker: 132 | dependency: "direct main" 133 | description: 134 | name: image_picker 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.8.2" 138 | image_picker_for_web: 139 | dependency: transitive 140 | description: 141 | name: image_picker_for_web 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "2.1.2" 145 | image_picker_platform_interface: 146 | dependency: transitive 147 | description: 148 | name: image_picker_platform_interface 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "2.2.0" 152 | js: 153 | dependency: transitive 154 | description: 155 | name: js 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "0.6.3" 159 | matcher: 160 | dependency: transitive 161 | description: 162 | name: matcher 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "0.12.10" 166 | meta: 167 | dependency: transitive 168 | description: 169 | name: meta 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "1.3.0" 173 | nested: 174 | dependency: transitive 175 | description: 176 | name: nested 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.0.0" 180 | path: 181 | dependency: transitive 182 | description: 183 | name: path 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "1.8.0" 187 | pedantic: 188 | dependency: transitive 189 | description: 190 | name: pedantic 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "1.11.1" 194 | plugin_platform_interface: 195 | dependency: transitive 196 | description: 197 | name: plugin_platform_interface 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "2.0.1" 201 | provider: 202 | dependency: "direct main" 203 | description: 204 | name: provider 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "5.0.0" 208 | quiver: 209 | dependency: transitive 210 | description: 211 | name: quiver 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "3.0.1" 215 | screenshot: 216 | dependency: "direct main" 217 | description: 218 | name: screenshot 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "1.2.3" 222 | sky_engine: 223 | dependency: transitive 224 | description: flutter 225 | source: sdk 226 | version: "0.0.99" 227 | source_span: 228 | dependency: transitive 229 | description: 230 | name: source_span 231 | url: "https://pub.dartlang.org" 232 | source: hosted 233 | version: "1.8.1" 234 | stack_trace: 235 | dependency: transitive 236 | description: 237 | name: stack_trace 238 | url: "https://pub.dartlang.org" 239 | source: hosted 240 | version: "1.10.0" 241 | stream_channel: 242 | dependency: transitive 243 | description: 244 | name: stream_channel 245 | url: "https://pub.dartlang.org" 246 | source: hosted 247 | version: "2.1.0" 248 | stream_transform: 249 | dependency: transitive 250 | description: 251 | name: stream_transform 252 | url: "https://pub.dartlang.org" 253 | source: hosted 254 | version: "2.0.0" 255 | string_scanner: 256 | dependency: transitive 257 | description: 258 | name: string_scanner 259 | url: "https://pub.dartlang.org" 260 | source: hosted 261 | version: "1.1.0" 262 | term_glyph: 263 | dependency: transitive 264 | description: 265 | name: term_glyph 266 | url: "https://pub.dartlang.org" 267 | source: hosted 268 | version: "1.2.0" 269 | test_api: 270 | dependency: transitive 271 | description: 272 | name: test_api 273 | url: "https://pub.dartlang.org" 274 | source: hosted 275 | version: "0.3.0" 276 | tflite: 277 | dependency: "direct main" 278 | description: 279 | name: tflite 280 | url: "https://pub.dartlang.org" 281 | source: hosted 282 | version: "1.1.2" 283 | typed_data: 284 | dependency: transitive 285 | description: 286 | name: typed_data 287 | url: "https://pub.dartlang.org" 288 | source: hosted 289 | version: "1.3.0" 290 | url_launcher: 291 | dependency: "direct main" 292 | description: 293 | name: url_launcher 294 | url: "https://pub.dartlang.org" 295 | source: hosted 296 | version: "6.0.9" 297 | url_launcher_linux: 298 | dependency: transitive 299 | description: 300 | name: url_launcher_linux 301 | url: "https://pub.dartlang.org" 302 | source: hosted 303 | version: "2.0.1" 304 | url_launcher_macos: 305 | dependency: transitive 306 | description: 307 | name: url_launcher_macos 308 | url: "https://pub.dartlang.org" 309 | source: hosted 310 | version: "2.0.1" 311 | url_launcher_platform_interface: 312 | dependency: transitive 313 | description: 314 | name: url_launcher_platform_interface 315 | url: "https://pub.dartlang.org" 316 | source: hosted 317 | version: "2.0.4" 318 | url_launcher_web: 319 | dependency: transitive 320 | description: 321 | name: url_launcher_web 322 | url: "https://pub.dartlang.org" 323 | source: hosted 324 | version: "2.0.2" 325 | url_launcher_windows: 326 | dependency: transitive 327 | description: 328 | name: url_launcher_windows 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "2.0.1" 332 | vector_math: 333 | dependency: transitive 334 | description: 335 | name: vector_math 336 | url: "https://pub.dartlang.org" 337 | source: hosted 338 | version: "2.1.0" 339 | sdks: 340 | dart: ">=2.12.0 <3.0.0" 341 | flutter: ">=2.0.0" 342 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_realtime_object_detection 2 | description: Flutter App reat-time object detection 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.2 31 | tflite: 1.1.2 32 | camera: ^0.8.1 33 | provider: ^5.0.0 34 | # Design responsive 35 | flutter_screenutil: 5.0.0+2 36 | # Utils 37 | url_launcher: ^6.0.9 38 | image_picker: ^0.8.2 39 | screenshot: ^1.2.3 40 | image_gallery_saver: '^1.6.9' 41 | 42 | dev_dependencies: 43 | flutter_test: 44 | sdk: flutter 45 | 46 | # For information on the generic Dart part of this file, see the 47 | # following page: https://dart.dev/tools/pub/pubspec 48 | 49 | # The following section is specific to Flutter. 50 | flutter: 51 | 52 | # The following line ensures that the Material Icons font is 53 | # included with your application, so that you can use the icons in 54 | # the material Icons class. 55 | uses-material-design: true 56 | 57 | # To add assets to your application, add an assets section, like this: 58 | assets: 59 | - assets/models/yolov2_tiny.txt 60 | - assets/models/yolov2_tiny.tflite 61 | - assets/models/ssd_mobilenet.txt 62 | - assets/models/ssd_mobilenet.tflite 63 | - assets/models/mobilenet_v1.txt 64 | - assets/models/mobilenet_v1.tflite 65 | - assets/models/posenet_mv1_checkpoints.tflite 66 | - assets/fonts/ 67 | - assets/images/ 68 | 69 | # An image asset can refer to one or more resolution-specific "variants", see 70 | # https://flutter.dev/assets-and-images/#resolution-aware. 71 | 72 | # For details regarding adding assets from package dependencies, see 73 | # https://flutter.dev/assets-and-images/#from-packages 74 | 75 | fonts: 76 | - family: Roboto 77 | fonts: 78 | - asset: assets/fonts/Roboto-Bold.ttf 79 | weight: 700 80 | - asset: assets/fonts/Roboto-Medium.ttf 81 | weight: 500 82 | - asset: assets/fonts/Roboto-Regular.ttf 83 | weight: 400 84 | 85 | # To add custom fonts to your application, add a fonts section here, 86 | # in this "flutter" section. Each entry in this list should have a 87 | # "family" key with the font family name, and a "fonts" key with a 88 | # list giving the asset and other descriptors for the font. For 89 | # example: 90 | # fonts: 91 | # - family: Schyler 92 | # fonts: 93 | # - asset: fonts/Schyler-Regular.ttf 94 | # - asset: fonts/Schyler-Italic.ttf 95 | # style: italic 96 | # - family: Trajan Pro 97 | # fonts: 98 | # - asset: fonts/TrajanPro.ttf 99 | # - asset: fonts/TrajanPro_Bold.ttf 100 | # weight: 700 101 | # 102 | # For details regarding fonts from package dependencies, 103 | # see https://flutter.dev/custom-fonts/#from-packages 104 | --------------------------------------------------------------------------------