├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── gradle.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── yolov8_detect │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── fire_640_v8.onnx │ │ └── label_fire_v8.txt │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── yolov8_detect │ │ │ ├── MainActivity.java │ │ │ ├── PermissionSupport.java │ │ │ ├── RectView.java │ │ │ ├── Result.java │ │ │ └── SupportOnnx.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── example │ └── yolov8_detect │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yolov8_Android 2 | 3 | ## Yolo V8 nano 화재 검출 모델입니다. 4 | 5 | ------------ 6 | 7 | #### 학습은 Yolo V8 공식사이트(https://github.com/ultralytics/ultralytics) 를 사용했습니다. 8 | * 학습 방식입니다. (공식 사이트에도 있습니다.) python 코드입니다. 9 | * cmd 창을 킵니다. 10 | * pip install ultralytics 11 | * (https://universe.roboflow.com/) 해당 사이트에서 학습하고싶은 데이터를 v8 버전으로 다운받습니다. 12 | * 해당 폴더에 아래와 같은 python 파일을 생성합니다. ("fire.yaml" -> 다운받은 yaml 파일의 이름으로 변경하시면 됩니다.) 13 | ``` 14 | from ultralytics import YOLO 15 | from multiprocessing import freeze_support 16 | 17 | # Load a model 18 | model = YOLO("yolov8n.yaml") # build a new model from scratch 19 | model = YOLO("yolov8n.pt") # load a pretrained model (recommended for training) 20 | 21 | if __name__ == '__main__': 22 | freeze_support() # for Windows support 23 | 24 | model.train(data="fire.yaml", epochs=100) # train the model 25 | ``` 26 | 27 | * 다음은 onnx 변환 파일입니다. 같은 폴더에 아래와 같은 python 파일을 생성합니다. (위의 학습 코드와 합치셔도 무관합니다.) 28 | 29 | ``` 30 | from ultralytics import YOLO 31 | 32 | model = YOLO("절대 경로를 적어주시면 됩니다\\best.pt", type="v8") 33 | model.fuse() 34 | model.info(verbose=True) # Print model information 35 | model.export(format= "onnx") # TODO: export to ONNX format 36 | ``` 37 | 38 | ------------ 39 | 40 | #### 해당 앱은 가로 모드로 고정되어있습니다. 가로모드로 사용해주세요. 41 | #### yolo v5는 실행되지 않습니다. 다른 깃허브를 참고해주시면 됩니다. 42 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | namespace 'com.example.yolov8_detect' 7 | compileSdk 33 8 | 9 | defaultConfig { 10 | applicationId "com.example.yolov8_detect" 11 | minSdk 21 12 | targetSdk 33 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | } 30 | 31 | dependencies { 32 | //OnnxRuntime 을 위해 33 | // https://mvnrepository.com/artifact/com.microsoft.onnxruntime/onnxruntime-android 34 | implementation 'com.microsoft.onnxruntime:onnxruntime-android:1.12.1' 35 | 36 | //CameraX 를 위해 37 | // The following line is optional, as the core library is included indirectly by camera-camera2 38 | implementation "androidx.camera:camera-camera2:1.2.1" 39 | implementation "androidx.camera:camera-lifecycle:1.2.1" 40 | // If you want to additionally use the CameraX View class 41 | implementation "androidx.camera:camera-view:1.2.1" 42 | implementation 'androidx.camera:camera-extensions:1.2.1' 43 | 44 | 45 | implementation 'androidx.appcompat:appcompat:1.6.0' 46 | implementation 'com.google.android.material:material:1.8.0' 47 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 48 | testImplementation 'junit:junit:4.13.2' 49 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 50 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 51 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/yolov8_detect/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.yolov8_detect; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.example.yolov8_detect", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 18 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/assets/fire_640_v8.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/assets/fire_640_v8.onnx -------------------------------------------------------------------------------- /app/src/main/assets/label_fire_v8.txt: -------------------------------------------------------------------------------- 1 | fire 2 | smoke -------------------------------------------------------------------------------- /app/src/main/java/com/example/yolov8_detect/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.yolov8_detect; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.graphics.Bitmap; 5 | import android.media.Image; 6 | import android.os.Bundle; 7 | import android.view.WindowManager; 8 | 9 | import androidx.appcompat.app.AppCompatActivity; 10 | import androidx.camera.core.AspectRatio; 11 | import androidx.camera.core.CameraSelector; 12 | import androidx.camera.core.ImageAnalysis; 13 | import androidx.camera.core.ImageProxy; 14 | import androidx.camera.core.Preview; 15 | import androidx.camera.lifecycle.ProcessCameraProvider; 16 | import androidx.camera.view.PreviewView; 17 | 18 | import com.google.common.util.concurrent.ListenableFuture; 19 | 20 | import java.nio.FloatBuffer; 21 | import java.util.ArrayList; 22 | import java.util.Collections; 23 | import java.util.concurrent.ExecutionException; 24 | import java.util.concurrent.Executors; 25 | 26 | import ai.onnxruntime.OnnxTensor; 27 | import ai.onnxruntime.OrtEnvironment; 28 | import ai.onnxruntime.OrtException; 29 | import ai.onnxruntime.OrtSession; 30 | 31 | public class MainActivity extends AppCompatActivity { 32 | private ProcessCameraProvider processCameraProvider; 33 | private PreviewView previewView; 34 | private RectView rectView; 35 | private SupportOnnx supportOnnx; 36 | private OrtEnvironment ortEnvironment; 37 | private OrtSession ortSession; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_main); 43 | previewView = findViewById(R.id.previewView); 44 | rectView = findViewById(R.id.rectView); 45 | 46 | //자동꺼짐 해제 47 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 48 | 49 | //권한 확인 50 | permissionCheck(); 51 | 52 | //Onnx 처리 지원 객체 53 | supportOnnx = new SupportOnnx(this); 54 | 55 | //모델 불러오기 56 | load(); 57 | 58 | //카메라 빌드 59 | setCamera(); 60 | 61 | //카메라 켜기 62 | startCamera(); 63 | } 64 | 65 | public void permissionCheck() { 66 | PermissionSupport permissionSupport = new PermissionSupport(this, this); 67 | permissionSupport.checkPermissions(); 68 | } 69 | 70 | public void load() { 71 | //model, label 불러오기 72 | supportOnnx.loadModel(); 73 | supportOnnx.loadLabel(); 74 | try { 75 | //onnxRuntime 활성화 76 | ortEnvironment = OrtEnvironment.getEnvironment(); 77 | ortSession = ortEnvironment.createSession(this.getFilesDir().getAbsolutePath() + "/" + SupportOnnx.fileName, 78 | new OrtSession.SessionOptions()); 79 | } catch (OrtException e) { 80 | e.printStackTrace(); 81 | } 82 | } 83 | 84 | public void setCamera() { 85 | try { 86 | ListenableFuture cameraProviderListenableFuture = ProcessCameraProvider.getInstance(this); 87 | processCameraProvider = cameraProviderListenableFuture.get(); 88 | } catch (ExecutionException | InterruptedException e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | 93 | public void startCamera() { 94 | //화면 중앙 95 | previewView.setScaleType(PreviewView.ScaleType.FILL_CENTER); 96 | //후면 카메라 97 | CameraSelector cameraSelector = new CameraSelector.Builder() 98 | .requireLensFacing(CameraSelector.LENS_FACING_BACK) 99 | .build(); 100 | 101 | Preview preview = new Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_16_9).build(); 102 | 103 | preview.setSurfaceProvider(previewView.getSurfaceProvider()); 104 | //이미지 분석 빌드 105 | ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() 106 | .setTargetAspectRatio(AspectRatio.RATIO_16_9) 107 | .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build(); 108 | 109 | //label 정보 전달 110 | rectView.setLabels(supportOnnx.getLabels()); 111 | 112 | //분석 113 | imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), imageProxy -> { 114 | imageProcessing(imageProxy); 115 | imageProxy.close(); 116 | }); 117 | 118 | //생명 주기 설정 119 | processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis); 120 | } 121 | 122 | @SuppressLint("UnsafeOptInUsageError") 123 | public void imageProcessing(ImageProxy imageProxy) { 124 | Image image = imageProxy.getImage(); 125 | if (image != null) { 126 | // image -> bitmap 127 | Bitmap bitmap = supportOnnx.imageToBitmap(image); 128 | Bitmap bitmap_640 = supportOnnx.rescaleBitmap(bitmap); 129 | // bitmap -> float buffer 130 | FloatBuffer imgDataFloat = supportOnnx.bitmapToFloatBuffer(bitmap_640); 131 | 132 | //모델명 133 | String inputName = ortSession.getInputNames().iterator().next(); 134 | //모델의 요구 입력값 135 | long[] shape = {SupportOnnx.BATCH_SIZE, SupportOnnx.PIXEL_SIZE, SupportOnnx.INPUT_SIZE, SupportOnnx.INPUT_SIZE}; 136 | 137 | try { 138 | // float buffer -> tensor 139 | OnnxTensor inputTensor = OnnxTensor.createTensor(ortEnvironment, imgDataFloat, shape); 140 | // 추론 141 | OrtSession.Result result = ortSession.run(Collections.singletonMap(inputName, inputTensor)); 142 | // 결과 (v8 의 출력은 [1][xywh + label 의 개수][8400] 입니다. 143 | float[][][] output = (float[][][]) result.get(0).getValue(); 144 | 145 | int rows = output[0][0].length; //8400 146 | // tensor -> label, score, rectF 147 | ArrayList results = supportOnnx.outputsToNMSPredictions(output, rows); 148 | 149 | // rectF 를 보이는 화면의 비율에 맞게 수정 150 | results = rectView.transFormRect(results); 151 | 152 | // Result(label, score, rectF) -> 화면에 출력 153 | rectView.clear(); 154 | rectView.resultToList(results); 155 | rectView.invalidate(); 156 | 157 | } catch (OrtException e) { 158 | e.printStackTrace(); 159 | } 160 | } 161 | } 162 | 163 | @Override 164 | protected void onStop() { 165 | try { 166 | ortSession.endProfiling(); 167 | } catch (OrtException e) { 168 | e.printStackTrace(); 169 | } 170 | super.onStop(); 171 | } 172 | 173 | @Override 174 | protected void onDestroy() { 175 | try { 176 | ortSession.close(); 177 | ortEnvironment.close(); 178 | } catch (OrtException e) { 179 | e.printStackTrace(); 180 | } 181 | super.onDestroy(); 182 | } 183 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/yolov8_detect/PermissionSupport.java: -------------------------------------------------------------------------------- 1 | package com.example.yolov8_detect; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.content.pm.PackageManager; 7 | 8 | import androidx.core.app.ActivityCompat; 9 | 10 | public class PermissionSupport { 11 | private final Context context; 12 | private final Activity activity; 13 | private final String[] permissions; 14 | 15 | public PermissionSupport(Context context, Activity activity){ 16 | this.context = context; 17 | this.activity = activity; 18 | 19 | permissions = new String[1]; 20 | permissions[0] = Manifest.permission.CAMERA; 21 | } 22 | 23 | public void checkPermissions(){ 24 | for(String permission : permissions){ 25 | if(ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED){ 26 | if(!ActivityCompat.shouldShowRequestPermissionRationale(activity,permission)){ 27 | ActivityCompat.requestPermissions(activity,permissions,1); 28 | } 29 | } 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/yolov8_detect/RectView.java: -------------------------------------------------------------------------------- 1 | package com.example.yolov8_detect; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.RectF; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import androidx.annotation.Nullable; 12 | 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | public class RectView extends View { 18 | private final Map fireMap = new HashMap<>(); 19 | private final Map smokeMap = new HashMap<>(); 20 | private final Paint firePaint = new Paint(); 21 | private final Paint smokePaint = new Paint(); 22 | private final Paint textPaint = new Paint(); 23 | 24 | private String[] labels; 25 | 26 | public RectView(Context context, @Nullable AttributeSet attrs) { 27 | super(context, attrs); 28 | 29 | firePaint.setStyle(Paint.Style.STROKE); //빈 사각형 그림 30 | firePaint.setStrokeWidth(10.0f); //굵기 10 31 | firePaint.setColor(Color.RED); //빨간색 32 | firePaint.setStrokeCap(Paint.Cap.ROUND); //끝을 뭉특하게 33 | firePaint.setStrokeJoin(Paint.Join.ROUND); //끝 주위도 뭉특하게 34 | firePaint.setStrokeMiter(100); //뭉특한 정도 100도 35 | 36 | smokePaint.setStyle(Paint.Style.STROKE); 37 | smokePaint.setStrokeWidth(10.0f); 38 | smokePaint.setColor(Color.GRAY); 39 | smokePaint.setStrokeCap(Paint.Cap.ROUND); 40 | smokePaint.setStrokeJoin(Paint.Join.ROUND); 41 | smokePaint.setStrokeMiter(100); 42 | 43 | textPaint.setTextSize(60.0f); 44 | textPaint.setColor(Color.WHITE); 45 | } 46 | 47 | public void setLabels(String[] labels) { 48 | this.labels = labels; 49 | } 50 | 51 | // rectF 비율 수정 52 | public ArrayList transFormRect(ArrayList resultArrayList) { 53 | //핸드폰의 기종에 따라 PreviewView 의 크기는 변한다. 54 | float scaleX = getWidth() / (float) SupportOnnx.INPUT_SIZE; 55 | // float scaleY = getHeight() / (float) SupportOnnx.INPUT_SIZE; 56 | float scaleY = scaleX * 9f / 16f; 57 | float realY = getWidth() * 9f / 16f; 58 | float diffY = realY - getHeight(); 59 | 60 | for (Result result : resultArrayList) { 61 | result.getRectF().left *= scaleX; 62 | result.getRectF().right *= scaleX; 63 | result.getRectF().top = result.getRectF().top * scaleY - (diffY / 2f); 64 | result.getRectF().bottom = result.getRectF().bottom * scaleY - (diffY / 2f); 65 | } 66 | return resultArrayList; 67 | } 68 | 69 | //초기화 70 | public void clear() { 71 | fireMap.clear(); 72 | smokeMap.clear(); 73 | } 74 | 75 | // Result -> 각각의 해시맵 (fireMap, smokeMap) 76 | public void resultToList(ArrayList results) { 77 | //rectF에는 상자의 좌표값 , String 에는 객체명(화재 or 연기) 과 확률을 적는다. 78 | for (Result result : results) { 79 | if (result.getLabel() == 0) { // fire 80 | fireMap.put(result.getRectF(), labels[0] + ", " + Math.round(result.getScore() * 100) + "%"); 81 | } else { // smoke 82 | smokeMap.put(result.getRectF(), labels[1] + ", " + Math.round(result.getScore() * 100) + "%"); 83 | } 84 | } 85 | } 86 | 87 | @Override 88 | protected void onDraw(Canvas canvas) { 89 | // fire(HashMap) -> canvas 90 | for (Map.Entry fire : fireMap.entrySet()) { 91 | canvas.drawRect(fire.getKey(), firePaint); 92 | canvas.drawText(fire.getValue(), fire.getKey().left + 10.0f, fire.getKey().top + 60.0f, textPaint); 93 | } 94 | // smoke(HashMap) -> canvas 95 | for (Map.Entry smoke : smokeMap.entrySet()) { 96 | canvas.drawRect(smoke.getKey(), smokePaint); 97 | canvas.drawText(smoke.getValue(), smoke.getKey().left + 10.0f, smoke.getKey().top + 60.0f, textPaint); 98 | } 99 | super.onDraw(canvas); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/yolov8_detect/Result.java: -------------------------------------------------------------------------------- 1 | package com.example.yolov8_detect; 2 | 3 | import android.graphics.RectF; 4 | 5 | public class Result { 6 | private final int label; 7 | private final float score; 8 | private final RectF rectF; 9 | 10 | public Result(int label, float score, RectF rectF) { 11 | this.label = label; 12 | this.score = score; 13 | this.rectF = rectF; 14 | } 15 | 16 | public int getLabel() { 17 | return label; 18 | } 19 | 20 | public float getScore() { 21 | return score; 22 | } 23 | 24 | public RectF getRectF() { 25 | return rectF; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/yolov8_detect/SupportOnnx.java: -------------------------------------------------------------------------------- 1 | package com.example.yolov8_detect; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.ImageFormat; 8 | import android.graphics.Rect; 9 | import android.graphics.RectF; 10 | import android.graphics.YuvImage; 11 | import android.media.Image; 12 | 13 | import java.io.BufferedReader; 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.File; 16 | import java.io.FileOutputStream; 17 | import java.io.IOException; 18 | import java.io.InputStream; 19 | import java.io.InputStreamReader; 20 | import java.io.OutputStream; 21 | import java.nio.ByteBuffer; 22 | import java.nio.ByteOrder; 23 | import java.nio.FloatBuffer; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.PriorityQueue; 27 | 28 | public class SupportOnnx { 29 | static final String fileName = "fire_640_v8.onnx"; 30 | static final String labelName = "label_fire_v8.txt"; 31 | static final int INPUT_SIZE = 640; 32 | static final int BATCH_SIZE = 1; 33 | static final int PIXEL_SIZE = 3; 34 | static final int FLOAT_SIZE = 4; 35 | 36 | public float iouThresh = 0.5f; 37 | public float objectThresh = 0.4f; 38 | private final Context context; 39 | private String[] labels; 40 | 41 | public SupportOnnx(Context context) { 42 | this.context = context; 43 | } 44 | 45 | //모델 불러오기 46 | public void loadModel() { 47 | //assets 안의 모델을 byte 형태로 읽어서 가져온다. 48 | AssetManager assetManager = context.getAssets(); 49 | File outputFile = new File(context.getFilesDir() + "/" + fileName); 50 | 51 | try { 52 | InputStream inputStream = assetManager.open(fileName); 53 | OutputStream outputStream = new FileOutputStream(outputFile); 54 | byte[] buffer = new byte[1024 * 4]; 55 | int read; 56 | while ((read = inputStream.read(buffer)) != -1) { 57 | outputStream.write(buffer, 0, read); 58 | } 59 | 60 | inputStream.close(); 61 | outputStream.flush(); 62 | outputStream.close(); 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | 68 | //라벨 불러오기 69 | public void loadLabel() { 70 | try { 71 | //assets 파일안에 있는 label (문자열) 을 한줄씩 읽어서 저장 72 | BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(labelName))); 73 | String line; 74 | List labelList = new ArrayList<>(); 75 | while ((line = reader.readLine()) != null) { 76 | labelList.add(line); 77 | } 78 | // arraylist -> array 79 | labels = new String[labelList.size()]; 80 | labelList.toArray(labels); 81 | } catch (IOException e) { 82 | e.printStackTrace(); 83 | } 84 | } 85 | 86 | //비트맵 변환 87 | public Bitmap imageToBitmap(Image image) { 88 | Image.Plane[] planes = image.getPlanes(); 89 | 90 | //YUV 평면 얻기 91 | // 1. Bytebuffer -> byte[] 92 | ByteBuffer yBuffer = planes[0].getBuffer(); 93 | ByteBuffer uBuffer = planes[1].getBuffer(); 94 | ByteBuffer vBuffer = planes[2].getBuffer(); 95 | int ySize = yBuffer.remaining(); 96 | int uSize = uBuffer.remaining(); 97 | int vSize = vBuffer.remaining(); 98 | byte[] yuvBytes = new byte[ySize + uSize + vSize]; 99 | yBuffer.get(yuvBytes, 0, ySize); 100 | vBuffer.get(yuvBytes, ySize, vSize); 101 | uBuffer.get(yuvBytes, ySize + vSize, uSize); 102 | 103 | // 2. byte[] -> yuvImage -> byteArray 104 | YuvImage yuvImage = new YuvImage(yuvBytes, ImageFormat.NV21, image.getWidth(), image.getHeight(), null); 105 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 106 | yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 90, out); 107 | 108 | // 3. byteArray -> bitmap 109 | byte[] imageBytes = out.toByteArray(); 110 | 111 | return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); 112 | } 113 | 114 | // [가로 * 세로] -> [640 * 640] 으로 변환 115 | public Bitmap rescaleBitmap(Bitmap bitmap) { 116 | return Bitmap.createScaledBitmap(bitmap, INPUT_SIZE, INPUT_SIZE, true); 117 | } 118 | 119 | // bitmap -> float buffer 120 | public FloatBuffer bitmapToFloatBuffer(Bitmap bitmap) { 121 | int cap = BATCH_SIZE * PIXEL_SIZE * INPUT_SIZE * INPUT_SIZE; 122 | ByteOrder order = ByteOrder.nativeOrder(); 123 | FloatBuffer buffer = ByteBuffer.allocate(cap * FLOAT_SIZE).order(order).asFloatBuffer(); 124 | 125 | int area = INPUT_SIZE * INPUT_SIZE; 126 | int[] bitmapData = new int[area]; 127 | 128 | bitmap.getPixels(bitmapData, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); 129 | for (int i = 0; i < INPUT_SIZE - 1; i++) { 130 | for (int j = 0; j < INPUT_SIZE - 1; j++) { 131 | //0~640*640 차례대로 하나씩 가져오기 132 | int idx = INPUT_SIZE * i + j; 133 | int pixelValue = bitmapData[idx]; 134 | float imageMean = 0.0f; 135 | float imageSTD = 255.0f; 136 | buffer.put(idx, (((pixelValue >> 16 & 0xFF) - imageMean) / imageSTD)); //r값을 정수형 -> 실수형 137 | buffer.put(idx + area, (((pixelValue >> 8 & 0xFF) - imageMean) / imageSTD)); //g값을 정수형 -> 실수형 138 | buffer.put(idx + area * 2, (((pixelValue & 0xFF) - imageMean) / imageSTD)); //b값을 정수형 -> 실수형 139 | } 140 | } 141 | buffer.rewind(); 142 | return buffer; 143 | } 144 | 145 | // 추론 결과 (3차원 텐서) -> 결과 추출 146 | public ArrayList outputsToNMSPredictions(float[][][] output, int rows) { 147 | ArrayList results = new ArrayList<>(); 148 | 149 | float[][][] outputV8 = new float[1][rows][output[0].length]; 150 | 151 | // 행렬 전치 (가로 세로 -> 세로 가로) 152 | for (int l = 0; l < output[0].length ; l++) { 153 | for (int m = 0; m < rows; m++) { 154 | outputV8[0][m][l] = output[0][l][m]; 155 | } 156 | } 157 | 158 | //그대로 output 을 입력으로 하지 않고 전치를 시킨 이유는 yolo v8 이 되면서 출력 행렬이 [1][xywh + label 개수][8400] 이 되었기 때문입니다. 159 | // yolo v5 의 경우 [1][25200][xywh + conf + label 개수] 형태였습니다. 160 | // v5의 함수와 함께 사용하기 위해 위와 같이 전치를 시킵니다. 물론 해당 앱은 v5 는 실행 되지 않습니다. 161 | // conf 값에 대한 내용을 뺐기 때문입니다. v5 를 보고싶으시면 다른 깃허브 코드를 참고해주시면 감사하겠습니다. 162 | 163 | // 각 bounding box 에 대해 가장 확률이 높은 Class 예측 164 | for (int i = 0; i < rows; ++i) { 165 | int detectionClass = -1; 166 | float maxClass = 0; 167 | 168 | float[] _classes = new float[labels.length]; 169 | //3차원 output 배열에서 4번부터있는 label 만 따로 빼서 새로운 1차원 클래스를 만든다. 170 | System.arraycopy(outputV8[0][i], 4, _classes, 0, labels.length); 171 | 172 | //그 label 중에서 가장 값이 큰 값을 선정한다. 173 | for (int c = 0; c < labels.length; ++c) { 174 | if (_classes[c] > maxClass) { 175 | detectionClass = c; 176 | maxClass = _classes[c]; 177 | } 178 | } 179 | 180 | //실제 확률 값은 4번의 확률값과 해당 label 의 확률값의 곱이다. 181 | float confidenceInClass = maxClass; 182 | //만약 그 확률 값이 특정 확률을 넘어서면 List 형태로 저장한다. 183 | if (confidenceInClass > objectThresh) { 184 | float xPos = outputV8[0][i][0]; 185 | float yPos = outputV8[0][i][1]; 186 | float width = outputV8[0][i][2]; 187 | float height = outputV8[0][i][3]; 188 | 189 | //사각형은 화면 밖으로 나갈 수 없으니 화면을 넘기면 최대 화면 값을 가지게 한다. 190 | RectF rectF = new RectF(Math.max(0, xPos - width / 2), Math.max(0, yPos - height / 2), 191 | Math.min(INPUT_SIZE - 1, xPos + width / 2), Math.min(INPUT_SIZE - 1, yPos + height / 2)); 192 | Result recognition = new Result(detectionClass, confidenceInClass, rectF); 193 | results.add(recognition); 194 | } 195 | } 196 | 197 | return nms(results); 198 | } 199 | 200 | // NMS (비최대 억제) 201 | public ArrayList nms(ArrayList results) { 202 | ArrayList nmsList = new ArrayList<>(); 203 | 204 | for (int k = 0; k < labels.length; k++) { 205 | //1.find max confidence per class 206 | PriorityQueue pq = 207 | new PriorityQueue<>(50, 208 | (o1, o2) -> Float.compare(o1.getScore(), o2.getScore())); 209 | 210 | for (int i = 0; i < results.size(); i++) { 211 | if (results.get(i).getLabel() == k) { 212 | pq.add(results.get(i)); 213 | } 214 | } 215 | 216 | //2.do non maximum suppression 217 | while (pq.size() > 0) { 218 | //insert detection with max confidence 219 | Result[] a = new Result[pq.size()]; 220 | Result[] detections = pq.toArray(a); 221 | Result max = detections[0]; 222 | nmsList.add(max); 223 | pq.clear(); 224 | 225 | for (int j = 1; j < detections.length; j++) { 226 | Result detection = detections[j]; 227 | RectF b = detection.getRectF(); 228 | if (box_iou(max.getRectF(), b) < iouThresh) { 229 | pq.add(detection); 230 | } 231 | } 232 | } 233 | } 234 | return nmsList; 235 | } 236 | 237 | // IOU = 교집합/합집합 238 | protected float box_iou(RectF a, RectF b) { 239 | return box_intersection(a, b) / box_union(a, b); 240 | } 241 | 242 | // 결과 box의 교집합 243 | protected float box_intersection(RectF a, RectF b) { 244 | float w = overlap((a.left + a.right) / 2, a.right - a.left, 245 | (b.left + b.right) / 2, b.right - b.left); 246 | float h = overlap((a.top + a.bottom) / 2, a.bottom - a.top, 247 | (b.top + b.bottom) / 2, b.bottom - b.top); 248 | if (w < 0 || h < 0) return 0; 249 | return w * h; 250 | } 251 | 252 | // 결과 box의 합집합 253 | protected float box_union(RectF a, RectF b) { 254 | float i = box_intersection(a, b); 255 | return (a.right - a.left) * (a.bottom - a.top) + (b.right - b.left) * (b.bottom - b.top) - i; 256 | } 257 | 258 | protected float overlap(float x1, float w1, float x2, float w2) { 259 | float l1 = x1 - w1 / 2; 260 | float l2 = x2 - w2 / 2; 261 | float left = Math.max(l1, l2); 262 | float r1 = x1 + w1 / 2; 263 | float r2 = x2 + w2 / 2; 264 | float right = Math.min(r1, r2); 265 | return right - left; 266 | } 267 | 268 | //라벨 전달 269 | public String[] getLabels() { 270 | return labels; 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | YoloV8_Detect 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/yolov8_detect/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.yolov8_detect; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id 'com.android.application' version '7.3.1' apply false 4 | id 'com.android.library' version '7.3.1' apply false 5 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Enables namespacing of each library's R class so that its R class includes only the 19 | # resources declared in the library itself and none from the library's dependencies, 20 | # thereby reducing the size of the R class for that library 21 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aloe-droid/Yolov8_Android/94a0736b7dde107e0a2b2f96cc08d0381ceaaa71/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Feb 09 15:35:29 KST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or 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 UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | rootProject.name = "YoloV8_Detect" 16 | include ':app' 17 | --------------------------------------------------------------------------------