├── README.md
├── app
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── mobilenet_ssd_voc_ncnn.bin
│ └── mobilenet_ssd_voc_ncnn.param
│ ├── java
│ └── com
│ │ └── tencent
│ │ └── mobilenetssdncnn
│ │ ├── MainActivity.java
│ │ └── MobilenetSSDNcnn.java
│ ├── jni
│ ├── CMakeLists.txt
│ └── mobilenetssdncnn_jni.cpp
│ └── res
│ ├── layout
│ └── main.xml
│ └── values
│ └── strings.xml
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshot.png
└── settings.gradle
/README.md:
--------------------------------------------------------------------------------
1 | # ncnn-android-mobilenetssd
2 |
3 | The mobilenetssd 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.mobilenetssdncnn"
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/mobilenet_ssd_voc_ncnn.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nihui/ncnn-android-mobilenetssd/9d4d95de5a876741015a957a534365c612bb7c57/app/src/main/assets/mobilenet_ssd_voc_ncnn.bin
--------------------------------------------------------------------------------
/app/src/main/assets/mobilenet_ssd_voc_ncnn.param:
--------------------------------------------------------------------------------
1 | 7767517
2 | 92 115
3 | Input data 0 1 data 0=300 1=300 2=3
4 | Split splitncnn_0 1 7 data data_splitncnn_0 data_splitncnn_1 data_splitncnn_2 data_splitncnn_3 data_splitncnn_4 data_splitncnn_5 data_splitncnn_6
5 | Convolution conv0 1 1 data_splitncnn_6 conv0_conv0/relu 0=32 1=3 3=2 4=1 5=1 6=864 9=1
6 | ConvolutionDepthWise conv1/dw 1 1 conv0_conv0/relu conv1/dw_conv1/dw/relu 0=32 1=3 4=1 5=1 6=288 7=32 9=1
7 | Convolution conv1 1 1 conv1/dw_conv1/dw/relu conv1_conv1/relu 0=64 1=1 5=1 6=2048 9=1
8 | ConvolutionDepthWise conv2/dw 1 1 conv1_conv1/relu conv2/dw_conv2/dw/relu 0=64 1=3 3=2 4=1 5=1 6=576 7=64 9=1
9 | Convolution conv2 1 1 conv2/dw_conv2/dw/relu conv2_conv2/relu 0=128 1=1 5=1 6=8192 9=1
10 | ConvolutionDepthWise conv3/dw 1 1 conv2_conv2/relu conv3/dw_conv3/dw/relu 0=128 1=3 4=1 5=1 6=1152 7=128 9=1
11 | Convolution conv3 1 1 conv3/dw_conv3/dw/relu conv3_conv3/relu 0=128 1=1 5=1 6=16384 9=1
12 | ConvolutionDepthWise conv4/dw 1 1 conv3_conv3/relu conv4/dw_conv4/dw/relu 0=128 1=3 3=2 4=1 5=1 6=1152 7=128 9=1
13 | Convolution conv4 1 1 conv4/dw_conv4/dw/relu conv4_conv4/relu 0=256 1=1 5=1 6=32768 9=1
14 | ConvolutionDepthWise conv5/dw 1 1 conv4_conv4/relu conv5/dw_conv5/dw/relu 0=256 1=3 4=1 5=1 6=2304 7=256 9=1
15 | Convolution conv5 1 1 conv5/dw_conv5/dw/relu conv5_conv5/relu 0=256 1=1 5=1 6=65536 9=1
16 | ConvolutionDepthWise conv6/dw 1 1 conv5_conv5/relu conv6/dw_conv6/dw/relu 0=256 1=3 3=2 4=1 5=1 6=2304 7=256 9=1
17 | Convolution conv6 1 1 conv6/dw_conv6/dw/relu conv6_conv6/relu 0=512 1=1 5=1 6=131072 9=1
18 | ConvolutionDepthWise conv7/dw 1 1 conv6_conv6/relu conv7/dw_conv7/dw/relu 0=512 1=3 4=1 5=1 6=4608 7=512 9=1
19 | Convolution conv7 1 1 conv7/dw_conv7/dw/relu conv7_conv7/relu 0=512 1=1 5=1 6=262144 9=1
20 | ConvolutionDepthWise conv8/dw 1 1 conv7_conv7/relu conv8/dw_conv8/dw/relu 0=512 1=3 4=1 5=1 6=4608 7=512 9=1
21 | Convolution conv8 1 1 conv8/dw_conv8/dw/relu conv8_conv8/relu 0=512 1=1 5=1 6=262144 9=1
22 | ConvolutionDepthWise conv9/dw 1 1 conv8_conv8/relu conv9/dw_conv9/dw/relu 0=512 1=3 4=1 5=1 6=4608 7=512 9=1
23 | Convolution conv9 1 1 conv9/dw_conv9/dw/relu conv9_conv9/relu 0=512 1=1 5=1 6=262144 9=1
24 | ConvolutionDepthWise conv10/dw 1 1 conv9_conv9/relu conv10/dw_conv10/dw/relu 0=512 1=3 4=1 5=1 6=4608 7=512 9=1
25 | Convolution conv10 1 1 conv10/dw_conv10/dw/relu conv10_conv10/relu 0=512 1=1 5=1 6=262144 9=1
26 | ConvolutionDepthWise conv11/dw 1 1 conv10_conv10/relu conv11/dw_conv11/dw/relu 0=512 1=3 4=1 5=1 6=4608 7=512 9=1
27 | Convolution conv11 1 1 conv11/dw_conv11/dw/relu conv11_conv11/relu 0=512 1=1 5=1 6=262144 9=1
28 | Split splitncnn_1 1 4 conv11_conv11/relu conv11_conv11/relu_splitncnn_0 conv11_conv11/relu_splitncnn_1 conv11_conv11/relu_splitncnn_2 conv11_conv11/relu_splitncnn_3
29 | ConvolutionDepthWise conv12/dw 1 1 conv11_conv11/relu_splitncnn_3 conv12/dw_conv12/dw/relu 0=512 1=3 3=2 4=1 5=1 6=4608 7=512 9=1
30 | Convolution conv12 1 1 conv12/dw_conv12/dw/relu conv12_conv12/relu 0=1024 1=1 5=1 6=524288 9=1
31 | ConvolutionDepthWise conv13/dw 1 1 conv12_conv12/relu conv13/dw_conv13/dw/relu 0=1024 1=3 4=1 5=1 6=9216 7=1024 9=1
32 | Convolution conv13 1 1 conv13/dw_conv13/dw/relu conv13_conv13/relu 0=1024 1=1 5=1 6=1048576 9=1
33 | Split splitncnn_2 1 4 conv13_conv13/relu conv13_conv13/relu_splitncnn_0 conv13_conv13/relu_splitncnn_1 conv13_conv13/relu_splitncnn_2 conv13_conv13/relu_splitncnn_3
34 | Convolution conv14_1 1 1 conv13_conv13/relu_splitncnn_3 conv14_1_conv14_1/relu 0=256 1=1 5=1 6=262144 9=1
35 | Convolution conv14_2 1 1 conv14_1_conv14_1/relu conv14_2_conv14_2/relu 0=512 1=3 3=2 4=1 5=1 6=1179648 9=1
36 | Split splitncnn_3 1 4 conv14_2_conv14_2/relu conv14_2_conv14_2/relu_splitncnn_0 conv14_2_conv14_2/relu_splitncnn_1 conv14_2_conv14_2/relu_splitncnn_2 conv14_2_conv14_2/relu_splitncnn_3
37 | Convolution conv15_1 1 1 conv14_2_conv14_2/relu_splitncnn_3 conv15_1_conv15_1/relu 0=128 1=1 5=1 6=65536 9=1
38 | Convolution conv15_2 1 1 conv15_1_conv15_1/relu conv15_2_conv15_2/relu 0=256 1=3 3=2 4=1 5=1 6=294912 9=1
39 | Split splitncnn_4 1 4 conv15_2_conv15_2/relu conv15_2_conv15_2/relu_splitncnn_0 conv15_2_conv15_2/relu_splitncnn_1 conv15_2_conv15_2/relu_splitncnn_2 conv15_2_conv15_2/relu_splitncnn_3
40 | Convolution conv16_1 1 1 conv15_2_conv15_2/relu_splitncnn_3 conv16_1_conv16_1/relu 0=128 1=1 5=1 6=32768 9=1
41 | Convolution conv16_2 1 1 conv16_1_conv16_1/relu conv16_2_conv16_2/relu 0=256 1=3 3=2 4=1 5=1 6=294912 9=1
42 | Split splitncnn_5 1 4 conv16_2_conv16_2/relu conv16_2_conv16_2/relu_splitncnn_0 conv16_2_conv16_2/relu_splitncnn_1 conv16_2_conv16_2/relu_splitncnn_2 conv16_2_conv16_2/relu_splitncnn_3
43 | Convolution conv17_1 1 1 conv16_2_conv16_2/relu_splitncnn_3 conv17_1_conv17_1/relu 0=64 1=1 5=1 6=16384 9=1
44 | Convolution conv17_2 1 1 conv17_1_conv17_1/relu conv17_2_conv17_2/relu 0=128 1=3 3=2 4=1 5=1 6=73728 9=1
45 | Split splitncnn_6 1 3 conv17_2_conv17_2/relu conv17_2_conv17_2/relu_splitncnn_0 conv17_2_conv17_2/relu_splitncnn_1 conv17_2_conv17_2/relu_splitncnn_2
46 | Convolution conv11_mbox_loc 1 1 conv11_conv11/relu_splitncnn_2 conv11_mbox_loc 0=12 1=1 5=1 6=6144
47 | Permute conv11_mbox_loc_perm 1 1 conv11_mbox_loc conv11_mbox_loc_perm 0=3
48 | Flatten conv11_mbox_loc_flat 1 1 conv11_mbox_loc_perm conv11_mbox_loc_flat
49 | Convolution conv11_mbox_conf 1 1 conv11_conv11/relu_splitncnn_1 conv11_mbox_conf 0=63 1=1 5=1 6=32256
50 | Permute conv11_mbox_conf_perm 1 1 conv11_mbox_conf conv11_mbox_conf_perm 0=3
51 | Flatten conv11_mbox_conf_flat 1 1 conv11_mbox_conf_perm conv11_mbox_conf_flat
52 | PriorBox conv11_mbox_priorbox 2 1 conv11_conv11/relu_splitncnn_0 data_splitncnn_5 conv11_mbox_priorbox -23300=1,6.000000e+01 -23302=1,2.000000e+00 9=-233 10=-233 13=5.000000e-01
53 | Convolution conv13_mbox_loc 1 1 conv13_conv13/relu_splitncnn_2 conv13_mbox_loc 0=24 1=1 5=1 6=24576
54 | Permute conv13_mbox_loc_perm 1 1 conv13_mbox_loc conv13_mbox_loc_perm 0=3
55 | Flatten conv13_mbox_loc_flat 1 1 conv13_mbox_loc_perm conv13_mbox_loc_flat
56 | Convolution conv13_mbox_conf 1 1 conv13_conv13/relu_splitncnn_1 conv13_mbox_conf 0=126 1=1 5=1 6=129024
57 | Permute conv13_mbox_conf_perm 1 1 conv13_mbox_conf conv13_mbox_conf_perm 0=3
58 | Flatten conv13_mbox_conf_flat 1 1 conv13_mbox_conf_perm conv13_mbox_conf_flat
59 | PriorBox conv13_mbox_priorbox 2 1 conv13_conv13/relu_splitncnn_0 data_splitncnn_4 conv13_mbox_priorbox -23300=1,1.050000e+02 -23301=1,1.500000e+02 -23302=2,2.000000e+00,3.000000e+00 9=-233 10=-233 13=5.000000e-01
60 | Convolution conv14_2_mbox_loc 1 1 conv14_2_conv14_2/relu_splitncnn_2 conv14_2_mbox_loc 0=24 1=1 5=1 6=12288
61 | Permute conv14_2_mbox_loc_perm 1 1 conv14_2_mbox_loc conv14_2_mbox_loc_perm 0=3
62 | Flatten conv14_2_mbox_loc_flat 1 1 conv14_2_mbox_loc_perm conv14_2_mbox_loc_flat
63 | Convolution conv14_2_mbox_conf 1 1 conv14_2_conv14_2/relu_splitncnn_1 conv14_2_mbox_conf 0=126 1=1 5=1 6=64512
64 | Permute conv14_2_mbox_conf_perm 1 1 conv14_2_mbox_conf conv14_2_mbox_conf_perm 0=3
65 | Flatten conv14_2_mbox_conf_flat 1 1 conv14_2_mbox_conf_perm conv14_2_mbox_conf_flat
66 | PriorBox conv14_2_mbox_priorbox 2 1 conv14_2_conv14_2/relu_splitncnn_0 data_splitncnn_3 conv14_2_mbox_priorbox -23300=1,1.500000e+02 -23301=1,1.950000e+02 -23302=2,2.000000e+00,3.000000e+00 9=-233 10=-233 13=5.000000e-01
67 | Convolution conv15_2_mbox_loc 1 1 conv15_2_conv15_2/relu_splitncnn_2 conv15_2_mbox_loc 0=24 1=1 5=1 6=6144
68 | Permute conv15_2_mbox_loc_perm 1 1 conv15_2_mbox_loc conv15_2_mbox_loc_perm 0=3
69 | Flatten conv15_2_mbox_loc_flat 1 1 conv15_2_mbox_loc_perm conv15_2_mbox_loc_flat
70 | Convolution conv15_2_mbox_conf 1 1 conv15_2_conv15_2/relu_splitncnn_1 conv15_2_mbox_conf 0=126 1=1 5=1 6=32256
71 | Permute conv15_2_mbox_conf_perm 1 1 conv15_2_mbox_conf conv15_2_mbox_conf_perm 0=3
72 | Flatten conv15_2_mbox_conf_flat 1 1 conv15_2_mbox_conf_perm conv15_2_mbox_conf_flat
73 | PriorBox conv15_2_mbox_priorbox 2 1 conv15_2_conv15_2/relu_splitncnn_0 data_splitncnn_2 conv15_2_mbox_priorbox -23300=1,1.950000e+02 -23301=1,2.400000e+02 -23302=2,2.000000e+00,3.000000e+00 9=-233 10=-233 13=5.000000e-01
74 | Convolution conv16_2_mbox_loc 1 1 conv16_2_conv16_2/relu_splitncnn_2 conv16_2_mbox_loc 0=24 1=1 5=1 6=6144
75 | Permute conv16_2_mbox_loc_perm 1 1 conv16_2_mbox_loc conv16_2_mbox_loc_perm 0=3
76 | Flatten conv16_2_mbox_loc_flat 1 1 conv16_2_mbox_loc_perm conv16_2_mbox_loc_flat
77 | Convolution conv16_2_mbox_conf 1 1 conv16_2_conv16_2/relu_splitncnn_1 conv16_2_mbox_conf 0=126 1=1 5=1 6=32256
78 | Permute conv16_2_mbox_conf_perm 1 1 conv16_2_mbox_conf conv16_2_mbox_conf_perm 0=3
79 | Flatten conv16_2_mbox_conf_flat 1 1 conv16_2_mbox_conf_perm conv16_2_mbox_conf_flat
80 | PriorBox conv16_2_mbox_priorbox 2 1 conv16_2_conv16_2/relu_splitncnn_0 data_splitncnn_1 conv16_2_mbox_priorbox -23300=1,2.400000e+02 -23301=1,2.850000e+02 -23302=2,2.000000e+00,3.000000e+00 9=-233 10=-233 13=5.000000e-01
81 | Convolution conv17_2_mbox_loc 1 1 conv17_2_conv17_2/relu_splitncnn_2 conv17_2_mbox_loc 0=24 1=1 5=1 6=3072
82 | Permute conv17_2_mbox_loc_perm 1 1 conv17_2_mbox_loc conv17_2_mbox_loc_perm 0=3
83 | Flatten conv17_2_mbox_loc_flat 1 1 conv17_2_mbox_loc_perm conv17_2_mbox_loc_flat
84 | Convolution conv17_2_mbox_conf 1 1 conv17_2_conv17_2/relu_splitncnn_1 conv17_2_mbox_conf 0=126 1=1 5=1 6=16128
85 | Permute conv17_2_mbox_conf_perm 1 1 conv17_2_mbox_conf conv17_2_mbox_conf_perm 0=3
86 | Flatten conv17_2_mbox_conf_flat 1 1 conv17_2_mbox_conf_perm conv17_2_mbox_conf_flat
87 | PriorBox conv17_2_mbox_priorbox 2 1 conv17_2_conv17_2/relu_splitncnn_0 data_splitncnn_0 conv17_2_mbox_priorbox -23300=1,2.850000e+02 -23301=1,3.000000e+02 -23302=2,2.000000e+00,3.000000e+00 9=-233 10=-233 13=5.000000e-01
88 | Concat mbox_loc 6 1 conv11_mbox_loc_flat conv13_mbox_loc_flat conv14_2_mbox_loc_flat conv15_2_mbox_loc_flat conv16_2_mbox_loc_flat conv17_2_mbox_loc_flat mbox_loc
89 | Concat mbox_conf 6 1 conv11_mbox_conf_flat conv13_mbox_conf_flat conv14_2_mbox_conf_flat conv15_2_mbox_conf_flat conv16_2_mbox_conf_flat conv17_2_mbox_conf_flat mbox_conf
90 | Concat mbox_priorbox 6 1 conv11_mbox_priorbox conv13_mbox_priorbox conv14_2_mbox_priorbox conv15_2_mbox_priorbox conv16_2_mbox_priorbox conv17_2_mbox_priorbox mbox_priorbox 0=1
91 | Reshape mbox_conf_reshape 1 1 mbox_conf mbox_conf_reshape 0=21 1=-1
92 | Softmax mbox_conf_softmax 1 1 mbox_conf_reshape mbox_conf_softmax 0=1 1=1
93 | Flatten mbox_conf_flatten 1 1 mbox_conf_softmax mbox_conf_flatten
94 | DetectionOutput detection_out 3 1 mbox_loc mbox_conf_flatten mbox_priorbox detection_out 0=21 1=4.500000e-01 2=100 4=2.500000e-01
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tencent/mobilenetssdncnn/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.mobilenetssdncnn;
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.net.Uri;
25 | import android.os.Bundle;
26 | import android.util.Log;
27 | import android.view.View;
28 | import android.widget.Button;
29 | import android.widget.ImageView;
30 |
31 | import java.io.FileNotFoundException;
32 |
33 | public class MainActivity extends Activity
34 | {
35 | private static final int SELECT_IMAGE = 1;
36 |
37 | private ImageView imageView;
38 | private Bitmap bitmap = null;
39 | private Bitmap yourSelectedImage = null;
40 |
41 | private MobilenetSSDNcnn mobilenetssdncnn = new MobilenetSSDNcnn();
42 |
43 | /** Called when the activity is first created. */
44 | @Override
45 | public void onCreate(Bundle savedInstanceState)
46 | {
47 | super.onCreate(savedInstanceState);
48 | setContentView(R.layout.main);
49 |
50 | boolean ret_init = mobilenetssdncnn.Init(getAssets());
51 | if (!ret_init)
52 | {
53 | Log.e("MainActivity", "mobilenetssdncnn Init failed");
54 | }
55 |
56 | imageView = (ImageView) findViewById(R.id.imageView);
57 |
58 | Button buttonImage = (Button) findViewById(R.id.buttonImage);
59 | buttonImage.setOnClickListener(new View.OnClickListener() {
60 | @Override
61 | public void onClick(View arg0) {
62 | Intent i = new Intent(Intent.ACTION_PICK);
63 | i.setType("image/*");
64 | startActivityForResult(i, SELECT_IMAGE);
65 | }
66 | });
67 |
68 | Button buttonDetect = (Button) findViewById(R.id.buttonDetect);
69 | buttonDetect.setOnClickListener(new View.OnClickListener() {
70 | @Override
71 | public void onClick(View arg0) {
72 | if (yourSelectedImage == null)
73 | return;
74 |
75 | MobilenetSSDNcnn.Obj[] objects = mobilenetssdncnn.Detect(yourSelectedImage, false);
76 |
77 | showObjects(objects);
78 | }
79 | });
80 |
81 | Button buttonDetectGPU = (Button) findViewById(R.id.buttonDetectGPU);
82 | buttonDetectGPU.setOnClickListener(new View.OnClickListener() {
83 | @Override
84 | public void onClick(View arg0) {
85 | if (yourSelectedImage == null)
86 | return;
87 |
88 | MobilenetSSDNcnn.Obj[] objects = mobilenetssdncnn.Detect(yourSelectedImage, true);
89 |
90 | showObjects(objects);
91 | }
92 | });
93 | }
94 |
95 | private void showObjects(MobilenetSSDNcnn.Obj[] objects)
96 | {
97 | if (objects == null)
98 | {
99 | imageView.setImageBitmap(bitmap);
100 | return;
101 | }
102 |
103 | // draw objects on bitmap
104 | Bitmap rgba = bitmap.copy(Bitmap.Config.ARGB_8888, true);
105 |
106 | Canvas canvas = new Canvas(rgba);
107 |
108 | Paint paint = new Paint();
109 | paint.setColor(Color.BLUE);
110 | paint.setStyle(Paint.Style.STROKE);
111 | paint.setStrokeWidth(4);
112 |
113 | Paint textbgpaint = new Paint();
114 | textbgpaint.setColor(Color.WHITE);
115 | textbgpaint.setStyle(Paint.Style.FILL);
116 |
117 | Paint textpaint = new Paint();
118 | textpaint.setColor(Color.BLACK);
119 | textpaint.setTextSize(26);
120 | textpaint.setTextAlign(Paint.Align.LEFT);
121 |
122 | for (int i = 0; i < objects.length; i++)
123 | {
124 | canvas.drawRect(objects[i].x, objects[i].y, objects[i].x + objects[i].w, objects[i].y + objects[i].h, paint);
125 |
126 | // draw filled text inside image
127 | {
128 | String text = objects[i].label + " = " + String.format("%.1f", objects[i].prob * 100) + "%";
129 |
130 | float text_width = textpaint.measureText(text);
131 | float text_height = - textpaint.ascent() + textpaint.descent();
132 |
133 | float x = objects[i].x;
134 | float y = objects[i].y - text_height;
135 | if (y < 0)
136 | y = 0;
137 | if (x + text_width > rgba.getWidth())
138 | x = rgba.getWidth() - text_width;
139 |
140 | canvas.drawRect(x, y, x + text_width, y + text_height, textbgpaint);
141 |
142 | canvas.drawText(text, x, y - textpaint.ascent(), textpaint);
143 | }
144 | }
145 |
146 | imageView.setImageBitmap(rgba);
147 | }
148 |
149 | @Override
150 | protected void onActivityResult(int requestCode, int resultCode, Intent data)
151 | {
152 | super.onActivityResult(requestCode, resultCode, data);
153 |
154 | if (resultCode == RESULT_OK && null != data) {
155 | Uri selectedImage = data.getData();
156 |
157 | try
158 | {
159 | if (requestCode == SELECT_IMAGE) {
160 | bitmap = decodeUri(selectedImage);
161 |
162 | yourSelectedImage = bitmap.copy(Bitmap.Config.ARGB_8888, true);
163 |
164 | imageView.setImageBitmap(bitmap);
165 | }
166 | }
167 | catch (FileNotFoundException e)
168 | {
169 | Log.e("MainActivity", "FileNotFoundException");
170 | return;
171 | }
172 | }
173 | }
174 |
175 | private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException
176 | {
177 | // Decode image size
178 | BitmapFactory.Options o = new BitmapFactory.Options();
179 | o.inJustDecodeBounds = true;
180 | BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);
181 |
182 | // The new size we want to scale to
183 | final int REQUIRED_SIZE = 400;
184 |
185 | // Find the correct scale value. It should be the power of 2.
186 | int width_tmp = o.outWidth, height_tmp = o.outHeight;
187 | int scale = 1;
188 | while (true) {
189 | if (width_tmp / 2 < REQUIRED_SIZE
190 | || height_tmp / 2 < REQUIRED_SIZE) {
191 | break;
192 | }
193 | width_tmp /= 2;
194 | height_tmp /= 2;
195 | scale *= 2;
196 | }
197 |
198 | // Decode with inSampleSize
199 | BitmapFactory.Options o2 = new BitmapFactory.Options();
200 | o2.inSampleSize = scale;
201 | return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);
202 | }
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tencent/mobilenetssdncnn/MobilenetSSDNcnn.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.mobilenetssdncnn;
16 |
17 | import android.content.res.AssetManager;
18 | import android.graphics.Bitmap;
19 |
20 | public class MobilenetSSDNcnn
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("mobilenetssdncnn");
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/jni/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | project(mobilenetssdncnn)
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(mobilenetssdncnn SHARED mobilenetssdncnn_jni.cpp)
9 |
10 | target_link_libraries(mobilenetssdncnn
11 | ncnn
12 |
13 | jnigraphics
14 | )
15 |
--------------------------------------------------------------------------------
/app/src/main/jni/mobilenetssdncnn_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 "net.h"
26 | #include "benchmark.h"
27 |
28 | static ncnn::UnlockedPoolAllocator g_blob_pool_allocator;
29 | static ncnn::PoolAllocator g_workspace_pool_allocator;
30 |
31 | static ncnn::Net mobilenetssd;
32 |
33 | struct Object
34 | {
35 | float x;
36 | float y;
37 | float w;
38 | float h;
39 | int label;
40 | float prob;
41 | };
42 |
43 | extern "C" {
44 |
45 | // FIXME DeleteGlobalRef is missing for objCls
46 | static jclass objCls = NULL;
47 | static jmethodID constructortorId;
48 | static jfieldID xId;
49 | static jfieldID yId;
50 | static jfieldID wId;
51 | static jfieldID hId;
52 | static jfieldID labelId;
53 | static jfieldID probId;
54 |
55 | JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
56 | {
57 | __android_log_print(ANDROID_LOG_DEBUG, "MobilenetSSDNcnn", "JNI_OnLoad");
58 |
59 | ncnn::create_gpu_instance();
60 |
61 | return JNI_VERSION_1_4;
62 | }
63 |
64 | JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
65 | {
66 | __android_log_print(ANDROID_LOG_DEBUG, "MobilenetSSDNcnn", "JNI_OnUnload");
67 |
68 | ncnn::destroy_gpu_instance();
69 | }
70 |
71 | // public native boolean Init(AssetManager mgr);
72 | JNIEXPORT jboolean JNICALL Java_com_tencent_mobilenetssdncnn_MobilenetSSDNcnn_Init(JNIEnv* env, jobject thiz, jobject assetManager)
73 | {
74 | ncnn::Option opt;
75 | opt.lightmode = true;
76 | opt.num_threads = 4;
77 | opt.blob_allocator = &g_blob_pool_allocator;
78 | opt.workspace_allocator = &g_workspace_pool_allocator;
79 | opt.use_packing_layout = true;
80 |
81 | // use vulkan compute
82 | if (ncnn::get_gpu_count() != 0)
83 | opt.use_vulkan_compute = true;
84 |
85 | AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
86 |
87 | mobilenetssd.opt = opt;
88 |
89 | // init param
90 | {
91 | int ret = mobilenetssd.load_param(mgr, "mobilenet_ssd_voc_ncnn.param");
92 | if (ret != 0)
93 | {
94 | __android_log_print(ANDROID_LOG_DEBUG, "MobilenetSSDNcnn", "load_param failed");
95 | return JNI_FALSE;
96 | }
97 | }
98 |
99 | // init bin
100 | {
101 | int ret = mobilenetssd.load_model(mgr, "mobilenet_ssd_voc_ncnn.bin");
102 | if (ret != 0)
103 | {
104 | __android_log_print(ANDROID_LOG_DEBUG, "MobilenetSSDNcnn", "load_model failed");
105 | return JNI_FALSE;
106 | }
107 | }
108 |
109 | // init jni glue
110 | jclass localObjCls = env->FindClass("com/tencent/mobilenetssdncnn/MobilenetSSDNcnn$Obj");
111 | objCls = reinterpret_cast(env->NewGlobalRef(localObjCls));
112 |
113 | constructortorId = env->GetMethodID(objCls, "", "(Lcom/tencent/mobilenetssdncnn/MobilenetSSDNcnn;)V");
114 |
115 | xId = env->GetFieldID(objCls, "x", "F");
116 | yId = env->GetFieldID(objCls, "y", "F");
117 | wId = env->GetFieldID(objCls, "w", "F");
118 | hId = env->GetFieldID(objCls, "h", "F");
119 | labelId = env->GetFieldID(objCls, "label", "Ljava/lang/String;");
120 | probId = env->GetFieldID(objCls, "prob", "F");
121 |
122 | return JNI_TRUE;
123 | }
124 |
125 | // public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
126 | JNIEXPORT jobjectArray JNICALL Java_com_tencent_mobilenetssdncnn_MobilenetSSDNcnn_Detect(JNIEnv* env, jobject thiz, jobject bitmap, jboolean use_gpu)
127 | {
128 | if (use_gpu == JNI_TRUE && ncnn::get_gpu_count() == 0)
129 | {
130 | return NULL;
131 | //return env->NewStringUTF("no vulkan capable gpu");
132 | }
133 |
134 | double start_time = ncnn::get_current_time();
135 |
136 | AndroidBitmapInfo info;
137 | AndroidBitmap_getInfo(env, bitmap, &info);
138 | int width = info.width;
139 | int height = info.height;
140 | if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
141 | return NULL;
142 |
143 | // ncnn from bitmap
144 | ncnn::Mat in = ncnn::Mat::from_android_bitmap_resize(env, bitmap, ncnn::Mat::PIXEL_BGR, 300, 300);
145 |
146 | // mobilenetssd
147 | std::vector