├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── AndroidManifest.xml │ └── kotlin │ │ └── com │ │ └── spring98 │ │ └── yolo_realtime_plugin │ │ └── YoloRealtimePlugin.kt │ └── test │ └── kotlin │ └── com │ └── spring98 │ └── yolo_realtime_plugin │ └── YoloRealtimePluginTest.kt ├── example ├── .gitignore ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── spring98 │ │ │ │ │ └── yolo_realtime_plugin_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ └── models │ │ └── yolov5s_320.pt ├── integration_test │ └── plugin_integration_test.dart ├── 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 │ │ └── yolov5s.mlmodel │ └── RunnerTests │ │ └── RunnerTests.swift ├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ └── YoloRealtimePlugin.swift └── yolo_realtime_plugin.podspec ├── lib ├── src │ ├── method_channel │ │ └── method_channel_yolo_realtime.dart │ ├── platform_interface │ │ └── yolo_realtime_platform_interface.dart │ ├── utils │ │ └── model.dart │ ├── widget │ │ ├── box_painter.dart │ │ └── yolo_realtime_view.dart │ ├── yolo_realtime_controller.dart │ └── yolo_realtime_preview.dart └── yolo_realtime_plugin.dart ├── pubspec.yaml └── test ├── yolo_realtime_plugin_method_channel_test.dart └── yolo_realtime_plugin_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 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /.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. 5 | 6 | version: 7 | revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 8 | channel: stable 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 17 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 18 | - platform: android 19 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 20 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 21 | - platform: ios 22 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 23 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 24 | 25 | # User provided section 26 | 27 | # List of Local paths (relative to this file) that should be 28 | # ignored by the migrate tool. 29 | # 30 | # Files that are not part of the templates will be ignored by default. 31 | unmanaged_files: 32 | - 'lib/main.dart' 33 | - 'ios/Runner.xcodeproj/project.pbxproj' 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | * Supports yolov5. 4 | 5 | ## 1.0.1 6 | 7 | * The existing model image size was fixed at 320*320 and 640*640, but expanded to all sizes. 8 | 9 | ## 1.0.2 10 | 11 | * update readme.md file 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 spring98 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 실시간 객체탐지 플러그인 2 | YOLO 실시간 객체 감지를 지원하는 Flutter 구현입니다. 3 | 4 | # preview 5 | 6 | ### iPhone 13 pro 7 | ![286609173-b0e97003-d4f9-4a19-b0e8-c1981c6e4cb8](https://github.com/spring98/flutter-yolo-realtime-plugin/assets/92755385/ebfd05c5-3e93-4d7d-9d8d-11f0a07728d6) 8 | 9 | ### Galaxy S10 10 | ![286611068-4da95ee3-2005-48ec-8d00-a717b2d0e8fb](https://github.com/spring98/flutter-yolo-realtime-plugin/assets/92755385/f727551c-5d41-4e12-98ae-b8df0c745b62) 11 | 12 |
13 |
14 | 15 | # 플러그인 개발 16 | 인공지능 모델을 이용하여 온디바이스 추론 프로젝트를 진행한 경험이 있습니다. 17 | 18 | 당시 Flutter 로 개발하기위해 여러가지 플러그인들을 테스트 했지만 실시간 추론을 지원하는 플러그인을 찾을 수 없었습니다. 19 | 20 | 해당 기능을 구현하기 위해서는 카메라 플러그인과 인공지능 추론 플러그인을 따로 설치 후 카메라 데이터를 가져와 다시 추론 플러그인을 거치는 방식을 사용하였습니다. 21 | 22 | 두 플러그인을 따로 사용하다보니 1회 추론시간이 1500 ~ 1600 ms 정도 걸리게 되었고, 실시간으로 사용하기에는 다소 무리가 있다고 판단해 결국 기존 AOS 네이티브로 개발된 코드를 리팩토링 하여 진행했었습니다. 23 | 24 | 프로젝트 종료 후 해당 문제를 해결하여 비슷한 문제를 겪고 있는 개발자들을 위해 플러그인 배포를 진행하였습니다. 25 | 26 |
27 |
28 | 29 | ## 기존 방식(성능 이슈 발생) 30 | 기존 방식을 그림으로 표현하면 아래와 같습니다. 31 | 32 | ![Sitemap (5)](https://github.com/spring98/flutter-yolo-realtime-plugin/assets/92755385/2a4cb729-b088-4bde-bbc2-a9849340d099) 33 | 34 |
35 | 36 | 1. 카메라 플러그인으로 네이티브에 접근 해 스트림 데이터 받아오기 (1,2,3,4) 37 | 2. 스트림 데이터를 인공지능 추론 플러그인으로 네이티브에 접근 해 결과 받아오기 (5,6,7,8) 38 | 3. 결과 내용을 출력하기 39 | 40 |
41 | 42 | 위의 프로세스에서 주목해야할 점은 2,3,6,7 화살표 입니다. 43 | 44 | Flutter 에서 플러그인을 개발할 때는 Method Channel 을 이용해서 네이티브와 통신하게 되는 데, 통신 횟수가 많아질수록, 통신 데이터가 많아질수록 지연시간이 발생합니다. 45 | 46 | 사진의 3번 화살표를 통해 기기 해상도에 맞는 이미지 데이터가 Flutter 로 전송되고 6번 화살표를 통해 다시 한번 네이티브로 전송됩니다. 47 | 48 | 데이터 크기가 큰 이미지 데이터가 1회 추론에 대해 플랫폼 사이를 2번 움직이는 통신 오버헤드가 발생하여 평균 추론시간은 1500~1600 ms 정도가 걸리게 됩니다. 49 | 50 | 51 |
52 |
53 | 54 | ## 개선 방식 55 | 기존 방식을 개선하면 아래 사진과 같습니다. 56 | 57 | 58 | 59 | 60 |
61 |
62 | 63 | 1. 플러그인에서 네이티브에 접근하여 카메라 스트림 데이터를 Flutter 로 가져오지 않고 바로 추론하기 64 | 2. 추론결과를 이용하여 네이티브 뷰 개발 65 | 3. Flutter 에서 네이티브 뷰를 띄우는 기능을 활용하여 제공 66 |
67 | 68 | 위의 프로세스에서 카메라 데이터는 네이티브 내에서 직접 연산, 추론되며 네이티브 뷰를 따로 만들어 띄우는 방식으로 개발 했기 때문에 Flutter 로 직접 전송되지 않으므로 오버헤드가 크게 발생하지 않습니다. 69 | 70 | 결과적으로 추론시간은 1500-1600 ms 에서 200-300 ms 로 크게 개선할 수 있었습니다. 71 | 72 |
73 |
74 |
75 | 76 | 2024.05.03 기준 상위 28% 수의 개발자들(popularity 72%)이 사용하고 있으며 YOLOv5 를 지원합니다. 77 | https://pub.dev/packages/yolo_realtime_plugin 78 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .cxx 10 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.spring98.yolo_realtime_plugin' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.7.10' 6 | repositories { 7 | google() 8 | mavenCentral() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:7.3.0' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | apply plugin: 'kotlin-android' 26 | 27 | android { 28 | compileSdkVersion 34 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | test.java.srcDirs += 'src/test/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | minSdkVersion 21 46 | } 47 | 48 | dependencies { 49 | testImplementation 'org.jetbrains.kotlin:kotlin-test' 50 | testImplementation 'org.mockito:mockito-core:5.0.0' 51 | } 52 | 53 | testOptions { 54 | unitTests.all { 55 | useJUnitPlatform() 56 | 57 | testLogging { 58 | events "passed", "skipped", "failed", "standardOut", "standardError" 59 | outputs.upToDateWhen {false} 60 | showStandardStreams = true 61 | } 62 | } 63 | } 64 | } 65 | 66 | 67 | dependencies { 68 | 69 | // PyTorch dependencies 70 | implementation 'org.pytorch:pytorch_android:1.8.0' 71 | implementation 'org.pytorch:pytorch_android_torchvision:1.8.0' 72 | implementation 'androidx.camera:camera-lifecycle:1.3.0' 73 | 74 | // CameraX core library 75 | implementation "androidx.camera:camera-core:1.3.0" 76 | implementation "androidx.camera:camera-camera2:1.3.0" 77 | implementation "androidx.camera:camera-lifecycle:1.3.0" 78 | implementation 'androidx.camera:camera-view:1.3.0' 79 | 80 | implementation 'androidx.appcompat:appcompat:1.6.1' 81 | implementation 'com.google.android.material:material:1.10.0' 82 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 83 | implementation 'com.android.support:multidex:1.0.3' 84 | 85 | } -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'yolo_realtime_plugin' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/spring98/yolo_realtime_plugin/YoloRealtimePlugin.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("LocalVariableName", "PrivatePropertyName") 2 | 3 | package com.spring98.yolo_realtime_plugin 4 | 5 | import android.Manifest 6 | import android.app.Activity 7 | import android.content.Context 8 | import android.content.pm.PackageManager 9 | import android.graphics.* 10 | import android.util.Log 11 | import android.view.View 12 | import androidx.annotation.OptIn 13 | import androidx.camera.core.* 14 | import androidx.camera.lifecycle.ProcessCameraProvider 15 | import androidx.camera.view.PreviewView 16 | import androidx.core.app.ActivityCompat 17 | import androidx.core.content.ContextCompat 18 | import androidx.lifecycle.LifecycleOwner 19 | import com.spring98.yolo_realtime_plugin.Constants.Companion.ACTIVE_CLASS_LABELS 20 | import com.spring98.yolo_realtime_plugin.Constants.Companion.CONFIDENCE_THRESHOLD 21 | import com.spring98.yolo_realtime_plugin.Constants.Companion.DETECTION_SIZE 22 | import com.spring98.yolo_realtime_plugin.Constants.Companion.FULL_CLASS_LABELS 23 | import com.spring98.yolo_realtime_plugin.Constants.Companion.IOU_THRESHOLD 24 | import com.spring98.yolo_realtime_plugin.Constants.Companion.MODEL 25 | import com.spring98.yolo_realtime_plugin.Constants.Companion.MODEL_HEIGHT 26 | import com.spring98.yolo_realtime_plugin.Constants.Companion.MODEL_WIDTH 27 | import io.flutter.embedding.engine.plugins.FlutterPlugin 28 | import io.flutter.embedding.engine.plugins.activity.ActivityAware 29 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding 30 | import io.flutter.plugin.common.MethodCall 31 | import io.flutter.plugin.common.MethodChannel 32 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 33 | import io.flutter.plugin.common.MethodChannel.Result 34 | import io.flutter.plugin.common.StandardMessageCodec 35 | import io.flutter.plugin.platform.PlatformView 36 | import io.flutter.plugin.platform.PlatformViewFactory 37 | import org.pytorch.IValue 38 | import org.pytorch.Module 39 | import org.pytorch.PyTorchAndroid 40 | import org.pytorch.torchvision.TensorImageUtils 41 | import java.io.ByteArrayOutputStream 42 | import java.util.concurrent.Executors 43 | 44 | 45 | /** YoloRealtimePlugin */ 46 | class YoloRealtimePlugin: FlutterPlugin, MethodCallHandler, ActivityAware { 47 | private lateinit var channel : MethodChannel 48 | private lateinit var binding: FlutterPlugin.FlutterPluginBinding 49 | private var activity: Activity? = null 50 | 51 | private val CAMERA_REQUEST_CODE = 100 // 카메라 요청 코드 52 | 53 | override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 54 | this.binding = flutterPluginBinding 55 | channel = MethodChannel(flutterPluginBinding.binaryMessenger, "yolo_realtime_plugin") 56 | channel.setMethodCallHandler(this) 57 | } 58 | 59 | override fun onMethodCall(call: MethodCall, result: Result) { 60 | // 카메라 트리거 처리 61 | when (call.method) { 62 | "initializeController" -> { 63 | val arguments = call.arguments as? Map<*, *> ?: return 64 | val modelPath = arguments["modelPath"] as? String 65 | val fullClasses = arguments["fullClasses"] as? List<*> 66 | val activeClasses = arguments["activeClasses"] as? List<*> 67 | 68 | val modelWidth = arguments["modelWidth"] as? Int 69 | val modelHeight = arguments["modelHeight"] as? Int 70 | val confThreshold = arguments["confThreshold"] as? Double 71 | val iouThreshold = arguments["iouThreshold"] as? Double 72 | 73 | // Log.d("[SPRING]", "Yolo controller initialized: $modelPath, $fullClassList, $activeClassList, $version, $modelInputSize, $confThreshold, $iouThreshold") 74 | 75 | DETECTION_SIZE = fullClasses?.size?.plus(5) ?: 0 76 | MODEL_WIDTH = modelWidth ?: 0 77 | MODEL_HEIGHT = modelHeight ?: 0 78 | CONFIDENCE_THRESHOLD = confThreshold ?: 0.0 79 | IOU_THRESHOLD = iouThreshold ?: 0.0 80 | FULL_CLASS_LABELS = fullClasses?.filterIsInstance()?.toMutableList() ?: mutableListOf() 81 | ACTIVE_CLASS_LABELS = activeClasses?.filterIsInstance()?.toMutableList() ?: mutableListOf() 82 | 83 | val assetKey = binding.flutterAssets.getAssetFilePathByName(modelPath ?: "") 84 | MODEL = PyTorchAndroid.loadModuleFromAsset(binding.applicationContext.assets, assetKey) 85 | } 86 | 87 | else -> { 88 | result.notImplemented() 89 | } 90 | } 91 | } 92 | 93 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { 94 | channel.setMethodCallHandler(null) 95 | } 96 | 97 | // 이 메서드는 플러그인이 Flutter 엔진에 연결된 후, 플러그인이 호스팅하는 액티비티에 첫 번째로 연결될 때 호출됩니다. 98 | // 이 시점에서 플러그인은 액티비티와의 상호작용을 설정할 수 있습니다. 99 | // 예를 들어, 액티비티의 컨텍스트를 사용하여 네이티브 기능을 구현하거나, 액티비티의 생명주기 이벤트를 수신할 수 있습니다. 100 | override fun onAttachedToActivity(binding: ActivityPluginBinding) { 101 | activity = binding.activity 102 | 103 | activity?.let { 104 | this.binding.platformViewRegistry.registerViewFactory( 105 | "camera_view", CameraViewFactory(it, channel) 106 | ) 107 | } 108 | 109 | checkCameraPermission() 110 | binding.addRequestPermissionsResultListener { requestCode, _, grantResults -> 111 | when (requestCode) { 112 | CAMERA_REQUEST_CODE -> { 113 | if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { 114 | // 권한이 허용됨 115 | Log.d("[SPRING]", "Allow permission") 116 | } else { 117 | // 권한이 거부됨 118 | Log.d("[SPRING]", "Permission denied") 119 | } 120 | } 121 | } 122 | true 123 | } 124 | } 125 | 126 | // 이 메서드는 구성 변경(예: 화면 회전)으로 인해 액티비티가 재생성되기 전에 호출됩니다. 127 | // 이 시점에서 플러그인은 액티비티와의 연결을 일시적으로 해제하고, 필요한 정리 작업을 수행할 수 있습니다. 128 | // 구성 변경 후에는 onReattachedToActivityForConfigChanges가 호출됩니다. 129 | override fun onDetachedFromActivityForConfigChanges() {} 130 | 131 | // 이 메서드는 구성 변경 후에 새로 생성된 액티비티에 플러그인이 다시 연결될 때 호출됩니다. 132 | // 이 메서드는 플러그인이 새 액티비티 인스턴스와 상호작용을 재설정할 수 있는 기회를 제공합니다. 133 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {} 134 | 135 | // 이 메서드는 플러그인이 액티비티와의 연결이 완전히 해제될 때 호출됩니다. 136 | // 이는 액티비티가 파괴되거나 플러그인이 Flutter 엔진으로부터 분리될 때 발생할 수 있습니다. 137 | // 이 시점에서 플러그인은 액티비티와의 모든 상호작용을 정리하고, 필요한 리소스를 해제해야 합니다. 138 | override fun onDetachedFromActivity() {} 139 | 140 | private fun checkCameraPermission() { 141 | if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { 142 | ActivityCompat.requestPermissions(activity!!, arrayOf(Manifest.permission.CAMERA), CAMERA_REQUEST_CODE) 143 | } 144 | } 145 | 146 | } 147 | 148 | 149 | class CameraViewFactory( 150 | private val activity: Activity, 151 | private val channel: MethodChannel, 152 | ) : 153 | PlatformViewFactory(StandardMessageCodec.INSTANCE) { 154 | override fun create(context: Context, viewId: Int, args: Any?): PlatformView { 155 | return CameraView(context, activity, channel) 156 | } 157 | } 158 | 159 | class CameraView( 160 | private val context: Context, 161 | private val activity: Activity, 162 | private val channel: MethodChannel, 163 | ) : PlatformView { 164 | private var cameraProvider: ProcessCameraProvider? = null 165 | private val previewView = PreviewView(context) 166 | 167 | init { 168 | setupCamera() 169 | } 170 | 171 | override fun dispose() { 172 | cameraProvider?.unbindAll() 173 | } 174 | 175 | private fun setupCamera() { 176 | previewView.scaleType = PreviewView.ScaleType.FILL_CENTER 177 | previewView.implementationMode = PreviewView.ImplementationMode.COMPATIBLE 178 | 179 | val cameraProviderFuture = ProcessCameraProvider.getInstance(context) 180 | cameraProviderFuture.addListener({ 181 | this.cameraProvider = cameraProviderFuture.get() 182 | 183 | // 단일 스레드 사용 184 | val executor = Executors.newSingleThreadExecutor() 185 | // 고정된 스레드 풀 사용 186 | // val executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) 187 | 188 | // Create a Preview 189 | val preview = Preview.Builder() 190 | .build() 191 | 192 | val imageAnalyzer = ImageAnalysis.Builder() 193 | .build() 194 | .also { 195 | it.setAnalyzer(executor, YoloImageAnalyzer()) 196 | } 197 | 198 | // Select the back camera 199 | val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA 200 | 201 | // Unbind any bound use cases before rebinding 202 | cameraProvider?.unbindAll() 203 | 204 | // Bind the Preview use case to the camera provider 205 | try { 206 | cameraProvider?.bindToLifecycle( 207 | activity as LifecycleOwner, 208 | cameraSelector, 209 | preview, 210 | imageAnalyzer 211 | ) 212 | 213 | // Connect the preview use case to the preview view 214 | preview.setSurfaceProvider(previewView.surfaceProvider) 215 | 216 | // 카메라가 성공적으로 열렸음을 나타내는 로그 217 | Log.d("[SPRING]", "카메라가 성공적으로 열렸습니다.") 218 | 219 | } catch (exc: Exception) { 220 | Log.e("[SPRING]", "카메라 사용 중 오류 발생: ${exc.localizedMessage}") 221 | } 222 | }, ContextCompat.getMainExecutor(context)) 223 | 224 | } 225 | 226 | override fun getView(): View { 227 | return previewView 228 | } 229 | 230 | private inner class YoloImageAnalyzer : ImageAnalysis.Analyzer { 231 | @OptIn(ExperimentalGetImage::class) 232 | override fun analyze(image: ImageProxy) { 233 | if(MODEL == null) { 234 | image.close() 235 | return 236 | } 237 | 238 | // 이미지를 Bitmap 으로 변환 239 | val bitmap_origin = image.toBitmap() 240 | 241 | val(resizedBitmap, padding_width, padding_height) = cameraSizeToModelSize(bitmap_origin, MODEL_WIDTH, MODEL_HEIGHT) 242 | 243 | // Bitmap To Tensor 244 | val inputTensor = TensorImageUtils.bitmapToFloat32Tensor( 245 | resizedBitmap, 246 | 247 | // NO_MEAN_RGB 248 | floatArrayOf(0.0f, 0.0f, 0.0f), 249 | 250 | // NO_STD_RGB 251 | floatArrayOf(1.0f, 1.0f, 1.0f) 252 | ) 253 | 254 | // Tensor -> FloatArray 255 | val outputTensor = MODEL!!.forward(IValue.from(inputTensor)).toTuple()[0].toTensor().dataAsFloatArray 256 | 257 | // 결과 처리 (예: 객체 위치, 신뢰도 등) 258 | val detectionResults = processOutput(outputTensor, padding_width, padding_height) 259 | 260 | val nmsDetectionResults = nms(detectionResults, IOU_THRESHOLD) 261 | 262 | // 추론 결과에 따라 필요한 작업 수행 263 | sendToFlutter(nmsDetectionResults, bitmap_origin) // Flutter로 결과 전송 264 | 265 | // 이미지 리소스 해제 266 | image.close() 267 | } 268 | 269 | private fun sendToFlutter(results: List, image: Bitmap) { 270 | val thread = Thread { 271 | try { 272 | val stream = ByteArrayOutputStream() 273 | image.compress(Bitmap.CompressFormat.JPEG, 100, stream) 274 | val byteArray: ByteArray = stream.toByteArray() 275 | 276 | val outerMap = results.mapIndexed { index, result -> 277 | "box$index" to mapOf( 278 | "x" to result.boundingBox.left, 279 | "y" to result.boundingBox.top, 280 | "width" to result.boundingBox.width, 281 | "height" to result.boundingBox.height, 282 | "label" to result.label, 283 | "confidence" to result.confidence, 284 | "image" to byteArray // 이 부분은 필요에 따라 조정 285 | ) 286 | }.toMap() 287 | 288 | activity.runOnUiThread { 289 | // Log.d("[SPRING]", outerMap.toString()) 290 | channel.invokeMethod("boxes", outerMap) 291 | } 292 | } catch (e: Exception) { 293 | e.printStackTrace() 294 | } 295 | } 296 | thread.start() 297 | } 298 | 299 | fun cameraSizeToModelSize( 300 | originalBitmap: Bitmap, 301 | targetWidth: Int, 302 | targetHeight: Int 303 | ): Triple { 304 | // 이미지 비율 계산 305 | val aspectRatio = originalBitmap.width.toFloat() / originalBitmap.height 306 | val targetAspectRatio = targetWidth.toFloat() / targetHeight 307 | 308 | // 비율에 따라 조절할 새 크기 결정 309 | val newWidth: Int 310 | val newHeight: Int 311 | if (aspectRatio > targetAspectRatio) { 312 | // 가로가 더 넓다면, 가로를 맞추고 세로를 조절 313 | newWidth = targetWidth 314 | newHeight = (targetWidth / aspectRatio).toInt() 315 | } else { 316 | // 세로가 더 길다면, 세로를 맞추고 가로를 조절 317 | newHeight = targetHeight 318 | newWidth = (targetHeight * aspectRatio).toInt() 319 | } 320 | 321 | // 이미지 크기 조절 322 | val resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true) 323 | 324 | // 필요한 경우 패딩 추가 325 | val paddedBitmap = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888) 326 | val canvas = Canvas(paddedBitmap) 327 | canvas.drawColor(Color.BLACK) 328 | canvas.drawBitmap( 329 | resizedBitmap, 330 | ((targetWidth - newWidth) / 2f), 331 | ((targetHeight - newHeight) / 2f), 332 | null 333 | ) 334 | 335 | return Triple(paddedBitmap, ((targetWidth - newWidth) / 2f), ((targetHeight - newHeight) / 2f)) 336 | } 337 | 338 | private fun processOutput(tensor: FloatArray, padding_width: Float, padding_height: Float): List { 339 | val results = mutableListOf() 340 | 341 | // tensor.size = 535500 / 85 = 6300 342 | for (i in tensor.indices step DETECTION_SIZE) { 343 | val confidence = tensor[i + 4] 344 | if (confidence > CONFIDENCE_THRESHOLD) { 345 | val x: Float = convertRange(tensor[i], MODEL_WIDTH, padding_width) 346 | val y: Float = convertRange(tensor[i + 1], MODEL_HEIGHT, padding_height) 347 | val w: Float = tensor[i + 2] * (MODEL_WIDTH + 2*padding_width)/(MODEL_WIDTH - 2*padding_width) 348 | val h: Float = tensor[i + 3] * (MODEL_HEIGHT + 2*padding_height)/(MODEL_HEIGHT - 2*padding_height) 349 | 350 | val left = (x - w / 2) / MODEL_WIDTH 351 | val top = ((MODEL_HEIGHT - y - h / 2) / MODEL_HEIGHT) 352 | val width = w / MODEL_WIDTH 353 | val height = (h / MODEL_HEIGHT) 354 | 355 | var maxClassScore = tensor[i + 5] 356 | var cls = 0 357 | for (j in 0 until DETECTION_SIZE - 5) { 358 | if (tensor[i + 5 + j] > maxClassScore) { 359 | maxClassScore = tensor[i + 5 + j] 360 | cls = j 361 | } 362 | } 363 | 364 | val rect = RectLTWH(left, top, width, height) 365 | results.add(DetectionResult(rect, getClassLabel(cls), confidence)) 366 | } 367 | } 368 | 369 | return results 370 | } 371 | 372 | fun convertRange(originalValue: Float, model_size: Int, padding_size: Float): Float { 373 | val originalMin = padding_size 374 | val originalMax = model_size - padding_size 375 | val newMin = - padding_size 376 | val newMax = model_size + padding_size 377 | 378 | return ((originalValue - originalMin) / (originalMax - originalMin)) * (newMax - newMin) + newMin 379 | } 380 | 381 | // 클래스 라벨을 얻는 함수 (클래스 인덱스를 클래스 이름으로 변환) 382 | private fun getClassLabel(classIndex: Int): String { 383 | return FULL_CLASS_LABELS[classIndex] 384 | } 385 | } 386 | 387 | fun nms(boxes: List, iouThreshold: Double): List { 388 | if (boxes.isEmpty()) return emptyList() 389 | 390 | val sortedBoxes = boxes.sortedByDescending { it.confidence } 391 | val selectedBoxes = mutableListOf() 392 | 393 | for (box in sortedBoxes) { 394 | var shouldSelect = true 395 | for (selectedBox in selectedBoxes) { 396 | if (iou(box.boundingBox.toRectF(), selectedBox.boundingBox.toRectF()) > iouThreshold) { 397 | shouldSelect = false 398 | break 399 | } 400 | } 401 | if (shouldSelect) { 402 | selectedBoxes.add(box) 403 | } 404 | } 405 | 406 | return selectedBoxes 407 | } 408 | 409 | private fun iou(boxA: RectF, boxB: RectF): Float { 410 | val intersectionArea = (boxA.right.coerceAtMost(boxB.right) - boxA.left.coerceAtLeast(boxB.left)).coerceAtLeast(0f) * 411 | (boxA.bottom.coerceAtMost(boxB.bottom) - boxA.top.coerceAtLeast(boxB.top)).coerceAtLeast(0f) 412 | 413 | val boxAArea = (boxA.right - boxA.left) * (boxA.bottom - boxA.top) 414 | val boxBArea = (boxB.right - boxB.left) * (boxB.bottom - boxB.top) 415 | 416 | val unionArea = boxAArea + boxBArea - intersectionArea 417 | 418 | return if (unionArea > 0f) intersectionArea / unionArea else 0f 419 | } 420 | 421 | // RectLTWH 클래스의 확장 함수로 RectF 변환 422 | private fun RectLTWH.toRectF(): RectF { 423 | return RectF(left, top, left + width, top + height) 424 | } 425 | } 426 | 427 | data class DetectionResult( 428 | val boundingBox: RectLTWH, // 객체의 위치 및 크기를 나타내는 경계 상자 429 | val label: String, // 객체의 클래스 라벨 430 | val confidence: Float // 객체 감지에 대한 신뢰도 431 | ) 432 | 433 | class RectLTWH ( 434 | left:Float, 435 | top:Float, 436 | width:Float, 437 | height:Float, 438 | ) { 439 | val left = left.coerceIn(0.0f, 1.0f) 440 | val top = top.coerceIn(0.0f, 1.0f) 441 | private val right = (left + width).coerceIn(0.0f, 1.0f) 442 | private val bottom = (top + height).coerceIn(0.0f, 1.0f) 443 | val width = right - this.left 444 | val height = bottom - this.top 445 | } 446 | 447 | 448 | class Constants { 449 | // 상수 정의 450 | companion object { 451 | // 각 탐지에 대한 정보 개수 80 + 5 = (x, y, width, height, confidence, 클래스 개수) 452 | var DETECTION_SIZE:Int = 85 453 | 454 | // 신뢰도 임계값 455 | var CONFIDENCE_THRESHOLD:Double = 0.5 456 | 457 | // 신뢰도 임계값 458 | var IOU_THRESHOLD:Double = 0.5 459 | 460 | // 모델 입력 크기 461 | var MODEL_WIDTH: Int = 320 462 | 463 | // 모델 입력 크기 464 | var MODEL_HEIGHT: Int = 320 465 | 466 | // 내가 사용한 모델의 전체 클래스 리스트 467 | var FULL_CLASS_LABELS: MutableList = mutableListOf() 468 | 469 | // 내가 사용한 모델의 전체 클래스 리스트 중 실제로 사용할 클래스 리스트 470 | var ACTIVE_CLASS_LABELS:MutableList = mutableListOf() 471 | 472 | var MODEL: Module? = null 473 | } 474 | 475 | } 476 | -------------------------------------------------------------------------------- /android/src/test/kotlin/com/spring98/yolo_realtime_plugin/YoloRealtimePluginTest.kt: -------------------------------------------------------------------------------- 1 | package com.spring98.yolo_realtime_plugin 2 | 3 | import io.flutter.plugin.common.MethodCall 4 | import io.flutter.plugin.common.MethodChannel 5 | import kotlin.test.Test 6 | import org.mockito.Mockito 7 | 8 | /* 9 | * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. 10 | * 11 | * Once you have built the plugin's example app, you can run these tests from the command 12 | * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or 13 | * you can run them directly from IDEs that support JUnit such as Android Studio. 14 | */ 15 | 16 | internal class YoloRealtimePluginTest { 17 | @Test 18 | fun onMethodCall_getPlatformVersion_returnsExpectedValue() { 19 | val plugin = YoloRealtimePlugin() 20 | 21 | val call = MethodCall("getPlatformVersion", null) 22 | val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java) 23 | plugin.onMethodCall(call, mockResult) 24 | 25 | Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # yolo_realtime_plugin_example 2 | 3 | Demonstrates how to use the yolo_realtime_plugin plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/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 | namespace "com.spring98.yolo_realtime_plugin_example" 30 | compileSdkVersion 34 31 | ndkVersion flutter.ndkVersion 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | 38 | kotlinOptions { 39 | jvmTarget = '1.8' 40 | } 41 | 42 | sourceSets { 43 | main.java.srcDirs += 'src/main/kotlin' 44 | } 45 | 46 | defaultConfig { 47 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 48 | applicationId "com.spring98.yolo_realtime_plugin_example" 49 | // You can update the following values to match your application needs. 50 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 51 | minSdkVersion 21 52 | targetSdkVersion flutter.targetSdkVersion 53 | versionCode flutterVersionCode.toInteger() 54 | versionName flutterVersionName 55 | } 56 | 57 | buildTypes { 58 | release { 59 | // TODO: Add your own signing config for the release build. 60 | // Signing with the debug keys for now, so `flutter run --release` works. 61 | signingConfig signingConfigs.debug 62 | } 63 | } 64 | } 65 | 66 | flutter { 67 | source '../..' 68 | } 69 | 70 | dependencies { 71 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 72 | } 73 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/spring98/yolo_realtime_plugin_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.spring98.yolo_realtime_plugin_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.3.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 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 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/assets/models/yolov5s_320.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/assets/models/yolov5s_320.pt -------------------------------------------------------------------------------- /example/integration_test/plugin_integration_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter integration test. 2 | // 3 | // Since integration tests run in a full Flutter application, they can interact 4 | // with the host side of a plugin implementation, unlike Dart unit tests. 5 | // 6 | // For more information about Flutter integration tests, please see 7 | // https://docs.flutter.dev/cookbook/testing/integration/introduction 8 | 9 | import 'package:flutter_test/flutter_test.dart'; 10 | import 'package:integration_test/integration_test.dart'; 11 | 12 | void main() { 13 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 14 | 15 | testWidgets('getPlatformVersion test', (WidgetTester tester) async { 16 | // final YoloRealtimePlugin plugin = YoloRealtimePlugin(); 17 | // final String? version = await plugin.getPlatformVersion(); 18 | // // The version string depends on the host platform running the test, so 19 | // // just assert that some non-empty string is returned. 20 | // expect(version?.isNotEmpty, true); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.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 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - integration_test (0.0.1): 4 | - Flutter 5 | - yolo_realtime_plugin (0.0.1): 6 | - Flutter 7 | 8 | DEPENDENCIES: 9 | - Flutter (from `Flutter`) 10 | - integration_test (from `.symlinks/plugins/integration_test/ios`) 11 | - yolo_realtime_plugin (from `.symlinks/plugins/yolo_realtime_plugin/ios`) 12 | 13 | EXTERNAL SOURCES: 14 | Flutter: 15 | :path: Flutter 16 | integration_test: 17 | :path: ".symlinks/plugins/integration_test/ios" 18 | yolo_realtime_plugin: 19 | :path: ".symlinks/plugins/yolo_realtime_plugin/ios" 20 | 21 | SPEC CHECKSUMS: 22 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 23 | integration_test: 13825b8a9334a850581300559b8839134b124670 24 | yolo_realtime_plugin: 11ce4e5c771643f2dc71dd4ee8ad94ff46927497 25 | 26 | PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189 27 | 28 | COCOAPODS: 1.14.2 29 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 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 | A90EEF13C373423F16F7F189 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AEA841E7B4747DFAB3A1E23 /* Pods_Runner.framework */; }; 18 | C56F5C08AFF5EFBFFC77698D /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8624ECFB2A811311F7A695F4 /* Pods_RunnerTests.framework */; }; 19 | E51E5C2C2B17098300F5F53D /* yolov5s.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = E51E5C2B2B17098300F5F53D /* yolov5s.mlmodel */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 97C146E61CF9000F007C117D /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 97C146ED1CF9000F007C117D; 28 | remoteInfo = Runner; 29 | }; 30 | /* End PBXContainerItemProxy section */ 31 | 32 | /* Begin PBXCopyFilesBuildPhase section */ 33 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 34 | isa = PBXCopyFilesBuildPhase; 35 | buildActionMask = 2147483647; 36 | dstPath = ""; 37 | dstSubfolderSpec = 10; 38 | files = ( 39 | ); 40 | name = "Embed Frameworks"; 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXCopyFilesBuildPhase section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 07A89B06321888C0FD239D29 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 47 | 0AEA841E7B4747DFAB3A1E23 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 0C325DE0A090E96D53CFBE5F /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 49 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 50 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 51 | 25D120210FCDA8BD94A9DF3E /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 52 | 32BBE0B51E240DC48BCD9FB8 /* 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 = ""; }; 53 | 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 54 | 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 56 | 484D9C716DEA1A74B4EE1443 /* 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 = ""; }; 57 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 58 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 59 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 60 | 8624ECFB2A811311F7A695F4 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 62 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 63 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 65 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 66 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 67 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68 | E14A77FDD5DE75EDFCAE9A9B /* 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 = ""; }; 69 | E51E5C2B2B17098300F5F53D /* yolov5s.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = yolov5s.mlmodel; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | A90EEF13C373423F16F7F189 /* Pods_Runner.framework in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | A4F54DE51EC62DE2B870FA72 /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | C56F5C08AFF5EFBFFC77698D /* Pods_RunnerTests.framework in Frameworks */, 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | /* End PBXFrameworksBuildPhase section */ 90 | 91 | /* Begin PBXGroup section */ 92 | 331C8082294A63A400263BE5 /* RunnerTests */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 331C807B294A618700263BE5 /* RunnerTests.swift */, 96 | ); 97 | path = RunnerTests; 98 | sourceTree = ""; 99 | }; 100 | 5A273D5EFA46603E6392F4D0 /* Pods */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | E14A77FDD5DE75EDFCAE9A9B /* Pods-Runner.debug.xcconfig */, 104 | 32BBE0B51E240DC48BCD9FB8 /* Pods-Runner.release.xcconfig */, 105 | 484D9C716DEA1A74B4EE1443 /* Pods-Runner.profile.xcconfig */, 106 | 0C325DE0A090E96D53CFBE5F /* Pods-RunnerTests.debug.xcconfig */, 107 | 25D120210FCDA8BD94A9DF3E /* Pods-RunnerTests.release.xcconfig */, 108 | 07A89B06321888C0FD239D29 /* Pods-RunnerTests.profile.xcconfig */, 109 | ); 110 | path = Pods; 111 | sourceTree = ""; 112 | }; 113 | 9740EEB11CF90186004384FC /* Flutter */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 117 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 118 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 119 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 120 | ); 121 | name = Flutter; 122 | sourceTree = ""; 123 | }; 124 | 97C146E51CF9000F007C117D = { 125 | isa = PBXGroup; 126 | children = ( 127 | 9740EEB11CF90186004384FC /* Flutter */, 128 | 97C146F01CF9000F007C117D /* Runner */, 129 | 97C146EF1CF9000F007C117D /* Products */, 130 | 331C8082294A63A400263BE5 /* RunnerTests */, 131 | 5A273D5EFA46603E6392F4D0 /* Pods */, 132 | C06CE69DAC770CC5DACF6C3A /* Frameworks */, 133 | ); 134 | sourceTree = ""; 135 | }; 136 | 97C146EF1CF9000F007C117D /* Products */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 97C146EE1CF9000F007C117D /* Runner.app */, 140 | 331C8081294A63A400263BE5 /* RunnerTests.xctest */, 141 | ); 142 | name = Products; 143 | sourceTree = ""; 144 | }; 145 | 97C146F01CF9000F007C117D /* Runner */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | E51E5C2B2B17098300F5F53D /* yolov5s.mlmodel */, 149 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 150 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 151 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 152 | 97C147021CF9000F007C117D /* Info.plist */, 153 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 154 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 155 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 156 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 157 | ); 158 | path = Runner; 159 | sourceTree = ""; 160 | }; 161 | C06CE69DAC770CC5DACF6C3A /* Frameworks */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 0AEA841E7B4747DFAB3A1E23 /* Pods_Runner.framework */, 165 | 8624ECFB2A811311F7A695F4 /* Pods_RunnerTests.framework */, 166 | ); 167 | name = Frameworks; 168 | sourceTree = ""; 169 | }; 170 | /* End PBXGroup section */ 171 | 172 | /* Begin PBXNativeTarget section */ 173 | 331C8080294A63A400263BE5 /* RunnerTests */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; 176 | buildPhases = ( 177 | 1ED8FCCA584B504017413D84 /* [CP] Check Pods Manifest.lock */, 178 | 331C807D294A63A400263BE5 /* Sources */, 179 | 331C807F294A63A400263BE5 /* Resources */, 180 | A4F54DE51EC62DE2B870FA72 /* Frameworks */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | 331C8086294A63A400263BE5 /* PBXTargetDependency */, 186 | ); 187 | name = RunnerTests; 188 | productName = RunnerTests; 189 | productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; 190 | productType = "com.apple.product-type.bundle.unit-test"; 191 | }; 192 | 97C146ED1CF9000F007C117D /* Runner */ = { 193 | isa = PBXNativeTarget; 194 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 195 | buildPhases = ( 196 | 43D89B7106600CD0D6E95C94 /* [CP] Check Pods Manifest.lock */, 197 | 9740EEB61CF901F6004384FC /* Run Script */, 198 | 97C146EA1CF9000F007C117D /* Sources */, 199 | 97C146EB1CF9000F007C117D /* Frameworks */, 200 | 97C146EC1CF9000F007C117D /* Resources */, 201 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 202 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 203 | 42A24BAAAC286DFC88D75873 /* [CP] Embed Pods Frameworks */, 204 | ); 205 | buildRules = ( 206 | ); 207 | dependencies = ( 208 | ); 209 | name = Runner; 210 | productName = Runner; 211 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 212 | productType = "com.apple.product-type.application"; 213 | }; 214 | /* End PBXNativeTarget section */ 215 | 216 | /* Begin PBXProject section */ 217 | 97C146E61CF9000F007C117D /* Project object */ = { 218 | isa = PBXProject; 219 | attributes = { 220 | LastUpgradeCheck = 1300; 221 | ORGANIZATIONNAME = ""; 222 | TargetAttributes = { 223 | 331C8080294A63A400263BE5 = { 224 | CreatedOnToolsVersion = 14.0; 225 | TestTargetID = 97C146ED1CF9000F007C117D; 226 | }; 227 | 97C146ED1CF9000F007C117D = { 228 | CreatedOnToolsVersion = 7.3.1; 229 | LastSwiftMigration = 1100; 230 | }; 231 | }; 232 | }; 233 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 234 | compatibilityVersion = "Xcode 9.3"; 235 | developmentRegion = en; 236 | hasScannedForEncodings = 0; 237 | knownRegions = ( 238 | en, 239 | Base, 240 | ); 241 | mainGroup = 97C146E51CF9000F007C117D; 242 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 243 | projectDirPath = ""; 244 | projectRoot = ""; 245 | targets = ( 246 | 97C146ED1CF9000F007C117D /* Runner */, 247 | 331C8080294A63A400263BE5 /* RunnerTests */, 248 | ); 249 | }; 250 | /* End PBXProject section */ 251 | 252 | /* Begin PBXResourcesBuildPhase section */ 253 | 331C807F294A63A400263BE5 /* Resources */ = { 254 | isa = PBXResourcesBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | ); 258 | runOnlyForDeploymentPostprocessing = 0; 259 | }; 260 | 97C146EC1CF9000F007C117D /* Resources */ = { 261 | isa = PBXResourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 265 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 266 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 267 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | }; 271 | /* End PBXResourcesBuildPhase section */ 272 | 273 | /* Begin PBXShellScriptBuildPhase section */ 274 | 1ED8FCCA584B504017413D84 /* [CP] Check Pods Manifest.lock */ = { 275 | isa = PBXShellScriptBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | ); 279 | inputFileListPaths = ( 280 | ); 281 | inputPaths = ( 282 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 283 | "${PODS_ROOT}/Manifest.lock", 284 | ); 285 | name = "[CP] Check Pods Manifest.lock"; 286 | outputFileListPaths = ( 287 | ); 288 | outputPaths = ( 289 | "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | shellPath = /bin/sh; 293 | 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"; 294 | showEnvVarsInLog = 0; 295 | }; 296 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 297 | isa = PBXShellScriptBuildPhase; 298 | alwaysOutOfDate = 1; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | ); 302 | inputPaths = ( 303 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", 304 | ); 305 | name = "Thin Binary"; 306 | outputPaths = ( 307 | ); 308 | runOnlyForDeploymentPostprocessing = 0; 309 | shellPath = /bin/sh; 310 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 311 | }; 312 | 42A24BAAAC286DFC88D75873 /* [CP] Embed Pods Frameworks */ = { 313 | isa = PBXShellScriptBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | ); 317 | inputFileListPaths = ( 318 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 319 | ); 320 | name = "[CP] Embed Pods Frameworks"; 321 | outputFileListPaths = ( 322 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | shellPath = /bin/sh; 326 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 327 | showEnvVarsInLog = 0; 328 | }; 329 | 43D89B7106600CD0D6E95C94 /* [CP] Check Pods Manifest.lock */ = { 330 | isa = PBXShellScriptBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | ); 334 | inputFileListPaths = ( 335 | ); 336 | inputPaths = ( 337 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 338 | "${PODS_ROOT}/Manifest.lock", 339 | ); 340 | name = "[CP] Check Pods Manifest.lock"; 341 | outputFileListPaths = ( 342 | ); 343 | outputPaths = ( 344 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | shellPath = /bin/sh; 348 | 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"; 349 | showEnvVarsInLog = 0; 350 | }; 351 | 9740EEB61CF901F6004384FC /* Run Script */ = { 352 | isa = PBXShellScriptBuildPhase; 353 | alwaysOutOfDate = 1; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | ); 357 | inputPaths = ( 358 | ); 359 | name = "Run Script"; 360 | outputPaths = ( 361 | ); 362 | runOnlyForDeploymentPostprocessing = 0; 363 | shellPath = /bin/sh; 364 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 365 | }; 366 | /* End PBXShellScriptBuildPhase section */ 367 | 368 | /* Begin PBXSourcesBuildPhase section */ 369 | 331C807D294A63A400263BE5 /* Sources */ = { 370 | isa = PBXSourcesBuildPhase; 371 | buildActionMask = 2147483647; 372 | files = ( 373 | 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | }; 377 | 97C146EA1CF9000F007C117D /* Sources */ = { 378 | isa = PBXSourcesBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 382 | E51E5C2C2B17098300F5F53D /* yolov5s.mlmodel in Sources */, 383 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 384 | ); 385 | runOnlyForDeploymentPostprocessing = 0; 386 | }; 387 | /* End PBXSourcesBuildPhase section */ 388 | 389 | /* Begin PBXTargetDependency section */ 390 | 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { 391 | isa = PBXTargetDependency; 392 | target = 97C146ED1CF9000F007C117D /* Runner */; 393 | targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; 394 | }; 395 | /* End PBXTargetDependency section */ 396 | 397 | /* Begin PBXVariantGroup section */ 398 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 399 | isa = PBXVariantGroup; 400 | children = ( 401 | 97C146FB1CF9000F007C117D /* Base */, 402 | ); 403 | name = Main.storyboard; 404 | sourceTree = ""; 405 | }; 406 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 407 | isa = PBXVariantGroup; 408 | children = ( 409 | 97C147001CF9000F007C117D /* Base */, 410 | ); 411 | name = LaunchScreen.storyboard; 412 | sourceTree = ""; 413 | }; 414 | /* End PBXVariantGroup section */ 415 | 416 | /* Begin XCBuildConfiguration section */ 417 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ALWAYS_SEARCH_USER_PATHS = NO; 421 | CLANG_ANALYZER_NONNULL = YES; 422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 423 | CLANG_CXX_LIBRARY = "libc++"; 424 | CLANG_ENABLE_MODULES = YES; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 427 | CLANG_WARN_BOOL_CONVERSION = YES; 428 | CLANG_WARN_COMMA = YES; 429 | CLANG_WARN_CONSTANT_CONVERSION = YES; 430 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 431 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 432 | CLANG_WARN_EMPTY_BODY = YES; 433 | CLANG_WARN_ENUM_CONVERSION = YES; 434 | CLANG_WARN_INFINITE_RECURSION = YES; 435 | CLANG_WARN_INT_CONVERSION = YES; 436 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 437 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 438 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 439 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 440 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 441 | CLANG_WARN_STRICT_PROTOTYPES = YES; 442 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 443 | CLANG_WARN_UNREACHABLE_CODE = YES; 444 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 445 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 446 | COPY_PHASE_STRIP = NO; 447 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 448 | ENABLE_NS_ASSERTIONS = NO; 449 | ENABLE_STRICT_OBJC_MSGSEND = YES; 450 | GCC_C_LANGUAGE_STANDARD = gnu99; 451 | GCC_NO_COMMON_BLOCKS = YES; 452 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 453 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 454 | GCC_WARN_UNDECLARED_SELECTOR = YES; 455 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 456 | GCC_WARN_UNUSED_FUNCTION = YES; 457 | GCC_WARN_UNUSED_VARIABLE = YES; 458 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 459 | MTL_ENABLE_DEBUG_INFO = NO; 460 | SDKROOT = iphoneos; 461 | SUPPORTED_PLATFORMS = iphoneos; 462 | TARGETED_DEVICE_FAMILY = "1,2"; 463 | VALIDATE_PRODUCT = YES; 464 | }; 465 | name = Profile; 466 | }; 467 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 468 | isa = XCBuildConfiguration; 469 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 470 | buildSettings = { 471 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 472 | CLANG_ENABLE_MODULES = YES; 473 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 474 | DEVELOPMENT_TEAM = GU33PWYX8W; 475 | ENABLE_BITCODE = NO; 476 | INFOPLIST_FILE = Runner/Info.plist; 477 | LD_RUNPATH_SEARCH_PATHS = ( 478 | "$(inherited)", 479 | "@executable_path/Frameworks", 480 | ); 481 | PRODUCT_BUNDLE_IDENTIFIER = com.spring98.yoloRealtimePluginExample; 482 | PRODUCT_NAME = "$(TARGET_NAME)"; 483 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 484 | SWIFT_VERSION = 5.0; 485 | VERSIONING_SYSTEM = "apple-generic"; 486 | }; 487 | name = Profile; 488 | }; 489 | 331C8088294A63A400263BE5 /* Debug */ = { 490 | isa = XCBuildConfiguration; 491 | baseConfigurationReference = 0C325DE0A090E96D53CFBE5F /* Pods-RunnerTests.debug.xcconfig */; 492 | buildSettings = { 493 | BUNDLE_LOADER = "$(TEST_HOST)"; 494 | CODE_SIGN_STYLE = Automatic; 495 | CURRENT_PROJECT_VERSION = 1; 496 | GENERATE_INFOPLIST_FILE = YES; 497 | MARKETING_VERSION = 1.0; 498 | PRODUCT_BUNDLE_IDENTIFIER = com.spring98.yoloRealtimePluginExample.RunnerTests; 499 | PRODUCT_NAME = "$(TARGET_NAME)"; 500 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 501 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 502 | SWIFT_VERSION = 5.0; 503 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 504 | }; 505 | name = Debug; 506 | }; 507 | 331C8089294A63A400263BE5 /* Release */ = { 508 | isa = XCBuildConfiguration; 509 | baseConfigurationReference = 25D120210FCDA8BD94A9DF3E /* Pods-RunnerTests.release.xcconfig */; 510 | buildSettings = { 511 | BUNDLE_LOADER = "$(TEST_HOST)"; 512 | CODE_SIGN_STYLE = Automatic; 513 | CURRENT_PROJECT_VERSION = 1; 514 | GENERATE_INFOPLIST_FILE = YES; 515 | MARKETING_VERSION = 1.0; 516 | PRODUCT_BUNDLE_IDENTIFIER = com.spring98.yoloRealtimePluginExample.RunnerTests; 517 | PRODUCT_NAME = "$(TARGET_NAME)"; 518 | SWIFT_VERSION = 5.0; 519 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 520 | }; 521 | name = Release; 522 | }; 523 | 331C808A294A63A400263BE5 /* Profile */ = { 524 | isa = XCBuildConfiguration; 525 | baseConfigurationReference = 07A89B06321888C0FD239D29 /* Pods-RunnerTests.profile.xcconfig */; 526 | buildSettings = { 527 | BUNDLE_LOADER = "$(TEST_HOST)"; 528 | CODE_SIGN_STYLE = Automatic; 529 | CURRENT_PROJECT_VERSION = 1; 530 | GENERATE_INFOPLIST_FILE = YES; 531 | MARKETING_VERSION = 1.0; 532 | PRODUCT_BUNDLE_IDENTIFIER = com.spring98.yoloRealtimePluginExample.RunnerTests; 533 | PRODUCT_NAME = "$(TARGET_NAME)"; 534 | SWIFT_VERSION = 5.0; 535 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 536 | }; 537 | name = Profile; 538 | }; 539 | 97C147031CF9000F007C117D /* Debug */ = { 540 | isa = XCBuildConfiguration; 541 | buildSettings = { 542 | ALWAYS_SEARCH_USER_PATHS = NO; 543 | CLANG_ANALYZER_NONNULL = YES; 544 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 545 | CLANG_CXX_LIBRARY = "libc++"; 546 | CLANG_ENABLE_MODULES = YES; 547 | CLANG_ENABLE_OBJC_ARC = YES; 548 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 549 | CLANG_WARN_BOOL_CONVERSION = YES; 550 | CLANG_WARN_COMMA = YES; 551 | CLANG_WARN_CONSTANT_CONVERSION = YES; 552 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 553 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 554 | CLANG_WARN_EMPTY_BODY = YES; 555 | CLANG_WARN_ENUM_CONVERSION = YES; 556 | CLANG_WARN_INFINITE_RECURSION = YES; 557 | CLANG_WARN_INT_CONVERSION = YES; 558 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 559 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 560 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 561 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 562 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 563 | CLANG_WARN_STRICT_PROTOTYPES = YES; 564 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 565 | CLANG_WARN_UNREACHABLE_CODE = YES; 566 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 567 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 568 | COPY_PHASE_STRIP = NO; 569 | DEBUG_INFORMATION_FORMAT = dwarf; 570 | ENABLE_STRICT_OBJC_MSGSEND = YES; 571 | ENABLE_TESTABILITY = YES; 572 | GCC_C_LANGUAGE_STANDARD = gnu99; 573 | GCC_DYNAMIC_NO_PIC = NO; 574 | GCC_NO_COMMON_BLOCKS = YES; 575 | GCC_OPTIMIZATION_LEVEL = 0; 576 | GCC_PREPROCESSOR_DEFINITIONS = ( 577 | "DEBUG=1", 578 | "$(inherited)", 579 | ); 580 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 581 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 582 | GCC_WARN_UNDECLARED_SELECTOR = YES; 583 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 584 | GCC_WARN_UNUSED_FUNCTION = YES; 585 | GCC_WARN_UNUSED_VARIABLE = YES; 586 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 587 | MTL_ENABLE_DEBUG_INFO = YES; 588 | ONLY_ACTIVE_ARCH = YES; 589 | SDKROOT = iphoneos; 590 | TARGETED_DEVICE_FAMILY = "1,2"; 591 | }; 592 | name = Debug; 593 | }; 594 | 97C147041CF9000F007C117D /* Release */ = { 595 | isa = XCBuildConfiguration; 596 | buildSettings = { 597 | ALWAYS_SEARCH_USER_PATHS = NO; 598 | CLANG_ANALYZER_NONNULL = YES; 599 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 600 | CLANG_CXX_LIBRARY = "libc++"; 601 | CLANG_ENABLE_MODULES = YES; 602 | CLANG_ENABLE_OBJC_ARC = YES; 603 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 604 | CLANG_WARN_BOOL_CONVERSION = YES; 605 | CLANG_WARN_COMMA = YES; 606 | CLANG_WARN_CONSTANT_CONVERSION = YES; 607 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 608 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 609 | CLANG_WARN_EMPTY_BODY = YES; 610 | CLANG_WARN_ENUM_CONVERSION = YES; 611 | CLANG_WARN_INFINITE_RECURSION = YES; 612 | CLANG_WARN_INT_CONVERSION = YES; 613 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 614 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 615 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 616 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 617 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 618 | CLANG_WARN_STRICT_PROTOTYPES = YES; 619 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 620 | CLANG_WARN_UNREACHABLE_CODE = YES; 621 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 622 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 623 | COPY_PHASE_STRIP = NO; 624 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 625 | ENABLE_NS_ASSERTIONS = NO; 626 | ENABLE_STRICT_OBJC_MSGSEND = YES; 627 | GCC_C_LANGUAGE_STANDARD = gnu99; 628 | GCC_NO_COMMON_BLOCKS = YES; 629 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 630 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 631 | GCC_WARN_UNDECLARED_SELECTOR = YES; 632 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 633 | GCC_WARN_UNUSED_FUNCTION = YES; 634 | GCC_WARN_UNUSED_VARIABLE = YES; 635 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 636 | MTL_ENABLE_DEBUG_INFO = NO; 637 | SDKROOT = iphoneos; 638 | SUPPORTED_PLATFORMS = iphoneos; 639 | SWIFT_COMPILATION_MODE = wholemodule; 640 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 641 | TARGETED_DEVICE_FAMILY = "1,2"; 642 | VALIDATE_PRODUCT = YES; 643 | }; 644 | name = Release; 645 | }; 646 | 97C147061CF9000F007C117D /* Debug */ = { 647 | isa = XCBuildConfiguration; 648 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 649 | buildSettings = { 650 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 651 | CLANG_ENABLE_MODULES = YES; 652 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 653 | DEVELOPMENT_TEAM = GU33PWYX8W; 654 | ENABLE_BITCODE = NO; 655 | INFOPLIST_FILE = Runner/Info.plist; 656 | LD_RUNPATH_SEARCH_PATHS = ( 657 | "$(inherited)", 658 | "@executable_path/Frameworks", 659 | ); 660 | PRODUCT_BUNDLE_IDENTIFIER = com.spring98.yoloRealtimePluginExample; 661 | PRODUCT_NAME = "$(TARGET_NAME)"; 662 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 663 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 664 | SWIFT_VERSION = 5.0; 665 | VERSIONING_SYSTEM = "apple-generic"; 666 | }; 667 | name = Debug; 668 | }; 669 | 97C147071CF9000F007C117D /* Release */ = { 670 | isa = XCBuildConfiguration; 671 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 672 | buildSettings = { 673 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 674 | CLANG_ENABLE_MODULES = YES; 675 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 676 | DEVELOPMENT_TEAM = GU33PWYX8W; 677 | ENABLE_BITCODE = NO; 678 | INFOPLIST_FILE = Runner/Info.plist; 679 | LD_RUNPATH_SEARCH_PATHS = ( 680 | "$(inherited)", 681 | "@executable_path/Frameworks", 682 | ); 683 | PRODUCT_BUNDLE_IDENTIFIER = com.spring98.yoloRealtimePluginExample; 684 | PRODUCT_NAME = "$(TARGET_NAME)"; 685 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 686 | SWIFT_VERSION = 5.0; 687 | VERSIONING_SYSTEM = "apple-generic"; 688 | }; 689 | name = Release; 690 | }; 691 | /* End XCBuildConfiguration section */ 692 | 693 | /* Begin XCConfigurationList section */ 694 | 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { 695 | isa = XCConfigurationList; 696 | buildConfigurations = ( 697 | 331C8088294A63A400263BE5 /* Debug */, 698 | 331C8089294A63A400263BE5 /* Release */, 699 | 331C808A294A63A400263BE5 /* Profile */, 700 | ); 701 | defaultConfigurationIsVisible = 0; 702 | defaultConfigurationName = Release; 703 | }; 704 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 705 | isa = XCConfigurationList; 706 | buildConfigurations = ( 707 | 97C147031CF9000F007C117D /* Debug */, 708 | 97C147041CF9000F007C117D /* Release */, 709 | 249021D3217E4FDB00AE95B9 /* Profile */, 710 | ); 711 | defaultConfigurationIsVisible = 0; 712 | defaultConfigurationName = Release; 713 | }; 714 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 715 | isa = XCConfigurationList; 716 | buildConfigurations = ( 717 | 97C147061CF9000F007C117D /* Debug */, 718 | 97C147071CF9000F007C117D /* Release */, 719 | 249021D4217E4FDB00AE95B9 /* Profile */, 720 | ); 721 | defaultConfigurationIsVisible = 0; 722 | defaultConfigurationName = Release; 723 | }; 724 | /* End XCConfigurationList section */ 725 | }; 726 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 727 | } 728 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/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. -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Yolo Realtime Plugin 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | yolo_realtime_plugin_example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | CADisableMinimumFrameDurationOnPhone 47 | 48 | UIApplicationSupportsIndirectInputEvents 49 | 50 | 51 | NSCameraUsageDescription 52 | We need access to your camera to take photos. 53 | 54 | NSMicrophoneUsageDescription 55 | We need access to your microphone to record audio. 56 | 57 | 58 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/ios/Runner/yolov5s.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/example/ios/Runner/yolov5s.mlmodel -------------------------------------------------------------------------------- /example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | @testable import yolo_realtime_plugin 6 | 7 | // This demonstrates a simple unit test of the Swift portion of this plugin's implementation. 8 | // 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | 11 | class RunnerTests: XCTestCase { 12 | 13 | func testGetPlatformVersion() { 14 | let plugin = YoloRealtimePlugin() 15 | 16 | let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) 17 | 18 | let resultExpectation = expectation(description: "result block must be called.") 19 | plugin.handle(call) { result in 20 | XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion) 21 | resultExpectation.fulfill() 22 | } 23 | waitForExpectations(timeout: 1) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: prefer_const_constructors 2 | 3 | import 'package:yolo_realtime_plugin/yolo_realtime_plugin.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'dart:async'; 6 | 7 | void main() { 8 | runApp( 9 | MaterialApp( 10 | home: const MyApp(), 11 | ), 12 | ); 13 | } 14 | 15 | class MyApp extends StatefulWidget { 16 | const MyApp({super.key}); 17 | 18 | @override 19 | State createState() => _MyAppState(); 20 | } 21 | 22 | class _MyAppState extends State { 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | body: Center( 27 | child: Column( 28 | mainAxisAlignment: MainAxisAlignment.center, 29 | children: [ 30 | ElevatedButton( 31 | onPressed: () { 32 | Navigator.push( 33 | context, 34 | MaterialPageRoute( 35 | builder: (context) => YoloRealTimeViewExample(), 36 | ), 37 | ); 38 | }, 39 | child: Text('START YOLO'), 40 | ) 41 | ], 42 | ), 43 | ), 44 | ); 45 | } 46 | } 47 | 48 | class YoloRealTimeViewExample extends StatefulWidget { 49 | const YoloRealTimeViewExample({Key? key}) : super(key: key); 50 | 51 | @override 52 | State createState() => 53 | _YoloRealTimeViewExampleState(); 54 | } 55 | 56 | class _YoloRealTimeViewExampleState extends State { 57 | YoloRealtimeController? yoloController; 58 | 59 | @override 60 | void initState() { 61 | super.initState(); 62 | 63 | yoloInit(); 64 | } 65 | 66 | Future yoloInit() async { 67 | yoloController = YoloRealtimeController( 68 | // common 69 | fullClasses: fullClasses, 70 | activeClasses: activeClasses, 71 | 72 | // android 73 | androidModelPath: 'assets/models/yolov5s_320.pt', 74 | androidModelWidth: 320, 75 | androidModelHeight: 320, 76 | androidConfThreshold: 0.5, 77 | androidIouThreshold: 0.5, 78 | 79 | // ios 80 | iOSModelPath: 'yolov5s', 81 | iOSConfThreshold: 0.5, 82 | ); 83 | 84 | try { 85 | await yoloController?.initialize(); 86 | } catch (e) { 87 | print('ERROR: $e'); 88 | } 89 | } 90 | 91 | @override 92 | Widget build(BuildContext context) { 93 | if (yoloController == null) { 94 | return Container(); 95 | } 96 | 97 | return YoloRealTimeView( 98 | width: MediaQuery.of(context).size.width, 99 | height: MediaQuery.of(context).size.height, 100 | controller: yoloController!, 101 | drawBox: true, 102 | captureBox: (boxes) { 103 | // print(boxes); 104 | }, 105 | captureImage: (data) async { 106 | // print('binary image: $data'); 107 | 108 | /// Process and use the binary image as you wish. 109 | // imageToFile(data); 110 | }, 111 | ); 112 | } 113 | 114 | // Future imageToFile(Uint8List? image) async { 115 | // File? file; 116 | // if (image != null) { 117 | // final tempDir = await getTemporaryDirectory(); 118 | // file = await File('${tempDir.path}/${DateTime.now()}.png').create(); 119 | // file.writeAsBytesSync(image); 120 | // 121 | // print('File saved: ${file.path}'); 122 | // } 123 | // return file; 124 | // } 125 | 126 | List activeClasses = [ 127 | "car", 128 | "person", 129 | "tv", 130 | "laptop", 131 | "mouse", 132 | "bottle", 133 | "cup", 134 | "keyboard", 135 | "cell phone", 136 | ]; 137 | 138 | List fullClasses = [ 139 | "person", 140 | "bicycle", 141 | "car", 142 | "motorcycle", 143 | "airplane", 144 | "bus", 145 | "train", 146 | "truck", 147 | "boat", 148 | "traffic light", 149 | "fire hydrant", 150 | "stop sign", 151 | "parking meter", 152 | "bench", 153 | "bird", 154 | "cat", 155 | "dog", 156 | "horse", 157 | "sheep", 158 | "cow", 159 | "elephant", 160 | "bear", 161 | "zebra", 162 | "giraffe", 163 | "backpack", 164 | "umbrella", 165 | "handbag", 166 | "tie", 167 | "suitcase", 168 | "frisbee", 169 | "skis", 170 | "snowboard", 171 | "sports ball", 172 | "kite", 173 | "baseball bat", 174 | "baseball glove", 175 | "skateboard", 176 | "surfboard", 177 | "tennis racket", 178 | "bottle", 179 | "wine glass", 180 | "cup", 181 | "fork", 182 | "knife", 183 | "spoon", 184 | "bowl", 185 | "banana", 186 | "apple", 187 | "sandwich", 188 | "orange", 189 | "broccoli", 190 | "carrot", 191 | "hot dog", 192 | "pizza", 193 | "donut", 194 | "cake", 195 | "chair", 196 | "couch", 197 | "potted plant", 198 | "bed", 199 | "dining table", 200 | "toilet", 201 | "tv", 202 | "laptop", 203 | "mouse", 204 | "remote", 205 | "keyboard", 206 | "cell phone", 207 | "microwave", 208 | "oven", 209 | "toaster", 210 | "sink", 211 | "refrigerator", 212 | "book", 213 | "clock", 214 | "vase", 215 | "scissors", 216 | "teddy bear", 217 | "hair drier", 218 | "toothbrush" 219 | ]; 220 | } 221 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.17.1" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.6" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | file: 61 | dependency: transitive 62 | description: 63 | name: file 64 | sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "6.1.4" 68 | flutter: 69 | dependency: "direct main" 70 | description: flutter 71 | source: sdk 72 | version: "0.0.0" 73 | flutter_driver: 74 | dependency: transitive 75 | description: flutter 76 | source: sdk 77 | version: "0.0.0" 78 | flutter_lints: 79 | dependency: "direct dev" 80 | description: 81 | name: flutter_lints 82 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "2.0.3" 86 | flutter_test: 87 | dependency: "direct dev" 88 | description: flutter 89 | source: sdk 90 | version: "0.0.0" 91 | fuchsia_remote_debug_protocol: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.0" 96 | integration_test: 97 | dependency: "direct dev" 98 | description: flutter 99 | source: sdk 100 | version: "0.0.0" 101 | js: 102 | dependency: transitive 103 | description: 104 | name: js 105 | sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 106 | url: "https://pub.dev" 107 | source: hosted 108 | version: "0.6.7" 109 | lints: 110 | dependency: transitive 111 | description: 112 | name: lints 113 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" 114 | url: "https://pub.dev" 115 | source: hosted 116 | version: "2.1.1" 117 | matcher: 118 | dependency: transitive 119 | description: 120 | name: matcher 121 | sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" 122 | url: "https://pub.dev" 123 | source: hosted 124 | version: "0.12.15" 125 | material_color_utilities: 126 | dependency: transitive 127 | description: 128 | name: material_color_utilities 129 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 130 | url: "https://pub.dev" 131 | source: hosted 132 | version: "0.2.0" 133 | meta: 134 | dependency: transitive 135 | description: 136 | name: meta 137 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 138 | url: "https://pub.dev" 139 | source: hosted 140 | version: "1.9.1" 141 | path: 142 | dependency: transitive 143 | description: 144 | name: path 145 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 146 | url: "https://pub.dev" 147 | source: hosted 148 | version: "1.8.3" 149 | platform: 150 | dependency: transitive 151 | description: 152 | name: platform 153 | sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" 154 | url: "https://pub.dev" 155 | source: hosted 156 | version: "3.1.0" 157 | plugin_platform_interface: 158 | dependency: transitive 159 | description: 160 | name: plugin_platform_interface 161 | sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d 162 | url: "https://pub.dev" 163 | source: hosted 164 | version: "2.1.6" 165 | process: 166 | dependency: transitive 167 | description: 168 | name: process 169 | sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" 170 | url: "https://pub.dev" 171 | source: hosted 172 | version: "4.2.4" 173 | sky_engine: 174 | dependency: transitive 175 | description: flutter 176 | source: sdk 177 | version: "0.0.99" 178 | source_span: 179 | dependency: transitive 180 | description: 181 | name: source_span 182 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 183 | url: "https://pub.dev" 184 | source: hosted 185 | version: "1.9.1" 186 | stack_trace: 187 | dependency: transitive 188 | description: 189 | name: stack_trace 190 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 191 | url: "https://pub.dev" 192 | source: hosted 193 | version: "1.11.0" 194 | stream_channel: 195 | dependency: transitive 196 | description: 197 | name: stream_channel 198 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 199 | url: "https://pub.dev" 200 | source: hosted 201 | version: "2.1.1" 202 | string_scanner: 203 | dependency: transitive 204 | description: 205 | name: string_scanner 206 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 207 | url: "https://pub.dev" 208 | source: hosted 209 | version: "1.2.0" 210 | sync_http: 211 | dependency: transitive 212 | description: 213 | name: sync_http 214 | sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" 215 | url: "https://pub.dev" 216 | source: hosted 217 | version: "0.3.1" 218 | term_glyph: 219 | dependency: transitive 220 | description: 221 | name: term_glyph 222 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 223 | url: "https://pub.dev" 224 | source: hosted 225 | version: "1.2.1" 226 | test_api: 227 | dependency: transitive 228 | description: 229 | name: test_api 230 | sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb 231 | url: "https://pub.dev" 232 | source: hosted 233 | version: "0.5.1" 234 | vector_math: 235 | dependency: transitive 236 | description: 237 | name: vector_math 238 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 239 | url: "https://pub.dev" 240 | source: hosted 241 | version: "2.1.4" 242 | vm_service: 243 | dependency: transitive 244 | description: 245 | name: vm_service 246 | sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe 247 | url: "https://pub.dev" 248 | source: hosted 249 | version: "11.3.0" 250 | webdriver: 251 | dependency: transitive 252 | description: 253 | name: webdriver 254 | sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" 255 | url: "https://pub.dev" 256 | source: hosted 257 | version: "3.0.2" 258 | yolo_realtime_plugin: 259 | dependency: "direct main" 260 | description: 261 | path: ".." 262 | relative: true 263 | source: path 264 | version: "0.0.1" 265 | sdks: 266 | dart: ">=3.0.0 <4.0.0" 267 | flutter: ">=3.3.0" 268 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: yolo_realtime_plugin_example 2 | description: Demonstrates how to use the yolo_realtime_plugin plugin. 3 | # The following line prevents the package from being accidentally published to 4 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 5 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 6 | 7 | environment: 8 | sdk: '>=3.0.0 <4.0.0' 9 | 10 | # Dependencies specify other packages that your package needs in order to work. 11 | # To automatically upgrade your package dependencies to the latest versions 12 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 13 | # dependencies can be manually updated by changing the version numbers below to 14 | # the latest version available on pub.dev. To see which dependencies have newer 15 | # versions available, run `flutter pub outdated`. 16 | dependencies: 17 | flutter: 18 | sdk: flutter 19 | 20 | yolo_realtime_plugin: 21 | # When depending on this package from a real application you should use: 22 | # yolo_realtime_plugin: ^x.y.z 23 | # See https://dart.dev/tools/pub/dependencies#version-constraints 24 | # The example app is bundled with the plugin so we use a path dependency on 25 | # the parent directory to use the current plugin's version. 26 | path: ../ 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.2 31 | 32 | 33 | dev_dependencies: 34 | integration_test: 35 | sdk: flutter 36 | flutter_test: 37 | sdk: flutter 38 | 39 | # The "flutter_lints" package below contains a set of recommended lints to 40 | # encourage good coding practices. The lint set provided by the package is 41 | # activated in the `analysis_options.yaml` file located at the root of your 42 | # package. See that file for information about deactivating specific lint 43 | # rules and activating additional ones. 44 | flutter_lints: ^2.0.0 45 | 46 | # For information on the generic Dart part of this file, see the 47 | # following page: https://dart.dev/tools/pub/pubspec 48 | 49 | # The following section is specific to Flutter packages. 50 | flutter: 51 | 52 | # The following line ensures that the Material Icons font is 53 | # included with your application, so that you can use the icons in 54 | # the material Icons class. 55 | uses-material-design: true 56 | 57 | # To add assets to your application, add an assets section, like this: 58 | assets: 59 | - assets/models/yolov5s_320.pt 60 | # - images/a_dot_ham.jpeg 61 | 62 | # An image asset can refer to one or more resolution-specific "variants", see 63 | # https://flutter.dev/assets-and-images/#resolution-aware 64 | 65 | # For details regarding adding assets from package dependencies, see 66 | # https://flutter.dev/assets-and-images/#from-packages 67 | 68 | # To add custom fonts to your application, add a fonts section here, 69 | # in this "flutter" section. Each entry in this list should have a 70 | # "family" key with the font family name, and a "fonts" key with a 71 | # list giving the asset and other descriptors for the font. For 72 | # example: 73 | # fonts: 74 | # - family: Schyler 75 | # fonts: 76 | # - asset: fonts/Schyler-Regular.ttf 77 | # - asset: fonts/Schyler-Italic.ttf 78 | # style: italic 79 | # - family: Trajan Pro 80 | # fonts: 81 | # - asset: fonts/TrajanPro.ttf 82 | # - asset: fonts/TrajanPro_Bold.ttf 83 | # weight: 700 84 | # 85 | # For details regarding fonts from package dependencies, 86 | # see https://flutter.dev/custom-fonts/#from-packages 87 | -------------------------------------------------------------------------------- /example/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 in the flutter_test package. 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:yolo_realtime_plugin_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => widget is Text && 22 | widget.data!.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/YoloRealtimePlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import Foundation 4 | import AVFoundation 5 | import CoreML 6 | import Vision 7 | import CoreImage 8 | import VideoToolbox 9 | 10 | @available(iOS 12.0, *) 11 | public class YoloRealtimePlugin: NSObject, FlutterPlugin { 12 | public static func register(with registrar: FlutterPluginRegistrar) { 13 | let channel = FlutterMethodChannel(name: "yolo_realtime_plugin", binaryMessenger: registrar.messenger()) 14 | let instance = YoloRealtimePlugin() 15 | 16 | let factory = CameraViewFactory(channel: channel) 17 | registrar.register(factory, withId: "camera_view") 18 | registrar.addMethodCallDelegate(instance, channel: channel) 19 | } 20 | 21 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 22 | switch call.method { 23 | case "initializeController": 24 | guard let arguments = call.arguments as? [String: Any], 25 | let modelPath = arguments["modelPath"] as? String, 26 | let activeClassList = arguments["activeClasses"] as? [String], 27 | let confThreshold = arguments["confThreshold"] as? Double else { return } 28 | 29 | guard let modelURL = Bundle.main.url(forResource: modelPath, withExtension: "mlmodelc"), 30 | let model = try? MLModel(contentsOf: modelURL) else { return } 31 | 32 | // 성공적으로 모델과 다른 파라미터를 로딩한 경우, 설정에 반영 33 | Constants.MODEL = model 34 | Constants.CONFIDENCE_THRESHOLD = Float(confThreshold) 35 | Constants.ACTIVE_CLASS_LABELS = activeClassList 36 | 37 | default: 38 | result(FlutterMethodNotImplemented) 39 | } 40 | } 41 | } 42 | 43 | 44 | @available(iOS 12.0, *) 45 | class CameraViewFactory: NSObject, FlutterPlatformViewFactory { 46 | private var channel: FlutterMethodChannel? 47 | 48 | init(channel: FlutterMethodChannel?) { 49 | self.channel = channel 50 | } 51 | 52 | // 자동으로 호출 53 | func create( 54 | withFrame frame: CGRect, 55 | viewIdentifier viewId: Int64, 56 | arguments args: Any? 57 | ) -> FlutterPlatformView { 58 | return CameraViewContainer(frame: frame, viewId: viewId, channel: channel) 59 | } 60 | } 61 | 62 | @available(iOS 12.0, *) 63 | class CameraViewContainer: NSObject, FlutterPlatformView { 64 | private let frame: CGRect 65 | private let viewId: Int64 66 | private let cameraView: CameraView 67 | 68 | init(frame: CGRect, viewId: Int64, channel: FlutterMethodChannel?) { 69 | self.frame = frame 70 | self.viewId = viewId 71 | self.cameraView = CameraView(frame: frame, channel: channel) 72 | super.init() 73 | } 74 | 75 | // 자동으로 호출 76 | func view() -> UIView { 77 | return cameraView 78 | } 79 | } 80 | 81 | @available(iOS 12.0, *) 82 | class CameraView: UIView { 83 | private var captureSession: AVCaptureSession? 84 | private var videoPreviewLayer: AVCaptureVideoPreviewLayer? 85 | private var channel: FlutterMethodChannel? 86 | 87 | init(frame: CGRect, channel: FlutterMethodChannel?) { 88 | super.init(frame: frame) 89 | self.channel = channel 90 | startCamera() 91 | } 92 | 93 | required init?(coder: NSCoder) { 94 | super.init(coder: coder) 95 | } 96 | 97 | override func layoutSubviews() { 98 | super.layoutSubviews() 99 | videoPreviewLayer?.frame = self.bounds 100 | } 101 | 102 | // Stop camera session when view is removed 103 | override func removeFromSuperview() { 104 | super.removeFromSuperview() 105 | captureSession?.stopRunning() 106 | videoPreviewLayer?.removeFromSuperlayer() 107 | } 108 | 109 | func startCamera() { 110 | // Create a session 111 | captureSession = AVCaptureSession() 112 | captureSession?.sessionPreset = .hd1920x1080 113 | 114 | // Get video capture device 115 | guard let videoDevice = AVCaptureDevice.default(for: .video) else { 116 | print("Failed to get video device") 117 | return 118 | } 119 | 120 | // Create input 121 | var videoInput: AVCaptureDeviceInput! 122 | do { 123 | videoInput = try AVCaptureDeviceInput(device: videoDevice) 124 | } catch { 125 | print("Failed to create video input: \(error)") 126 | return 127 | } 128 | 129 | // Add input to session 130 | if (captureSession?.canAddInput(videoInput) == true) { 131 | captureSession?.addInput(videoInput) 132 | } else { 133 | print("Failed to add video input to session") 134 | return 135 | } 136 | 137 | // Create video data output 138 | let videoOutput = AVCaptureVideoDataOutput() 139 | videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue")) 140 | 141 | // Add output to session 142 | if (captureSession?.canAddOutput(videoOutput) == true) { 143 | captureSession?.addOutput(videoOutput) 144 | } else { 145 | print("Failed to add video output to session") 146 | return 147 | } 148 | 149 | // Create preview layer 150 | videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!) 151 | videoPreviewLayer?.videoGravity = .resizeAspectFill 152 | videoPreviewLayer?.frame = self.layer.bounds 153 | 154 | // Add preview layer to view 155 | self.layer.addSublayer(videoPreviewLayer!) 156 | 157 | // 카메라 세션 시작 158 | captureSession?.startRunning() 159 | } 160 | } 161 | 162 | @available(iOS 12.0, *) 163 | extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate { 164 | func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 165 | guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { 166 | print("Failed to convert CMSampleBuffer to CVPixelBuffer") 167 | return 168 | } 169 | 170 | detect(image: pixelBuffer) 171 | } 172 | } 173 | 174 | // MARK: - CoreML 이미지 분류 175 | @available(iOS 12.0, *) 176 | extension CameraView { 177 | // CoreML의 CVPixelBuffer (이미지 주소)에 접근해 모델에 통과시킨다. 178 | func detect(image: CVPixelBuffer) { 179 | // Vision 프레임워크인 VNCoreMLModel 컨터이너를 사용하여 CoreML의 model에 접근한다. 180 | guard let mlModel = Constants.MODEL else { return } 181 | guard let visionModel = try? VNCoreMLModel(for: mlModel) else { return } 182 | 183 | // 이미치 처리를 요청 184 | let request = VNCoreMLRequest(model: visionModel) { [self] request, error in 185 | guard error == nil else { 186 | fatalError("Failed Request") 187 | } 188 | 189 | guard let observations = request.results as? [VNRecognizedObjectObservation] else { 190 | fatalError("Faild convert VNClassificationObservation") 191 | } 192 | 193 | parseObservations(observations, pixelBuffer: image) 194 | } 195 | 196 | // 이미지를 받아와서 perform을 요청하여 분석한다. 197 | let handler = VNImageRequestHandler(cvPixelBuffer: image) 198 | do { 199 | try handler.perform([request]) 200 | } catch { 201 | print(error) 202 | } 203 | } 204 | 205 | func parseObservations(_ observations: [VNRecognizedObjectObservation], pixelBuffer: CVPixelBuffer) { 206 | var outerMap: [String: [String: Any]] = [:] // 외부 맵 생성 207 | var image: Data? 208 | 209 | if(!observations.isEmpty) { 210 | image = pixelBufferToData(pixelBuffer: pixelBuffer) 211 | } 212 | 213 | for (index, observation) in observations.enumerated() { 214 | // CONFIDENCE_THRESHOLD와 ACTIVE_CLASS_LABELS 확인 215 | if observation.confidence > Constants.CONFIDENCE_THRESHOLD, 216 | let label = observation.labels.first?.identifier, 217 | Constants.ACTIVE_CLASS_LABELS.contains(label) { 218 | 219 | guard let image = image else {return} 220 | // bounding box 좌표를 얻습니다. 221 | let boundingBox = observation.boundingBox 222 | 223 | // 내부 맵을 생성합니다. 224 | let innerMap: [String: Any] = [ 225 | "x": boundingBox.origin.x, 226 | "y": boundingBox.origin.y, 227 | "width": boundingBox.size.width, 228 | "height": boundingBox.size.height, 229 | "label": observation.labels.first?.identifier ?? "Unknown", 230 | "confidence": observation.confidence, 231 | "image": image 232 | ] 233 | 234 | // 내부 맵을 외부 맵에 추가합니다. 235 | outerMap["box\(index)"] = innerMap 236 | } 237 | } 238 | 239 | // 외부 맵을 Flutter로 전송합니다. 240 | channel?.invokeMethod("boxes", arguments: outerMap) 241 | } 242 | 243 | func pixelBufferToData(pixelBuffer: CVPixelBuffer) -> Data? { 244 | CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags.readOnly) 245 | defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags.readOnly) } 246 | 247 | guard let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer) else { 248 | return nil 249 | } 250 | 251 | let size = CVPixelBufferGetDataSize(pixelBuffer) 252 | return Data(bytes: baseAddress, count: size) 253 | } 254 | 255 | } 256 | 257 | class Constants { 258 | // 모델 259 | static var MODEL: MLModel? = nil 260 | 261 | // 신뢰도 임계값 262 | static var CONFIDENCE_THRESHOLD: Float = 0.5 263 | 264 | // 내가 사용한 모델의 전체 클래스 리스트 중 실제로 사용할 클래스 리스트 265 | static var ACTIVE_CLASS_LABELS: [String] = [] 266 | 267 | } 268 | -------------------------------------------------------------------------------- /ios/yolo_realtime_plugin.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint yolo_realtime_plugin.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'yolo_realtime_plugin' 7 | s.version = '0.0.1' 8 | s.summary = 'A new Flutter plugin project.' 9 | s.description = <<-DESC 10 | A new Flutter plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '11.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /lib/src/method_channel/method_channel_yolo_realtime.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:yolo_realtime_plugin/yolo_realtime_plugin.dart'; 4 | 5 | /// An implementation of [YoloRealtimePlatform] that uses method channels. 6 | class MethodChannelYoloRealtime extends YoloRealtimePlatformInterface { 7 | final methodChannel = const MethodChannel('yolo_realtime_plugin'); 8 | final StreamController> _boxesController = 9 | StreamController.broadcast(); 10 | 11 | @override 12 | Future initializeController(Map args) async { 13 | await methodChannel.invokeMethod('initializeController', args); 14 | } 15 | 16 | @override 17 | Stream> watchBoxes() { 18 | methodChannel.setMethodCallHandler(pluginHandler); 19 | return _boxesController.stream; 20 | } 21 | 22 | Future pluginHandler(MethodCall call) async { 23 | switch (call.method) { 24 | case 'boxes': 25 | boxesHandler(call); 26 | break; 27 | default: 28 | throw ('Not implemented: ${call.method}'); 29 | } 30 | } 31 | 32 | // _handleOnDiscovered 33 | void boxesHandler(MethodCall call) async { 34 | List boxes = []; 35 | final Map outerMap = call.arguments; // arguments를 맵으로 변환 36 | 37 | if (outerMap.keys.isNotEmpty) { 38 | for (var key in outerMap.keys) { 39 | final Map boundingBox = outerMap[key]; // 각 키에 대해 내부 맵을 가져옵니다. 40 | final double x = boundingBox['x']; 41 | final double y = boundingBox['y']; 42 | final double width = boundingBox['width']; 43 | final double height = boundingBox['height']; 44 | final String label = boundingBox['label']; 45 | final double confidence = boundingBox['confidence']; 46 | final Uint8List image = boundingBox['image']; 47 | 48 | boxes.add( 49 | BoxModel( 50 | rect: Rect.fromLTWH(x, y, width, height), 51 | label: label, 52 | confidence: confidence, 53 | image: image, 54 | ), 55 | ); 56 | } 57 | } 58 | 59 | _boxesController.add(boxes); // 스트림에 박스 목록 추가 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/platform_interface/yolo_realtime_platform_interface.dart: -------------------------------------------------------------------------------- 1 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 2 | import 'package:yolo_realtime_plugin/yolo_realtime_plugin.dart'; 3 | 4 | abstract class YoloRealtimePlatformInterface extends PlatformInterface { 5 | /// Constructs a YoloRealtimePluginPlatform. 6 | YoloRealtimePlatformInterface() : super(token: _token); 7 | 8 | static final Object _token = Object(); 9 | 10 | static YoloRealtimePlatformInterface _instance = MethodChannelYoloRealtime(); 11 | 12 | /// The default instance of [YoloRealtimePlatformInterface] to use. 13 | /// 14 | /// Defaults to [MethodChannelYoloRealtimePlugin]. 15 | static YoloRealtimePlatformInterface get instance => _instance; 16 | 17 | /// Platform-specific implementations should set this with their own 18 | /// platform-specific class that extends [YoloRealtimePlatformInterface] when 19 | /// they register themselves. 20 | static set instance(YoloRealtimePlatformInterface instance) { 21 | PlatformInterface.verifyToken(instance, _token); 22 | _instance = instance; 23 | } 24 | 25 | Stream> watchBoxes() { 26 | throw UnimplementedError('watchBoxes() is not implemented.'); 27 | } 28 | 29 | Future initializeController(Map args) { 30 | throw UnimplementedError('initializeController() is not implemented.'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/utils/model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'dart:ui'; 3 | 4 | class BoxModel { 5 | final Rect rect; 6 | final String label; 7 | final double confidence; 8 | final Uint8List image; 9 | 10 | BoxModel({ 11 | required this.rect, 12 | required this.label, 13 | required this.confidence, 14 | required this.image, 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/widget/box_painter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math'; 3 | import 'package:yolo_realtime_plugin/yolo_realtime_plugin.dart'; 4 | 5 | class YoloBoxPainter extends CustomPainter { 6 | final List boxes; 7 | final List colors; 8 | 9 | YoloBoxPainter({ 10 | required this.boxes, 11 | required this.colors, 12 | }); 13 | 14 | @override 15 | void paint(Canvas canvas, Size size) { 16 | final TextPainter textPainter = TextPainter( 17 | textDirection: TextDirection.ltr, 18 | ); 19 | 20 | for (int i = 0; i < boxes.length; i++) { 21 | final BoxModel box = boxes[i]; 22 | final Paint paint = Paint() 23 | ..color = colors[i % colors.length] 24 | ..style = PaintingStyle.stroke 25 | ..strokeWidth = 3; 26 | 27 | canvas.drawRect(box.rect, paint); 28 | 29 | textPainter.text = TextSpan( 30 | text: '${box.label}(${box.confidence.toStringAsFixed(2)})', 31 | style: TextStyle( 32 | color: colors[i % colors.length], 33 | fontSize: 16, 34 | fontWeight: FontWeight.w500), 35 | ); 36 | textPainter.layout(); 37 | 38 | // Save the canvas state 39 | canvas.save(); 40 | 41 | // Rotate the canvas 42 | canvas.translate(box.rect.left, box.rect.top); 43 | canvas.rotate(pi / 2); 44 | 45 | // Draw the text 46 | textPainter.paint(canvas, const Offset(0, 0)); 47 | 48 | // Restore the canvas state 49 | canvas.restore(); 50 | } 51 | } 52 | 53 | @override 54 | bool shouldRepaint(CustomPainter oldDelegate) { 55 | return true; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/widget/yolo_realtime_view.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:yolo_realtime_plugin/yolo_realtime_plugin.dart'; 5 | import 'package:yolo_realtime_plugin/src/widget/box_painter.dart'; 6 | 7 | class YoloRealTimeView extends StatefulWidget { 8 | final YoloRealtimeController controller; 9 | final double width; 10 | final double height; 11 | final bool drawBox; 12 | final List colors; 13 | final void Function(Uint8List)? captureImage; 14 | final void Function(List)? captureBox; 15 | 16 | const YoloRealTimeView({ 17 | Key? key, 18 | required this.controller, 19 | required this.width, 20 | required this.height, 21 | this.drawBox = true, 22 | this.captureImage, 23 | this.captureBox, 24 | List? boxColors, 25 | }) : colors = boxColors ?? 26 | const [ 27 | Color(0xFFF26D6F), 28 | Color(0xFFF2835D), 29 | Color(0xFFDE3E47), 30 | Colors.blue, 31 | Color(0xFF7AB974), 32 | Color(0xFFFFC16E), 33 | ], 34 | super(key: key); 35 | 36 | @override 37 | State createState() => _YoloRealTimeViewState(); 38 | } 39 | 40 | class _YoloRealTimeViewState extends State { 41 | final key = GlobalKey(); 42 | List boxes = []; 43 | 44 | @override 45 | void initState() { 46 | super.initState(); 47 | init(); 48 | } 49 | 50 | // var start = DateTime.now().millisecond; 51 | Future init() async { 52 | try { 53 | Stream> boxStream = await widget.controller.watchBoxes(); 54 | boxStream.listen((event) async { 55 | // var end = DateTime.now().millisecond; 56 | // print('🔥 time: ${end - start} ms, frame: ${1000 / (end - start)}'); 57 | // start = DateTime.now().millisecond; 58 | 59 | boxes = []; 60 | 61 | if (mounted) { 62 | setState(() { 63 | for (var box in event) { 64 | final double x = box.rect.left; 65 | final double y = box.rect.top; 66 | final double width = box.rect.width; 67 | final double height = box.rect.height; 68 | final String label = box.label; 69 | final double confidence = box.confidence; 70 | 71 | final double screenWidth = widget.width; 72 | final double screenHeight = widget.height; 73 | 74 | final double rectX = y * screenWidth; 75 | final double rectY = x * screenHeight; 76 | final double rectWidth = height * screenWidth; 77 | final double rectHeight = width * screenHeight; 78 | 79 | boxes.add( 80 | BoxModel( 81 | rect: Rect.fromLTWH(rectX, rectY, rectWidth, rectHeight), 82 | label: label, 83 | confidence: confidence, 84 | image: box.image, 85 | ), 86 | ); 87 | } 88 | 89 | // 감지된 이미지 전송 90 | if (widget.captureImage != null) { 91 | if (boxes.isNotEmpty) { 92 | widget.captureImage!(boxes.first.image); 93 | } 94 | } 95 | 96 | // 감지된 박스 리스트 전송 97 | if (widget.captureBox != null) { 98 | if (boxes.isNotEmpty) { 99 | widget.captureBox!(boxes); 100 | } 101 | } 102 | }); 103 | } 104 | }); 105 | } catch (e) { 106 | // 107 | } 108 | } 109 | 110 | @override 111 | Widget build(BuildContext context) { 112 | Widget nativeView = Container(); 113 | 114 | if (Platform.isAndroid) { 115 | nativeView = const AndroidView( 116 | viewType: 'camera_view', 117 | creationParamsCodec: StandardMessageCodec(), 118 | ); 119 | } else if (Platform.isIOS) { 120 | nativeView = const UiKitView( 121 | viewType: 'camera_view', 122 | creationParamsCodec: StandardMessageCodec(), 123 | ); 124 | } 125 | 126 | return Stack( 127 | children: [ 128 | SizedBox( 129 | width: widget.width, 130 | height: widget.height, 131 | child: nativeView, 132 | ), 133 | if (widget.drawBox) ...[ 134 | CustomPaint( 135 | painter: YoloBoxPainter( 136 | boxes: boxes, 137 | colors: widget.colors, 138 | ), 139 | ), 140 | ] 141 | ], 142 | ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /lib/src/yolo_realtime_controller.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names, slash_for_doc_comments 2 | 3 | import 'package:yolo_realtime_plugin/yolo_realtime_plugin.dart'; 4 | import 'dart:io'; 5 | 6 | enum YoloVersion { 7 | v5, 8 | } 9 | 10 | enum ModelInputSize { 11 | SIZE_320, 12 | SIZE_640, 13 | } 14 | 15 | class YoloRealtimeController { 16 | /// Android, iOS Common 17 | final YoloVersion version; 18 | final List fullClasses; 19 | final List activeClasses; 20 | 21 | /// Android Only 22 | final String? androidModelPath; 23 | final int? androidModelWidth; 24 | final int? androidModelHeight; 25 | final double androidConfThreshold; 26 | final double androidIouThreshold; 27 | 28 | /// iOS Only 29 | final String? iOSModelPath; 30 | final double iOSConfThreshold; 31 | 32 | /// The information you need to enter varies depending on the platform. 33 | /// 34 | /// Both platforms require 35 | /// version; 36 | /// fullClasses; 37 | /// activeClasses; 38 | /// 39 | /// 40 | /// On Android Platform, 41 | /// You must enter 42 | /// androidModelPath; 43 | /// androidModelWidth; 44 | /// androidModelHeight; 45 | /// androidConfThreshold; 46 | /// androidIouThreshold; 47 | /// 48 | /// 49 | /// On iOS Platform, 50 | /// You must enter 51 | /// iOSModelPath; 52 | /// iOSConfThreshold; 53 | 54 | YoloRealtimeController({ 55 | required this.fullClasses, 56 | required this.activeClasses, 57 | this.version = YoloVersion.v5, 58 | this.androidModelPath, 59 | this.androidModelWidth, 60 | this.androidModelHeight, 61 | this.androidConfThreshold = 0.5, 62 | this.androidIouThreshold = 0.5, 63 | this.iOSModelPath, 64 | this.iOSConfThreshold = 0.5, 65 | }); 66 | 67 | Future initialize() async { 68 | /// Android 69 | if (Platform.isAndroid) { 70 | if (androidModelPath == null || 71 | androidModelWidth == null || 72 | androidModelHeight == null) { 73 | throw AssertionError('You must enter the Android parameters.'); 74 | } 75 | 76 | final Map args = { 77 | 'modelPath': androidModelPath, 78 | 'fullClasses': fullClasses, 79 | 'activeClasses': activeClasses, 80 | 'version': version.toString(), 81 | 'modelWidth': androidModelWidth, 82 | 'modelHeight': androidModelHeight, 83 | 'confThreshold': androidConfThreshold, 84 | 'iouThreshold': androidIouThreshold, 85 | }; 86 | 87 | YoloRealtimePlatformInterface.instance.initializeController(args); 88 | } 89 | 90 | /// iOS 91 | if (Platform.isIOS) { 92 | if (iOSModelPath == null) { 93 | throw AssertionError('You must enter the iOS parameters.'); 94 | } 95 | 96 | final Map args = { 97 | 'modelPath': iOSModelPath, 98 | 'fullClasses': fullClasses, 99 | 'activeClasses': activeClasses, 100 | 'version': version.toString(), 101 | 'confThreshold': iOSConfThreshold, 102 | }; 103 | 104 | YoloRealtimePlatformInterface.instance.initializeController(args); 105 | } 106 | } 107 | 108 | Future>> watchBoxes() async { 109 | return YoloRealtimePlatformInterface.instance.watchBoxes(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /lib/src/yolo_realtime_preview.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring98/flutter-yolo-realtime-plugin/3487dc0336911f8a51f675a663818dfb788b867c/lib/src/yolo_realtime_preview.dart -------------------------------------------------------------------------------- /lib/yolo_realtime_plugin.dart: -------------------------------------------------------------------------------- 1 | export 'src/method_channel/method_channel_yolo_realtime.dart'; 2 | export 'src/platform_interface/yolo_realtime_platform_interface.dart'; 3 | export 'src/utils/model.dart'; 4 | export 'src/yolo_realtime_controller.dart'; 5 | export 'src/yolo_realtime_preview.dart'; 6 | export 'src/widget/yolo_realtime_view.dart'; 7 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: yolo_realtime_plugin 2 | description: This is a plugin that supports yolo realtime. 3 | version: 1.0.2 4 | homepage: https://github.com/spring98/flutter-yolo-realtime-plugin 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: ">=3.3.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | plugin_platform_interface: ^2.0.2 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | flutter_lints: ^2.0.0 19 | 20 | # For information on the generic Dart part of this file, see the 21 | # following page: https://dart.dev/tools/pub/pubspec 22 | 23 | # The following section is specific to Flutter packages. 24 | flutter: 25 | # This section identifies this Flutter project as a plugin project. 26 | # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) 27 | # which should be registered in the plugin registry. This is required for 28 | # using method channels. 29 | # The Android 'package' specifies package in which the registered class is. 30 | # This is required for using method channels on Android. 31 | # The 'ffiPlugin' specifies that native code should be built and bundled. 32 | # This is required for using `dart:ffi`. 33 | # All these are used by the tooling to maintain consistency when 34 | # adding or updating assets for this project. 35 | plugin: 36 | platforms: 37 | android: 38 | package: com.spring98.yolo_realtime_plugin 39 | pluginClass: YoloRealtimePlugin 40 | ios: 41 | pluginClass: YoloRealtimePlugin 42 | 43 | # To add assets to your plugin package, add an assets section, like this: 44 | # assets: 45 | # - images/a_dot_burr.jpeg 46 | # - images/a_dot_ham.jpeg 47 | # 48 | # For details regarding assets in packages, see 49 | # https://flutter.dev/assets-and-images/#from-packages 50 | # 51 | # An image asset can refer to one or more resolution-specific "variants", see 52 | # https://flutter.dev/assets-and-images/#resolution-aware 53 | 54 | # To add custom fonts to your plugin package, add a fonts section here, 55 | # in this "flutter" section. Each entry in this list should have a 56 | # "family" key with the font family name, and a "fonts" key with a 57 | # list giving the asset and other descriptors for the font. For 58 | # example: 59 | # fonts: 60 | # - family: Schyler 61 | # fonts: 62 | # - asset: fonts/Schyler-Regular.ttf 63 | # - asset: fonts/Schyler-Italic.ttf 64 | # style: italic 65 | # - family: Trajan Pro 66 | # fonts: 67 | # - asset: fonts/TrajanPro.ttf 68 | # - asset: fonts/TrajanPro_Bold.ttf 69 | # weight: 700 70 | # 71 | # For details regarding fonts in packages, see 72 | # https://flutter.dev/custom-fonts/#from-packages 73 | -------------------------------------------------------------------------------- /test/yolo_realtime_plugin_method_channel_test.dart: -------------------------------------------------------------------------------- 1 | void main() {} 2 | -------------------------------------------------------------------------------- /test/yolo_realtime_plugin_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 3 | import 'package:yolo_realtime_plugin/src/platform_interface/yolo_realtime_platform_interface.dart'; 4 | import 'package:yolo_realtime_plugin/src/utils/model.dart'; 5 | 6 | class MockYoloRealtimePluginPlatform 7 | with MockPlatformInterfaceMixin 8 | implements YoloRealtimePlatformInterface { 9 | @override 10 | Future initializeController(Map args) { 11 | // TODO: implement initializeController 12 | throw UnimplementedError(); 13 | } 14 | 15 | @override 16 | Stream> watchBoxes() { 17 | // TODO: implement watchBoxes 18 | throw UnimplementedError(); 19 | } 20 | } 21 | 22 | void main() {} 23 | --------------------------------------------------------------------------------