├── README.md
├── app
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── yolov5s.bin
│ └── yolov5s.param
│ ├── java
│ └── com
│ │ └── tencent
│ │ └── yolov5ncnn
│ │ ├── MainActivity.java
│ │ └── YoloV5Ncnn.java
│ ├── jni
│ ├── CMakeLists.txt
│ └── yolov5ncnn_jni.cpp
│ └── res
│ ├── layout
│ └── main.xml
│ └── values
│ └── strings.xml
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshot.jpg
└── settings.gradle
/README.md:
--------------------------------------------------------------------------------
1 | # ncnn-android-yolov5
2 |
3 | The YOLOv5 object detection
4 |
5 | this is a sample ncnn android project, it depends on ncnn library only
6 |
7 | https://github.com/Tencent/ncnn
8 |
9 | ## how to build and run
10 | ### step1
11 | https://github.com/Tencent/ncnn/releases
12 |
13 | download ncnn-android-vulkan.zip or build ncnn for android yourself
14 |
15 | ### step2
16 | extract ncnn-android-vulkan.zip into app/src/main/jni or change the ncnn_DIR path to yours in app/src/main/jni/CMakeLists.txt
17 |
18 | ### step3
19 | open this project with Android Studio, build it and enjoy!
20 |
21 | ## screenshot
22 | 
23 |
24 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "29.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.tencent.yolov5ncnn"
9 | archivesBaseName = "$applicationId"
10 |
11 | ndk {
12 | moduleName "ncnn"
13 | abiFilters "armeabi-v7a", "arm64-v8a"
14 | }
15 | minSdkVersion 24
16 | }
17 |
18 | externalNativeBuild {
19 | cmake {
20 | version "3.10.2"
21 | path file('src/main/jni/CMakeLists.txt')
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/assets/yolov5s.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nihui/ncnn-android-yolov5/14e728f4e3819824fbf8bcce10607481a932ac09/app/src/main/assets/yolov5s.bin
--------------------------------------------------------------------------------
/app/src/main/assets/yolov5s.param:
--------------------------------------------------------------------------------
1 | 7767517
2 | 192 216
3 | Input images 0 1 images
4 | YoloV5Focus focus 1 1 images 207
5 | Convolution Conv_41 1 1 207 208 0=32 1=3 4=1 5=1 6=3456
6 | HardSwish Div_49 1 1 208 216 0=1.666667e-01
7 | Convolution Conv_50 1 1 216 217 0=64 1=3 3=2 4=1 5=1 6=18432
8 | HardSwish Div_58 1 1 217 225 0=1.666667e-01
9 | Split splitncnn_0 1 2 225 225_splitncnn_0 225_splitncnn_1
10 | Convolution Conv_59 1 1 225_splitncnn_1 226 0=32 1=1 5=1 6=2048
11 | HardSwish Div_67 1 1 226 234 0=1.666667e-01
12 | Split splitncnn_1 1 2 234 234_splitncnn_0 234_splitncnn_1
13 | Convolution Conv_68 1 1 234_splitncnn_1 235 0=32 1=1 5=1 6=1024
14 | HardSwish Div_76 1 1 235 243 0=1.666667e-01
15 | Convolution Conv_77 1 1 243 244 0=32 1=3 4=1 5=1 6=9216
16 | HardSwish Div_85 1 1 244 252 0=1.666667e-01
17 | BinaryOp Add_86 2 1 234_splitncnn_0 252 253
18 | Convolution Conv_87 1 1 253 254 0=32 1=1 6=1024
19 | Convolution Conv_88 1 1 225_splitncnn_0 255 0=32 1=1 6=2048
20 | Concat Concat_89 2 1 254 255 256
21 | BatchNorm BatchNormalization_90 1 1 256 257 0=64
22 | ReLU LeakyRelu_91 1 1 257 258 0=1.000000e-01
23 | Convolution Conv_92 1 1 258 259 0=64 1=1 5=1 6=4096
24 | HardSwish Div_100 1 1 259 267 0=1.666667e-01
25 | Convolution Conv_101 1 1 267 268 0=128 1=3 3=2 4=1 5=1 6=73728
26 | HardSwish Div_109 1 1 268 276 0=1.666667e-01
27 | Split splitncnn_2 1 2 276 276_splitncnn_0 276_splitncnn_1
28 | Convolution Conv_110 1 1 276_splitncnn_1 277 0=64 1=1 5=1 6=8192
29 | HardSwish Div_118 1 1 277 285 0=1.666667e-01
30 | Split splitncnn_3 1 2 285 285_splitncnn_0 285_splitncnn_1
31 | Convolution Conv_119 1 1 285_splitncnn_1 286 0=64 1=1 5=1 6=4096
32 | HardSwish Div_127 1 1 286 294 0=1.666667e-01
33 | Convolution Conv_128 1 1 294 295 0=64 1=3 4=1 5=1 6=36864
34 | HardSwish Div_136 1 1 295 303 0=1.666667e-01
35 | BinaryOp Add_137 2 1 285_splitncnn_0 303 304
36 | Split splitncnn_4 1 2 304 304_splitncnn_0 304_splitncnn_1
37 | Convolution Conv_138 1 1 304_splitncnn_1 305 0=64 1=1 5=1 6=4096
38 | HardSwish Div_146 1 1 305 313 0=1.666667e-01
39 | Convolution Conv_147 1 1 313 314 0=64 1=3 4=1 5=1 6=36864
40 | HardSwish Div_155 1 1 314 322 0=1.666667e-01
41 | BinaryOp Add_156 2 1 304_splitncnn_0 322 323
42 | Split splitncnn_5 1 2 323 323_splitncnn_0 323_splitncnn_1
43 | Convolution Conv_157 1 1 323_splitncnn_1 324 0=64 1=1 5=1 6=4096
44 | HardSwish Div_165 1 1 324 332 0=1.666667e-01
45 | Convolution Conv_166 1 1 332 333 0=64 1=3 4=1 5=1 6=36864
46 | HardSwish Div_174 1 1 333 341 0=1.666667e-01
47 | BinaryOp Add_175 2 1 323_splitncnn_0 341 342
48 | Convolution Conv_176 1 1 342 343 0=64 1=1 6=4096
49 | Convolution Conv_177 1 1 276_splitncnn_0 344 0=64 1=1 6=8192
50 | Concat Concat_178 2 1 343 344 345
51 | BatchNorm BatchNormalization_179 1 1 345 346 0=128
52 | ReLU LeakyRelu_180 1 1 346 347 0=1.000000e-01
53 | Convolution Conv_181 1 1 347 348 0=128 1=1 5=1 6=16384
54 | HardSwish Div_189 1 1 348 356 0=1.666667e-01
55 | Split splitncnn_6 1 2 356 356_splitncnn_0 356_splitncnn_1
56 | Convolution Conv_190 1 1 356_splitncnn_1 357 0=256 1=3 3=2 4=1 5=1 6=294912
57 | HardSwish Div_198 1 1 357 365 0=1.666667e-01
58 | Split splitncnn_7 1 2 365 365_splitncnn_0 365_splitncnn_1
59 | Convolution Conv_199 1 1 365_splitncnn_1 366 0=128 1=1 5=1 6=32768
60 | HardSwish Div_207 1 1 366 374 0=1.666667e-01
61 | Split splitncnn_8 1 2 374 374_splitncnn_0 374_splitncnn_1
62 | Convolution Conv_208 1 1 374_splitncnn_1 375 0=128 1=1 5=1 6=16384
63 | HardSwish Div_216 1 1 375 383 0=1.666667e-01
64 | Convolution Conv_217 1 1 383 384 0=128 1=3 4=1 5=1 6=147456
65 | HardSwish Div_225 1 1 384 392 0=1.666667e-01
66 | BinaryOp Add_226 2 1 374_splitncnn_0 392 393
67 | Split splitncnn_9 1 2 393 393_splitncnn_0 393_splitncnn_1
68 | Convolution Conv_227 1 1 393_splitncnn_1 394 0=128 1=1 5=1 6=16384
69 | HardSwish Div_235 1 1 394 402 0=1.666667e-01
70 | Convolution Conv_236 1 1 402 403 0=128 1=3 4=1 5=1 6=147456
71 | HardSwish Div_244 1 1 403 411 0=1.666667e-01
72 | BinaryOp Add_245 2 1 393_splitncnn_0 411 412
73 | Split splitncnn_10 1 2 412 412_splitncnn_0 412_splitncnn_1
74 | Convolution Conv_246 1 1 412_splitncnn_1 413 0=128 1=1 5=1 6=16384
75 | HardSwish Div_254 1 1 413 421 0=1.666667e-01
76 | Convolution Conv_255 1 1 421 422 0=128 1=3 4=1 5=1 6=147456
77 | HardSwish Div_263 1 1 422 430 0=1.666667e-01
78 | BinaryOp Add_264 2 1 412_splitncnn_0 430 431
79 | Convolution Conv_265 1 1 431 432 0=128 1=1 6=16384
80 | Convolution Conv_266 1 1 365_splitncnn_0 433 0=128 1=1 6=32768
81 | Concat Concat_267 2 1 432 433 434
82 | BatchNorm BatchNormalization_268 1 1 434 435 0=256
83 | ReLU LeakyRelu_269 1 1 435 436 0=1.000000e-01
84 | Convolution Conv_270 1 1 436 437 0=256 1=1 5=1 6=65536
85 | HardSwish Div_278 1 1 437 445 0=1.666667e-01
86 | Split splitncnn_11 1 2 445 445_splitncnn_0 445_splitncnn_1
87 | Convolution Conv_279 1 1 445_splitncnn_1 446 0=512 1=3 3=2 4=1 5=1 6=1179648
88 | HardSwish Div_287 1 1 446 454 0=1.666667e-01
89 | Convolution Conv_288 1 1 454 455 0=256 1=1 5=1 6=131072
90 | HardSwish Div_296 1 1 455 463 0=1.666667e-01
91 | Split splitncnn_12 1 4 463 463_splitncnn_0 463_splitncnn_1 463_splitncnn_2 463_splitncnn_3
92 | Pooling MaxPool_297 1 1 463_splitncnn_3 464 1=5 3=2 5=1
93 | Pooling MaxPool_298 1 1 463_splitncnn_2 465 1=9 3=4 5=1
94 | Pooling MaxPool_299 1 1 463_splitncnn_1 466 1=13 3=6 5=1
95 | Concat Concat_300 4 1 463_splitncnn_0 464 465 466 467
96 | Convolution Conv_301 1 1 467 468 0=512 1=1 5=1 6=524288
97 | HardSwish Div_309 1 1 468 476 0=1.666667e-01
98 | Split splitncnn_13 1 2 476 476_splitncnn_0 476_splitncnn_1
99 | Convolution Conv_310 1 1 476_splitncnn_1 477 0=256 1=1 5=1 6=131072
100 | HardSwish Div_318 1 1 477 485 0=1.666667e-01
101 | Convolution Conv_319 1 1 485 486 0=256 1=1 5=1 6=65536
102 | HardSwish Div_327 1 1 486 494 0=1.666667e-01
103 | Convolution Conv_328 1 1 494 495 0=256 1=3 4=1 5=1 6=589824
104 | HardSwish Div_336 1 1 495 503 0=1.666667e-01
105 | Convolution Conv_337 1 1 503 504 0=256 1=1 6=65536
106 | Convolution Conv_338 1 1 476_splitncnn_0 505 0=256 1=1 6=131072
107 | Concat Concat_339 2 1 504 505 506
108 | BatchNorm BatchNormalization_340 1 1 506 507 0=512
109 | ReLU LeakyRelu_341 1 1 507 508 0=1.000000e-01
110 | Convolution Conv_342 1 1 508 509 0=512 1=1 5=1 6=262144
111 | HardSwish Div_350 1 1 509 517 0=1.666667e-01
112 | Convolution Conv_351 1 1 517 518 0=256 1=1 5=1 6=131072
113 | HardSwish Div_359 1 1 518 526 0=1.666667e-01
114 | Split splitncnn_14 1 2 526 526_splitncnn_0 526_splitncnn_1
115 | Interp Resize_361 1 1 526_splitncnn_1 536 0=1 1=2.000000e+00 2=2.000000e+00
116 | Concat Concat_362 2 1 536 445_splitncnn_0 537
117 | Split splitncnn_15 1 2 537 537_splitncnn_0 537_splitncnn_1
118 | Convolution Conv_363 1 1 537_splitncnn_1 538 0=128 1=1 5=1 6=65536
119 | HardSwish Div_371 1 1 538 546 0=1.666667e-01
120 | Convolution Conv_372 1 1 546 547 0=128 1=1 5=1 6=16384
121 | HardSwish Div_380 1 1 547 555 0=1.666667e-01
122 | Convolution Conv_381 1 1 555 556 0=128 1=3 4=1 5=1 6=147456
123 | HardSwish Div_389 1 1 556 564 0=1.666667e-01
124 | Convolution Conv_390 1 1 564 565 0=128 1=1 6=16384
125 | Convolution Conv_391 1 1 537_splitncnn_0 566 0=128 1=1 6=65536
126 | Concat Concat_392 2 1 565 566 567
127 | BatchNorm BatchNormalization_393 1 1 567 568 0=256
128 | ReLU LeakyRelu_394 1 1 568 569 0=1.000000e-01
129 | Convolution Conv_395 1 1 569 570 0=256 1=1 5=1 6=65536
130 | HardSwish Div_403 1 1 570 578 0=1.666667e-01
131 | Convolution Conv_404 1 1 578 579 0=128 1=1 5=1 6=32768
132 | HardSwish Div_412 1 1 579 587 0=1.666667e-01
133 | Split splitncnn_16 1 2 587 587_splitncnn_0 587_splitncnn_1
134 | Interp Resize_414 1 1 587_splitncnn_1 597 0=1 1=2.000000e+00 2=2.000000e+00
135 | Concat Concat_415 2 1 597 356_splitncnn_0 598
136 | Split splitncnn_17 1 2 598 598_splitncnn_0 598_splitncnn_1
137 | Convolution Conv_416 1 1 598_splitncnn_1 599 0=64 1=1 5=1 6=16384
138 | HardSwish Div_424 1 1 599 607 0=1.666667e-01
139 | Convolution Conv_425 1 1 607 608 0=64 1=1 5=1 6=4096
140 | HardSwish Div_433 1 1 608 616 0=1.666667e-01
141 | Convolution Conv_434 1 1 616 617 0=64 1=3 4=1 5=1 6=36864
142 | HardSwish Div_442 1 1 617 625 0=1.666667e-01
143 | Convolution Conv_443 1 1 625 626 0=64 1=1 6=4096
144 | Convolution Conv_444 1 1 598_splitncnn_0 627 0=64 1=1 6=16384
145 | Concat Concat_445 2 1 626 627 628
146 | BatchNorm BatchNormalization_446 1 1 628 629 0=128
147 | ReLU LeakyRelu_447 1 1 629 630 0=1.000000e-01
148 | Convolution Conv_448 1 1 630 631 0=128 1=1 5=1 6=16384
149 | HardSwish Div_456 1 1 631 639 0=1.666667e-01
150 | Split splitncnn_18 1 2 639 639_splitncnn_0 639_splitncnn_1
151 | Convolution Conv_457 1 1 639_splitncnn_1 640 0=128 1=3 3=2 4=1 5=1 6=147456
152 | HardSwish Div_465 1 1 640 648 0=1.666667e-01
153 | Concat Concat_466 2 1 648 587_splitncnn_0 649
154 | Split splitncnn_19 1 2 649 649_splitncnn_0 649_splitncnn_1
155 | Convolution Conv_467 1 1 649_splitncnn_1 650 0=128 1=1 5=1 6=32768
156 | HardSwish Div_475 1 1 650 658 0=1.666667e-01
157 | Convolution Conv_476 1 1 658 659 0=128 1=1 5=1 6=16384
158 | HardSwish Div_484 1 1 659 667 0=1.666667e-01
159 | Convolution Conv_485 1 1 667 668 0=128 1=3 4=1 5=1 6=147456
160 | HardSwish Div_493 1 1 668 676 0=1.666667e-01
161 | Convolution Conv_494 1 1 676 677 0=128 1=1 6=16384
162 | Convolution Conv_495 1 1 649_splitncnn_0 678 0=128 1=1 6=32768
163 | Concat Concat_496 2 1 677 678 679
164 | BatchNorm BatchNormalization_497 1 1 679 680 0=256
165 | ReLU LeakyRelu_498 1 1 680 681 0=1.000000e-01
166 | Convolution Conv_499 1 1 681 682 0=256 1=1 5=1 6=65536
167 | HardSwish Div_507 1 1 682 690 0=1.666667e-01
168 | Split splitncnn_20 1 2 690 690_splitncnn_0 690_splitncnn_1
169 | Convolution Conv_508 1 1 690_splitncnn_1 691 0=256 1=3 3=2 4=1 5=1 6=589824
170 | HardSwish Div_516 1 1 691 699 0=1.666667e-01
171 | Concat Concat_517 2 1 699 526_splitncnn_0 700
172 | Split splitncnn_21 1 2 700 700_splitncnn_0 700_splitncnn_1
173 | Convolution Conv_518 1 1 700_splitncnn_1 701 0=256 1=1 5=1 6=131072
174 | HardSwish Div_526 1 1 701 709 0=1.666667e-01
175 | Convolution Conv_527 1 1 709 710 0=256 1=1 5=1 6=65536
176 | HardSwish Div_535 1 1 710 718 0=1.666667e-01
177 | Convolution Conv_536 1 1 718 719 0=256 1=3 4=1 5=1 6=589824
178 | HardSwish Div_544 1 1 719 727 0=1.666667e-01
179 | Convolution Conv_545 1 1 727 728 0=256 1=1 6=65536
180 | Convolution Conv_546 1 1 700_splitncnn_0 729 0=256 1=1 6=131072
181 | Concat Concat_547 2 1 728 729 730
182 | BatchNorm BatchNormalization_548 1 1 730 731 0=512
183 | ReLU LeakyRelu_549 1 1 731 732 0=1.000000e-01
184 | Convolution Conv_550 1 1 732 733 0=512 1=1 5=1 6=262144
185 | HardSwish Div_558 1 1 733 741 0=1.666667e-01
186 | Convolution Conv_559 1 1 639_splitncnn_0 742 0=255 1=1 5=1 6=32640
187 | Reshape Reshape_573 1 1 742 760 0=-1 1=85 2=3
188 | Permute Transpose_574 1 1 760 output 0=1
189 | Convolution Conv_575 1 1 690_splitncnn_0 762 0=255 1=1 5=1 6=65280
190 | Reshape Reshape_589 1 1 762 780 0=-1 1=85 2=3
191 | Permute Transpose_590 1 1 780 781 0=1
192 | Convolution Conv_591 1 1 741 782 0=255 1=1 5=1 6=130560
193 | Reshape Reshape_605 1 1 782 800 0=-1 1=85 2=3
194 | Permute Transpose_606 1 1 800 801 0=1
195 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tencent/yolov5ncnn/MainActivity.java:
--------------------------------------------------------------------------------
1 | // Tencent is pleased to support the open source community by making ncnn available.
2 | //
3 | // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
4 | //
5 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
6 | // in compliance with the License. You may obtain a copy of the License at
7 | //
8 | // https://opensource.org/licenses/BSD-3-Clause
9 | //
10 | // Unless required by applicable law or agreed to in writing, software distributed
11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 | // specific language governing permissions and limitations under the License.
14 |
15 | package com.tencent.yolov5ncnn;
16 |
17 | import android.app.Activity;
18 | import android.content.Intent;
19 | import android.graphics.Bitmap;
20 | import android.graphics.BitmapFactory;
21 | import android.graphics.Canvas;
22 | import android.graphics.Color;
23 | import android.graphics.Paint;
24 | import android.media.ExifInterface;
25 | import android.graphics.Matrix;
26 | import android.net.Uri;
27 | import android.os.Bundle;
28 | import android.util.Log;
29 | import android.view.View;
30 | import android.widget.Button;
31 | import android.widget.ImageView;
32 |
33 | import java.io.FileNotFoundException;
34 | import java.io.InputStream;
35 | import java.io.IOException;
36 |
37 | public class MainActivity extends Activity
38 | {
39 | private static final int SELECT_IMAGE = 1;
40 |
41 | private ImageView imageView;
42 | private Bitmap bitmap = null;
43 | private Bitmap yourSelectedImage = null;
44 |
45 | private YoloV5Ncnn yolov5ncnn = new YoloV5Ncnn();
46 |
47 | /** Called when the activity is first created. */
48 | @Override
49 | public void onCreate(Bundle savedInstanceState)
50 | {
51 | super.onCreate(savedInstanceState);
52 | setContentView(R.layout.main);
53 |
54 | boolean ret_init = yolov5ncnn.Init(getAssets());
55 | if (!ret_init)
56 | {
57 | Log.e("MainActivity", "yolov5ncnn Init failed");
58 | }
59 |
60 | imageView = (ImageView) findViewById(R.id.imageView);
61 |
62 | Button buttonImage = (Button) findViewById(R.id.buttonImage);
63 | buttonImage.setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View arg0) {
66 | Intent i = new Intent(Intent.ACTION_PICK);
67 | i.setType("image/*");
68 | startActivityForResult(i, SELECT_IMAGE);
69 | }
70 | });
71 |
72 | Button buttonDetect = (Button) findViewById(R.id.buttonDetect);
73 | buttonDetect.setOnClickListener(new View.OnClickListener() {
74 | @Override
75 | public void onClick(View arg0) {
76 | if (yourSelectedImage == null)
77 | return;
78 |
79 | YoloV5Ncnn.Obj[] objects = yolov5ncnn.Detect(yourSelectedImage, false);
80 |
81 | showObjects(objects);
82 | }
83 | });
84 |
85 | Button buttonDetectGPU = (Button) findViewById(R.id.buttonDetectGPU);
86 | buttonDetectGPU.setOnClickListener(new View.OnClickListener() {
87 | @Override
88 | public void onClick(View arg0) {
89 | if (yourSelectedImage == null)
90 | return;
91 |
92 | YoloV5Ncnn.Obj[] objects = yolov5ncnn.Detect(yourSelectedImage, true);
93 |
94 | showObjects(objects);
95 | }
96 | });
97 | }
98 |
99 | private void showObjects(YoloV5Ncnn.Obj[] objects)
100 | {
101 | if (objects == null)
102 | {
103 | imageView.setImageBitmap(bitmap);
104 | return;
105 | }
106 |
107 | // draw objects on bitmap
108 | Bitmap rgba = bitmap.copy(Bitmap.Config.ARGB_8888, true);
109 |
110 | final int[] colors = new int[] {
111 | Color.rgb( 54, 67, 244),
112 | Color.rgb( 99, 30, 233),
113 | Color.rgb(176, 39, 156),
114 | Color.rgb(183, 58, 103),
115 | Color.rgb(181, 81, 63),
116 | Color.rgb(243, 150, 33),
117 | Color.rgb(244, 169, 3),
118 | Color.rgb(212, 188, 0),
119 | Color.rgb(136, 150, 0),
120 | Color.rgb( 80, 175, 76),
121 | Color.rgb( 74, 195, 139),
122 | Color.rgb( 57, 220, 205),
123 | Color.rgb( 59, 235, 255),
124 | Color.rgb( 7, 193, 255),
125 | Color.rgb( 0, 152, 255),
126 | Color.rgb( 34, 87, 255),
127 | Color.rgb( 72, 85, 121),
128 | Color.rgb(158, 158, 158),
129 | Color.rgb(139, 125, 96)
130 | };
131 |
132 | Canvas canvas = new Canvas(rgba);
133 |
134 | Paint paint = new Paint();
135 | paint.setStyle(Paint.Style.STROKE);
136 | paint.setStrokeWidth(4);
137 |
138 | Paint textbgpaint = new Paint();
139 | textbgpaint.setColor(Color.WHITE);
140 | textbgpaint.setStyle(Paint.Style.FILL);
141 |
142 | Paint textpaint = new Paint();
143 | textpaint.setColor(Color.BLACK);
144 | textpaint.setTextSize(26);
145 | textpaint.setTextAlign(Paint.Align.LEFT);
146 |
147 | for (int i = 0; i < objects.length; i++)
148 | {
149 | paint.setColor(colors[i % 19]);
150 |
151 | canvas.drawRect(objects[i].x, objects[i].y, objects[i].x + objects[i].w, objects[i].y + objects[i].h, paint);
152 |
153 | // draw filled text inside image
154 | {
155 | String text = objects[i].label + " = " + String.format("%.1f", objects[i].prob * 100) + "%";
156 |
157 | float text_width = textpaint.measureText(text);
158 | float text_height = - textpaint.ascent() + textpaint.descent();
159 |
160 | float x = objects[i].x;
161 | float y = objects[i].y - text_height;
162 | if (y < 0)
163 | y = 0;
164 | if (x + text_width > rgba.getWidth())
165 | x = rgba.getWidth() - text_width;
166 |
167 | canvas.drawRect(x, y, x + text_width, y + text_height, textbgpaint);
168 |
169 | canvas.drawText(text, x, y - textpaint.ascent(), textpaint);
170 | }
171 | }
172 |
173 | imageView.setImageBitmap(rgba);
174 | }
175 |
176 | @Override
177 | protected void onActivityResult(int requestCode, int resultCode, Intent data)
178 | {
179 | super.onActivityResult(requestCode, resultCode, data);
180 |
181 | if (resultCode == RESULT_OK && null != data) {
182 | Uri selectedImage = data.getData();
183 |
184 | try
185 | {
186 | if (requestCode == SELECT_IMAGE) {
187 | bitmap = decodeUri(selectedImage);
188 |
189 | yourSelectedImage = bitmap.copy(Bitmap.Config.ARGB_8888, true);
190 |
191 | imageView.setImageBitmap(bitmap);
192 | }
193 | }
194 | catch (FileNotFoundException e)
195 | {
196 | Log.e("MainActivity", "FileNotFoundException");
197 | return;
198 | }
199 | }
200 | }
201 |
202 | private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException
203 | {
204 | // Decode image size
205 | BitmapFactory.Options o = new BitmapFactory.Options();
206 | o.inJustDecodeBounds = true;
207 | BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);
208 |
209 | // The new size we want to scale to
210 | final int REQUIRED_SIZE = 640;
211 |
212 | // Find the correct scale value. It should be the power of 2.
213 | int width_tmp = o.outWidth, height_tmp = o.outHeight;
214 | int scale = 1;
215 | while (true) {
216 | if (width_tmp / 2 < REQUIRED_SIZE
217 | || height_tmp / 2 < REQUIRED_SIZE) {
218 | break;
219 | }
220 | width_tmp /= 2;
221 | height_tmp /= 2;
222 | scale *= 2;
223 | }
224 |
225 | // Decode with inSampleSize
226 | BitmapFactory.Options o2 = new BitmapFactory.Options();
227 | o2.inSampleSize = scale;
228 | Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);
229 |
230 | // Rotate according to EXIF
231 | int rotate = 0;
232 | try
233 | {
234 | ExifInterface exif = new ExifInterface(getContentResolver().openInputStream(selectedImage));
235 | int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
236 | switch (orientation) {
237 | case ExifInterface.ORIENTATION_ROTATE_270:
238 | rotate = 270;
239 | break;
240 | case ExifInterface.ORIENTATION_ROTATE_180:
241 | rotate = 180;
242 | break;
243 | case ExifInterface.ORIENTATION_ROTATE_90:
244 | rotate = 90;
245 | break;
246 | }
247 | }
248 | catch (IOException e)
249 | {
250 | Log.e("MainActivity", "ExifInterface IOException");
251 | }
252 |
253 | Matrix matrix = new Matrix();
254 | matrix.postRotate(rotate);
255 | return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
256 | }
257 |
258 | }
259 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tencent/yolov5ncnn/YoloV5Ncnn.java:
--------------------------------------------------------------------------------
1 | // Tencent is pleased to support the open source community by making ncnn available.
2 | //
3 | // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
4 | //
5 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
6 | // in compliance with the License. You may obtain a copy of the License at
7 | //
8 | // https://opensource.org/licenses/BSD-3-Clause
9 | //
10 | // Unless required by applicable law or agreed to in writing, software distributed
11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 | // specific language governing permissions and limitations under the License.
14 |
15 | package com.tencent.yolov5ncnn;
16 |
17 | import android.content.res.AssetManager;
18 | import android.graphics.Bitmap;
19 |
20 | public class YoloV5Ncnn
21 | {
22 | public native boolean Init(AssetManager mgr);
23 |
24 | public class Obj
25 | {
26 | public float x;
27 | public float y;
28 | public float w;
29 | public float h;
30 | public String label;
31 | public float prob;
32 | }
33 |
34 | public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
35 |
36 | static {
37 | System.loadLibrary("yolov5ncnn");
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/jni/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | project(yolov5ncnn)
2 |
3 | cmake_minimum_required(VERSION 3.4.1)
4 |
5 | set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20201218-android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn)
6 | find_package(ncnn REQUIRED)
7 |
8 | add_library(yolov5ncnn SHARED yolov5ncnn_jni.cpp)
9 |
10 | target_link_libraries(yolov5ncnn
11 | ncnn
12 |
13 | jnigraphics
14 | )
15 |
--------------------------------------------------------------------------------
/app/src/main/jni/yolov5ncnn_jni.cpp:
--------------------------------------------------------------------------------
1 | // Tencent is pleased to support the open source community by making ncnn available.
2 | //
3 | // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
4 | //
5 | // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
6 | // in compliance with the License. You may obtain a copy of the License at
7 | //
8 | // https://opensource.org/licenses/BSD-3-Clause
9 | //
10 | // Unless required by applicable law or agreed to in writing, software distributed
11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 | // specific language governing permissions and limitations under the License.
14 |
15 | #include
16 | #include
17 | #include
18 |
19 | #include
20 |
21 | #include
22 | #include
23 |
24 | // ncnn
25 | #include "layer.h"
26 | #include "net.h"
27 | #include "benchmark.h"
28 |
29 | static ncnn::UnlockedPoolAllocator g_blob_pool_allocator;
30 | static ncnn::PoolAllocator g_workspace_pool_allocator;
31 |
32 | static ncnn::Net yolov5;
33 |
34 | class YoloV5Focus : public ncnn::Layer
35 | {
36 | public:
37 | YoloV5Focus()
38 | {
39 | one_blob_only = true;
40 | }
41 |
42 | virtual int forward(const ncnn::Mat& bottom_blob, ncnn::Mat& top_blob, const ncnn::Option& opt) const
43 | {
44 | int w = bottom_blob.w;
45 | int h = bottom_blob.h;
46 | int channels = bottom_blob.c;
47 |
48 | int outw = w / 2;
49 | int outh = h / 2;
50 | int outc = channels * 4;
51 |
52 | top_blob.create(outw, outh, outc, 4u, 1, opt.blob_allocator);
53 | if (top_blob.empty())
54 | return -100;
55 |
56 | #pragma omp parallel for num_threads(opt.num_threads)
57 | for (int p = 0; p < outc; p++)
58 | {
59 | const float* ptr = bottom_blob.channel(p % channels).row((p / channels) % 2) + ((p / channels) / 2);
60 | float* outptr = top_blob.channel(p);
61 |
62 | for (int i = 0; i < outh; i++)
63 | {
64 | for (int j = 0; j < outw; j++)
65 | {
66 | *outptr = *ptr;
67 |
68 | outptr += 1;
69 | ptr += 2;
70 | }
71 |
72 | ptr += w;
73 | }
74 | }
75 |
76 | return 0;
77 | }
78 | };
79 |
80 | DEFINE_LAYER_CREATOR(YoloV5Focus)
81 |
82 | struct Object
83 | {
84 | float x;
85 | float y;
86 | float w;
87 | float h;
88 | int label;
89 | float prob;
90 | };
91 |
92 | static inline float intersection_area(const Object& a, const Object& b)
93 | {
94 | if (a.x > b.x + b.w || a.x + a.w < b.x || a.y > b.y + b.h || a.y + a.h < b.y)
95 | {
96 | // no intersection
97 | return 0.f;
98 | }
99 |
100 | float inter_width = std::min(a.x + a.w, b.x + b.w) - std::max(a.x, b.x);
101 | float inter_height = std::min(a.y + a.h, b.y + b.h) - std::max(a.y, b.y);
102 |
103 | return inter_width * inter_height;
104 | }
105 |
106 | static void qsort_descent_inplace(std::vector