Feng Wang commited on
Commit
7ab6881
·
1 Parent(s): 39bbed9

feat(demo): add android demo of YOLOX

Browse files
demo/ncnn/android/README.md ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLOX-Android-NCNN
2
+
3
+ Andoird app of YOLOX object detection base on [NCNN](https://github.com/Tencent/ncnn)
4
+
5
+
6
+ ## Tutorial
7
+
8
+ ### Step1
9
+
10
+ Download ncnn-android-vulkan.zip from [releases of ncnn](https://github.com/Tencent/ncnn/releases). This repo us
11
+ [20210525 release](https://github.com/Tencent/ncnn/releases/download/20210525/ncnn-20210525-android-vulkan.zip) for building.
12
+
13
+ ### Step2
14
+
15
+ After downloading, please extract your zip file. Then, there are two ways to finish this step:
16
+ * put your extracted directory into app/src/main/jni
17
+ * change the ncnn_DIR path in app/src/main/jni/CMakeLists.txt to your extracted directory.
18
+
19
+ ### Step3
20
+ Open this project with Android Studio, build it and enjoy!
21
+
22
+
23
+ ## Reference
24
+
25
+ * [ncnn-android-yolov5](https://github.com/nihui/ncnn-android-yolov5)
demo/ncnn/android/app/build.gradle ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ apply plugin: 'com.android.application'
2
+
3
+ android {
4
+ compileSdkVersion 24
5
+ buildToolsVersion "29.0.2"
6
+
7
+ defaultConfig {
8
+ applicationId "com.megvii.yoloXncnn"
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
+ }
demo/ncnn/android/app/src/main/AndroidManifest.xml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+ package="com.megvii.yoloXncnn"
4
+ android:versionCode="1"
5
+ android:versionName="1.1">
6
+ <application android:label="@string/app_name" >
7
+ <activity android:name="MainActivity"
8
+ android:label="@string/app_name">
9
+ <intent-filter>
10
+ <action android:name="android.intent.action.MAIN" />
11
+ <category android:name="android.intent.category.LAUNCHER" />
12
+ </intent-filter>
13
+ </activity>
14
+ </application>
15
+ </manifest>
demo/ncnn/android/app/src/main/assets/yolox.param ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 7767517
2
+ 220 250
3
+ Input images 0 1 images
4
+ YoloV5Focus focus 1 1 images 503
5
+ Convolution Conv_41 1 1 503 877 0=32 1=3 4=1 5=1 6=3456
6
+ Swish Mul_43 1 1 877 507
7
+ Convolution Conv_44 1 1 507 880 0=64 1=3 3=2 4=1 5=1 6=18432
8
+ Swish Mul_46 1 1 880 511
9
+ Split splitncnn_0 1 2 511 511_splitncnn_0 511_splitncnn_1
10
+ Convolution Conv_47 1 1 511_splitncnn_1 883 0=32 1=1 5=1 6=2048
11
+ Swish Mul_49 1 1 883 515
12
+ Split splitncnn_1 1 2 515 515_splitncnn_0 515_splitncnn_1
13
+ Convolution Conv_50 1 1 511_splitncnn_0 886 0=32 1=1 5=1 6=2048
14
+ Swish Mul_52 1 1 886 519
15
+ Convolution Conv_53 1 1 515_splitncnn_1 889 0=32 1=1 5=1 6=1024
16
+ Swish Mul_55 1 1 889 523
17
+ Convolution Conv_56 1 1 523 892 0=32 1=3 4=1 5=1 6=9216
18
+ Swish Mul_58 1 1 892 527
19
+ BinaryOp Add_59 2 1 527 515_splitncnn_0 528
20
+ Concat Concat_60 2 1 528 519 529
21
+ Convolution Conv_61 1 1 529 895 0=64 1=1 5=1 6=4096
22
+ Swish Mul_63 1 1 895 533
23
+ Convolution Conv_64 1 1 533 898 0=128 1=3 3=2 4=1 5=1 6=73728
24
+ Swish Mul_66 1 1 898 537
25
+ Split splitncnn_2 1 2 537 537_splitncnn_0 537_splitncnn_1
26
+ Convolution Conv_67 1 1 537_splitncnn_1 901 0=64 1=1 5=1 6=8192
27
+ Swish Mul_69 1 1 901 541
28
+ Split splitncnn_3 1 2 541 541_splitncnn_0 541_splitncnn_1
29
+ Convolution Conv_70 1 1 537_splitncnn_0 904 0=64 1=1 5=1 6=8192
30
+ Swish Mul_72 1 1 904 545
31
+ Convolution Conv_73 1 1 541_splitncnn_1 907 0=64 1=1 5=1 6=4096
32
+ Swish Mul_75 1 1 907 549
33
+ Convolution Conv_76 1 1 549 910 0=64 1=3 4=1 5=1 6=36864
34
+ Swish Mul_78 1 1 910 553
35
+ BinaryOp Add_79 2 1 553 541_splitncnn_0 554
36
+ Split splitncnn_4 1 2 554 554_splitncnn_0 554_splitncnn_1
37
+ Convolution Conv_80 1 1 554_splitncnn_1 913 0=64 1=1 5=1 6=4096
38
+ Swish Mul_82 1 1 913 558
39
+ Convolution Conv_83 1 1 558 916 0=64 1=3 4=1 5=1 6=36864
40
+ Swish Mul_85 1 1 916 562
41
+ BinaryOp Add_86 2 1 562 554_splitncnn_0 563
42
+ Split splitncnn_5 1 2 563 563_splitncnn_0 563_splitncnn_1
43
+ Convolution Conv_87 1 1 563_splitncnn_1 919 0=64 1=1 5=1 6=4096
44
+ Swish Mul_89 1 1 919 567
45
+ Convolution Conv_90 1 1 567 922 0=64 1=3 4=1 5=1 6=36864
46
+ Swish Mul_92 1 1 922 571
47
+ BinaryOp Add_93 2 1 571 563_splitncnn_0 572
48
+ Concat Concat_94 2 1 572 545 573
49
+ Convolution Conv_95 1 1 573 925 0=128 1=1 5=1 6=16384
50
+ Swish Mul_97 1 1 925 577
51
+ Split splitncnn_6 1 2 577 577_splitncnn_0 577_splitncnn_1
52
+ Convolution Conv_98 1 1 577_splitncnn_1 928 0=256 1=3 3=2 4=1 5=1 6=294912
53
+ Swish Mul_100 1 1 928 581
54
+ Split splitncnn_7 1 2 581 581_splitncnn_0 581_splitncnn_1
55
+ Convolution Conv_101 1 1 581_splitncnn_1 931 0=128 1=1 5=1 6=32768
56
+ Swish Mul_103 1 1 931 585
57
+ Split splitncnn_8 1 2 585 585_splitncnn_0 585_splitncnn_1
58
+ Convolution Conv_104 1 1 581_splitncnn_0 934 0=128 1=1 5=1 6=32768
59
+ Swish Mul_106 1 1 934 589
60
+ Convolution Conv_107 1 1 585_splitncnn_1 937 0=128 1=1 5=1 6=16384
61
+ Swish Mul_109 1 1 937 593
62
+ Convolution Conv_110 1 1 593 940 0=128 1=3 4=1 5=1 6=147456
63
+ Swish Mul_112 1 1 940 597
64
+ BinaryOp Add_113 2 1 597 585_splitncnn_0 598
65
+ Split splitncnn_9 1 2 598 598_splitncnn_0 598_splitncnn_1
66
+ Convolution Conv_114 1 1 598_splitncnn_1 943 0=128 1=1 5=1 6=16384
67
+ Swish Mul_116 1 1 943 602
68
+ Convolution Conv_117 1 1 602 946 0=128 1=3 4=1 5=1 6=147456
69
+ Swish Mul_119 1 1 946 606
70
+ BinaryOp Add_120 2 1 606 598_splitncnn_0 607
71
+ Split splitncnn_10 1 2 607 607_splitncnn_0 607_splitncnn_1
72
+ Convolution Conv_121 1 1 607_splitncnn_1 949 0=128 1=1 5=1 6=16384
73
+ Swish Mul_123 1 1 949 611
74
+ Convolution Conv_124 1 1 611 952 0=128 1=3 4=1 5=1 6=147456
75
+ Swish Mul_126 1 1 952 615
76
+ BinaryOp Add_127 2 1 615 607_splitncnn_0 616
77
+ Concat Concat_128 2 1 616 589 617
78
+ Convolution Conv_129 1 1 617 955 0=256 1=1 5=1 6=65536
79
+ Swish Mul_131 1 1 955 621
80
+ Split splitncnn_11 1 2 621 621_splitncnn_0 621_splitncnn_1
81
+ Convolution Conv_132 1 1 621_splitncnn_1 958 0=512 1=3 3=2 4=1 5=1 6=1179648
82
+ Swish Mul_134 1 1 958 625
83
+ Convolution Conv_135 1 1 625 961 0=256 1=1 5=1 6=131072
84
+ Swish Mul_137 1 1 961 629
85
+ Split splitncnn_12 1 4 629 629_splitncnn_0 629_splitncnn_1 629_splitncnn_2 629_splitncnn_3
86
+ Pooling MaxPool_138 1 1 629_splitncnn_3 630 1=5 3=2 5=1
87
+ Pooling MaxPool_139 1 1 629_splitncnn_2 631 1=9 3=4 5=1
88
+ Pooling MaxPool_140 1 1 629_splitncnn_1 632 1=13 3=6 5=1
89
+ Concat Concat_141 4 1 629_splitncnn_0 630 631 632 633
90
+ Convolution Conv_142 1 1 633 964 0=512 1=1 5=1 6=524288
91
+ Swish Mul_144 1 1 964 637
92
+ Split splitncnn_13 1 2 637 637_splitncnn_0 637_splitncnn_1
93
+ Convolution Conv_145 1 1 637_splitncnn_1 967 0=256 1=1 5=1 6=131072
94
+ Swish Mul_147 1 1 967 641
95
+ Convolution Conv_148 1 1 637_splitncnn_0 970 0=256 1=1 5=1 6=131072
96
+ Swish Mul_150 1 1 970 645
97
+ Convolution Conv_151 1 1 641 973 0=256 1=1 5=1 6=65536
98
+ Swish Mul_153 1 1 973 649
99
+ Convolution Conv_154 1 1 649 976 0=256 1=3 4=1 5=1 6=589824
100
+ Swish Mul_156 1 1 976 653
101
+ Concat Concat_157 2 1 653 645 654
102
+ Convolution Conv_158 1 1 654 979 0=512 1=1 5=1 6=262144
103
+ Swish Mul_160 1 1 979 658
104
+ Convolution Conv_161 1 1 658 982 0=256 1=1 5=1 6=131072
105
+ Swish Mul_163 1 1 982 662
106
+ Split splitncnn_14 1 2 662 662_splitncnn_0 662_splitncnn_1
107
+ Interp Resize_165 1 1 662_splitncnn_1 667 0=1 1=2.000000e+00 2=2.000000e+00
108
+ Concat Concat_166 2 1 667 621_splitncnn_0 668
109
+ Split splitncnn_15 1 2 668 668_splitncnn_0 668_splitncnn_1
110
+ Convolution Conv_167 1 1 668_splitncnn_1 985 0=128 1=1 5=1 6=65536
111
+ Swish Mul_169 1 1 985 672
112
+ Convolution Conv_170 1 1 668_splitncnn_0 988 0=128 1=1 5=1 6=65536
113
+ Swish Mul_172 1 1 988 676
114
+ Convolution Conv_173 1 1 672 991 0=128 1=1 5=1 6=16384
115
+ Swish Mul_175 1 1 991 680
116
+ Convolution Conv_176 1 1 680 994 0=128 1=3 4=1 5=1 6=147456
117
+ Swish Mul_178 1 1 994 684
118
+ Concat Concat_179 2 1 684 676 685
119
+ Convolution Conv_180 1 1 685 997 0=256 1=1 5=1 6=65536
120
+ Swish Mul_182 1 1 997 689
121
+ Convolution Conv_183 1 1 689 1000 0=128 1=1 5=1 6=32768
122
+ Swish Mul_185 1 1 1000 693
123
+ Split splitncnn_16 1 2 693 693_splitncnn_0 693_splitncnn_1
124
+ Interp Resize_187 1 1 693_splitncnn_1 698 0=1 1=2.000000e+00 2=2.000000e+00
125
+ Concat Concat_188 2 1 698 577_splitncnn_0 699
126
+ Split splitncnn_17 1 2 699 699_splitncnn_0 699_splitncnn_1
127
+ Convolution Conv_189 1 1 699_splitncnn_1 1003 0=64 1=1 5=1 6=16384
128
+ Swish Mul_191 1 1 1003 703
129
+ Convolution Conv_192 1 1 699_splitncnn_0 1006 0=64 1=1 5=1 6=16384
130
+ Swish Mul_194 1 1 1006 707
131
+ Convolution Conv_195 1 1 703 1009 0=64 1=1 5=1 6=4096
132
+ Swish Mul_197 1 1 1009 711
133
+ Convolution Conv_198 1 1 711 1012 0=64 1=3 4=1 5=1 6=36864
134
+ Swish Mul_200 1 1 1012 715
135
+ Concat Concat_201 2 1 715 707 716
136
+ Convolution Conv_202 1 1 716 1015 0=128 1=1 5=1 6=16384
137
+ Swish Mul_204 1 1 1015 720
138
+ Split splitncnn_18 1 2 720 720_splitncnn_0 720_splitncnn_1
139
+ Convolution Conv_205 1 1 720_splitncnn_1 1018 0=128 1=3 3=2 4=1 5=1 6=147456
140
+ Swish Mul_207 1 1 1018 724
141
+ Concat Concat_208 2 1 724 693_splitncnn_0 725
142
+ Split splitncnn_19 1 2 725 725_splitncnn_0 725_splitncnn_1
143
+ Convolution Conv_209 1 1 725_splitncnn_1 1021 0=128 1=1 5=1 6=32768
144
+ Swish Mul_211 1 1 1021 729
145
+ Convolution Conv_212 1 1 725_splitncnn_0 1024 0=128 1=1 5=1 6=32768
146
+ Swish Mul_214 1 1 1024 733
147
+ Convolution Conv_215 1 1 729 1027 0=128 1=1 5=1 6=16384
148
+ Swish Mul_217 1 1 1027 737
149
+ Convolution Conv_218 1 1 737 1030 0=128 1=3 4=1 5=1 6=147456
150
+ Swish Mul_220 1 1 1030 741
151
+ Concat Concat_221 2 1 741 733 742
152
+ Convolution Conv_222 1 1 742 1033 0=256 1=1 5=1 6=65536
153
+ Swish Mul_224 1 1 1033 746
154
+ Split splitncnn_20 1 2 746 746_splitncnn_0 746_splitncnn_1
155
+ Convolution Conv_225 1 1 746_splitncnn_1 1036 0=256 1=3 3=2 4=1 5=1 6=589824
156
+ Swish Mul_227 1 1 1036 750
157
+ Concat Concat_228 2 1 750 662_splitncnn_0 751
158
+ Split splitncnn_21 1 2 751 751_splitncnn_0 751_splitncnn_1
159
+ Convolution Conv_229 1 1 751_splitncnn_1 1039 0=256 1=1 5=1 6=131072
160
+ Swish Mul_231 1 1 1039 755
161
+ Convolution Conv_232 1 1 751_splitncnn_0 1042 0=256 1=1 5=1 6=131072
162
+ Swish Mul_234 1 1 1042 759
163
+ Convolution Conv_235 1 1 755 1045 0=256 1=1 5=1 6=65536
164
+ Swish Mul_237 1 1 1045 763
165
+ Convolution Conv_238 1 1 763 1048 0=256 1=3 4=1 5=1 6=589824
166
+ Swish Mul_240 1 1 1048 767
167
+ Concat Concat_241 2 1 767 759 768
168
+ Convolution Conv_242 1 1 768 1051 0=512 1=1 5=1 6=262144
169
+ Swish Mul_244 1 1 1051 772
170
+ Convolution Conv_245 1 1 720_splitncnn_0 1054 0=128 1=1 5=1 6=16384
171
+ Swish Mul_247 1 1 1054 776
172
+ Split splitncnn_22 1 2 776 776_splitncnn_0 776_splitncnn_1
173
+ Convolution Conv_248 1 1 776_splitncnn_1 1057 0=128 1=3 4=1 5=1 6=147456
174
+ Swish Mul_250 1 1 1057 780
175
+ Convolution Conv_251 1 1 780 1060 0=128 1=3 4=1 5=1 6=147456
176
+ Swish Mul_253 1 1 1060 784
177
+ Convolution Conv_254 1 1 784 797 0=80 1=1 5=1 6=10240 9=4
178
+ Convolution Conv_255 1 1 776_splitncnn_0 1063 0=128 1=3 4=1 5=1 6=147456
179
+ Swish Mul_257 1 1 1063 789
180
+ Convolution Conv_258 1 1 789 1066 0=128 1=3 4=1 5=1 6=147456
181
+ Swish Mul_260 1 1 1066 793
182
+ Split splitncnn_23 1 2 793 793_splitncnn_0 793_splitncnn_1
183
+ Convolution Conv_261 1 1 793_splitncnn_1 794 0=4 1=1 5=1 6=512
184
+ Convolution Conv_262 1 1 793_splitncnn_0 796 0=1 1=1 5=1 6=128 9=4
185
+ Concat Concat_265 3 1 794 796 797 798
186
+ Convolution Conv_266 1 1 746_splitncnn_0 1069 0=128 1=1 5=1 6=32768
187
+ Swish Mul_268 1 1 1069 802
188
+ Split splitncnn_24 1 2 802 802_splitncnn_0 802_splitncnn_1
189
+ Convolution Conv_269 1 1 802_splitncnn_1 1072 0=128 1=3 4=1 5=1 6=147456
190
+ Swish Mul_271 1 1 1072 806
191
+ Convolution Conv_272 1 1 806 1075 0=128 1=3 4=1 5=1 6=147456
192
+ Swish Mul_274 1 1 1075 810
193
+ Convolution Conv_275 1 1 810 823 0=80 1=1 5=1 6=10240 9=4
194
+ Convolution Conv_276 1 1 802_splitncnn_0 1078 0=128 1=3 4=1 5=1 6=147456
195
+ Swish Mul_278 1 1 1078 815
196
+ Convolution Conv_279 1 1 815 1081 0=128 1=3 4=1 5=1 6=147456
197
+ Swish Mul_281 1 1 1081 819
198
+ Split splitncnn_25 1 2 819 819_splitncnn_0 819_splitncnn_1
199
+ Convolution Conv_282 1 1 819_splitncnn_1 820 0=4 1=1 5=1 6=512
200
+ Convolution Conv_283 1 1 819_splitncnn_0 822 0=1 1=1 5=1 6=128 9=4
201
+ Concat Concat_286 3 1 820 822 823 824
202
+ Convolution Conv_287 1 1 772 1084 0=128 1=1 5=1 6=65536
203
+ Swish Mul_289 1 1 1084 828
204
+ Split splitncnn_26 1 2 828 828_splitncnn_0 828_splitncnn_1
205
+ Convolution Conv_290 1 1 828_splitncnn_1 1087 0=128 1=3 4=1 5=1 6=147456
206
+ Swish Mul_292 1 1 1087 832
207
+ Convolution Conv_293 1 1 832 1090 0=128 1=3 4=1 5=1 6=147456
208
+ Swish Mul_295 1 1 1090 836
209
+ Convolution Conv_296 1 1 836 849 0=80 1=1 5=1 6=10240 9=4
210
+ Convolution Conv_297 1 1 828_splitncnn_0 1093 0=128 1=3 4=1 5=1 6=147456
211
+ Swish Mul_299 1 1 1093 841
212
+ Convolution Conv_300 1 1 841 1096 0=128 1=3 4=1 5=1 6=147456
213
+ Swish Mul_302 1 1 1096 845
214
+ Split splitncnn_27 1 2 845 845_splitncnn_0 845_splitncnn_1
215
+ Convolution Conv_303 1 1 845_splitncnn_1 846 0=4 1=1 5=1 6=512
216
+ Convolution Conv_304 1 1 845_splitncnn_0 848 0=1 1=1 5=1 6=128 9=4
217
+ Concat Concat_307 3 1 846 848 849 850
218
+ Reshape Reshape_315 1 1 798 858 0=-1 1=85
219
+ Reshape Reshape_323 1 1 824 866 0=-1 1=85
220
+ Reshape Reshape_331 1 1 850 874 0=-1 1=85
221
+ Concat Concat_332 3 1 858 866 874 875 0=1
222
+ Permute Transpose_333 1 1 875 output 0=1
demo/ncnn/android/app/src/main/java/com/megvii/yoloXncnn/MainActivity.java ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Some code in this file is based on:
2
+ // https://github.com/nihui/ncnn-android-yolov5/blob/master/app/src/main/java/com/tencent/yolov5ncnn/MainActivity.java
3
+ // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
4
+ // Copyright (C) Megvii, Inc. and its affiliates. All rights reserved.
5
+
6
+ package com.megvii.yoloXncnn;
7
+
8
+ import android.app.Activity;
9
+ import android.content.Intent;
10
+ import android.graphics.Bitmap;
11
+ import android.graphics.BitmapFactory;
12
+ import android.graphics.Canvas;
13
+ import android.graphics.Color;
14
+ import android.graphics.Paint;
15
+ import android.media.ExifInterface;
16
+ import android.graphics.Matrix;
17
+ import android.net.Uri;
18
+ import android.os.Bundle;
19
+ import android.util.Log;
20
+ import android.view.View;
21
+ import android.widget.Button;
22
+ import android.widget.ImageView;
23
+
24
+ import java.io.FileNotFoundException;
25
+ import java.io.InputStream;
26
+ import java.io.IOException;
27
+
28
+ public class MainActivity extends Activity
29
+ {
30
+ private static final int SELECT_IMAGE = 1;
31
+
32
+ private ImageView imageView;
33
+ private Bitmap bitmap = null;
34
+ private Bitmap yourSelectedImage = null;
35
+
36
+ private YOLOXncnn yoloX = new YOLOXncnn();
37
+
38
+ /** Called when the activity is first created. */
39
+ @Override
40
+ public void onCreate(Bundle savedInstanceState)
41
+ {
42
+ super.onCreate(savedInstanceState);
43
+ setContentView(R.layout.main);
44
+
45
+ boolean ret_init = yoloX.Init(getAssets());
46
+ if (!ret_init)
47
+ {
48
+ Log.e("MainActivity", "yoloXncnn Init failed");
49
+ }
50
+
51
+ imageView = (ImageView) findViewById(R.id.imageView);
52
+
53
+ Button buttonImage = (Button) findViewById(R.id.buttonImage);
54
+ buttonImage.setOnClickListener(new View.OnClickListener() {
55
+ @Override
56
+ public void onClick(View arg0) {
57
+ Intent i = new Intent(Intent.ACTION_PICK);
58
+ i.setType("image/*");
59
+ startActivityForResult(i, SELECT_IMAGE);
60
+ }
61
+ });
62
+
63
+ Button buttonDetect = (Button) findViewById(R.id.buttonDetect);
64
+ buttonDetect.setOnClickListener(new View.OnClickListener() {
65
+ @Override
66
+ public void onClick(View arg0) {
67
+ if (yourSelectedImage == null)
68
+ return;
69
+ YOLOXncnn.Obj[] objects = yoloX.Detect(yourSelectedImage, false);
70
+
71
+ showObjects(objects);
72
+ }
73
+ });
74
+
75
+ Button buttonDetectGPU = (Button) findViewById(R.id.buttonDetectGPU);
76
+ buttonDetectGPU.setOnClickListener(new View.OnClickListener() {
77
+ @Override
78
+ public void onClick(View arg0) {
79
+ if (yourSelectedImage == null)
80
+ return;
81
+
82
+ YOLOXncnn.Obj[] objects = yoloX.Detect(yourSelectedImage, true);
83
+
84
+ showObjects(objects);
85
+ }
86
+ });
87
+ }
88
+
89
+ private void showObjects(YOLOXncnn.Obj[] objects)
90
+ {
91
+ if (objects == null)
92
+ {
93
+ imageView.setImageBitmap(bitmap);
94
+ return;
95
+ }
96
+
97
+ // draw objects on bitmap
98
+ Bitmap rgba = bitmap.copy(Bitmap.Config.ARGB_8888, true);
99
+
100
+ final int[] colors = new int[] {
101
+ Color.rgb( 54, 67, 244),
102
+ Color.rgb( 99, 30, 233),
103
+ Color.rgb(176, 39, 156),
104
+ Color.rgb(183, 58, 103),
105
+ Color.rgb(181, 81, 63),
106
+ Color.rgb(243, 150, 33),
107
+ Color.rgb(244, 169, 3),
108
+ Color.rgb(212, 188, 0),
109
+ Color.rgb(136, 150, 0),
110
+ Color.rgb( 80, 175, 76),
111
+ Color.rgb( 74, 195, 139),
112
+ Color.rgb( 57, 220, 205),
113
+ Color.rgb( 59, 235, 255),
114
+ Color.rgb( 7, 193, 255),
115
+ Color.rgb( 0, 152, 255),
116
+ Color.rgb( 34, 87, 255),
117
+ Color.rgb( 72, 85, 121),
118
+ Color.rgb(158, 158, 158),
119
+ Color.rgb(139, 125, 96)
120
+ };
121
+
122
+ Canvas canvas = new Canvas(rgba);
123
+
124
+ Paint paint = new Paint();
125
+ paint.setStyle(Paint.Style.STROKE);
126
+ paint.setStrokeWidth(4);
127
+
128
+ Paint textbgpaint = new Paint();
129
+ textbgpaint.setColor(Color.WHITE);
130
+ textbgpaint.setStyle(Paint.Style.FILL);
131
+
132
+ Paint textpaint = new Paint();
133
+ textpaint.setColor(Color.BLACK);
134
+ textpaint.setTextSize(26);
135
+ textpaint.setTextAlign(Paint.Align.LEFT);
136
+
137
+ for (int i = 0; i < objects.length; i++)
138
+ {
139
+ paint.setColor(colors[i % 19]);
140
+
141
+ canvas.drawRect(objects[i].x, objects[i].y, objects[i].x + objects[i].w, objects[i].y + objects[i].h, paint);
142
+
143
+ // draw filled text inside image
144
+ {
145
+ String text = objects[i].label + " = " + String.format("%.1f", objects[i].prob * 100) + "%";
146
+
147
+ float text_width = textpaint.measureText(text);
148
+ float text_height = - textpaint.ascent() + textpaint.descent();
149
+
150
+ float x = objects[i].x;
151
+ float y = objects[i].y - text_height;
152
+ if (y < 0)
153
+ y = 0;
154
+ if (x + text_width > rgba.getWidth())
155
+ x = rgba.getWidth() - text_width;
156
+
157
+ canvas.drawRect(x, y, x + text_width, y + text_height, textbgpaint);
158
+
159
+ canvas.drawText(text, x, y - textpaint.ascent(), textpaint);
160
+ }
161
+ }
162
+
163
+ imageView.setImageBitmap(rgba);
164
+ }
165
+
166
+ @Override
167
+ protected void onActivityResult(int requestCode, int resultCode, Intent data)
168
+ {
169
+ super.onActivityResult(requestCode, resultCode, data);
170
+
171
+ if (resultCode == RESULT_OK && null != data) {
172
+ Uri selectedImage = data.getData();
173
+
174
+ try
175
+ {
176
+ if (requestCode == SELECT_IMAGE) {
177
+ bitmap = decodeUri(selectedImage);
178
+
179
+ yourSelectedImage = bitmap.copy(Bitmap.Config.ARGB_8888, true);
180
+
181
+ imageView.setImageBitmap(bitmap);
182
+ }
183
+ }
184
+ catch (FileNotFoundException e)
185
+ {
186
+ Log.e("MainActivity", "FileNotFoundException");
187
+ return;
188
+ }
189
+ }
190
+ }
191
+
192
+ private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException
193
+ {
194
+ // Decode image size
195
+ BitmapFactory.Options o = new BitmapFactory.Options();
196
+ o.inJustDecodeBounds = true;
197
+ BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);
198
+
199
+ // The new size we want to scale to
200
+ final int REQUIRED_SIZE = 640;
201
+
202
+ // Find the correct scale value. It should be the power of 2.
203
+ int width_tmp = o.outWidth, height_tmp = o.outHeight;
204
+ int scale = 1;
205
+ while (true) {
206
+ if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
207
+ break;
208
+ }
209
+ width_tmp /= 2;
210
+ height_tmp /= 2;
211
+ scale *= 2;
212
+ }
213
+
214
+ // Decode with inSampleSize
215
+ BitmapFactory.Options o2 = new BitmapFactory.Options();
216
+ o2.inSampleSize = scale;
217
+ Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);
218
+
219
+ // Rotate according to EXIF
220
+ int rotate = 0;
221
+ try
222
+ {
223
+ ExifInterface exif = new ExifInterface(getContentResolver().openInputStream(selectedImage));
224
+ int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
225
+ switch (orientation) {
226
+ case ExifInterface.ORIENTATION_ROTATE_270:
227
+ rotate = 270;
228
+ break;
229
+ case ExifInterface.ORIENTATION_ROTATE_180:
230
+ rotate = 180;
231
+ break;
232
+ case ExifInterface.ORIENTATION_ROTATE_90:
233
+ rotate = 90;
234
+ break;
235
+ }
236
+ }
237
+ catch (IOException e)
238
+ {
239
+ Log.e("MainActivity", "ExifInterface IOException");
240
+ }
241
+
242
+ Matrix matrix = new Matrix();
243
+ matrix.postRotate(rotate);
244
+ return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
245
+ }
246
+
247
+ }
demo/ncnn/android/app/src/main/java/com/megvii/yoloXncnn/YOLOXncnn.java ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (C) Megvii, Inc. and its affiliates. All rights reserved.
2
+
3
+ package com.megvii.yoloXncnn;
4
+
5
+ import android.content.res.AssetManager;
6
+ import android.graphics.Bitmap;
7
+
8
+ public class YOLOXncnn
9
+ {
10
+ public native boolean Init(AssetManager mgr);
11
+
12
+ public class Obj
13
+ {
14
+ public float x;
15
+ public float y;
16
+ public float w;
17
+ public float h;
18
+ public String label;
19
+ public float prob;
20
+ }
21
+
22
+ public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
23
+
24
+ static {
25
+ System.loadLibrary("yoloXncnn");
26
+ }
27
+ }
demo/ncnn/android/app/src/main/java/com/megvii/yoloXncnn/yoloXncnn.java ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (C) Megvii, Inc. and its affiliates. All rights reserved.
2
+
3
+ package com.megvii.yoloXncnn;
4
+
5
+ import android.content.res.AssetManager;
6
+ import android.graphics.Bitmap;
7
+
8
+ public class YOLOXncnn
9
+ {
10
+ public native boolean Init(AssetManager mgr);
11
+
12
+ public class Obj
13
+ {
14
+ public float x;
15
+ public float y;
16
+ public float w;
17
+ public float h;
18
+ public String label;
19
+ public float prob;
20
+ }
21
+
22
+ public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
23
+
24
+ static {
25
+ System.loadLibrary("yoloXncnn");
26
+ }
27
+ }
demo/ncnn/android/app/src/main/jni/CMakeLists.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project(yoloXncnn)
2
+
3
+ cmake_minimum_required(VERSION 3.4.1)
4
+
5
+ set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20210525-android-vulkan/${ANDROID_ABI}/lib/cmake/ncnn)
6
+ find_package(ncnn REQUIRED)
7
+
8
+ add_library(yoloXncnn SHARED yoloXncnn_jni.cpp)
9
+
10
+ target_link_libraries(yoloXncnn
11
+ ncnn
12
+
13
+ jnigraphics
14
+ )
demo/ncnn/android/app/src/main/jni/yoloXncnn_jni.cpp ADDED
@@ -0,0 +1,480 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Some code in this file is based on:
2
+ // https://github.com/nihui/ncnn-android-yolov5/blob/master/app/src/main/jni/yolov5ncnn_jni.cpp
3
+ // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
4
+ // Copyright (C) Megvii, Inc. and its affiliates. All rights reserved.
5
+
6
+ #include <android/asset_manager_jni.h>
7
+ #include <android/bitmap.h>
8
+ #include <android/log.h>
9
+
10
+ #include <jni.h>
11
+
12
+ #include <string>
13
+ #include <vector>
14
+
15
+ // ncnn
16
+ #include "layer.h"
17
+ #include "net.h"
18
+ #include "benchmark.h"
19
+
20
+ static ncnn::UnlockedPoolAllocator g_blob_pool_allocator;
21
+ static ncnn::PoolAllocator g_workspace_pool_allocator;
22
+
23
+ static ncnn::Net yoloX;
24
+
25
+ class YoloV5Focus : public ncnn::Layer
26
+ {
27
+ public:
28
+ YoloV5Focus()
29
+ {
30
+ one_blob_only = true;
31
+ }
32
+
33
+ virtual int forward(const ncnn::Mat& bottom_blob, ncnn::Mat& top_blob, const ncnn::Option& opt) const
34
+ {
35
+ int w = bottom_blob.w;
36
+ int h = bottom_blob.h;
37
+ int channels = bottom_blob.c;
38
+
39
+ int outw = w / 2;
40
+ int outh = h / 2;
41
+ int outc = channels * 4;
42
+
43
+ top_blob.create(outw, outh, outc, 4u, 1, opt.blob_allocator);
44
+ if (top_blob.empty())
45
+ return -100;
46
+
47
+ #pragma omp parallel for num_threads(opt.num_threads)
48
+ for (int p = 0; p < outc; p++)
49
+ {
50
+ const float* ptr = bottom_blob.channel(p % channels).row((p / channels) % 2) + ((p / channels) / 2);
51
+ float* outptr = top_blob.channel(p);
52
+
53
+ for (int i = 0; i < outh; i++)
54
+ {
55
+ for (int j = 0; j < outw; j++)
56
+ {
57
+ *outptr = *ptr;
58
+
59
+ outptr += 1;
60
+ ptr += 2;
61
+ }
62
+
63
+ ptr += w;
64
+ }
65
+ }
66
+
67
+ return 0;
68
+ }
69
+ };
70
+
71
+ DEFINE_LAYER_CREATOR(YoloV5Focus)
72
+
73
+ struct Object
74
+ {
75
+ float x;
76
+ float y;
77
+ float w;
78
+ float h;
79
+ int label;
80
+ float prob;
81
+ };
82
+
83
+ struct GridAndStride
84
+ {
85
+ int grid0;
86
+ int grid1;
87
+ int stride;
88
+ };
89
+
90
+ static inline float intersection_area(const Object& a, const Object& b)
91
+ {
92
+ 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)
93
+ {
94
+ // no intersection
95
+ return 0.f;
96
+ }
97
+
98
+ float inter_width = std::min(a.x + a.w, b.x + b.w) - std::max(a.x, b.x);
99
+ float inter_height = std::min(a.y + a.h, b.y + b.h) - std::max(a.y, b.y);
100
+
101
+ return inter_width * inter_height;
102
+ }
103
+
104
+ static void qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right)
105
+ {
106
+ int i = left;
107
+ int j = right;
108
+ float p = faceobjects[(left + right) / 2].prob;
109
+
110
+ while (i <= j)
111
+ {
112
+ while (faceobjects[i].prob > p)
113
+ i++;
114
+
115
+ while (faceobjects[j].prob < p)
116
+ j--;
117
+
118
+ if (i <= j)
119
+ {
120
+ // swap
121
+ std::swap(faceobjects[i], faceobjects[j]);
122
+
123
+ i++;
124
+ j--;
125
+ }
126
+ }
127
+
128
+ #pragma omp parallel sections
129
+ {
130
+ #pragma omp section
131
+ {
132
+ if (left < j) qsort_descent_inplace(faceobjects, left, j);
133
+ }
134
+ #pragma omp section
135
+ {
136
+ if (i < right) qsort_descent_inplace(faceobjects, i, right);
137
+ }
138
+ }
139
+ }
140
+
141
+ static void qsort_descent_inplace(std::vector<Object>& faceobjects)
142
+ {
143
+ if (faceobjects.empty())
144
+ return;
145
+
146
+ qsort_descent_inplace(faceobjects, 0, faceobjects.size() - 1);
147
+ }
148
+
149
+ static void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>& picked, float nms_threshold)
150
+ {
151
+ picked.clear();
152
+
153
+ const int n = faceobjects.size();
154
+
155
+ std::vector<float> areas(n);
156
+ for (int i = 0; i < n; i++)
157
+ {
158
+ areas[i] = faceobjects[i].w * faceobjects[i].h;
159
+ }
160
+
161
+ for (int i = 0; i < n; i++)
162
+ {
163
+ const Object& a = faceobjects[i];
164
+
165
+ int keep = 1;
166
+ for (int j = 0; j < (int)picked.size(); j++)
167
+ {
168
+ const Object& b = faceobjects[picked[j]];
169
+
170
+ // intersection over union
171
+ float inter_area = intersection_area(a, b);
172
+ float union_area = areas[i] + areas[picked[j]] - inter_area;
173
+ // float IoU = inter_area / union_area
174
+ if (inter_area / union_area > nms_threshold)
175
+ keep = 0;
176
+ }
177
+
178
+ if (keep)
179
+ picked.push_back(i);
180
+ }
181
+ }
182
+
183
+ static void generate_grids_and_stride(const int target_size, std::vector<int>& strides, std::vector<GridAndStride>& grid_strides)
184
+ {
185
+ for (auto stride : strides)
186
+ {
187
+ int num_grid = target_size / stride;
188
+ for (int g1 = 0; g1 < num_grid; g1++)
189
+ {
190
+ for (int g0 = 0; g0 < num_grid; g0++)
191
+ {
192
+ grid_strides.push_back((GridAndStride){g0, g1, stride});
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ static void generate_yolox_proposals(std::vector<GridAndStride> grid_strides, const ncnn::Mat& feat_blob, float prob_threshold, std::vector<Object>& objects)
199
+ {
200
+ const int num_grid = feat_blob.h;
201
+ fprintf(stderr, "output height: %d, width: %d, channels: %d, dims:%d\n", feat_blob.h, feat_blob.w, feat_blob.c, feat_blob.dims);
202
+
203
+ const int num_class = feat_blob.w - 5;
204
+
205
+ const int num_anchors = grid_strides.size();
206
+
207
+ const float* feat_ptr = feat_blob.channel(0);
208
+ for (int anchor_idx = 0; anchor_idx < num_anchors; anchor_idx++)
209
+ {
210
+ const int grid0 = grid_strides[anchor_idx].grid0;
211
+ const int grid1 = grid_strides[anchor_idx].grid1;
212
+ const int stride = grid_strides[anchor_idx].stride;
213
+
214
+ // yolox/models/yolo_head.py decode logic
215
+ // outputs[..., :2] = (outputs[..., :2] + grids) * strides
216
+ // outputs[..., 2:4] = torch.exp(outputs[..., 2:4]) * strides
217
+ float x_center = (feat_ptr[0] + grid0) * stride;
218
+ float y_center = (feat_ptr[1] + grid1) * stride;
219
+ float w = exp(feat_ptr[2]) * stride;
220
+ float h = exp(feat_ptr[3]) * stride;
221
+ float x0 = x_center - w * 0.5f;
222
+ float y0 = y_center - h * 0.5f;
223
+
224
+ float box_objectness = feat_ptr[4];
225
+ for (int class_idx = 0; class_idx < num_class; class_idx++)
226
+ {
227
+ float box_cls_score = feat_ptr[5 + class_idx];
228
+ float box_prob = box_objectness * box_cls_score;
229
+ if (box_prob > prob_threshold)
230
+ {
231
+ Object obj;
232
+ obj.x = x0;
233
+ obj.y = y0;
234
+ obj.w = w;
235
+ obj.h = h;
236
+ obj.label = class_idx;
237
+ obj.prob = box_prob;
238
+
239
+ objects.push_back(obj);
240
+ }
241
+
242
+ } // class loop
243
+ feat_ptr += feat_blob.w;
244
+
245
+ } // point anchor loop
246
+ }
247
+
248
+
249
+ extern "C" {
250
+
251
+ // FIXME DeleteGlobalRef is missing for objCls
252
+ static jclass objCls = NULL;
253
+ static jmethodID constructortorId;
254
+ static jfieldID xId;
255
+ static jfieldID yId;
256
+ static jfieldID wId;
257
+ static jfieldID hId;
258
+ static jfieldID labelId;
259
+ static jfieldID probId;
260
+
261
+ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
262
+ {
263
+ __android_log_print(ANDROID_LOG_DEBUG, "YOLOXncnn", "JNI_OnLoad");
264
+
265
+ ncnn::create_gpu_instance();
266
+
267
+ return JNI_VERSION_1_4;
268
+ }
269
+
270
+ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
271
+ {
272
+ __android_log_print(ANDROID_LOG_DEBUG, "YOLOXncnn", "JNI_OnUnload");
273
+
274
+ ncnn::destroy_gpu_instance();
275
+ }
276
+
277
+ // public native boolean Init(AssetManager mgr);
278
+ JNIEXPORT jboolean JNICALL Java_com_megvii_yoloXncnn_YOLOXncnn_Init(JNIEnv* env, jobject thiz, jobject assetManager)
279
+ {
280
+ ncnn::Option opt;
281
+ opt.lightmode = true;
282
+ opt.num_threads = 4;
283
+ opt.blob_allocator = &g_blob_pool_allocator;
284
+ opt.workspace_allocator = &g_workspace_pool_allocator;
285
+ opt.use_packing_layout = true;
286
+
287
+ // use vulkan compute
288
+ if (ncnn::get_gpu_count() != 0)
289
+ opt.use_vulkan_compute = true;
290
+
291
+ AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
292
+
293
+ yoloX.opt = opt;
294
+
295
+ yoloX.register_custom_layer("YoloV5Focus", YoloV5Focus_layer_creator);
296
+
297
+ // init param
298
+ {
299
+ int ret = yoloX.load_param(mgr, "yolox.param");
300
+ if (ret != 0)
301
+ {
302
+ __android_log_print(ANDROID_LOG_DEBUG, "YOLOXncnn", "load_param failed");
303
+ return JNI_FALSE;
304
+ }
305
+ }
306
+
307
+ // init bin
308
+ {
309
+ int ret = yoloX.load_model(mgr, "yolox.bin");
310
+ if (ret != 0)
311
+ {
312
+ __android_log_print(ANDROID_LOG_DEBUG, "YOLOXncnn", "load_model failed");
313
+ return JNI_FALSE;
314
+ }
315
+ }
316
+
317
+ // init jni glue
318
+ jclass localObjCls = env->FindClass("com/megvii/yoloXncnn/YOLOXncnn$Obj");
319
+ objCls = reinterpret_cast<jclass>(env->NewGlobalRef(localObjCls));
320
+
321
+ constructortorId = env->GetMethodID(objCls, "<init>", "(Lcom/megvii/yoloXncnn/YOLOXncnn;)V");
322
+
323
+ xId = env->GetFieldID(objCls, "x", "F");
324
+ yId = env->GetFieldID(objCls, "y", "F");
325
+ wId = env->GetFieldID(objCls, "w", "F");
326
+ hId = env->GetFieldID(objCls, "h", "F");
327
+ labelId = env->GetFieldID(objCls, "label", "Ljava/lang/String;");
328
+ probId = env->GetFieldID(objCls, "prob", "F");
329
+
330
+ return JNI_TRUE;
331
+ }
332
+
333
+ // public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
334
+ JNIEXPORT jobjectArray JNICALL Java_com_megvii_yoloXncnn_YOLOXncnn_Detect(JNIEnv* env, jobject thiz, jobject bitmap, jboolean use_gpu)
335
+ {
336
+ if (use_gpu == JNI_TRUE && ncnn::get_gpu_count() == 0)
337
+ {
338
+ return NULL;
339
+ //return env->NewStringUTF("no vulkan capable gpu");
340
+ }
341
+
342
+ double start_time = ncnn::get_current_time();
343
+
344
+ AndroidBitmapInfo info;
345
+ AndroidBitmap_getInfo(env, bitmap, &info);
346
+ const int width = info.width;
347
+ const int height = info.height;
348
+ if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
349
+ return NULL;
350
+
351
+ // parameters which might change for different model
352
+ const int target_size = 640;
353
+ const float prob_threshold = 0.3f;
354
+ const float nms_threshold = 0.65f;
355
+ std::vector<int> strides = {8, 16, 32}; // might have stride=64
356
+ // python 0-1 input tensor with rgb_means = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)
357
+ // so for 0-255 input image, rgb_mean should multiply 255 and norm should div by std.
358
+ const float mean_vals[3] = {255.f * 0.485f, 255.f * 0.456, 255.f * 0.406f};
359
+ const float norm_vals[3] = {1 / (255.f * 0.229f), 1 / (255.f * 0.224f), 1 / (255.f * 0.225f)};
360
+
361
+ int w = width;
362
+ int h = height;
363
+ float scale = 1.f;
364
+ if (w > h)
365
+ {
366
+ scale = (float)target_size / w;
367
+ w = target_size;
368
+ h = h * scale;
369
+ }
370
+ else
371
+ {
372
+ scale = (float)target_size / h;
373
+ h = target_size;
374
+ w = w * scale;
375
+ }
376
+
377
+ ncnn::Mat in = ncnn::Mat::from_android_bitmap_resize(env, bitmap, ncnn::Mat::PIXEL_RGB, w, h);
378
+
379
+ // pad to target_size rectangle
380
+ int wpad = target_size - w;
381
+ int hpad = target_size - h;
382
+ ncnn::Mat in_pad;
383
+ // different from yolov5, yolox only pad on bottom and right side,
384
+ // which means users don't need to extra padding info to decode boxes coordinate.
385
+ ncnn::copy_make_border(in, in_pad, 0, hpad, 0, wpad, ncnn::BORDER_CONSTANT, 114.f);
386
+
387
+ // yolox
388
+ std::vector<Object> objects;
389
+ {
390
+
391
+ in_pad.substract_mean_normalize(mean_vals, norm_vals);
392
+
393
+ ncnn::Extractor ex = yoloX.create_extractor();
394
+
395
+ ex.set_vulkan_compute(use_gpu);
396
+
397
+ ex.input("images", in_pad);
398
+
399
+ std::vector<Object> proposals;
400
+
401
+ // yolox decode and generate proposal logic
402
+ {
403
+ ncnn::Mat out;
404
+ ex.extract("output", out);
405
+
406
+ std::vector<GridAndStride> grid_strides;
407
+ generate_grids_and_stride(target_size, strides, grid_strides);
408
+ generate_yolox_proposals(grid_strides, out, prob_threshold, proposals);
409
+
410
+ }
411
+
412
+ // sort all proposals by score from highest to lowest
413
+ qsort_descent_inplace(proposals);
414
+
415
+ // apply nms with nms_threshold
416
+ std::vector<int> picked;
417
+ nms_sorted_bboxes(proposals, picked, nms_threshold);
418
+
419
+ int count = picked.size();
420
+
421
+ objects.resize(count);
422
+ for (int i = 0; i < count; i++)
423
+ {
424
+ objects[i] = proposals[picked[i]];
425
+
426
+ // adjust offset to original unpadded
427
+ float x0 = (objects[i].x) / scale;
428
+ float y0 = (objects[i].y) / scale;
429
+ float x1 = (objects[i].x + objects[i].w) / scale;
430
+ float y1 = (objects[i].y + objects[i].h) / scale;
431
+
432
+ // clip
433
+ x0 = std::max(std::min(x0, (float)(width - 1)), 0.f);
434
+ y0 = std::max(std::min(y0, (float)(height - 1)), 0.f);
435
+ x1 = std::max(std::min(x1, (float)(width - 1)), 0.f);
436
+ y1 = std::max(std::min(y1, (float)(height - 1)), 0.f);
437
+
438
+ objects[i].x = x0;
439
+ objects[i].y = y0;
440
+ objects[i].w = x1 - x0;
441
+ objects[i].h = y1 - y0;
442
+ }
443
+ }
444
+
445
+ // objects to Obj[]
446
+ static const char* class_names[] = {
447
+ "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
448
+ "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
449
+ "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
450
+ "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
451
+ "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
452
+ "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
453
+ "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
454
+ "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
455
+ "hair drier", "toothbrush"
456
+ };
457
+
458
+ jobjectArray jObjArray = env->NewObjectArray(objects.size(), objCls, NULL);
459
+
460
+ for (size_t i=0; i<objects.size(); i++)
461
+ {
462
+ jobject jObj = env->NewObject(objCls, constructortorId, thiz);
463
+
464
+ env->SetFloatField(jObj, xId, objects[i].x);
465
+ env->SetFloatField(jObj, yId, objects[i].y);
466
+ env->SetFloatField(jObj, wId, objects[i].w);
467
+ env->SetFloatField(jObj, hId, objects[i].h);
468
+ env->SetObjectField(jObj, labelId, env->NewStringUTF(class_names[objects[i].label]));
469
+ env->SetFloatField(jObj, probId, objects[i].prob);
470
+
471
+ env->SetObjectArrayElement(jObjArray, i, jObj);
472
+ }
473
+
474
+ double elasped = ncnn::get_current_time() - start_time;
475
+ __android_log_print(ANDROID_LOG_DEBUG, "YOLOXncnn", "%.2fms detect", elasped);
476
+
477
+ return jObjArray;
478
+ }
479
+
480
+ }
demo/ncnn/android/app/src/main/res/layout/main.xml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:orientation="vertical"
4
+ android:layout_width="fill_parent"
5
+ android:layout_height="fill_parent">
6
+
7
+ <LinearLayout
8
+ android:orientation="horizontal"
9
+ android:layout_width="fill_parent"
10
+ android:layout_height="wrap_content">
11
+
12
+ <Button
13
+ android:id="@+id/buttonImage"
14
+ android:layout_width="wrap_content"
15
+ android:layout_height="wrap_content"
16
+ android:text="image" />
17
+ <Button
18
+ android:id="@+id/buttonDetect"
19
+ android:layout_width="wrap_content"
20
+ android:layout_height="wrap_content"
21
+ android:text="infer-cpu" />
22
+ <Button
23
+ android:id="@+id/buttonDetectGPU"
24
+ android:layout_width="wrap_content"
25
+ android:layout_height="wrap_content"
26
+ android:text="infer-gpu" />
27
+ </LinearLayout>
28
+
29
+ <ImageView
30
+ android:id="@+id/imageView"
31
+ android:layout_width="fill_parent"
32
+ android:layout_height="fill_parent"
33
+ android:layout_weight="1" />
34
+
35
+ </LinearLayout>
demo/ncnn/android/app/src/main/res/values/strings.xml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <string name="app_name">yoloXncnn</string>
4
+ </resources>
demo/ncnn/android/build.gradle ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Top-level build file where you can add configuration options common to all sub-projects/modules.
2
+ buildscript {
3
+ repositories {
4
+ jcenter()
5
+ google()
6
+ }
7
+ dependencies {
8
+ classpath 'com.android.tools.build:gradle:3.5.0'
9
+ }
10
+ }
11
+
12
+ allprojects {
13
+ repositories {
14
+ jcenter()
15
+ google()
16
+ }
17
+ }
demo/ncnn/android/gradle/wrapper/gradle-wrapper.jar ADDED
Binary file (54.3 kB). View file
 
demo/ncnn/android/gradle/wrapper/gradle-wrapper.properties ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ #Sun Aug 25 10:34:48 CST 2019
2
+ distributionBase=GRADLE_USER_HOME
3
+ distributionPath=wrapper/dists
4
+ zipStoreBase=GRADLE_USER_HOME
5
+ zipStorePath=wrapper/dists
6
+ distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
demo/ncnn/android/gradlew ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+
3
+ ##############################################################################
4
+ ##
5
+ ## Gradle start up script for UN*X
6
+ ##
7
+ ##############################################################################
8
+
9
+ # Attempt to set APP_HOME
10
+ # Resolve links: $0 may be a link
11
+ PRG="$0"
12
+ # Need this for relative symlinks.
13
+ while [ -h "$PRG" ] ; do
14
+ ls=`ls -ld "$PRG"`
15
+ link=`expr "$ls" : '.*-> \(.*\)$'`
16
+ if expr "$link" : '/.*' > /dev/null; then
17
+ PRG="$link"
18
+ else
19
+ PRG=`dirname "$PRG"`"/$link"
20
+ fi
21
+ done
22
+ SAVED="`pwd`"
23
+ cd "`dirname \"$PRG\"`/" >/dev/null
24
+ APP_HOME="`pwd -P`"
25
+ cd "$SAVED" >/dev/null
26
+
27
+ APP_NAME="Gradle"
28
+ APP_BASE_NAME=`basename "$0"`
29
+
30
+ # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31
+ DEFAULT_JVM_OPTS=""
32
+
33
+ # Use the maximum available, or set MAX_FD != -1 to use that value.
34
+ MAX_FD="maximum"
35
+
36
+ warn () {
37
+ echo "$*"
38
+ }
39
+
40
+ die () {
41
+ echo
42
+ echo "$*"
43
+ echo
44
+ exit 1
45
+ }
46
+
47
+ # OS specific support (must be 'true' or 'false').
48
+ cygwin=false
49
+ msys=false
50
+ darwin=false
51
+ nonstop=false
52
+ case "`uname`" in
53
+ CYGWIN* )
54
+ cygwin=true
55
+ ;;
56
+ Darwin* )
57
+ darwin=true
58
+ ;;
59
+ MINGW* )
60
+ msys=true
61
+ ;;
62
+ NONSTOP* )
63
+ nonstop=true
64
+ ;;
65
+ esac
66
+
67
+ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68
+
69
+ # Determine the Java command to use to start the JVM.
70
+ if [ -n "$JAVA_HOME" ] ; then
71
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72
+ # IBM's JDK on AIX uses strange locations for the executables
73
+ JAVACMD="$JAVA_HOME/jre/sh/java"
74
+ else
75
+ JAVACMD="$JAVA_HOME/bin/java"
76
+ fi
77
+ if [ ! -x "$JAVACMD" ] ; then
78
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79
+
80
+ Please set the JAVA_HOME variable in your environment to match the
81
+ location of your Java installation."
82
+ fi
83
+ else
84
+ JAVACMD="java"
85
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86
+
87
+ Please set the JAVA_HOME variable in your environment to match the
88
+ location of your Java installation."
89
+ fi
90
+
91
+ # Increase the maximum file descriptors if we can.
92
+ if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93
+ MAX_FD_LIMIT=`ulimit -H -n`
94
+ if [ $? -eq 0 ] ; then
95
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96
+ MAX_FD="$MAX_FD_LIMIT"
97
+ fi
98
+ ulimit -n $MAX_FD
99
+ if [ $? -ne 0 ] ; then
100
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
101
+ fi
102
+ else
103
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104
+ fi
105
+ fi
106
+
107
+ # For Darwin, add options to specify how the application appears in the dock
108
+ if $darwin; then
109
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110
+ fi
111
+
112
+ # For Cygwin, switch paths to Windows format before running java
113
+ if $cygwin ; then
114
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116
+ JAVACMD=`cygpath --unix "$JAVACMD"`
117
+
118
+ # We build the pattern for arguments to be converted via cygpath
119
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120
+ SEP=""
121
+ for dir in $ROOTDIRSRAW ; do
122
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
123
+ SEP="|"
124
+ done
125
+ OURCYGPATTERN="(^($ROOTDIRS))"
126
+ # Add a user-defined pattern to the cygpath arguments
127
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129
+ fi
130
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
131
+ i=0
132
+ for arg in "$@" ; do
133
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135
+
136
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138
+ else
139
+ eval `echo args$i`="\"$arg\""
140
+ fi
141
+ i=$((i+1))
142
+ done
143
+ case $i in
144
+ (0) set -- ;;
145
+ (1) set -- "$args0" ;;
146
+ (2) set -- "$args0" "$args1" ;;
147
+ (3) set -- "$args0" "$args1" "$args2" ;;
148
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154
+ esac
155
+ fi
156
+
157
+ # Escape application args
158
+ save () {
159
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160
+ echo " "
161
+ }
162
+ APP_ARGS=$(save "$@")
163
+
164
+ # Collect all arguments for the java command, following the shell quoting and substitution rules
165
+ eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166
+
167
+ # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168
+ if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169
+ cd "$(dirname "$0")"
170
+ fi
171
+
172
+ exec "$JAVACMD" "$@"
demo/ncnn/android/gradlew.bat ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @if "%DEBUG%" == "" @echo off
2
+ @rem ##########################################################################
3
+ @rem
4
+ @rem Gradle startup script for Windows
5
+ @rem
6
+ @rem ##########################################################################
7
+
8
+ @rem Set local scope for the variables with windows NT shell
9
+ if "%OS%"=="Windows_NT" setlocal
10
+
11
+ set DIRNAME=%~dp0
12
+ if "%DIRNAME%" == "" set DIRNAME=.
13
+ set APP_BASE_NAME=%~n0
14
+ set APP_HOME=%DIRNAME%
15
+
16
+ @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17
+ set DEFAULT_JVM_OPTS=
18
+
19
+ @rem Find java.exe
20
+ if defined JAVA_HOME goto findJavaFromJavaHome
21
+
22
+ set JAVA_EXE=java.exe
23
+ %JAVA_EXE% -version >NUL 2>&1
24
+ if "%ERRORLEVEL%" == "0" goto init
25
+
26
+ echo.
27
+ echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28
+ echo.
29
+ echo Please set the JAVA_HOME variable in your environment to match the
30
+ echo location of your Java installation.
31
+
32
+ goto fail
33
+
34
+ :findJavaFromJavaHome
35
+ set JAVA_HOME=%JAVA_HOME:"=%
36
+ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37
+
38
+ if exist "%JAVA_EXE%" goto init
39
+
40
+ echo.
41
+ echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42
+ echo.
43
+ echo Please set the JAVA_HOME variable in your environment to match the
44
+ echo location of your Java installation.
45
+
46
+ goto fail
47
+
48
+ :init
49
+ @rem Get command-line arguments, handling Windows variants
50
+
51
+ if not "%OS%" == "Windows_NT" goto win9xME_args
52
+
53
+ :win9xME_args
54
+ @rem Slurp the command line arguments.
55
+ set CMD_LINE_ARGS=
56
+ set _SKIP=2
57
+
58
+ :win9xME_args_slurp
59
+ if "x%~1" == "x" goto execute
60
+
61
+ set CMD_LINE_ARGS=%*
62
+
63
+ :execute
64
+ @rem Setup the command line
65
+
66
+ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67
+
68
+ @rem Execute Gradle
69
+ "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70
+
71
+ :end
72
+ @rem End local scope for the variables with windows NT shell
73
+ if "%ERRORLEVEL%"=="0" goto mainEnd
74
+
75
+ :fail
76
+ rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77
+ rem the _cmd.exe /c_ return code!
78
+ if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79
+ exit /b 1
80
+
81
+ :mainEnd
82
+ if "%OS%"=="Windows_NT" endlocal
83
+
84
+ :omega
demo/ncnn/android/settings.gradle ADDED
@@ -0,0 +1 @@
 
 
1
+ include ':app'
demo/ncnn/{yolox.cpp → cpp/yolox.cpp} RENAMED
File without changes