├── .gitignore ├── .gradle ├── 5.2.1 │ ├── fileChanges │ │ └── last-build.bin │ ├── fileHashes │ │ └── fileHashes.lock │ └── gc.properties ├── buildOutputCleanup │ ├── buildOutputCleanup.lock │ └── cache.properties └── vcs-1 │ └── gc.properties ├── .metadata ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── object_detection │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── 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 │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── settings_aar.gradle ├── assets ├── detect.tflite └── labelmap.txt ├── install.bat ├── install.sh ├── 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 │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── main.dart ├── tflite │ ├── classifier.dart │ ├── recognition.dart │ └── stats.dart ├── ui │ ├── box_widget.dart │ ├── camera_view.dart │ ├── camera_view_singleton.dart │ └── home_view.dart └── utils │ ├── image_utils.dart │ └── isolate_utils.dart ├── object_detection_demo.gif ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.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 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Exceptions to above rules. 43 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 44 | -------------------------------------------------------------------------------- /.gradle/5.2.1/fileChanges/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/5.2.1/fileHashes/fileHashes.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/.gradle/5.2.1/fileHashes/fileHashes.lock -------------------------------------------------------------------------------- /.gradle/5.2.1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/.gradle/5.2.1/gc.properties -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/buildOutputCleanup.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/.gradle/buildOutputCleanup/buildOutputCleanup.lock -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/cache.properties: -------------------------------------------------------------------------------- 1 | #Thu Jul 16 15:25:30 IST 2020 2 | gradle.version=5.2.1 3 | -------------------------------------------------------------------------------- /.gradle/vcs-1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/.gradle/vcs-1/gc.properties -------------------------------------------------------------------------------- /.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: 8af6b2f038c1172e61d418869363a28dffec3cb4 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TensorFlow Lite Flutter Object Detection 2 | 3 | Object Detection app built using [TFLite Flutter Plugin](https://github.com/am15h/tflite_flutter_plugin) 4 | and [TFLite Flutter Helper Library](https://github.com/am15h/tflite_flutter_helper) 5 | 6 | #### **Important** 7 | 8 | * execute `install.sh`(linux) or `install.bat`(windows) for downloading tflite binaries. 9 | More info [here](https://github.com/am15h/tflite_flutter_plugin#important-initial-setup). 10 | 11 | ## Demo 12 | 13 | ![DEMO](object_detection_demo.gif) 14 | 15 | Shot on Pixel 4 16 | 17 | The pre-built APK can be found [here](https://drive.google.com/file/d/1QRdq28doFegBL8x7daaZ5ivwXDjslfkg/view?usp=sharing). 18 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | .so -------------------------------------------------------------------------------- /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 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | checkReleaseBuilds false // Adding this line to avoid release build failure 38 | } 39 | 40 | defaultConfig { 41 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 42 | applicationId "com.example.object_detection" 43 | minSdkVersion 21 44 | targetSdkVersion 28 45 | versionCode flutterVersionCode.toInteger() 46 | versionName flutterVersionName 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 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 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/object_detection/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.object_detection 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /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.0.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 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jul 16 21:28:33 IST 2020 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.1.1-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | include ':app' 6 | 7 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 8 | def properties = new Properties() 9 | 10 | assert localPropertiesFile.exists() 11 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 12 | 13 | def flutterSdkPath = properties.getProperty("flutter.sdk") 14 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 15 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 16 | -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /assets/detect.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/assets/detect.tflite -------------------------------------------------------------------------------- /assets/labelmap.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 | -------------------------------------------------------------------------------- /install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enableextensions 3 | 4 | cd %~dp0 5 | 6 | set URL=https://github.com/am15h/tflite_flutter_plugin/releases/download/ 7 | set TAG=v0.2.0 8 | 9 | set ANDROID_DIR=android\app\src\main\jniLibs\ 10 | set ANDROID_LIB=libtensorflowlite_c.so 11 | 12 | set ARM_DELEGATE=libtensorflowlite_c_arm_delegate.so 13 | set ARM_64_DELEGATE=libtensorflowlite_c_arm64_delegate.so 14 | set ARM=libtensorflowlite_c_arm.so 15 | set ARM_64=libtensorflowlite_c_arm64.so 16 | set X86=libtensorflowlite_c_x86.so 17 | set X86_64=libtensorflowlite_c_x86_64.so 18 | 19 | SET /A d = 0 20 | 21 | :GETOPT 22 | if /I "%1"=="-d" SET /A d = 1 23 | 24 | SETLOCAL 25 | if %d%==1 CALL :Download %ARM_DELEGATE% armeabi-v7a 26 | if %d%==1 CALL :Download %ARM_64_DELEGATE% arm64-v8a 27 | if %d%==0 CALL :Download %ARM% armeabi-v7a 28 | if %d%==0 CALL :Download %ARM_64% arm64-v8a 29 | CALL :Download %X86% x86 30 | CALL :Download %X86_64% x86_64 31 | EXIT /B %ERRORLEVEL% 32 | 33 | :Download 34 | curl -L -o %~1 %URL%%TAG%/%~1 35 | mkdir %ANDROID_DIR%%~2\ 36 | move /-Y %~1 %ANDROID_DIR%%~2\%ANDROID_LIB% 37 | EXIT /B 0 -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname "$(readlink -f "$0")")" 4 | 5 | URL="https://github.com/am15h/tflite_flutter_plugin/releases/download/" 6 | TAG="v0.2.0" 7 | 8 | ANDROID_DIR="android/app/src/main/jniLibs/" 9 | ANDROID_LIB="libtensorflowlite_c.so" 10 | 11 | ARM_DELEGATE="libtensorflowlite_c_arm_delegate.so" 12 | ARM_64_DELEGATE="libtensorflowlite_c_arm64_delegate.so" 13 | ARM="libtensorflowlite_c_arm.so" 14 | ARM_64="libtensorflowlite_c_arm64.so" 15 | X86="libtensorflowlite_c_x86.so" 16 | X86_64="libtensorflowlite_c_x86_64.so" 17 | 18 | delegate=0 19 | 20 | while getopts "d" OPTION 21 | do 22 | case $OPTION in 23 | d) delegate=1;; 24 | esac 25 | done 26 | 27 | 28 | download () { 29 | wget "${URL}${TAG}/$1" 30 | mkdir -p "${ANDROID_DIR}$2/" 31 | mv $1 "${ANDROID_DIR}$2/${ANDROID_LIB}" 32 | } 33 | 34 | if [ ${delegate} -eq 1 ] 35 | then 36 | 37 | download ${ARM_DELEGATE} "armeabi-v7a" 38 | download ${ARM_64_DELEGATE} "arm64-v8a" 39 | 40 | else 41 | 42 | download ${ARM} "armeabi-v7a" 43 | download ${ARM_64} "arm64-v8a" 44 | 45 | fi 46 | 47 | download ${X86} "x86" 48 | download ${X86_64} "x86_64" -------------------------------------------------------------------------------- /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/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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_picker (0.0.1): 6 | - Flutter 7 | - path_provider (0.0.1): 8 | - Flutter 9 | - tflite_flutter (0.1.0): 10 | - Flutter 11 | 12 | DEPENDENCIES: 13 | - camera (from `.symlinks/plugins/camera/ios`) 14 | - Flutter (from `Flutter`) 15 | - image_picker (from `.symlinks/plugins/image_picker/ios`) 16 | - path_provider (from `.symlinks/plugins/path_provider/ios`) 17 | - tflite_flutter (from `.symlinks/plugins/tflite_flutter/ios`) 18 | 19 | EXTERNAL SOURCES: 20 | camera: 21 | :path: ".symlinks/plugins/camera/ios" 22 | Flutter: 23 | :path: Flutter 24 | image_picker: 25 | :path: ".symlinks/plugins/image_picker/ios" 26 | path_provider: 27 | :path: ".symlinks/plugins/path_provider/ios" 28 | tflite_flutter: 29 | :path: ".symlinks/plugins/tflite_flutter/ios" 30 | 31 | SPEC CHECKSUMS: 32 | camera: 38cc83ae9a5667bb5a71c7d9edaf60a91920fd4e 33 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c 34 | image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 35 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c 36 | tflite_flutter: 9157a660578930a99728974f247369af1c3595d5 37 | 38 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 39 | 40 | COCOAPODS: 1.10.1 41 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 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 | 3C8E3E958CF35C847584F741 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD3E6D373D44B691ADA6B10F /* Pods_Runner.framework */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 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 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 36 | 6A6D314123D9912BD4560337 /* 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 = ""; }; 37 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 38 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 39 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 40 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 41 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 42 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | C3ADCBE32306D92A75026291 /* 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 = ""; }; 48 | CD3E6D373D44B691ADA6B10F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | FAE4B4A3467CABB29B95A4DE /* 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 = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 3C8E3E958CF35C847584F741 /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 31097D0FD4CA070B4D7B0B35 /* Pods */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | FAE4B4A3467CABB29B95A4DE /* Pods-Runner.debug.xcconfig */, 68 | 6A6D314123D9912BD4560337 /* Pods-Runner.release.xcconfig */, 69 | C3ADCBE32306D92A75026291 /* Pods-Runner.profile.xcconfig */, 70 | ); 71 | name = Pods; 72 | path = Pods; 73 | sourceTree = ""; 74 | }; 75 | 5E27ABCE050B161EB710B4E8 /* Frameworks */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | CD3E6D373D44B691ADA6B10F /* Pods_Runner.framework */, 79 | ); 80 | name = Frameworks; 81 | sourceTree = ""; 82 | }; 83 | 9740EEB11CF90186004384FC /* Flutter */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 87 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 88 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 89 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 90 | ); 91 | name = Flutter; 92 | sourceTree = ""; 93 | }; 94 | 97C146E51CF9000F007C117D = { 95 | isa = PBXGroup; 96 | children = ( 97 | 9740EEB11CF90186004384FC /* Flutter */, 98 | 97C146F01CF9000F007C117D /* Runner */, 99 | 97C146EF1CF9000F007C117D /* Products */, 100 | 31097D0FD4CA070B4D7B0B35 /* Pods */, 101 | 5E27ABCE050B161EB710B4E8 /* Frameworks */, 102 | ); 103 | sourceTree = ""; 104 | }; 105 | 97C146EF1CF9000F007C117D /* Products */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 97C146EE1CF9000F007C117D /* Runner.app */, 109 | ); 110 | name = Products; 111 | sourceTree = ""; 112 | }; 113 | 97C146F01CF9000F007C117D /* Runner */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 117 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 118 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 119 | 97C147021CF9000F007C117D /* Info.plist */, 120 | 97C146F11CF9000F007C117D /* Supporting Files */, 121 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 122 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 123 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 124 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 125 | ); 126 | path = Runner; 127 | sourceTree = ""; 128 | }; 129 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | ); 133 | name = "Supporting Files"; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | 97C146ED1CF9000F007C117D /* Runner */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 142 | buildPhases = ( 143 | 7ECEE2A0C96557B3F1C5F2EB /* [CP] Check Pods Manifest.lock */, 144 | 9740EEB61CF901F6004384FC /* Run Script */, 145 | 97C146EA1CF9000F007C117D /* Sources */, 146 | 97C146EB1CF9000F007C117D /* Frameworks */, 147 | 97C146EC1CF9000F007C117D /* Resources */, 148 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 149 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 150 | 68525521AAF107B7D3C1DBAD /* [CP] Embed Pods Frameworks */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = Runner; 157 | productName = Runner; 158 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 159 | productType = "com.apple.product-type.application"; 160 | }; 161 | /* End PBXNativeTarget section */ 162 | 163 | /* Begin PBXProject section */ 164 | 97C146E61CF9000F007C117D /* Project object */ = { 165 | isa = PBXProject; 166 | attributes = { 167 | LastUpgradeCheck = 1020; 168 | ORGANIZATIONNAME = ""; 169 | TargetAttributes = { 170 | 97C146ED1CF9000F007C117D = { 171 | CreatedOnToolsVersion = 7.3.1; 172 | LastSwiftMigration = 1100; 173 | }; 174 | }; 175 | }; 176 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 177 | compatibilityVersion = "Xcode 9.3"; 178 | developmentRegion = en; 179 | hasScannedForEncodings = 0; 180 | knownRegions = ( 181 | en, 182 | Base, 183 | ); 184 | mainGroup = 97C146E51CF9000F007C117D; 185 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 186 | projectDirPath = ""; 187 | projectRoot = ""; 188 | targets = ( 189 | 97C146ED1CF9000F007C117D /* Runner */, 190 | ); 191 | }; 192 | /* End PBXProject section */ 193 | 194 | /* Begin PBXResourcesBuildPhase section */ 195 | 97C146EC1CF9000F007C117D /* Resources */ = { 196 | isa = PBXResourcesBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 200 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 201 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 202 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXResourcesBuildPhase section */ 207 | 208 | /* Begin PBXShellScriptBuildPhase section */ 209 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 210 | isa = PBXShellScriptBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | ); 214 | inputPaths = ( 215 | ); 216 | name = "Thin Binary"; 217 | outputPaths = ( 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | shellPath = /bin/sh; 221 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 222 | }; 223 | 68525521AAF107B7D3C1DBAD /* [CP] Embed Pods Frameworks */ = { 224 | isa = PBXShellScriptBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | inputFileListPaths = ( 229 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 230 | ); 231 | name = "[CP] Embed Pods Frameworks"; 232 | outputFileListPaths = ( 233 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | shellPath = /bin/sh; 237 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 238 | showEnvVarsInLog = 0; 239 | }; 240 | 7ECEE2A0C96557B3F1C5F2EB /* [CP] Check Pods Manifest.lock */ = { 241 | isa = PBXShellScriptBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | inputFileListPaths = ( 246 | ); 247 | inputPaths = ( 248 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 249 | "${PODS_ROOT}/Manifest.lock", 250 | ); 251 | name = "[CP] Check Pods Manifest.lock"; 252 | outputFileListPaths = ( 253 | ); 254 | outputPaths = ( 255 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 256 | ); 257 | runOnlyForDeploymentPostprocessing = 0; 258 | shellPath = /bin/sh; 259 | 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"; 260 | showEnvVarsInLog = 0; 261 | }; 262 | 9740EEB61CF901F6004384FC /* Run Script */ = { 263 | isa = PBXShellScriptBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | ); 267 | inputPaths = ( 268 | ); 269 | name = "Run Script"; 270 | outputPaths = ( 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | shellPath = /bin/sh; 274 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 275 | }; 276 | /* End PBXShellScriptBuildPhase section */ 277 | 278 | /* Begin PBXSourcesBuildPhase section */ 279 | 97C146EA1CF9000F007C117D /* Sources */ = { 280 | isa = PBXSourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 284 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | }; 288 | /* End PBXSourcesBuildPhase section */ 289 | 290 | /* Begin PBXVariantGroup section */ 291 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 292 | isa = PBXVariantGroup; 293 | children = ( 294 | 97C146FB1CF9000F007C117D /* Base */, 295 | ); 296 | name = Main.storyboard; 297 | sourceTree = ""; 298 | }; 299 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 300 | isa = PBXVariantGroup; 301 | children = ( 302 | 97C147001CF9000F007C117D /* Base */, 303 | ); 304 | name = LaunchScreen.storyboard; 305 | sourceTree = ""; 306 | }; 307 | /* End PBXVariantGroup section */ 308 | 309 | /* Begin XCBuildConfiguration section */ 310 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | ALWAYS_SEARCH_USER_PATHS = NO; 314 | CLANG_ANALYZER_NONNULL = YES; 315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 316 | CLANG_CXX_LIBRARY = "libc++"; 317 | CLANG_ENABLE_MODULES = YES; 318 | CLANG_ENABLE_OBJC_ARC = YES; 319 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 320 | CLANG_WARN_BOOL_CONVERSION = YES; 321 | CLANG_WARN_COMMA = YES; 322 | CLANG_WARN_CONSTANT_CONVERSION = YES; 323 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 325 | CLANG_WARN_EMPTY_BODY = YES; 326 | CLANG_WARN_ENUM_CONVERSION = YES; 327 | CLANG_WARN_INFINITE_RECURSION = YES; 328 | CLANG_WARN_INT_CONVERSION = YES; 329 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 330 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 334 | CLANG_WARN_STRICT_PROTOTYPES = YES; 335 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 336 | CLANG_WARN_UNREACHABLE_CODE = YES; 337 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 339 | COPY_PHASE_STRIP = NO; 340 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 341 | ENABLE_NS_ASSERTIONS = NO; 342 | ENABLE_STRICT_OBJC_MSGSEND = YES; 343 | GCC_C_LANGUAGE_STANDARD = gnu99; 344 | GCC_NO_COMMON_BLOCKS = YES; 345 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 346 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 347 | GCC_WARN_UNDECLARED_SELECTOR = YES; 348 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 349 | GCC_WARN_UNUSED_FUNCTION = YES; 350 | GCC_WARN_UNUSED_VARIABLE = YES; 351 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 352 | MTL_ENABLE_DEBUG_INFO = NO; 353 | SDKROOT = iphoneos; 354 | SUPPORTED_PLATFORMS = iphoneos; 355 | TARGETED_DEVICE_FAMILY = "1,2"; 356 | VALIDATE_PRODUCT = YES; 357 | }; 358 | name = Profile; 359 | }; 360 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 361 | isa = XCBuildConfiguration; 362 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 363 | buildSettings = { 364 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 365 | CLANG_ENABLE_MODULES = YES; 366 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 367 | ENABLE_BITCODE = NO; 368 | FRAMEWORK_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "$(PROJECT_DIR)/Flutter", 371 | ); 372 | INFOPLIST_FILE = Runner/Info.plist; 373 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 374 | LD_RUNPATH_SEARCH_PATHS = ( 375 | "$(inherited)", 376 | "@executable_path/Frameworks", 377 | ); 378 | LIBRARY_SEARCH_PATHS = ( 379 | "$(inherited)", 380 | "$(PROJECT_DIR)/Flutter", 381 | ); 382 | PRODUCT_BUNDLE_IDENTIFIER = com.example.objectDetection; 383 | PRODUCT_NAME = "$(TARGET_NAME)"; 384 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 385 | SWIFT_VERSION = 5.0; 386 | VERSIONING_SYSTEM = "apple-generic"; 387 | }; 388 | name = Profile; 389 | }; 390 | 97C147031CF9000F007C117D /* Debug */ = { 391 | isa = XCBuildConfiguration; 392 | buildSettings = { 393 | ALWAYS_SEARCH_USER_PATHS = NO; 394 | CLANG_ANALYZER_NONNULL = YES; 395 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 396 | CLANG_CXX_LIBRARY = "libc++"; 397 | CLANG_ENABLE_MODULES = YES; 398 | CLANG_ENABLE_OBJC_ARC = YES; 399 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 400 | CLANG_WARN_BOOL_CONVERSION = YES; 401 | CLANG_WARN_COMMA = YES; 402 | CLANG_WARN_CONSTANT_CONVERSION = YES; 403 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 405 | CLANG_WARN_EMPTY_BODY = YES; 406 | CLANG_WARN_ENUM_CONVERSION = YES; 407 | CLANG_WARN_INFINITE_RECURSION = YES; 408 | CLANG_WARN_INT_CONVERSION = YES; 409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 411 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 412 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 413 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 414 | CLANG_WARN_STRICT_PROTOTYPES = YES; 415 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 416 | CLANG_WARN_UNREACHABLE_CODE = YES; 417 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 418 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 419 | COPY_PHASE_STRIP = NO; 420 | DEBUG_INFORMATION_FORMAT = dwarf; 421 | ENABLE_STRICT_OBJC_MSGSEND = YES; 422 | ENABLE_TESTABILITY = YES; 423 | GCC_C_LANGUAGE_STANDARD = gnu99; 424 | GCC_DYNAMIC_NO_PIC = NO; 425 | GCC_NO_COMMON_BLOCKS = YES; 426 | GCC_OPTIMIZATION_LEVEL = 0; 427 | GCC_PREPROCESSOR_DEFINITIONS = ( 428 | "DEBUG=1", 429 | "$(inherited)", 430 | ); 431 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 432 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 433 | GCC_WARN_UNDECLARED_SELECTOR = YES; 434 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 435 | GCC_WARN_UNUSED_FUNCTION = YES; 436 | GCC_WARN_UNUSED_VARIABLE = YES; 437 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 438 | MTL_ENABLE_DEBUG_INFO = YES; 439 | ONLY_ACTIVE_ARCH = YES; 440 | SDKROOT = iphoneos; 441 | TARGETED_DEVICE_FAMILY = "1,2"; 442 | }; 443 | name = Debug; 444 | }; 445 | 97C147041CF9000F007C117D /* Release */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_SEARCH_USER_PATHS = NO; 449 | CLANG_ANALYZER_NONNULL = YES; 450 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 451 | CLANG_CXX_LIBRARY = "libc++"; 452 | CLANG_ENABLE_MODULES = YES; 453 | CLANG_ENABLE_OBJC_ARC = YES; 454 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 455 | CLANG_WARN_BOOL_CONVERSION = YES; 456 | CLANG_WARN_COMMA = YES; 457 | CLANG_WARN_CONSTANT_CONVERSION = YES; 458 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 459 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 460 | CLANG_WARN_EMPTY_BODY = YES; 461 | CLANG_WARN_ENUM_CONVERSION = YES; 462 | CLANG_WARN_INFINITE_RECURSION = YES; 463 | CLANG_WARN_INT_CONVERSION = YES; 464 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 465 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 466 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 467 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 468 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 469 | CLANG_WARN_STRICT_PROTOTYPES = YES; 470 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 471 | CLANG_WARN_UNREACHABLE_CODE = YES; 472 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 473 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 474 | COPY_PHASE_STRIP = NO; 475 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 476 | ENABLE_NS_ASSERTIONS = NO; 477 | ENABLE_STRICT_OBJC_MSGSEND = YES; 478 | GCC_C_LANGUAGE_STANDARD = gnu99; 479 | GCC_NO_COMMON_BLOCKS = YES; 480 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 481 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 482 | GCC_WARN_UNDECLARED_SELECTOR = YES; 483 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 484 | GCC_WARN_UNUSED_FUNCTION = YES; 485 | GCC_WARN_UNUSED_VARIABLE = YES; 486 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 487 | MTL_ENABLE_DEBUG_INFO = NO; 488 | SDKROOT = iphoneos; 489 | SUPPORTED_PLATFORMS = iphoneos; 490 | SWIFT_COMPILATION_MODE = wholemodule; 491 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 492 | TARGETED_DEVICE_FAMILY = "1,2"; 493 | VALIDATE_PRODUCT = YES; 494 | }; 495 | name = Release; 496 | }; 497 | 97C147061CF9000F007C117D /* Debug */ = { 498 | isa = XCBuildConfiguration; 499 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 500 | buildSettings = { 501 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 502 | CLANG_ENABLE_MODULES = YES; 503 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 504 | ENABLE_BITCODE = NO; 505 | FRAMEWORK_SEARCH_PATHS = ( 506 | "$(inherited)", 507 | "$(PROJECT_DIR)/Flutter", 508 | ); 509 | INFOPLIST_FILE = Runner/Info.plist; 510 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 511 | LD_RUNPATH_SEARCH_PATHS = ( 512 | "$(inherited)", 513 | "@executable_path/Frameworks", 514 | ); 515 | LIBRARY_SEARCH_PATHS = ( 516 | "$(inherited)", 517 | "$(PROJECT_DIR)/Flutter", 518 | ); 519 | PRODUCT_BUNDLE_IDENTIFIER = com.example.objectDetection; 520 | PRODUCT_NAME = "$(TARGET_NAME)"; 521 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 522 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 523 | SWIFT_VERSION = 5.0; 524 | VERSIONING_SYSTEM = "apple-generic"; 525 | }; 526 | name = Debug; 527 | }; 528 | 97C147071CF9000F007C117D /* Release */ = { 529 | isa = XCBuildConfiguration; 530 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 531 | buildSettings = { 532 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 533 | CLANG_ENABLE_MODULES = YES; 534 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 535 | ENABLE_BITCODE = NO; 536 | FRAMEWORK_SEARCH_PATHS = ( 537 | "$(inherited)", 538 | "$(PROJECT_DIR)/Flutter", 539 | ); 540 | INFOPLIST_FILE = Runner/Info.plist; 541 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 542 | LD_RUNPATH_SEARCH_PATHS = ( 543 | "$(inherited)", 544 | "@executable_path/Frameworks", 545 | ); 546 | LIBRARY_SEARCH_PATHS = ( 547 | "$(inherited)", 548 | "$(PROJECT_DIR)/Flutter", 549 | ); 550 | PRODUCT_BUNDLE_IDENTIFIER = com.example.objectDetection; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 553 | SWIFT_VERSION = 5.0; 554 | VERSIONING_SYSTEM = "apple-generic"; 555 | }; 556 | name = Release; 557 | }; 558 | /* End XCBuildConfiguration section */ 559 | 560 | /* Begin XCConfigurationList section */ 561 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 562 | isa = XCConfigurationList; 563 | buildConfigurations = ( 564 | 97C147031CF9000F007C117D /* Debug */, 565 | 97C147041CF9000F007C117D /* Release */, 566 | 249021D3217E4FDB00AE95B9 /* Profile */, 567 | ); 568 | defaultConfigurationIsVisible = 0; 569 | defaultConfigurationName = Release; 570 | }; 571 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 572 | isa = XCConfigurationList; 573 | buildConfigurations = ( 574 | 97C147061CF9000F007C117D /* Debug */, 575 | 97C147071CF9000F007C117D /* Release */, 576 | 249021D4217E4FDB00AE95B9 /* Profile */, 577 | ); 578 | defaultConfigurationIsVisible = 0; 579 | defaultConfigurationName = Release; 580 | }; 581 | /* End XCConfigurationList section */ 582 | }; 583 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 584 | } 585 | -------------------------------------------------------------------------------- /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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/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 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | object_detection 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | NSCameraUsageDescription 45 | Can I use the camera please? 46 | NSMicrophoneUsageDescription 47 | Can I use the mic please? 48 | 49 | 50 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:object_detection/ui/home_view.dart'; 4 | 5 | void main() async { 6 | WidgetsFlutterBinding.ensureInitialized(); 7 | await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); 8 | runApp(MyApp()); 9 | } 10 | 11 | class MyApp extends StatelessWidget { 12 | @override 13 | Widget build(BuildContext context) { 14 | return MaterialApp( 15 | title: 'Object Detection TFLite', 16 | theme: ThemeData( 17 | primarySwatch: Colors.blue, 18 | visualDensity: VisualDensity.adaptivePlatformDensity, 19 | ), 20 | home: HomeView(), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/tflite/classifier.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:ui'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:image/image.dart' as imageLib; 6 | import 'package:object_detection/tflite/recognition.dart'; 7 | import 'package:tflite_flutter/tflite_flutter.dart'; 8 | import 'package:tflite_flutter_helper/tflite_flutter_helper.dart'; 9 | 10 | import 'stats.dart'; 11 | 12 | /// Classifier 13 | class Classifier { 14 | /// Instance of Interpreter 15 | Interpreter _interpreter; 16 | 17 | /// Labels file loaded as list 18 | List _labels; 19 | 20 | static const String MODEL_FILE_NAME = "detect.tflite"; 21 | static const String LABEL_FILE_NAME = "labelmap.txt"; 22 | 23 | /// Input size of image (height = width = 300) 24 | static const int INPUT_SIZE = 300; 25 | 26 | /// Result score threshold 27 | static const double THRESHOLD = 0.5; 28 | 29 | /// [ImageProcessor] used to pre-process the image 30 | ImageProcessor imageProcessor; 31 | 32 | /// Padding the image to transform into square 33 | int padSize; 34 | 35 | /// Shapes of output tensors 36 | List> _outputShapes; 37 | 38 | /// Types of output tensors 39 | List _outputTypes; 40 | 41 | /// Number of results to show 42 | static const int NUM_RESULTS = 10; 43 | 44 | Classifier({ 45 | Interpreter interpreter, 46 | List labels, 47 | }) { 48 | loadModel(interpreter: interpreter); 49 | loadLabels(labels: labels); 50 | } 51 | 52 | /// Loads interpreter from asset 53 | void loadModel({Interpreter interpreter}) async { 54 | try { 55 | _interpreter = interpreter ?? 56 | await Interpreter.fromAsset( 57 | MODEL_FILE_NAME, 58 | options: InterpreterOptions()..threads = 4, 59 | ); 60 | 61 | var outputTensors = _interpreter.getOutputTensors(); 62 | _outputShapes = []; 63 | _outputTypes = []; 64 | outputTensors.forEach((tensor) { 65 | _outputShapes.add(tensor.shape); 66 | _outputTypes.add(tensor.type); 67 | }); 68 | } catch (e) { 69 | print("Error while creating interpreter: $e"); 70 | } 71 | } 72 | 73 | /// Loads labels from assets 74 | void loadLabels({List labels}) async { 75 | try { 76 | _labels = 77 | labels ?? await FileUtil.loadLabels("assets/" + LABEL_FILE_NAME); 78 | } catch (e) { 79 | print("Error while loading labels: $e"); 80 | } 81 | } 82 | 83 | /// Pre-process the image 84 | TensorImage getProcessedImage(TensorImage inputImage) { 85 | padSize = max(inputImage.height, inputImage.width); 86 | if (imageProcessor == null) { 87 | imageProcessor = ImageProcessorBuilder() 88 | .add(ResizeWithCropOrPadOp(padSize, padSize)) 89 | .add(ResizeOp(INPUT_SIZE, INPUT_SIZE, ResizeMethod.BILINEAR)) 90 | .build(); 91 | } 92 | inputImage = imageProcessor.process(inputImage); 93 | return inputImage; 94 | } 95 | 96 | /// Runs object detection on the input image 97 | Map predict(imageLib.Image image) { 98 | var predictStartTime = DateTime.now().millisecondsSinceEpoch; 99 | 100 | if (_interpreter == null) { 101 | print("Interpreter not initialized"); 102 | return null; 103 | } 104 | 105 | var preProcessStart = DateTime.now().millisecondsSinceEpoch; 106 | 107 | // Create TensorImage from image 108 | TensorImage inputImage = TensorImage.fromImage(image); 109 | 110 | // Pre-process TensorImage 111 | inputImage = getProcessedImage(inputImage); 112 | 113 | var preProcessElapsedTime = 114 | DateTime.now().millisecondsSinceEpoch - preProcessStart; 115 | 116 | // TensorBuffers for output tensors 117 | TensorBuffer outputLocations = TensorBufferFloat(_outputShapes[0]); 118 | TensorBuffer outputClasses = TensorBufferFloat(_outputShapes[1]); 119 | TensorBuffer outputScores = TensorBufferFloat(_outputShapes[2]); 120 | TensorBuffer numLocations = TensorBufferFloat(_outputShapes[3]); 121 | 122 | // Inputs object for runForMultipleInputs 123 | // Use [TensorImage.buffer] or [TensorBuffer.buffer] to pass by reference 124 | List inputs = [inputImage.buffer]; 125 | 126 | // Outputs map 127 | Map outputs = { 128 | 0: outputLocations.buffer, 129 | 1: outputClasses.buffer, 130 | 2: outputScores.buffer, 131 | 3: numLocations.buffer, 132 | }; 133 | 134 | var inferenceTimeStart = DateTime.now().millisecondsSinceEpoch; 135 | 136 | // run inference 137 | _interpreter.runForMultipleInputs(inputs, outputs); 138 | 139 | var inferenceTimeElapsed = 140 | DateTime.now().millisecondsSinceEpoch - inferenceTimeStart; 141 | 142 | // Maximum number of results to show 143 | int resultsCount = min(NUM_RESULTS, numLocations.getIntValue(0)); 144 | 145 | // Using labelOffset = 1 as ??? at index 0 146 | int labelOffset = 1; 147 | 148 | // Using bounding box utils for easy conversion of tensorbuffer to List 149 | List locations = BoundingBoxUtils.convert( 150 | tensor: outputLocations, 151 | valueIndex: [1, 0, 3, 2], 152 | boundingBoxAxis: 2, 153 | boundingBoxType: BoundingBoxType.BOUNDARIES, 154 | coordinateType: CoordinateType.RATIO, 155 | height: INPUT_SIZE, 156 | width: INPUT_SIZE, 157 | ); 158 | 159 | List recognitions = []; 160 | 161 | for (int i = 0; i < resultsCount; i++) { 162 | // Prediction score 163 | var score = outputScores.getDoubleValue(i); 164 | 165 | // Label string 166 | var labelIndex = outputClasses.getIntValue(i) + labelOffset; 167 | var label = _labels.elementAt(labelIndex); 168 | 169 | if (score > THRESHOLD) { 170 | // inverse of rect 171 | // [locations] corresponds to the image size 300 X 300 172 | // inverseTransformRect transforms it our [inputImage] 173 | Rect transformedRect = imageProcessor.inverseTransformRect( 174 | locations[i], image.height, image.width); 175 | 176 | recognitions.add( 177 | Recognition(i, label, score, transformedRect), 178 | ); 179 | } 180 | } 181 | 182 | var predictElapsedTime = 183 | DateTime.now().millisecondsSinceEpoch - predictStartTime; 184 | 185 | return { 186 | "recognitions": recognitions, 187 | "stats": Stats( 188 | totalPredictTime: predictElapsedTime, 189 | inferenceTime: inferenceTimeElapsed, 190 | preProcessingTime: preProcessElapsedTime) 191 | }; 192 | } 193 | 194 | /// Gets the interpreter instance 195 | Interpreter get interpreter => _interpreter; 196 | 197 | /// Gets the loaded labels 198 | List get labels => _labels; 199 | } 200 | -------------------------------------------------------------------------------- /lib/tflite/recognition.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:object_detection/ui/camera_view_singleton.dart'; 5 | 6 | /// Represents the recognition output from the model 7 | class Recognition { 8 | /// Index of the result 9 | int _id; 10 | 11 | /// Label of the result 12 | String _label; 13 | 14 | /// Confidence [0.0, 1.0] 15 | double _score; 16 | 17 | /// Location of bounding box rect 18 | /// 19 | /// The rectangle corresponds to the raw input image 20 | /// passed for inference 21 | Rect _location; 22 | 23 | Recognition(this._id, this._label, this._score, [this._location]); 24 | 25 | int get id => _id; 26 | 27 | String get label => _label; 28 | 29 | double get score => _score; 30 | 31 | Rect get location => _location; 32 | 33 | /// Returns bounding box rectangle corresponding to the 34 | /// displayed image on screen 35 | /// 36 | /// This is the actual location where rectangle is rendered on 37 | /// the screen 38 | Rect get renderLocation { 39 | // ratioX = screenWidth / imageInputWidth 40 | // ratioY = ratioX if image fits screenWidth with aspectRatio = constant 41 | 42 | double ratioX = CameraViewSingleton.ratio; 43 | double ratioY = ratioX; 44 | 45 | double transLeft = max(0.1, location.left * ratioX); 46 | double transTop = max(0.1, location.top * ratioY); 47 | double transWidth = min( 48 | location.width * ratioX, CameraViewSingleton.actualPreviewSize.width); 49 | double transHeight = min( 50 | location.height * ratioY, CameraViewSingleton.actualPreviewSize.height); 51 | 52 | Rect transformedRect = 53 | Rect.fromLTWH(transLeft, transTop, transWidth, transHeight); 54 | return transformedRect; 55 | } 56 | 57 | @override 58 | String toString() { 59 | return 'Recognition(id: $id, label: $label, score: $score, location: $location)'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/tflite/stats.dart: -------------------------------------------------------------------------------- 1 | /// Bundles different elapsed times 2 | class Stats { 3 | /// Total time taken in the isolate where the inference runs 4 | int totalPredictTime; 5 | 6 | /// [totalPredictTime] + communication overhead time 7 | /// between main isolate and another isolate 8 | int totalElapsedTime; 9 | 10 | /// Time for which inference runs 11 | int inferenceTime; 12 | 13 | /// Time taken to pre-process the image 14 | int preProcessingTime; 15 | 16 | Stats( 17 | {this.totalPredictTime, 18 | this.totalElapsedTime, 19 | this.inferenceTime, 20 | this.preProcessingTime}); 21 | 22 | @override 23 | String toString() { 24 | return 'Stats{totalPredictTime: $totalPredictTime, totalElapsedTime: $totalElapsedTime, inferenceTime: $inferenceTime, preProcessingTime: $preProcessingTime}'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/ui/box_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:object_detection/tflite/recognition.dart'; 3 | 4 | /// Individual bounding box 5 | class BoxWidget extends StatelessWidget { 6 | final Recognition result; 7 | 8 | const BoxWidget({Key key, this.result}) : super(key: key); 9 | @override 10 | Widget build(BuildContext context) { 11 | // Color for bounding box 12 | Color color = Colors.primaries[ 13 | (result.label.length + result.label.codeUnitAt(0) + result.id) % 14 | Colors.primaries.length]; 15 | 16 | return Positioned( 17 | left: result.renderLocation.left, 18 | top: result.renderLocation.top, 19 | width: result.renderLocation.width, 20 | height: result.renderLocation.height, 21 | child: Container( 22 | width: result.renderLocation.width, 23 | height: result.renderLocation.height, 24 | decoration: BoxDecoration( 25 | border: Border.all(color: color, width: 3), 26 | borderRadius: BorderRadius.all(Radius.circular(2))), 27 | child: Align( 28 | alignment: Alignment.topLeft, 29 | child: FittedBox( 30 | child: Container( 31 | color: color, 32 | child: Row( 33 | mainAxisSize: MainAxisSize.min, 34 | children: [ 35 | Text(result.label), 36 | Text(" " + result.score.toStringAsFixed(2)), 37 | ], 38 | ), 39 | ), 40 | ), 41 | ), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/ui/camera_view.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:isolate'; 3 | 4 | import 'package:camera/camera.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:object_detection/tflite/classifier.dart'; 7 | import 'package:object_detection/tflite/recognition.dart'; 8 | import 'package:object_detection/tflite/stats.dart'; 9 | import 'package:object_detection/ui/camera_view_singleton.dart'; 10 | import 'package:object_detection/utils/isolate_utils.dart'; 11 | 12 | /// [CameraView] sends each frame for inference 13 | class CameraView extends StatefulWidget { 14 | /// Callback to pass results after inference to [HomeView] 15 | final Function(List recognitions) resultsCallback; 16 | 17 | /// Callback to inference stats to [HomeView] 18 | final Function(Stats stats) statsCallback; 19 | 20 | /// Constructor 21 | const CameraView(this.resultsCallback, this.statsCallback); 22 | @override 23 | _CameraViewState createState() => _CameraViewState(); 24 | } 25 | 26 | class _CameraViewState extends State with WidgetsBindingObserver { 27 | /// List of available cameras 28 | List cameras; 29 | 30 | /// Controller 31 | CameraController cameraController; 32 | 33 | /// true when inference is ongoing 34 | bool predicting; 35 | 36 | /// Instance of [Classifier] 37 | Classifier classifier; 38 | 39 | /// Instance of [IsolateUtils] 40 | IsolateUtils isolateUtils; 41 | 42 | @override 43 | void initState() { 44 | super.initState(); 45 | initStateAsync(); 46 | } 47 | 48 | void initStateAsync() async { 49 | WidgetsBinding.instance.addObserver(this); 50 | 51 | // Spawn a new isolate 52 | isolateUtils = IsolateUtils(); 53 | await isolateUtils.start(); 54 | 55 | // Camera initialization 56 | initializeCamera(); 57 | 58 | // Create an instance of classifier to load model and labels 59 | classifier = Classifier(); 60 | 61 | // Initially predicting = false 62 | predicting = false; 63 | } 64 | 65 | /// Initializes the camera by setting [cameraController] 66 | void initializeCamera() async { 67 | cameras = await availableCameras(); 68 | 69 | // cameras[0] for rear-camera 70 | cameraController = 71 | CameraController(cameras[0], ResolutionPreset.low, enableAudio: false); 72 | 73 | cameraController.initialize().then((_) async { 74 | // Stream of image passed to [onLatestImageAvailable] callback 75 | await cameraController.startImageStream(onLatestImageAvailable); 76 | 77 | /// previewSize is size of each image frame captured by controller 78 | /// 79 | /// 352x288 on iOS, 240p (320x240) on Android with ResolutionPreset.low 80 | Size previewSize = cameraController.value.previewSize; 81 | 82 | /// previewSize is size of raw input image to the model 83 | CameraViewSingleton.inputImageSize = previewSize; 84 | 85 | // the display width of image on screen is 86 | // same as screenWidth while maintaining the aspectRatio 87 | Size screenSize = MediaQuery.of(context).size; 88 | CameraViewSingleton.screenSize = screenSize; 89 | CameraViewSingleton.ratio = screenSize.width / previewSize.height; 90 | }); 91 | } 92 | 93 | @override 94 | Widget build(BuildContext context) { 95 | // Return empty container while the camera is not initialized 96 | if (cameraController == null || !cameraController.value.isInitialized) { 97 | return Container(); 98 | } 99 | 100 | return AspectRatio( 101 | aspectRatio: cameraController.value.aspectRatio, 102 | child: CameraPreview(cameraController)); 103 | } 104 | 105 | /// Callback to receive each frame [CameraImage] perform inference on it 106 | onLatestImageAvailable(CameraImage cameraImage) async { 107 | if (classifier.interpreter != null && classifier.labels != null) { 108 | // If previous inference has not completed then return 109 | if (predicting) { 110 | return; 111 | } 112 | 113 | setState(() { 114 | predicting = true; 115 | }); 116 | 117 | var uiThreadTimeStart = DateTime.now().millisecondsSinceEpoch; 118 | 119 | // Data to be passed to inference isolate 120 | var isolateData = IsolateData( 121 | cameraImage, classifier.interpreter.address, classifier.labels); 122 | 123 | // We could have simply used the compute method as well however 124 | // it would be as in-efficient as we need to continuously passing data 125 | // to another isolate. 126 | 127 | /// perform inference in separate isolate 128 | Map inferenceResults = await inference(isolateData); 129 | 130 | var uiThreadInferenceElapsedTime = 131 | DateTime.now().millisecondsSinceEpoch - uiThreadTimeStart; 132 | 133 | // pass results to HomeView 134 | widget.resultsCallback(inferenceResults["recognitions"]); 135 | 136 | // pass stats to HomeView 137 | widget.statsCallback((inferenceResults["stats"] as Stats) 138 | ..totalElapsedTime = uiThreadInferenceElapsedTime); 139 | 140 | // set predicting to false to allow new frames 141 | setState(() { 142 | predicting = false; 143 | }); 144 | } 145 | } 146 | 147 | /// Runs inference in another isolate 148 | Future> inference(IsolateData isolateData) async { 149 | ReceivePort responsePort = ReceivePort(); 150 | isolateUtils.sendPort 151 | .send(isolateData..responsePort = responsePort.sendPort); 152 | var results = await responsePort.first; 153 | return results; 154 | } 155 | 156 | @override 157 | void didChangeAppLifecycleState(AppLifecycleState state) async { 158 | switch (state) { 159 | case AppLifecycleState.paused: 160 | cameraController.stopImageStream(); 161 | break; 162 | case AppLifecycleState.resumed: 163 | if (!cameraController.value.isStreamingImages) { 164 | await cameraController.startImageStream(onLatestImageAvailable); 165 | } 166 | break; 167 | default: 168 | } 169 | } 170 | 171 | @override 172 | void dispose() { 173 | WidgetsBinding.instance.removeObserver(this); 174 | cameraController.dispose(); 175 | super.dispose(); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /lib/ui/camera_view_singleton.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | /// Singleton to record size related data 4 | class CameraViewSingleton { 5 | static double ratio; 6 | static Size screenSize; 7 | static Size inputImageSize; 8 | static Size get actualPreviewSize => 9 | Size(screenSize.width, screenSize.width * ratio); 10 | } 11 | -------------------------------------------------------------------------------- /lib/ui/home_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:object_detection/tflite/recognition.dart'; 4 | import 'package:object_detection/tflite/stats.dart'; 5 | import 'package:object_detection/ui/box_widget.dart'; 6 | import 'package:object_detection/ui/camera_view_singleton.dart'; 7 | 8 | import 'camera_view.dart'; 9 | 10 | /// [HomeView] stacks [CameraView] and [BoxWidget]s with bottom sheet for stats 11 | class HomeView extends StatefulWidget { 12 | @override 13 | _HomeViewState createState() => _HomeViewState(); 14 | } 15 | 16 | class _HomeViewState extends State { 17 | /// Results to draw bounding boxes 18 | List results; 19 | 20 | /// Realtime stats 21 | Stats stats; 22 | 23 | /// Scaffold Key 24 | GlobalKey scaffoldKey = GlobalKey(); 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | key: scaffoldKey, 30 | backgroundColor: Colors.black, 31 | body: Stack( 32 | children: [ 33 | // Camera View 34 | CameraView(resultsCallback, statsCallback), 35 | 36 | // Bounding boxes 37 | boundingBoxes(results), 38 | 39 | // Heading 40 | Align( 41 | alignment: Alignment.topLeft, 42 | child: Container( 43 | padding: EdgeInsets.only(top: 20), 44 | child: Text( 45 | 'Object Detection Flutter', 46 | textAlign: TextAlign.left, 47 | style: TextStyle( 48 | fontSize: 28, 49 | fontWeight: FontWeight.bold, 50 | color: Colors.deepOrangeAccent.withOpacity(0.6), 51 | ), 52 | ), 53 | ), 54 | ), 55 | 56 | // Bottom Sheet 57 | Align( 58 | alignment: Alignment.bottomCenter, 59 | child: DraggableScrollableSheet( 60 | initialChildSize: 0.4, 61 | minChildSize: 0.1, 62 | maxChildSize: 0.5, 63 | builder: (_, ScrollController scrollController) => Container( 64 | width: double.maxFinite, 65 | decoration: BoxDecoration( 66 | color: Colors.white.withOpacity(0.9), 67 | borderRadius: BORDER_RADIUS_BOTTOM_SHEET), 68 | child: SingleChildScrollView( 69 | controller: scrollController, 70 | child: Center( 71 | child: Column( 72 | mainAxisSize: MainAxisSize.min, 73 | children: [ 74 | Icon(Icons.keyboard_arrow_up, 75 | size: 48, color: Colors.orange), 76 | (stats != null) 77 | ? Padding( 78 | padding: const EdgeInsets.all(8.0), 79 | child: Column( 80 | children: [ 81 | StatsRow('Inference time:', 82 | '${stats.inferenceTime} ms'), 83 | StatsRow('Total prediction time:', 84 | '${stats.totalElapsedTime} ms'), 85 | StatsRow('Pre-processing time:', 86 | '${stats.preProcessingTime} ms'), 87 | StatsRow('Frame', 88 | '${CameraViewSingleton.inputImageSize?.width} X ${CameraViewSingleton.inputImageSize?.height}'), 89 | ], 90 | ), 91 | ) 92 | : Container() 93 | ], 94 | ), 95 | ), 96 | ), 97 | ), 98 | ), 99 | ) 100 | ], 101 | ), 102 | ); 103 | } 104 | 105 | /// Returns Stack of bounding boxes 106 | Widget boundingBoxes(List results) { 107 | if (results == null) { 108 | return Container(); 109 | } 110 | return Stack( 111 | children: results 112 | .map((e) => BoxWidget( 113 | result: e, 114 | )) 115 | .toList(), 116 | ); 117 | } 118 | 119 | /// Callback to get inference results from [CameraView] 120 | void resultsCallback(List results) { 121 | setState(() { 122 | this.results = results; 123 | }); 124 | } 125 | 126 | /// Callback to get inference stats from [CameraView] 127 | void statsCallback(Stats stats) { 128 | setState(() { 129 | this.stats = stats; 130 | }); 131 | } 132 | 133 | static const BOTTOM_SHEET_RADIUS = Radius.circular(24.0); 134 | static const BORDER_RADIUS_BOTTOM_SHEET = BorderRadius.only( 135 | topLeft: BOTTOM_SHEET_RADIUS, topRight: BOTTOM_SHEET_RADIUS); 136 | } 137 | 138 | /// Row for one Stats field 139 | class StatsRow extends StatelessWidget { 140 | final String left; 141 | final String right; 142 | 143 | StatsRow(this.left, this.right); 144 | 145 | @override 146 | Widget build(BuildContext context) { 147 | return Padding( 148 | padding: const EdgeInsets.only(bottom: 8.0), 149 | child: Row( 150 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 151 | children: [Text(left), Text(right)], 152 | ), 153 | ); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /lib/utils/image_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:camera/camera.dart'; 4 | import 'package:image/image.dart' as imageLib; 5 | import 'package:path_provider/path_provider.dart'; 6 | 7 | /// ImageUtils 8 | class ImageUtils { 9 | /// Converts a [CameraImage] in YUV420 format to [imageLib.Image] in RGB format 10 | static imageLib.Image convertCameraImage(CameraImage cameraImage) { 11 | if (cameraImage.format.group == ImageFormatGroup.yuv420) { 12 | return convertYUV420ToImage(cameraImage); 13 | } else if (cameraImage.format.group == ImageFormatGroup.bgra8888) { 14 | return convertBGRA8888ToImage(cameraImage); 15 | } else { 16 | return null; 17 | } 18 | } 19 | 20 | /// Converts a [CameraImage] in BGRA888 format to [imageLib.Image] in RGB format 21 | static imageLib.Image convertBGRA8888ToImage(CameraImage cameraImage) { 22 | imageLib.Image img = imageLib.Image.fromBytes(cameraImage.planes[0].width, 23 | cameraImage.planes[0].height, cameraImage.planes[0].bytes, 24 | format: imageLib.Format.bgra); 25 | return img; 26 | } 27 | 28 | /// Converts a [CameraImage] in YUV420 format to [imageLib.Image] in RGB format 29 | static imageLib.Image convertYUV420ToImage(CameraImage cameraImage) { 30 | final int width = cameraImage.width; 31 | final int height = cameraImage.height; 32 | 33 | final int uvRowStride = cameraImage.planes[1].bytesPerRow; 34 | final int uvPixelStride = cameraImage.planes[1].bytesPerPixel; 35 | 36 | final image = imageLib.Image(width, height); 37 | 38 | for (int w = 0; w < width; w++) { 39 | for (int h = 0; h < height; h++) { 40 | final int uvIndex = 41 | uvPixelStride * (w / 2).floor() + uvRowStride * (h / 2).floor(); 42 | final int index = h * width + w; 43 | 44 | final y = cameraImage.planes[0].bytes[index]; 45 | final u = cameraImage.planes[1].bytes[uvIndex]; 46 | final v = cameraImage.planes[2].bytes[uvIndex]; 47 | 48 | image.data[index] = ImageUtils.yuv2rgb(y, u, v); 49 | } 50 | } 51 | return image; 52 | } 53 | 54 | /// Convert a single YUV pixel to RGB 55 | static int yuv2rgb(int y, int u, int v) { 56 | // Convert yuv pixel to rgb 57 | int r = (y + v * 1436 / 1024 - 179).round(); 58 | int g = (y - u * 46549 / 131072 + 44 - v * 93604 / 131072 + 91).round(); 59 | int b = (y + u * 1814 / 1024 - 227).round(); 60 | 61 | // Clipping RGB values to be inside boundaries [ 0 , 255 ] 62 | r = r.clamp(0, 255); 63 | g = g.clamp(0, 255); 64 | b = b.clamp(0, 255); 65 | 66 | return 0xff000000 | 67 | ((b << 16) & 0xff0000) | 68 | ((g << 8) & 0xff00) | 69 | (r & 0xff); 70 | } 71 | 72 | static void saveImage(imageLib.Image image, [int i = 0]) async { 73 | List jpeg = imageLib.JpegEncoder().encodeImage(image); 74 | final appDir = await getTemporaryDirectory(); 75 | final appPath = appDir.path; 76 | final fileOnDevice = File('$appPath/out$i.jpg'); 77 | await fileOnDevice.writeAsBytes(jpeg, flush: true); 78 | print('Saved $appPath/out$i.jpg'); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/utils/isolate_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:isolate'; 3 | 4 | import 'package:camera/camera.dart'; 5 | import 'package:image/image.dart' as imageLib; 6 | import 'package:object_detection/tflite/classifier.dart'; 7 | import 'package:object_detection/utils/image_utils.dart'; 8 | import 'package:tflite_flutter/tflite_flutter.dart'; 9 | 10 | /// Manages separate Isolate instance for inference 11 | class IsolateUtils { 12 | static const String DEBUG_NAME = "InferenceIsolate"; 13 | 14 | Isolate _isolate; 15 | ReceivePort _receivePort = ReceivePort(); 16 | SendPort _sendPort; 17 | 18 | SendPort get sendPort => _sendPort; 19 | 20 | Future start() async { 21 | _isolate = await Isolate.spawn( 22 | entryPoint, 23 | _receivePort.sendPort, 24 | debugName: DEBUG_NAME, 25 | ); 26 | 27 | _sendPort = await _receivePort.first; 28 | } 29 | 30 | static void entryPoint(SendPort sendPort) async { 31 | final port = ReceivePort(); 32 | sendPort.send(port.sendPort); 33 | 34 | await for (final IsolateData isolateData in port) { 35 | if (isolateData != null) { 36 | Classifier classifier = Classifier( 37 | interpreter: 38 | Interpreter.fromAddress(isolateData.interpreterAddress), 39 | labels: isolateData.labels); 40 | imageLib.Image image = 41 | ImageUtils.convertCameraImage(isolateData.cameraImage); 42 | if (Platform.isAndroid) { 43 | image = imageLib.copyRotate(image, 90); 44 | } 45 | Map results = classifier.predict(image); 46 | isolateData.responsePort.send(results); 47 | } 48 | } 49 | } 50 | } 51 | 52 | /// Bundles data to pass between Isolate 53 | class IsolateData { 54 | CameraImage cameraImage; 55 | int interpreterAddress; 56 | List labels; 57 | SendPort responsePort; 58 | 59 | IsolateData( 60 | this.cameraImage, 61 | this.interpreterAddress, 62 | this.labels, 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /object_detection_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/am15h/object_detection_flutter/8dc807af8b05791806f32dd5d81b4c274aa2e99e/object_detection_demo.gif -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | archive: 5 | dependency: transitive 6 | description: 7 | name: archive 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.0.13" 11 | args: 12 | dependency: transitive 13 | description: 14 | name: args 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.6.0" 18 | async: 19 | dependency: transitive 20 | description: 21 | name: async 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.5.0" 25 | boolean_selector: 26 | dependency: transitive 27 | description: 28 | name: boolean_selector 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.1.0" 32 | camera: 33 | dependency: "direct main" 34 | description: 35 | name: camera 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "0.5.8+2" 39 | characters: 40 | dependency: transitive 41 | description: 42 | name: characters 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.1.0" 46 | charcode: 47 | dependency: transitive 48 | description: 49 | name: charcode 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.2.0" 53 | clock: 54 | dependency: transitive 55 | description: 56 | name: clock 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.1.0" 60 | collection: 61 | dependency: transitive 62 | description: 63 | name: collection 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.15.0" 67 | convert: 68 | dependency: transitive 69 | description: 70 | name: convert 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "2.1.1" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "2.1.4" 81 | cupertino_icons: 82 | dependency: "direct main" 83 | description: 84 | name: cupertino_icons 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.1.3" 88 | fake_async: 89 | dependency: transitive 90 | description: 91 | name: fake_async 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.2.0" 95 | ffi: 96 | dependency: transitive 97 | description: 98 | name: ffi 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "0.1.3" 102 | file: 103 | dependency: transitive 104 | description: 105 | name: file 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "5.2.1" 109 | flutter: 110 | dependency: "direct main" 111 | description: flutter 112 | source: sdk 113 | version: "0.0.0" 114 | flutter_plugin_android_lifecycle: 115 | dependency: transitive 116 | description: 117 | name: flutter_plugin_android_lifecycle 118 | url: "https://pub.dartlang.org" 119 | source: hosted 120 | version: "1.0.8" 121 | flutter_test: 122 | dependency: "direct dev" 123 | description: flutter 124 | source: sdk 125 | version: "0.0.0" 126 | http: 127 | dependency: transitive 128 | description: 129 | name: http 130 | url: "https://pub.dartlang.org" 131 | source: hosted 132 | version: "0.12.2" 133 | http_parser: 134 | dependency: transitive 135 | description: 136 | name: http_parser 137 | url: "https://pub.dartlang.org" 138 | source: hosted 139 | version: "3.1.4" 140 | image: 141 | dependency: "direct main" 142 | description: 143 | name: image 144 | url: "https://pub.dartlang.org" 145 | source: hosted 146 | version: "2.1.12" 147 | image_picker: 148 | dependency: "direct main" 149 | description: 150 | name: image_picker 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "0.6.7+4" 154 | image_picker_platform_interface: 155 | dependency: transitive 156 | description: 157 | name: image_picker_platform_interface 158 | url: "https://pub.dartlang.org" 159 | source: hosted 160 | version: "1.1.0" 161 | intl: 162 | dependency: transitive 163 | description: 164 | name: intl 165 | url: "https://pub.dartlang.org" 166 | source: hosted 167 | version: "0.16.1" 168 | matcher: 169 | dependency: transitive 170 | description: 171 | name: matcher 172 | url: "https://pub.dartlang.org" 173 | source: hosted 174 | version: "0.12.10" 175 | meta: 176 | dependency: transitive 177 | description: 178 | name: meta 179 | url: "https://pub.dartlang.org" 180 | source: hosted 181 | version: "1.3.0" 182 | path: 183 | dependency: transitive 184 | description: 185 | name: path 186 | url: "https://pub.dartlang.org" 187 | source: hosted 188 | version: "1.8.0" 189 | path_provider: 190 | dependency: "direct main" 191 | description: 192 | name: path_provider 193 | url: "https://pub.dartlang.org" 194 | source: hosted 195 | version: "1.6.11" 196 | path_provider_linux: 197 | dependency: transitive 198 | description: 199 | name: path_provider_linux 200 | url: "https://pub.dartlang.org" 201 | source: hosted 202 | version: "0.0.1+2" 203 | path_provider_macos: 204 | dependency: transitive 205 | description: 206 | name: path_provider_macos 207 | url: "https://pub.dartlang.org" 208 | source: hosted 209 | version: "0.0.4+3" 210 | path_provider_platform_interface: 211 | dependency: transitive 212 | description: 213 | name: path_provider_platform_interface 214 | url: "https://pub.dartlang.org" 215 | source: hosted 216 | version: "1.0.2" 217 | pedantic: 218 | dependency: transitive 219 | description: 220 | name: pedantic 221 | url: "https://pub.dartlang.org" 222 | source: hosted 223 | version: "1.9.0" 224 | petitparser: 225 | dependency: transitive 226 | description: 227 | name: petitparser 228 | url: "https://pub.dartlang.org" 229 | source: hosted 230 | version: "2.4.0" 231 | platform: 232 | dependency: transitive 233 | description: 234 | name: platform 235 | url: "https://pub.dartlang.org" 236 | source: hosted 237 | version: "2.2.1" 238 | plugin_platform_interface: 239 | dependency: transitive 240 | description: 241 | name: plugin_platform_interface 242 | url: "https://pub.dartlang.org" 243 | source: hosted 244 | version: "1.0.2" 245 | process: 246 | dependency: transitive 247 | description: 248 | name: process 249 | url: "https://pub.dartlang.org" 250 | source: hosted 251 | version: "3.0.13" 252 | quiver: 253 | dependency: transitive 254 | description: 255 | name: quiver 256 | url: "https://pub.dartlang.org" 257 | source: hosted 258 | version: "2.1.3" 259 | sky_engine: 260 | dependency: transitive 261 | description: flutter 262 | source: sdk 263 | version: "0.0.99" 264 | source_span: 265 | dependency: transitive 266 | description: 267 | name: source_span 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "1.8.0" 271 | stack_trace: 272 | dependency: transitive 273 | description: 274 | name: stack_trace 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.10.0" 278 | stream_channel: 279 | dependency: transitive 280 | description: 281 | name: stream_channel 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "2.1.0" 285 | string_scanner: 286 | dependency: transitive 287 | description: 288 | name: string_scanner 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "1.1.0" 292 | term_glyph: 293 | dependency: transitive 294 | description: 295 | name: term_glyph 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "1.2.0" 299 | test_api: 300 | dependency: transitive 301 | description: 302 | name: test_api 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "0.2.19" 306 | tflite_flutter: 307 | dependency: "direct main" 308 | description: 309 | name: tflite_flutter 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "0.5.0" 313 | tflite_flutter_helper: 314 | dependency: "direct main" 315 | description: 316 | name: tflite_flutter_helper 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "0.1.2" 320 | typed_data: 321 | dependency: transitive 322 | description: 323 | name: typed_data 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "1.3.0" 327 | vector_math: 328 | dependency: transitive 329 | description: 330 | name: vector_math 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "2.1.0" 334 | xdg_directories: 335 | dependency: transitive 336 | description: 337 | name: xdg_directories 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "0.1.0" 341 | xml: 342 | dependency: transitive 343 | description: 344 | name: xml 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "3.6.1" 348 | sdks: 349 | dart: ">=2.12.0-0.0 <3.0.0" 350 | flutter: ">=1.12.13+hotfix.5" 351 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: object_detection 2 | description: A new Flutter project. 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.7.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: ^0.1.3 31 | camera: ^0.5.8+2 32 | tflite_flutter: ^0.5.0 33 | tflite_flutter_helper: ^0.1.2 34 | image: ^2.1.12 35 | path_provider: ^1.6.11 36 | image_picker: ^0.6.7+2 37 | 38 | dev_dependencies: 39 | flutter_test: 40 | sdk: flutter 41 | 42 | # For information on the generic Dart part of this file, see the 43 | # following page: https://dart.dev/tools/pub/pubspec 44 | 45 | # The following section is specific to Flutter. 46 | flutter: 47 | 48 | # The following line ensures that the Material Icons font is 49 | # included with your application, so that you can use the icons in 50 | # the material Icons class. 51 | uses-material-design: true 52 | 53 | # To add assets to your application, add an assets section, like this: 54 | assets: 55 | - assets/ 56 | # - images/a_dot_burr.jpeg 57 | # - images/a_dot_ham.jpeg 58 | 59 | # An image asset can refer to one or more resolution-specific "variants", see 60 | # https://flutter.dev/assets-and-images/#resolution-aware. 61 | 62 | # For details regarding adding assets from package dependencies, see 63 | # https://flutter.dev/assets-and-images/#from-packages 64 | 65 | # To add custom fonts to your application, add a fonts section here, 66 | # in this "flutter" section. Each entry in this list should have a 67 | # "family" key with the font family name, and a "fonts" key with a 68 | # list giving the asset and other descriptors for the font. For 69 | # example: 70 | # fonts: 71 | # - family: Schyler 72 | # fonts: 73 | # - asset: fonts/Schyler-Regular.ttf 74 | # - asset: fonts/Schyler-Italic.ttf 75 | # style: italic 76 | # - family: Trajan Pro 77 | # fonts: 78 | # - asset: fonts/TrajanPro.ttf 79 | # - asset: fonts/TrajanPro_Bold.ttf 80 | # weight: 700 81 | # 82 | # For details regarding fonts from package dependencies, 83 | # see https://flutter.dev/custom-fonts/#from-packages 84 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:object_detection/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | --------------------------------------------------------------------------------