├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── .travis.yml
├── README.md
├── VisionRecognition.iml
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── synset_words.txt~
│ ├── java
│ └── com
│ │ └── tzutalin
│ │ └── vision
│ │ └── demo
│ │ ├── AutoFitTextureView.java
│ │ ├── Camera2BasicFragment.java
│ │ ├── CameraActivity.java
│ │ ├── ObjectDetectActivity.java
│ │ └── SceneRecognitionActivity.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_action_info.png
│ ├── ic_launcher.png
│ └── tile.9.png
│ ├── drawable-mdpi
│ ├── ic_action_info.png
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ ├── ic_action_info.png
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ ├── ic_action_info.png
│ └── ic_launcher.png
│ ├── drawable
│ └── ic_launcher.png
│ ├── layout-land
│ └── fragment_camera2_basic.xml
│ ├── layout
│ ├── activity_camera.xml
│ ├── activity_main.xml
│ ├── activity_object_detect.xml
│ ├── activity_scene_recognition.xml
│ └── fragment_camera2_basic.xml
│ ├── menu
│ ├── menu_main.xml
│ ├── menu_object_detect.xml
│ └── menu_scene_recognition.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-sw600dp
│ └── template-styles.xml
│ ├── values-v11
│ └── template-styles.xml
│ ├── values-v21
│ ├── base-colors.xml
│ ├── base-template-styles.xml
│ └── styles.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── styles.xml
│ ├── template-dimens.xml
│ └── template-styles.xml
├── build.gradle
├── cnnlibs
├── .gitignore
├── build.gradle
├── cnnlibs.iml
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── tzutalin
│ │ └── vision
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── tzutalin
│ │ └── vision
│ │ └── visionrecognition
│ │ ├── CaffeClassifier.java
│ │ ├── ObjectDetector.java
│ │ ├── SceneClassifier.java
│ │ ├── Utils.java
│ │ ├── VisionClassifierCreator.java
│ │ └── VisionDetRet.java
│ ├── jniLibs
│ ├── armeabi-v7a
│ │ ├── libobjrek.so
│ │ └── libobjrek_jni.so
│ └── x86
│ │ ├── libobjrek.so
│ │ └── libobjrek_jni.so
│ └── res
│ └── values
│ └── strings.xml
├── contributors.txt
├── demo
├── 1.png
├── 2.png
├── 3.png
├── 4.png
└── 5.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
├── setup.sh
└── tools
├── get_model.py
└── testcar.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 | *.swp
9 | phone_data
10 | /projectFilesBackup/
11 | *.iml
12 | .gradle
13 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Android-Object-Detection
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 1.8
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 |
3 | script: "./gradlew assembleDebug"
4 |
5 | jdk:
6 | - oraclejdk8
7 |
8 | android:
9 | components:
10 | # The BuildTools version used by your project
11 | - tools
12 | - platform-tools
13 | - build-tools-25.0.0
14 | # The SDK version used to compile your project
15 | - android-25
16 | - extra-android-m2repository
17 | - extra-android-support
18 | # Additional components
19 | #- extra-android-m2repository
20 | licenses:
21 | - android-sdk-license-.+
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android-Object-Detection
2 | [](https://travis-ci.org/tzutalin/Android-Object-Detection)
3 |
4 | ## Requirements
5 | * Android 4.0+ support
6 |
7 | * ARMv7 and x86 based devices
8 |
9 | * Get the Caffe model and push it to Phone SDCard. For object detection, network(*.prototxt) should use ROILayer, you can refer to [Fast-RCNN](https://github.com/rbgirshick/fast-rcnn). For scene recognition(object recognition), it can use any caffe network and weight with memory input layer.
10 |
11 | * Build with Gradle. You can use Android studio to build
12 |
13 | ## Feature
14 | * [Object detection - Region-based Convolutional Networks detection](http://arxiv.org/abs/1504.08083)
15 | [Selective Search on Android](https://github.com/tzutalin/dlib-android) + [FastRCNN](https://github.com/rbgirshick/caffe-fast-rcnn)
16 |
17 | * [Scene recognition - Convolutional neural networks trained on Places](http://places.csail.mit.edu/downloadCNN.html)
18 | Input a picture of a place or scene and predicts it.
19 |
20 | ## Demo
21 |
22 | 
23 |
24 | 
25 |
26 | 
27 |
28 | 
29 |
30 | 
31 |
32 | ## Usage
33 |
34 | * Download and push the neccessary file to your phone. There should be model and weight in /sdcard/fastrcnn and /sdcard/vision_scene.
35 |
36 | ` $ ./setup.sh `
37 |
38 | * Build and run the application using gradlew or you can open AndroidStudio to import this project
39 |
40 | ` $ ./gradlew assembleDebug`
41 |
42 | ` $ adb install -r ./app/build/outputs/apk`
43 |
44 | Besides, you can change deep learning's model, weight, etc in VisionClassifierCreator.java
45 | ``` java
46 |
47 | public class VisionClassifierCreator {
48 | private final static String SCENE_MODEL_PATH = "..";
49 | private final static String SCENE_WIEGHTS_PATH = "..";
50 | private final static String SCENE_MEAN_FILE = "..";
51 | private final static String SCENE_SYNSET_FILE = "..";
52 |
53 | private final static String DETECT_MODEL_PATH = "..";
54 | private final static String DETECT_WIEGHTS_PATH = "..";
55 | private final static String DETECT_MEAN_FILE = "..";
56 | private final static String DETECT_SYNSET_FILE = "..";
57 | }
58 | ```
59 |
60 | ## Contribution
61 | * Send pull request
62 | *
63 |
64 | ## License
65 |
66 | Copyright (C) 2015-2016 TzuTaLin
67 |
68 | Licensed under the Apache License, Version 2.0 (the "License");
69 | you may not use this file except in compliance with the License.
70 | You may obtain a copy of the License at
71 |
72 | http://www.apache.org/licenses/LICENSE-2.0
73 |
74 | Unless required by applicable law or agreed to in writing, software
75 | distributed under the License is distributed on an "AS IS" BASIS,
76 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
77 | See the License for the specific language governing permissions and
78 | limitations under the License.
79 |
--------------------------------------------------------------------------------
/VisionRecognition.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.androidCompileSdkVersion
5 | buildToolsVersion "${rootProject.ext.androidBuildToolsVersion}"
6 |
7 | defaultConfig {
8 | applicationId "com.tzutalin.vision.visionrecognition"
9 | minSdkVersion rootProject.ext.minSdkVersion
10 | targetSdkVersion rootProject.ext.targetSdkVersion
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 |
21 | dependencies {
22 | compile "com.android.support:support-v4:${rootProject.ext.androidSupportSdkVersion}"
23 | compile "com.android.support:support-v13:${rootProject.ext.androidSupportSdkVersion}"
24 | compile "com.android.support:cardview-v7:${rootProject.ext.androidSupportSdkVersion}"
25 | compile "com.android.support:appcompat-v7:${rootProject.ext.androidSupportSdkVersion}"
26 | compile "com.github.dexafree:materiallist:3.0.1"
27 | compile project(':cnnlibs')
28 | }
29 | }
30 |
31 | dependencies {
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | compile "com.android.support:support-annotations:${rootProject.ext.androidSupportSdkVersion}"
34 | }
35 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/darrenl/tools/android-sdk-linux/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/assets/synset_words.txt~:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/assets/synset_words.txt~
--------------------------------------------------------------------------------
/app/src/main/java/com/tzutalin/vision/demo/AutoFitTextureView.java:
--------------------------------------------------------------------------------
1 | package com.tzutalin.vision.demo;
2 |
3 | /**
4 | * Created by darrenl on 2015/9/10.
5 | */
6 | import android.content.Context;
7 | import android.util.AttributeSet;
8 | import android.view.TextureView;
9 |
10 | /**
11 | * A {@link TextureView} that opencan be adjusted to a specified aspect ratio.
12 | */
13 | public class AutoFitTextureView extends TextureView {
14 |
15 | private int mRatioWidth;
16 | private int mRatioHeight;
17 |
18 | public AutoFitTextureView(Context context) {
19 | this(context, null);
20 | }
21 |
22 | public AutoFitTextureView(Context context, AttributeSet attrs) {
23 | this(context, attrs, 0);
24 | }
25 |
26 | public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
27 | super(context, attrs, defStyle);
28 | }
29 |
30 | /**
31 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
32 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
33 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
34 | *
35 | * @param width Relative horizontal size
36 | * @param height Relative vertical size
37 | */
38 | public void setAspectRatio(int width, int height) {
39 | if (width < 0 || height < 0) {
40 | throw new IllegalArgumentException("Size cannot be negative.");
41 | }
42 | mRatioWidth = width;
43 | mRatioHeight = height;
44 | requestLayout();
45 | }
46 |
47 | @Override
48 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
49 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
50 | int width = MeasureSpec.getSize(widthMeasureSpec);
51 | int height = MeasureSpec.getSize(heightMeasureSpec);
52 | if (0 == mRatioWidth || 0 == mRatioHeight) {
53 | setMeasuredDimension(width, height);
54 | } else {
55 | if (width < height * mRatioWidth / mRatioHeight) {
56 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
57 | } else {
58 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
59 | }
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tzutalin/vision/demo/Camera2BasicFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.tzutalin.vision.demo;
17 |
18 | import android.Manifest;
19 | import android.app.Activity;
20 | import android.app.AlertDialog;
21 | import android.app.Dialog;
22 | import android.app.DialogFragment;
23 | import android.app.Fragment;
24 | import android.content.Context;
25 | import android.content.DialogInterface;
26 | import android.content.Intent;
27 | import android.content.pm.PackageManager;
28 | import android.content.res.Configuration;
29 | import android.graphics.ImageFormat;
30 | import android.graphics.Matrix;
31 | import android.graphics.RectF;
32 | import android.graphics.SurfaceTexture;
33 | import android.hardware.camera2.CameraAccessException;
34 | import android.hardware.camera2.CameraCaptureSession;
35 | import android.hardware.camera2.CameraCharacteristics;
36 | import android.hardware.camera2.CameraDevice;
37 | import android.hardware.camera2.CameraManager;
38 | import android.hardware.camera2.CameraMetadata;
39 | import android.hardware.camera2.CaptureRequest;
40 | import android.hardware.camera2.CaptureResult;
41 | import android.hardware.camera2.TotalCaptureResult;
42 | import android.hardware.camera2.params.StreamConfigurationMap;
43 | import android.media.Image;
44 | import android.media.ImageReader;
45 | import android.os.Bundle;
46 | import android.os.Handler;
47 | import android.os.HandlerThread;
48 | import android.support.annotation.NonNull;
49 | import android.support.v13.app.FragmentCompat;
50 | import android.util.Log;
51 | import android.util.Size;
52 | import android.util.SparseIntArray;
53 | import android.view.LayoutInflater;
54 | import android.view.Surface;
55 | import android.view.TextureView;
56 | import android.view.View;
57 | import android.view.ViewGroup;
58 | import android.widget.Toast;
59 |
60 | import com.tzutalin.vision.visionrecognition.R;
61 |
62 | import java.io.File;
63 | import java.io.FileOutputStream;
64 | import java.io.IOException;
65 | import java.nio.ByteBuffer;
66 | import java.util.ArrayList;
67 | import java.util.Arrays;
68 | import java.util.Collections;
69 | import java.util.Comparator;
70 | import java.util.List;
71 | import java.util.concurrent.Semaphore;
72 | import java.util.concurrent.TimeUnit;
73 |
74 | public class Camera2BasicFragment extends Fragment
75 | implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
76 |
77 | /**
78 | * Conversion from screen rotation to JPEG orientation.
79 | */
80 | private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
81 | private static final int REQUEST_CAMERA_PERMISSION = 1;
82 | private static final String FRAGMENT_DIALOG = "dialog";
83 | public static final String KEY_IMGPATH = "KEY_IMGPATH";
84 |
85 | static {
86 | ORIENTATIONS.append(Surface.ROTATION_0, 90);
87 | ORIENTATIONS.append(Surface.ROTATION_90, 0);
88 | ORIENTATIONS.append(Surface.ROTATION_180, 270);
89 | ORIENTATIONS.append(Surface.ROTATION_270, 180);
90 | }
91 |
92 | enum VisionAction { ObjDetect, SceneRecognition}
93 |
94 | VisionAction mAction;
95 | /**
96 | * Tag for the {@link Log}.
97 | */
98 | private static final String TAG = "Camera2BasicFragment";
99 |
100 | /**
101 | * Camera state: Showing camera preview.
102 | */
103 | private static final int STATE_PREVIEW = 0;
104 |
105 | /**
106 | * Camera state: Waiting for the focus to be locked.
107 | */
108 | private static final int STATE_WAITING_LOCK = 1;
109 |
110 | /**
111 | * Camera state: Waiting for the exposure to be precapture state.
112 | */
113 | private static final int STATE_WAITING_PRECAPTURE = 2;
114 |
115 | /**
116 | * Camera state: Waiting for the exposure state to be something other than precapture.
117 | */
118 | private static final int STATE_WAITING_NON_PRECAPTURE = 3;
119 |
120 | /**
121 | * Camera state: Picture was taken.
122 | */
123 | private static final int STATE_PICTURE_TAKEN = 4;
124 |
125 | /**
126 | * {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
127 | * {@link TextureView}.
128 | */
129 | private final TextureView.SurfaceTextureListener mSurfaceTextureListener
130 | = new TextureView.SurfaceTextureListener() {
131 |
132 | @Override
133 | public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
134 | openCamera(width, height);
135 | }
136 |
137 | @Override
138 | public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
139 | configureTransform(width, height);
140 | }
141 |
142 | @Override
143 | public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
144 | return true;
145 | }
146 |
147 | @Override
148 | public void onSurfaceTextureUpdated(SurfaceTexture texture) {
149 | }
150 |
151 | };
152 |
153 | /**
154 | * ID of the current {@link CameraDevice}.
155 | */
156 | private String mCameraId;
157 |
158 | /**
159 | * An {@link AutoFitTextureView} for camera preview.
160 | */
161 | private AutoFitTextureView mTextureView;
162 |
163 | /**
164 | * A {@link CameraCaptureSession } for camera preview.
165 | */
166 | private CameraCaptureSession mCaptureSession;
167 |
168 | /**
169 | * A reference to the opened {@link CameraDevice}.
170 | */
171 | private CameraDevice mCameraDevice;
172 |
173 | /**
174 | * The {@link android.util.Size} of camera preview.
175 | */
176 | private Size mPreviewSize;
177 |
178 | /**
179 | * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
180 | */
181 | private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
182 |
183 | @Override
184 | public void onOpened(@NonNull CameraDevice cameraDevice) {
185 | // This method is called when the camera is opened. We start camera preview here.
186 | mCameraOpenCloseLock.release();
187 | mCameraDevice = cameraDevice;
188 | createCameraPreviewSession();
189 | }
190 |
191 | @Override
192 | public void onDisconnected(@NonNull CameraDevice cameraDevice) {
193 | mCameraOpenCloseLock.release();
194 | cameraDevice.close();
195 | mCameraDevice = null;
196 | }
197 |
198 | @Override
199 | public void onError(@NonNull CameraDevice cameraDevice, int error) {
200 | mCameraOpenCloseLock.release();
201 | cameraDevice.close();
202 | mCameraDevice = null;
203 | Activity activity = getActivity();
204 | if (null != activity) {
205 | activity.finish();
206 | }
207 | }
208 |
209 | };
210 |
211 | /**
212 | * An additional thread for running tasks that shouldn't block the UI.
213 | */
214 | private HandlerThread mBackgroundThread;
215 |
216 | /**
217 | * A {@link Handler} for running tasks in the background.
218 | */
219 | private Handler mBackgroundHandler;
220 |
221 | /**
222 | * An {@link ImageReader} that handles still image capture.
223 | */
224 | private ImageReader mImageReader;
225 |
226 | /**
227 | * This is the output file for our picture.
228 | */
229 | private File mFile;
230 |
231 | /**
232 | * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
233 | * still image is ready to be saved.
234 | */
235 | private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
236 | = new ImageReader.OnImageAvailableListener() {
237 |
238 | @Override
239 | public void onImageAvailable(ImageReader reader) {
240 | mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
241 | }
242 |
243 | };
244 |
245 | /**
246 | * {@link CaptureRequest.Builder} for the camera preview
247 | */
248 | private CaptureRequest.Builder mPreviewRequestBuilder;
249 |
250 | /**
251 | * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
252 | */
253 | private CaptureRequest mPreviewRequest;
254 |
255 | /**
256 | * The current state of camera state for taking pictures.
257 | *
258 | * @see #mCaptureCallback
259 | */
260 | private int mState = STATE_PREVIEW;
261 |
262 | /**
263 | * A {@link Semaphore} to prevent the app from exiting before closing the camera.
264 | */
265 | private final Semaphore mCameraOpenCloseLock = new Semaphore(1);
266 |
267 | /**
268 | * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
269 | */
270 | private final CameraCaptureSession.CaptureCallback mCaptureCallback
271 | = new CameraCaptureSession.CaptureCallback() {
272 |
273 | private void process(CaptureResult result) {
274 | switch (mState) {
275 | case STATE_PREVIEW: {
276 | // We have nothing to do when the camera preview is working normally.
277 | break;
278 | }
279 | case STATE_WAITING_LOCK: {
280 | Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
281 | if (afState == null) {
282 | captureStillPicture();
283 | } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
284 | CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
285 | // CONTROL_AE_STATE can be null on some devices
286 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
287 | if (aeState == null ||
288 | aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
289 | mState = STATE_PICTURE_TAKEN;
290 | captureStillPicture();
291 | } else {
292 | runPrecaptureSequence();
293 | }
294 | }
295 | break;
296 | }
297 | case STATE_WAITING_PRECAPTURE: {
298 | // CONTROL_AE_STATE can be null on some devices
299 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
300 | if (aeState == null ||
301 | aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
302 | aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
303 | mState = STATE_WAITING_NON_PRECAPTURE;
304 | }
305 | break;
306 | }
307 | case STATE_WAITING_NON_PRECAPTURE: {
308 | // CONTROL_AE_STATE can be null on some devices
309 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
310 | if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
311 | mState = STATE_PICTURE_TAKEN;
312 | captureStillPicture();
313 | }
314 | break;
315 | }
316 | default:
317 | break;
318 | }
319 | }
320 |
321 | @Override
322 | public void onCaptureProgressed(@NonNull CameraCaptureSession session,
323 | @NonNull CaptureRequest request,
324 | @NonNull CaptureResult partialResult) {
325 | process(partialResult);
326 | }
327 |
328 | @Override
329 | public void onCaptureCompleted(@NonNull CameraCaptureSession session,
330 | @NonNull CaptureRequest request,
331 | @NonNull TotalCaptureResult result) {
332 | process(result);
333 | }
334 |
335 | };
336 |
337 | /**
338 | * Shows a {@link Toast} on the UI thread.
339 | *
340 | * @param text The message to show
341 | */
342 | private void showToast(final String text) {
343 | final Activity activity = getActivity();
344 | if (activity != null) {
345 | activity.runOnUiThread(new Runnable() {
346 | @Override
347 | public void run() {
348 | Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
349 | }
350 | });
351 | }
352 | }
353 |
354 | /**
355 | * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
356 | * width and height are at least as large as the respective requested values, and whose aspect
357 | * ratio matches with the specified value.
358 | *
359 | * @param choices The list of sizes that the camera supports for the intended output class
360 | * @param width The minimum desired width
361 | * @param height The minimum desired height
362 | * @param aspectRatio The aspect ratio
363 | * @return The optimal {@code Size}, or an arbitrary one if none were big enough
364 | */
365 | private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
366 | // Collect the supported resolutions that are at least as big as the preview Surface
367 | List bigEnough = new ArrayList<>();
368 | int w = aspectRatio.getWidth();
369 | int h = aspectRatio.getHeight();
370 | for (Size option : choices) {
371 | if (option.getHeight() == option.getWidth() * h / w &&
372 | option.getWidth() >= width && option.getHeight() >= height) {
373 | bigEnough.add(option);
374 | }
375 | }
376 |
377 | // Pick the smallest of those, assuming we found any
378 | if (bigEnough.size() > 0) {
379 | return Collections.min(bigEnough, new CompareSizesByArea());
380 | } else {
381 | Log.e(TAG, "Couldn't find any suitable preview size");
382 | return choices[0];
383 | }
384 | }
385 |
386 | public static Camera2BasicFragment newInstance() {
387 | return new Camera2BasicFragment();
388 | }
389 |
390 | @Override
391 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
392 | Bundle savedInstanceState) {
393 | return inflater.inflate(R.layout.fragment_camera2_basic, container, false);
394 | }
395 |
396 | @Override
397 | public void onViewCreated(final View view, Bundle savedInstanceState) {
398 | view.findViewById(R.id.picture_scene).setOnClickListener(this);
399 | view.findViewById(R.id.picture_detect).setOnClickListener(this);
400 | view.findViewById(R.id.info).setOnClickListener(this);
401 | mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
402 | }
403 |
404 | @Override
405 | public void onActivityCreated(Bundle savedInstanceState) {
406 | super.onActivityCreated(savedInstanceState);
407 | mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");
408 | }
409 |
410 | @Override
411 | public void onResume() {
412 | super.onResume();
413 | startBackgroundThread();
414 |
415 | // When the screen is turned off and turned back on, the SurfaceTexture is already
416 | // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
417 | // a camera and start preview from here (otherwise, we wait until the surface is ready in
418 | // the SurfaceTextureListener).
419 | if (mTextureView.isAvailable()) {
420 | openCamera(mTextureView.getWidth(), mTextureView.getHeight());
421 | } else {
422 | mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
423 | }
424 | }
425 |
426 | @Override
427 | public void onPause() {
428 | closeCamera();
429 | stopBackgroundThread();
430 | super.onPause();
431 | }
432 |
433 | private void requestCameraPermission() {
434 | if (FragmentCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
435 | new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
436 | } else {
437 | FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
438 | REQUEST_CAMERA_PERMISSION);
439 | }
440 | }
441 |
442 | @Override
443 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
444 | @NonNull int[] grantResults) {
445 | if (requestCode == REQUEST_CAMERA_PERMISSION) {
446 | if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
447 | ErrorDialog.newInstance(getString(R.string.request_permission))
448 | .show(getChildFragmentManager(), FRAGMENT_DIALOG);
449 | }
450 | } else {
451 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
452 | }
453 | }
454 |
455 | /**
456 | * Sets up member variables related to camera.
457 | *
458 | * @param width The width of available size for camera preview
459 | * @param height The height of available size for camera preview
460 | */
461 | private void setUpCameraOutputs(int width, int height) {
462 | Activity activity = getActivity();
463 | CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
464 | try {
465 | for (String cameraId : manager.getCameraIdList()) {
466 | CameraCharacteristics characteristics
467 | = manager.getCameraCharacteristics(cameraId);
468 |
469 | // We don't use a front facing camera in this sample.
470 | Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
471 | if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
472 | continue;
473 | }
474 |
475 | StreamConfigurationMap map = characteristics.get(
476 | CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
477 | if (map == null) {
478 | continue;
479 | }
480 |
481 | // For still image captures, we use the largest available size.
482 | Size largest = Collections.max(
483 | Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
484 | new CompareSizesByArea());
485 | mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
486 | ImageFormat.JPEG, /*maxImages*/2);
487 | mImageReader.setOnImageAvailableListener(
488 | mOnImageAvailableListener, mBackgroundHandler);
489 |
490 | // Danger, W.R.! Attempting to use too large a preview size could exceed the camera
491 | // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
492 | // garbage capture data.
493 | mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
494 | width, height, largest);
495 |
496 | // We fit the aspect ratio of TextureView to the size of preview we picked.
497 | int orientation = getResources().getConfiguration().orientation;
498 | if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
499 | mTextureView.setAspectRatio(
500 | mPreviewSize.getWidth(), mPreviewSize.getHeight());
501 | } else {
502 | mTextureView.setAspectRatio(
503 | mPreviewSize.getHeight(), mPreviewSize.getWidth());
504 | }
505 |
506 | mCameraId = cameraId;
507 | return;
508 | }
509 | } catch (CameraAccessException e) {
510 | e.printStackTrace();
511 | } catch (NullPointerException e) {
512 | // Currently an NPE is thrown when the Camera2API is used but not supported on the
513 | // device this code runs.
514 | ErrorDialog.newInstance(getString(R.string.camera_error))
515 | .show(getChildFragmentManager(), FRAGMENT_DIALOG);
516 | }
517 | }
518 |
519 | /**
520 | * Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.
521 | */
522 | private void openCamera(int width, int height) {
523 | setUpCameraOutputs(width, height);
524 | configureTransform(width, height);
525 | Activity activity = getActivity();
526 | CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
527 | try {
528 | if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
529 | throw new RuntimeException("Time out waiting to lock camera opening.");
530 | }
531 | manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
532 | } catch (CameraAccessException e) {
533 | e.printStackTrace();
534 | } catch (InterruptedException e) {
535 | throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
536 | }
537 | }
538 |
539 | /**
540 | * Closes the current {@link CameraDevice}.
541 | */
542 | private void closeCamera() {
543 | try {
544 | mCameraOpenCloseLock.acquire();
545 | if (null != mCaptureSession) {
546 | mCaptureSession.close();
547 | mCaptureSession = null;
548 | }
549 | if (null != mCameraDevice) {
550 | mCameraDevice.close();
551 | mCameraDevice = null;
552 | }
553 | if (null != mImageReader) {
554 | mImageReader.close();
555 | mImageReader = null;
556 | }
557 | } catch (InterruptedException e) {
558 | throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
559 | } finally {
560 | mCameraOpenCloseLock.release();
561 | }
562 | }
563 |
564 | /**
565 | * Starts a background thread and its {@link Handler}.
566 | */
567 | private void startBackgroundThread() {
568 | mBackgroundThread = new HandlerThread("CameraBackground");
569 | mBackgroundThread.start();
570 | mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
571 | }
572 |
573 | /**
574 | * Stops the background thread and its {@link Handler}.
575 | */
576 | private void stopBackgroundThread() {
577 | mBackgroundThread.quitSafely();
578 | try {
579 | mBackgroundThread.join();
580 | mBackgroundThread = null;
581 | mBackgroundHandler = null;
582 | } catch (InterruptedException e) {
583 | e.printStackTrace();
584 | }
585 | }
586 |
587 | /**
588 | * Creates a new {@link CameraCaptureSession} for camera preview.
589 | */
590 | private void createCameraPreviewSession() {
591 | try {
592 | SurfaceTexture texture = mTextureView.getSurfaceTexture();
593 | assert texture != null;
594 |
595 | // We configure the size of default buffer to be the size of camera preview we want.
596 | texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
597 |
598 | // This is the output Surface we need to start preview.
599 | Surface surface = new Surface(texture);
600 |
601 | // We set up a CaptureRequest.Builder with the output Surface.
602 | mPreviewRequestBuilder
603 | = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
604 | mPreviewRequestBuilder.addTarget(surface);
605 |
606 | // Here, we create a CameraCaptureSession for camera preview.
607 | mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
608 | new CameraCaptureSession.StateCallback() {
609 |
610 | @Override
611 | public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
612 | // The camera is already closed
613 | if (null == mCameraDevice) {
614 | return;
615 | }
616 |
617 | // When the session is ready, we start displaying the preview.
618 | mCaptureSession = cameraCaptureSession;
619 | try {
620 | // Auto focus should be continuous for camera preview.
621 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
622 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
623 | // Flash is automatically enabled when necessary.
624 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
625 | CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
626 |
627 | // Finally, we start displaying the camera preview.
628 | mPreviewRequest = mPreviewRequestBuilder.build();
629 | mCaptureSession.setRepeatingRequest(mPreviewRequest,
630 | mCaptureCallback, mBackgroundHandler);
631 | } catch (CameraAccessException e) {
632 | e.printStackTrace();
633 | }
634 | }
635 |
636 | @Override
637 | public void onConfigureFailed(
638 | @NonNull CameraCaptureSession cameraCaptureSession) {
639 | showToast("Failed");
640 | }
641 | }, null
642 | );
643 | } catch (CameraAccessException e) {
644 | e.printStackTrace();
645 | }
646 | }
647 |
648 | /**
649 | * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
650 | * This method should be called after the camera preview size is determined in
651 | * setUpCameraOutputs and also the size of `mTextureView` is fixed.
652 | *
653 | * @param viewWidth The width of `mTextureView`
654 | * @param viewHeight The height of `mTextureView`
655 | */
656 | private void configureTransform(int viewWidth, int viewHeight) {
657 | Activity activity = getActivity();
658 | if (null == mTextureView || null == mPreviewSize || null == activity) {
659 | return;
660 | }
661 | int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
662 | Matrix matrix = new Matrix();
663 | RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
664 | RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
665 | float centerX = viewRect.centerX();
666 | float centerY = viewRect.centerY();
667 | if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
668 | bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
669 | matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
670 | float scale = Math.max(
671 | (float) viewHeight / mPreviewSize.getHeight(),
672 | (float) viewWidth / mPreviewSize.getWidth());
673 | matrix.postScale(scale, scale, centerX, centerY);
674 | matrix.postRotate(90 * (rotation - 2), centerX, centerY);
675 | } else if (Surface.ROTATION_180 == rotation) {
676 | matrix.postRotate(180, centerX, centerY);
677 | }
678 | mTextureView.setTransform(matrix);
679 | }
680 |
681 | /**
682 | * Initiate a still image capture.
683 | */
684 | private void sceneRecognize() {
685 | Log.d(TAG, "sceneRecognize");
686 | mAction = VisionAction.SceneRecognition;
687 | lockFocus();
688 | }
689 |
690 | private void objDetect() {
691 | Log.d(TAG, "objDetect");
692 | mAction = VisionAction.ObjDetect;
693 | lockFocus();
694 | }
695 | /**
696 | * Lock the focus as the first step for a still image capture.
697 | */
698 | private void lockFocus() {
699 | try {
700 | // This is how to tell the camera to lock focus.
701 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
702 | CameraMetadata.CONTROL_AF_TRIGGER_START);
703 | // Tell #mCaptureCallback to wait for the lock.
704 | mState = STATE_WAITING_LOCK;
705 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
706 | mBackgroundHandler);
707 | } catch (CameraAccessException e) {
708 | e.printStackTrace();
709 | }
710 | }
711 |
712 | /**
713 | * Run the precapture sequence for capturing a still image. This method should be called when
714 | * we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
715 | */
716 | private void runPrecaptureSequence() {
717 | try {
718 | // This is how to tell the camera to trigger.
719 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
720 | CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
721 | // Tell #mCaptureCallback to wait for the precapture sequence to be set.
722 | mState = STATE_WAITING_PRECAPTURE;
723 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
724 | mBackgroundHandler);
725 | } catch (CameraAccessException e) {
726 | e.printStackTrace();
727 | }
728 | }
729 |
730 | /**
731 | * Capture a still picture. This method should be called when we get a response in
732 | * {@link #mCaptureCallback} from both {@link #lockFocus()}.
733 | */
734 | private void captureStillPicture() {
735 | try {
736 | final Activity activity = getActivity();
737 | if (null == activity || null == mCameraDevice) {
738 | return;
739 | }
740 | // This is the CaptureRequest.Builder that we use to take a picture.
741 | final CaptureRequest.Builder captureBuilder =
742 | mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
743 | captureBuilder.addTarget(mImageReader.getSurface());
744 |
745 | // Use the same AE and AF modes as the preview.
746 | captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
747 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
748 | captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,
749 | CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
750 |
751 | // Orientation
752 | int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
753 | captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
754 |
755 | CameraCaptureSession.CaptureCallback captureCallback
756 | = new CameraCaptureSession.CaptureCallback() {
757 |
758 | @Override
759 | public void onCaptureCompleted(@NonNull CameraCaptureSession session,
760 | @NonNull CaptureRequest request,
761 | @NonNull TotalCaptureResult result) {
762 | Log.d(TAG, mFile.toString());
763 | unlockFocus();
764 |
765 | Intent intent = null;
766 | if (mAction == VisionAction.ObjDetect) {
767 | intent = new Intent(getActivity(), ObjectDetectActivity.class);
768 | } else if (mAction == VisionAction.SceneRecognition) {
769 | intent = new Intent(getActivity(), SceneRecognitionActivity.class);
770 | }
771 | if (intent != null) {
772 | Bundle bundle = new Bundle();
773 | bundle.putString(Camera2BasicFragment.KEY_IMGPATH, mFile.toString());
774 | intent.putExtras(bundle);
775 | startActivity(intent);
776 | }
777 | }
778 | };
779 |
780 | mCaptureSession.stopRepeating();
781 | mCaptureSession.capture(captureBuilder.build(), captureCallback, null);
782 | } catch (CameraAccessException e) {
783 | e.printStackTrace();
784 | }
785 | }
786 |
787 | /**
788 | * Unlock the focus. This method should be called when still image capture sequence is
789 | * finished.
790 | */
791 | private void unlockFocus() {
792 | try {
793 | // Reset the auto-focus trigger
794 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
795 | CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
796 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
797 | CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
798 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
799 | mBackgroundHandler);
800 | // After this, the camera will go back to the normal state of preview.
801 | mState = STATE_PREVIEW;
802 | mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
803 | mBackgroundHandler);
804 | } catch (CameraAccessException e) {
805 | e.printStackTrace();
806 | }
807 | }
808 |
809 | @Override
810 | public void onClick(View view) {
811 | switch (view.getId()) {
812 | case R.id.picture_scene: {
813 | sceneRecognize();
814 | break;
815 | }
816 | case R.id.picture_detect: {
817 | objDetect();
818 | break;
819 | }
820 | case R.id.info: {
821 | Activity activity = getActivity();
822 | if (null != activity) {
823 | new AlertDialog.Builder(activity)
824 | .setMessage(R.string.intro_message)
825 | .setPositiveButton(android.R.string.ok, null)
826 | .show();
827 | }
828 | break;
829 | }
830 | default:
831 | break;
832 | }
833 | }
834 |
835 | /**
836 | * Saves a JPEG {@link Image} into the specified {@link File}.
837 | */
838 | private static class ImageSaver implements Runnable {
839 |
840 | /**
841 | * The JPEG image
842 | */
843 | private final Image mImage;
844 | /**
845 | * The file we save the image into.
846 | */
847 | private final File mFile;
848 |
849 | public ImageSaver(Image image, File file) {
850 | mImage = image;
851 | mFile = file;
852 | }
853 |
854 | @Override
855 | public void run() {
856 | ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
857 | byte[] bytes = new byte[buffer.remaining()];
858 | buffer.get(bytes);
859 | FileOutputStream output = null;
860 | try {
861 | output = new FileOutputStream(mFile);
862 | output.write(bytes);
863 | } catch (IOException e) {
864 | e.printStackTrace();
865 | } finally {
866 | mImage.close();
867 | if (null != output) {
868 | try {
869 | output.close();
870 | } catch (IOException e) {
871 | e.printStackTrace();
872 | }
873 | }
874 | }
875 | }
876 |
877 | }
878 |
879 | /**
880 | * Compares two {@code Size}s based on their areas.
881 | */
882 | static class CompareSizesByArea implements Comparator {
883 |
884 | @Override
885 | public int compare(Size lhs, Size rhs) {
886 | // We cast here to ensure the multiplications won't overflow
887 | return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
888 | (long) rhs.getWidth() * rhs.getHeight());
889 | }
890 |
891 | }
892 |
893 | /**
894 | * Shows an error message dialog.
895 | */
896 | public static class ErrorDialog extends DialogFragment {
897 |
898 | private static final String ARG_MESSAGE = "message";
899 |
900 | public static ErrorDialog newInstance(String message) {
901 | ErrorDialog dialog = new ErrorDialog();
902 | Bundle args = new Bundle();
903 | args.putString(ARG_MESSAGE, message);
904 | dialog.setArguments(args);
905 | return dialog;
906 | }
907 |
908 | @Override
909 | public Dialog onCreateDialog(Bundle savedInstanceState) {
910 | final Activity activity = getActivity();
911 | return new AlertDialog.Builder(activity)
912 | .setMessage(getArguments().getString(ARG_MESSAGE))
913 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
914 | @Override
915 | public void onClick(DialogInterface dialogInterface, int i) {
916 | activity.finish();
917 | }
918 | })
919 | .create();
920 | }
921 |
922 | }
923 |
924 | /**
925 | * Shows OK/Cancel confirmation dialog about camera permission.
926 | */
927 | public static class ConfirmationDialog extends DialogFragment {
928 |
929 | @Override
930 | public Dialog onCreateDialog(Bundle savedInstanceState) {
931 | final Fragment parent = getParentFragment();
932 | return new AlertDialog.Builder(getActivity())
933 | .setMessage(R.string.request_permission)
934 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
935 | @Override
936 | public void onClick(DialogInterface dialog, int which) {
937 | FragmentCompat.requestPermissions(parent,
938 | new String[]{Manifest.permission.CAMERA},
939 | REQUEST_CAMERA_PERMISSION);
940 | }
941 | })
942 | .setNegativeButton(android.R.string.cancel,
943 | new DialogInterface.OnClickListener() {
944 | @Override
945 | public void onClick(DialogInterface dialog, int which) {
946 | Activity activity = parent.getActivity();
947 | if (activity != null) {
948 | activity.finish();
949 | }
950 | }
951 | })
952 | .create();
953 | }
954 | }
955 |
956 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/tzutalin/vision/demo/CameraActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.tzutalin.vision.demo;
17 |
18 | import android.Manifest;
19 | import android.app.Activity;
20 | import android.content.pm.PackageManager;
21 | import android.os.Build;
22 | import android.os.Bundle;
23 | import android.support.v4.app.ActivityCompat;
24 | import android.widget.Toast;
25 |
26 | import com.tzutalin.vision.visionrecognition.R;
27 |
28 | public class CameraActivity extends Activity {
29 |
30 | private static final int REQUEST_CODE_PERMISSION = 1;
31 |
32 | private static final String TAG = "CameraActivity";
33 |
34 | // Storage Permissions
35 | private static String[] PERMISSIONS_REQ = {
36 | Manifest.permission.READ_EXTERNAL_STORAGE,
37 | Manifest.permission.WRITE_EXTERNAL_STORAGE,
38 | Manifest.permission.CAMERA
39 | };
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_camera);
45 |
46 | boolean avialbe_permission = true;
47 | // For API 23+ you need to request the read/write permissions even if they are already in your manifest.
48 | int currentapiVersion = android.os.Build.VERSION.SDK_INT;
49 | if (currentapiVersion >= Build.VERSION_CODES.M ) {
50 | avialbe_permission = verifyPermissions(this);
51 | }
52 |
53 | if (avialbe_permission && null == savedInstanceState) {
54 | getFragmentManager().beginTransaction()
55 | .replace(R.id.container, Camera2BasicFragment.newInstance())
56 | .commit();
57 | }
58 | }
59 |
60 | private static boolean verifyPermissions(Activity activity) {
61 | // Check if we have write permission
62 | int write_permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
63 | int read_persmission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
64 | int camera_permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
65 |
66 | if (write_permission != PackageManager.PERMISSION_GRANTED ||
67 | read_persmission != PackageManager.PERMISSION_GRANTED ||
68 | camera_permission != PackageManager.PERMISSION_GRANTED) {
69 | // We don't have permission so prompt the user
70 | ActivityCompat.requestPermissions(
71 | activity,
72 | PERMISSIONS_REQ,
73 | REQUEST_CODE_PERMISSION
74 | );
75 | return false;
76 | } else {
77 | return true;
78 | }
79 | }
80 |
81 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
82 | try {
83 | // Restart it after granting permission
84 | if (requestCode == REQUEST_CODE_PERMISSION) {
85 | finish();
86 | startActivity(getIntent());
87 | }
88 | } catch (Exception e) {
89 | Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG).show();
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tzutalin/vision/demo/ObjectDetectActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.tzutalin.vision.demo;
17 |
18 | import android.app.Activity;
19 | import android.app.ProgressDialog;
20 | import android.graphics.Bitmap;
21 | import android.graphics.BitmapFactory;
22 | import android.graphics.drawable.BitmapDrawable;
23 | import android.graphics.drawable.Drawable;
24 | import android.os.AsyncTask;
25 | import android.os.Bundle;
26 | import android.util.Log;
27 | import android.view.Menu;
28 | import android.view.MenuItem;
29 | import android.view.Window;
30 | import android.widget.Toast;
31 |
32 | import com.dexafree.materialList.card.Card;
33 | import com.dexafree.materialList.card.provider.BigImageCardProvider;
34 | import com.dexafree.materialList.view.MaterialListView;
35 | import com.tzutalin.vision.visionrecognition.ObjectDetector;
36 | import com.tzutalin.vision.visionrecognition.R;
37 | import com.tzutalin.vision.visionrecognition.VisionClassifierCreator;
38 | import com.tzutalin.vision.visionrecognition.VisionDetRet;
39 |
40 | import java.io.File;
41 | import java.util.ArrayList;
42 | import java.util.List;
43 |
44 | public class ObjectDetectActivity extends Activity {
45 | private final static String TAG = "ObjectDetectActivity";
46 | private ObjectDetector mObjectDet;
47 | // UI
48 | MaterialListView mListView;
49 | @Override
50 | protected void onCreate(Bundle savedInstanceState) {
51 | super.onCreate(savedInstanceState);
52 | requestWindowFeature(Window.FEATURE_NO_TITLE);
53 | setContentView(R.layout.activity_object_detect);
54 | mListView = (MaterialListView) findViewById(R.id.material_listview);
55 | final String key = Camera2BasicFragment.KEY_IMGPATH;
56 | String imgPath = getIntent().getExtras().getString(key);
57 | if (!new File(imgPath).exists()) {
58 | Toast.makeText(this, "No file path", Toast.LENGTH_SHORT).show();
59 | this.finish();
60 | return;
61 | }
62 | DetectTask task = new DetectTask();
63 | task.execute(imgPath);
64 | }
65 |
66 | @Override
67 | public boolean onCreateOptionsMenu(Menu menu) {
68 | // Inflate the menu; this adds items to the action bar if it is present.
69 | getMenuInflater().inflate(R.menu.menu_object_detect, menu);
70 | return true;
71 | }
72 |
73 | @Override
74 | public boolean onOptionsItemSelected(MenuItem item) {
75 | int id = item.getItemId();
76 | if (id == R.id.action_settings) {
77 | return true;
78 | }
79 |
80 | return super.onOptionsItemSelected(item);
81 | }
82 |
83 | // ==========================================================
84 | // Tasks inner class
85 | // ==========================================================
86 | private class DetectTask extends AsyncTask> {
87 | private ProgressDialog mmDialog;
88 |
89 | @Override
90 | protected void onPreExecute() {
91 | super.onPreExecute();
92 | mmDialog = ProgressDialog.show(ObjectDetectActivity.this, getString(R.string.dialog_wait),getString(R.string.dialog_object_decscription), true);
93 | }
94 |
95 | @Override
96 | protected List doInBackground(String... strings) {
97 | final String filePath = strings[0];
98 | long startTime;
99 | long endTime;
100 | Log.d(TAG, "DetectTask filePath:" + filePath);
101 | if (mObjectDet == null) {
102 | try {
103 | mObjectDet = VisionClassifierCreator.createObjectDetector(getApplicationContext());
104 | // TODO: Get Image's height and width
105 | mObjectDet.init(0, 0);
106 | } catch (IllegalAccessException e) {
107 | e.printStackTrace();
108 | }
109 | }
110 | List ret = new ArrayList<>();
111 | if (mObjectDet != null) {
112 | startTime = System.currentTimeMillis();
113 | Log.d(TAG, "Start objDetect");
114 | ret.addAll(mObjectDet.classifyByPath(filePath));
115 | Log.d(TAG, "end objDetect");
116 | endTime = System.currentTimeMillis();
117 | final double diffTime = (double) (endTime - startTime) / 1000;
118 | runOnUiThread(new Runnable() {
119 | @Override
120 | public void run() {
121 | Toast.makeText(ObjectDetectActivity.this, "Take " + diffTime + " second", Toast.LENGTH_LONG).show();
122 | }
123 | });
124 | }
125 | File beDeletedFile = new File(filePath);
126 | if (beDeletedFile.exists()) {
127 | beDeletedFile.delete();
128 | } else {
129 | Log.d(TAG, "file does not exist " + filePath);
130 | }
131 |
132 | mObjectDet.deInit();
133 | return ret;
134 | }
135 |
136 | @Override
137 | protected void onPostExecute(List rets) {
138 | super.onPostExecute(rets);
139 | if (mmDialog != null) {
140 | mmDialog.dismiss();
141 | }
142 | // TODO: Remvoe it
143 | BitmapFactory.Options options = new BitmapFactory.Options();
144 | options.inSampleSize = 4;
145 | String retImgPath = "/sdcard/temp.jpg";
146 | Bitmap bitmap = BitmapFactory.decodeFile(retImgPath, options);
147 |
148 | Drawable d = new BitmapDrawable(getResources(), bitmap);
149 | Card card = new Card.Builder(ObjectDetectActivity.this)
150 | .withProvider(BigImageCardProvider.class)
151 | .setDrawable(d)
152 | .endConfig()
153 | .build();
154 | mListView.add(card);
155 | for (VisionDetRet item : rets) {
156 | StringBuilder sb = new StringBuilder();
157 | sb.append(item.getLabel())
158 | .append(", Prob:").append(item.getConfidence())
159 | .append(" [")
160 | .append(item.getLeft()).append(',')
161 | .append(item.getTop()).append(',')
162 | .append(item.getRight()).append(',')
163 | .append(item.getBottom())
164 | .append(']');
165 | Log.d(TAG, sb.toString());
166 |
167 | if (!item.getLabel().equalsIgnoreCase("background")) {
168 | card = new Card.Builder(ObjectDetectActivity.this)
169 | .withProvider(BigImageCardProvider.class)
170 | .setTitle("Detect Result")
171 | .setDescription(sb.toString())
172 | .endConfig()
173 | .build();
174 | mListView.add(card);
175 | }
176 | }
177 |
178 | File beDeletedFile = new File(retImgPath);
179 | if (beDeletedFile.exists()) {
180 | beDeletedFile.delete();
181 | }
182 |
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tzutalin/vision/demo/SceneRecognitionActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.tzutalin.vision.demo;
18 |
19 | import android.app.Activity;
20 | import android.app.ProgressDialog;
21 | import android.graphics.Bitmap;
22 | import android.graphics.BitmapFactory;
23 | import android.graphics.drawable.BitmapDrawable;
24 | import android.graphics.drawable.Drawable;
25 | import android.os.AsyncTask;
26 | import android.os.Bundle;
27 | import android.util.Log;
28 | import android.view.Menu;
29 | import android.view.MenuItem;
30 | import android.view.Window;
31 | import android.widget.Toast;
32 |
33 | import com.tzutalin.vision.visionrecognition.R;
34 | import com.tzutalin.vision.visionrecognition.SceneClassifier;
35 | import com.tzutalin.vision.visionrecognition.VisionClassifierCreator;
36 | import com.tzutalin.vision.visionrecognition.VisionDetRet;
37 | import com.dexafree.materialList.card.Card;
38 | import com.dexafree.materialList.card.provider.BigImageCardProvider;
39 | import com.dexafree.materialList.view.MaterialListView;
40 |
41 | import java.io.File;
42 | import java.util.ArrayList;
43 | import java.util.List;
44 |
45 | public class SceneRecognitionActivity extends Activity {
46 | private final static String TAG = "SceneRecognitionActivity";
47 | // UI
48 | MaterialListView mListView;
49 | private SceneClassifier mClassifier;
50 |
51 | @Override
52 | protected void onCreate(Bundle savedInstanceState) {
53 | super.onCreate(savedInstanceState);
54 | requestWindowFeature(Window.FEATURE_NO_TITLE);
55 | setContentView(R.layout.activity_scene_recognition);
56 | mListView = (MaterialListView) findViewById(R.id.material_listview);
57 | final String key = Camera2BasicFragment.KEY_IMGPATH;
58 | String imgPath = getIntent().getExtras().getString(key);
59 | if (!new File(imgPath).exists()) {
60 | Toast.makeText(this, "No file path", Toast.LENGTH_SHORT).show();
61 | this.finish();
62 | return;
63 | }
64 |
65 | PredictTask task = new PredictTask();
66 | task.execute(imgPath);
67 |
68 | BitmapFactory.Options options = new BitmapFactory.Options();
69 | options.inSampleSize = 4;
70 | Bitmap bm = BitmapFactory.decodeFile(imgPath, options);
71 | Drawable d = new BitmapDrawable(getResources(), bm);
72 |
73 | Card card = new Card.Builder(SceneRecognitionActivity.this)
74 | .withProvider(BigImageCardProvider.class)
75 | .setDescription("Input image")
76 | .setDrawable(d)
77 | .endConfig()
78 | .build();
79 | mListView.add(card);
80 | }
81 |
82 | @Override
83 | protected void onDestroy() {
84 | super.onDestroy();
85 | if (mClassifier != null) {
86 | mClassifier.deInit();
87 | }
88 | }
89 |
90 | @Override
91 | public boolean onCreateOptionsMenu(Menu menu) {
92 | // Inflate the menu; this adds items to the action bar if it is present.
93 | getMenuInflater().inflate(R.menu.menu_scene_recognition, menu);
94 | return true;
95 | }
96 |
97 | @Override
98 | public boolean onOptionsItemSelected(MenuItem item) {
99 | // Handle action bar item clicks here. The action bar will
100 | // automatically handle clicks on the Home/Up button, so long
101 | // as you specify a parent activity in AndroidManifest.xml.
102 | int id = item.getItemId();
103 |
104 | //noinspection SimplifiableIfStatement
105 | if (id == R.id.action_settings) {
106 | return true;
107 | }
108 |
109 | return super.onOptionsItemSelected(item);
110 | }
111 |
112 | // ==========================================================
113 | // Tasks inner class
114 | // ==========================================================
115 | private class PredictTask extends AsyncTask> {
116 | private ProgressDialog mmDialog;
117 |
118 | @Override
119 | protected void onPreExecute() {
120 | super.onPreExecute();
121 | mmDialog = ProgressDialog.show(SceneRecognitionActivity.this, getString(R.string.dialog_wait),getString(R.string.dialog_scene_decscription), true);
122 | }
123 |
124 | @Override
125 | protected List doInBackground(String... strings) {
126 | initCaffeMobile();
127 | long startTime;
128 | long endTime;
129 | final String filePath = strings[0];
130 | List rets = new ArrayList<>();
131 | Log.d(TAG, "PredictTask filePath:" + filePath);
132 | if (mClassifier != null) {
133 |
134 | BitmapFactory.Options options = new BitmapFactory.Options();
135 | options.inSampleSize = 4;
136 | Log.d(TAG, "format:" + options.inPreferredConfig);
137 | Bitmap bitmapImg = BitmapFactory.decodeFile(filePath, options);
138 | startTime = System.currentTimeMillis();
139 | rets.addAll(mClassifier.classify(bitmapImg));
140 |
141 | endTime = System.currentTimeMillis();
142 | final double diffTime = (double) (endTime - startTime) / 1000;
143 | runOnUiThread(new Runnable() {
144 | @Override
145 | public void run() {
146 | Toast.makeText(SceneRecognitionActivity.this, "Take " + diffTime + " second", Toast.LENGTH_LONG).show();
147 | }
148 | });
149 | }
150 | File beDeletedFile = new File(filePath);
151 | if (beDeletedFile.exists()) {
152 | beDeletedFile.delete();
153 | } else {
154 | Log.d(TAG, "file does not exist " + filePath);
155 | }
156 | return rets;
157 | }
158 |
159 | @Override
160 | protected void onPostExecute(List rets) {
161 | super.onPostExecute(rets);
162 | if (mmDialog != null) {
163 | mmDialog.dismiss();
164 | }
165 |
166 | ArrayList items = new ArrayList<>();
167 | for (VisionDetRet each : rets) {
168 | items.add("[" + each.getLabel() + "] Prob: " + each.getConfidence());
169 | }
170 |
171 | int count = 0;
172 | for (String item : items) {
173 | count++;
174 | Card card = new Card.Builder(SceneRecognitionActivity.this)
175 | .withProvider(BigImageCardProvider.class)
176 | .setTitle("Top " + count)
177 | .setDescription(item)
178 | .endConfig()
179 | .build();
180 | mListView.add(card);
181 | }
182 | }
183 | }
184 | // ==========================================================
185 | // Private methods
186 | // ==========================================================
187 | private void initCaffeMobile() {
188 | if (mClassifier == null) {
189 | try {
190 | mClassifier = VisionClassifierCreator.createSceneClassifier(getApplicationContext());
191 | Log.d(TAG, "Start Load model");
192 | // TODO : Fix it
193 | mClassifier.init(224,224); // init once
194 | Log.d(TAG, "End Load model");
195 | } catch (IllegalAccessException e) {
196 | e.printStackTrace();
197 | }
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-hdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/tile.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-hdpi/tile.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-mdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-xhdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-xxhdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/fragment_camera2_basic.xml:
--------------------------------------------------------------------------------
1 |
16 |
19 |
20 |
27 |
28 |
38 |
39 |
48 |
49 |
58 |
59 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_camera.xml:
--------------------------------------------------------------------------------
1 |
16 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
15 |
16 |
24 |
25 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_object_detect.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_scene_recognition.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_camera2_basic.xml:
--------------------------------------------------------------------------------
1 |
16 |
19 |
20 |
26 |
27 |
34 |
35 |
42 |
43 |
50 |
51 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_object_detect.xml:
--------------------------------------------------------------------------------
1 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_scene_recognition.xml:
--------------------------------------------------------------------------------
1 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/base-colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/base-template-styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | #cc4285f4
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | VisionRecognition
3 |
4 | Settings
5 | It will take some time to init at first
6 |
7 | Scene
8 | Objects
9 | Info
10 | This sample needs camera permission.
11 | This device doesn\'t support Camera2 API.
12 |
13 |
14 |
22 |
23 | SceneRecognitionActivity
24 | ObjectDetectActivity
25 | Please wait
26 | Selective Search + Region-based Convolutional Networks (Fast RCNN)
27 | Run Convolutional Networks
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/template-dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 | 4dp
22 | 8dp
23 | 16dp
24 | 32dp
25 | 64dp
26 |
27 |
28 |
29 | @dimen/margin_medium
30 | @dimen/margin_medium
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/values/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.0'
9 | // NOTE: Do not place your application dependencies here; they belong
10 | // in the individual module build.gradle files
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | jcenter()
17 | }
18 | }
19 |
20 | ext {
21 | groupName = 'com.github.tzutalin'
22 | artifactName = 'Android-Object-Detection'
23 | artifactDescription = 'Fast-RCNN and Scene Recognition using Caffe'
24 | artifactLabels = ['object detection', 'android']
25 | releaseVersionCode = 1
26 | releaseVersionName = '1.0.0'
27 |
28 | androidBuildToolsVersion = '25.0.0'
29 | androidSupportSdkVersion = '25.0.0'
30 |
31 | androidCompileSdkVersion = 25
32 | minSdkVersion = 21
33 | targetSdkVersion = 25
34 | }
35 |
--------------------------------------------------------------------------------
/cnnlibs/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/cnnlibs/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.androidCompileSdkVersion
5 | buildToolsVersion "${rootProject.ext.androidBuildToolsVersion}"
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.minSdkVersion
9 | targetSdkVersion rootProject.ext.targetSdkVersion
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | compile "com.android.support:support-annotations:${rootProject.ext.androidSupportSdkVersion}"
24 | }
25 |
--------------------------------------------------------------------------------
/cnnlibs/cnnlibs.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/cnnlibs/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/darrenl/tools/android-sdk-linux/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/cnnlibs/src/androidTest/java/com/tzutalin/vision/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.tzutalin.vision;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/cnnlibs/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/cnnlibs/src/main/java/com/tzutalin/vision/visionrecognition/CaffeClassifier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.tzutalin.vision.visionrecognition;
18 |
19 | import android.content.Context;
20 | import android.graphics.Bitmap;
21 | import android.text.TextUtils;
22 |
23 | import java.io.BufferedReader;
24 | import java.io.File;
25 | import java.io.FileReader;
26 | import java.io.IOException;
27 | import java.nio.ByteBuffer;
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 | /**
32 | * Base class for using caffe
33 | *
34 | * @param
35 | */
36 | public abstract class CaffeClassifier {
37 | protected static boolean sInitialized;
38 | static {
39 | try {
40 | System.loadLibrary("objrek");
41 | System.loadLibrary("objrek_jni");
42 | jniNativeClassInit();
43 | sInitialized = true;
44 | android.util.Log.d("CaffeClassifier", "jniNativeClassInit success");
45 | } catch (UnsatisfiedLinkError e) {
46 | android.util.Log.d("CaffeClassifier", "objrek objrek_jni library not found!");
47 | }
48 | }
49 |
50 | protected Context mContext;
51 | protected String mModelPath;
52 | protected String mWeightsPath;
53 | protected String mMeanPath;
54 | protected String mSynsetPath;
55 | protected String[] mSynsets;
56 | protected int mImgWidth;
57 | protected int mImgHeight;
58 | private String mSelectedLabel;
59 |
60 | /**
61 | *
62 | * @param modelPath Caffe's model
63 | * @param wieghtsPath Caffe's trained wieght
64 | * @param manefile The file path of the image image
65 | * @param synsetFile The file path to load label's titles
66 | */
67 | protected CaffeClassifier(Context context, String modelPath, String wieghtsPath, String manefile, String synsetFile) {
68 | mContext = context;
69 | mModelPath = modelPath;
70 | mWeightsPath = wieghtsPath;
71 | mMeanPath = manefile;
72 | mSynsetPath = synsetFile;
73 | }
74 |
75 | /**
76 | * Init image width and height and start to load model, weight, allocate byte buffer, etc.
77 | *
78 | * @param imgWidth The width of the image
79 | * @param imgHeight The height of the image
80 | */
81 | public void init(int imgWidth, int imgHeight) {
82 | mSynsets = getSynsetsFromFile(mContext);
83 | mImgWidth = imgWidth;
84 | mImgHeight = imgHeight;
85 | }
86 |
87 | /**
88 | * Pass the image path to do classifiction or detection
89 | * @param imgPath image path
90 | * @return
91 | */
92 | public abstract T classifyByPath(String imgPath);
93 |
94 | /**
95 | * Pass {@link android.graphics.Bitmap} graphic object to do classifiction or detection
96 | * @param bitmap
97 | * @return
98 | */
99 | public abstract T classify(Bitmap bitmap);
100 |
101 | /**
102 | * Release the resource, model, weight, deallocate the buffer
103 | */
104 | public void deInit() {
105 | }
106 |
107 |
108 | public void setSelectedLabel(String label) {
109 | mSelectedLabel = label;
110 | }
111 |
112 | public void clearSelectedLabel() {
113 | mSelectedLabel = null;
114 | }
115 |
116 | private String[] getSynsetsFromFile(Context context) {
117 | if (!TextUtils.isEmpty(mSynsetPath)) {
118 | File file = new File(mSynsetPath);
119 | BufferedReader br = null;
120 | try {
121 | br = new BufferedReader(new FileReader(file));
122 | String line;
123 | List lines = new ArrayList<>();
124 | while ((line = br.readLine()) != null) {
125 | String temp = line.substring(line.lastIndexOf("/") + 1);
126 | lines.add(temp.split(" ")[0]);
127 | }
128 | return lines.toArray(new String[0]);
129 | } catch (IOException e) {
130 | e.printStackTrace();
131 | } finally {
132 | if (br != null) {
133 | try {
134 | br.close();
135 | } catch (IOException e) {
136 | e.printStackTrace();
137 | }
138 | }
139 | }
140 | }
141 | return null;
142 | }
143 |
144 | private native static void jniNativeClassInit();
145 | }
--------------------------------------------------------------------------------
/cnnlibs/src/main/java/com/tzutalin/vision/visionrecognition/ObjectDetector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.tzutalin.vision.visionrecognition;
18 |
19 | import android.content.Context;
20 | import android.graphics.Bitmap;
21 | import android.graphics.BitmapFactory;
22 | import android.text.TextUtils;
23 | import android.util.Log;
24 |
25 | import java.io.File;
26 | import java.nio.ByteBuffer;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | /**
31 | * Identifies and locate the specified objects in a
32 | * {@link android.graphics.Bitmap} graphic object.
33 | */
34 | public class ObjectDetector extends CaffeClassifier >{
35 | private static final String TAG = "ObjectDetector";
36 | private ByteBuffer _handler;
37 |
38 | /**
39 | * Creates a ObjectDetector, configured with its model path, trained weights, etc.
40 | * These parameters cannot be changed once the object is constructed.
41 | * @param context Context
42 | * @param modelPath Caffe's model
43 | * @param wieghtsPath Caffe's trained wieght
44 | * @param manefile The file path of the image image
45 | * @param synsetFile The file path to load label's titles
46 | */
47 | public ObjectDetector(Context context, String modelPath, String wieghtsPath, String manefile, String synsetFile) throws IllegalAccessException {
48 | super(context, modelPath, wieghtsPath, manefile, synsetFile);
49 | if (!new File(mModelPath).exists() ||
50 | !new File(mWeightsPath).exists() ||
51 | !new File(mSynsetPath).exists() ) {
52 | throw new IllegalAccessException("ObjectDetector cannot find model");
53 | }
54 | }
55 |
56 | @Override
57 | public void init(int imgWidth, int imgHeight) {
58 | super.init(imgWidth, imgHeight);
59 | jniLoadModel(mModelPath, mWeightsPath, mMeanPath, mSynsetPath);
60 | }
61 |
62 | @Override
63 | public void deInit() {
64 | super.deInit();
65 | jniRelease();
66 | }
67 |
68 | @Override
69 | public void setSelectedLabel(String label) {
70 | super.setSelectedLabel(label);
71 | jniSetSelectedLabel(label);
72 | }
73 |
74 | @Override
75 | public void clearSelectedLabel() {
76 | super.clearSelectedLabel();
77 | jniSetSelectedLabel("");
78 | }
79 |
80 | /**
81 | * Detect and locate objects according to the given image path
82 | * @param imgPath image path
83 | * @return The list of the result {@link VisionDetRet} which objected are detected
84 | * @throws IllegalArgumentException if the Bitmap dimensions don't match
85 | * the dimensions defined at initialization or the given array
86 | * is not sized equal to the width and hegiht defined at initialization
87 | */
88 | @Override
89 | public List classifyByPath(String imgPath) {
90 | List ret = new ArrayList<>();
91 |
92 | if (TextUtils.isEmpty(imgPath) || !new File(imgPath).exists()) {
93 | Log.e(TAG, "classifyByPath. Invalid Input path");
94 | return ret;
95 | }
96 |
97 | int numObjs = jniClassifyImgByPath(imgPath);
98 | for (int i = 0; i != numObjs; i++) {
99 | VisionDetRet det = new VisionDetRet();
100 | int success = jniGetDetRet(det, i);
101 | if (success >= 0)
102 | ret.add(det);
103 |
104 | }
105 | return ret;
106 | }
107 |
108 | /**
109 | * Detect and locate objects according to the given bitmap
110 | * @param bitmap bitmap object {@link android.graphics.Bitmap} graphic object.
111 | * @return The list of the result {@link VisionDetRet} which objected are detected
112 | * @throws IllegalArgumentException if the Bitmap dimensions don't match
113 | * the dimensions defined at initialization or the given array
114 | * is not sized equal to the width and hegiht defined at initialization
115 | */
116 | @Override
117 | public List classify(Bitmap bitmap) {
118 | List ret = new ArrayList<>();
119 |
120 | // Check input
121 | if (bitmap == null) {
122 | Log.e(TAG, "classify. Invalid Input bitmap");
123 | return ret;
124 | }
125 |
126 | storeBitmap(bitmap);
127 |
128 | int numObjs = jniClassifyBitmap(_handler);
129 | for (int i = 0; i != numObjs; i++) {
130 | VisionDetRet det = new VisionDetRet();
131 | int success = jniGetDetRet(det, i);
132 | if (success >= 0)
133 | ret.add(det);
134 | }
135 |
136 | freeBitmap();
137 | return ret;
138 | }
139 |
140 | private void storeBitmap(final Bitmap bitmap) {
141 | if (_handler != null)
142 | freeBitmap();
143 | _handler = jniStoreBitmapData(bitmap);
144 | }
145 |
146 | private void freeBitmap() {
147 | if (_handler == null)
148 | return;
149 | jniFreeBitmapData(_handler);
150 | _handler = null;
151 | }
152 |
153 | protected native int jniLoadModel(String modelPath, String weightsPath, String meanfilePath, String sysetPath);
154 |
155 | protected native int jniRelease();
156 |
157 | protected native int jniSetSelectedLabel(String label);
158 |
159 | protected native int jniClassifyImgByPath(String imgPath);
160 |
161 | private native int jniClassifyBitmap(ByteBuffer handler);
162 |
163 | private native int jniGetDetRet(VisionDetRet det, int index);
164 |
165 | // Bitmap
166 | private native ByteBuffer jniStoreBitmapData(Bitmap bitmap);
167 |
168 | private native void jniFreeBitmapData(ByteBuffer handler);
169 | }
170 |
--------------------------------------------------------------------------------
/cnnlibs/src/main/java/com/tzutalin/vision/visionrecognition/SceneClassifier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.tzutalin.vision.visionrecognition;
18 |
19 | import android.content.Context;
20 | import android.graphics.Bitmap;
21 | import android.text.TextUtils;
22 | import android.util.Log;
23 |
24 | import java.io.File;
25 | import java.io.FileOutputStream;
26 | import java.nio.ByteBuffer;
27 | import java.util.ArrayList;
28 | import java.util.LinkedHashMap;
29 | import java.util.List;
30 | import java.util.Map;
31 |
32 | /**
33 | * Identifies the current scene in a
34 | * {@link android.graphics.Bitmap} graphic object.
35 | */
36 | public class SceneClassifier extends CaffeClassifier> {
37 | private static final String TAG = "SceneClassifier";
38 | private static final int MODEL_DIM = 224;
39 | private ByteBuffer _handler;
40 |
41 | /**
42 | * Creates a SceneClassifier, configured with its model path, trained weights, etc.
43 | * These parameters cannot be changed once the object is constructed.
44 | *
45 | * @param context Context
46 | * @param sceneModelPath Caffe's model
47 | * @param sceneWieghtsPath Caffe's trained wieght
48 | * @param sceneManefile The file path of the image image
49 | * @param sceneSynsetFile The file path to load label's titles
50 | */
51 | public SceneClassifier(Context context, String sceneModelPath, String sceneWieghtsPath, String sceneManefile, String sceneSynsetFile) throws IllegalAccessException {
52 | super(context, sceneModelPath, sceneWieghtsPath, sceneManefile, sceneSynsetFile);
53 | if (!new File(mModelPath).exists() ||
54 | !new File(mWeightsPath).exists() ||
55 | !new File(mSynsetPath).exists() ) {
56 | throw new IllegalAccessException("SceneClassifier cannot find model");
57 | }
58 | }
59 |
60 | /**
61 | * Recognize the scene according to the given image path
62 | *
63 | * @param imgPath image path
64 | * @return The list of the result {@link VisionDetRet} which scenes are recognized
65 | * @throws IllegalArgumentException if the Bitmap dimensions don't match
66 | * the dimensions defined at initialization or the given array
67 | * is not sized equal to the width and hegiht defined at initialization
68 | */
69 | @Override
70 | public List classifyByPath(String imgPath) {
71 | List ret = new ArrayList<>();
72 |
73 | if (TextUtils.isEmpty(imgPath) || !new File(imgPath).exists()) {
74 | Log.e(TAG, "classifyByPath. Invalid Input path");
75 | return ret;
76 | }
77 |
78 | float[] propArray = jniClassifyImgByPath(imgPath);
79 | if (propArray != null) {
80 | Map sortedMap = Utils.sortPrediction(mSynsets, propArray);
81 | int kSize = 10;
82 | for (Map.Entry sortedmapEntry : sortedMap.entrySet()) {
83 | VisionDetRet det = new VisionDetRet(sortedmapEntry.getKey(), sortedmapEntry.getValue(), 0, 0, 0, 0);
84 | ret.add(det);
85 | if (kSize == ret.size())
86 | break;
87 | }
88 | }
89 |
90 | return ret;
91 | }
92 |
93 | /**
94 | * Recognize the scene according to the given bitmap
95 | *
96 | * @param bitmap bitmap object {@link android.graphics.Bitmap} graphic object.
97 | * @return The list of the result {@link VisionDetRet} which scenes are recognized
98 | * @throws IllegalArgumentException if the Bitmap dimensions don't match
99 | * the dimensions defined at initialization or the given array
100 | * is not sized equal to the width and hegiht defined at initialization
101 | */
102 | @Override
103 | public List classify(Bitmap bitmap) {
104 | List ret = new ArrayList<>();
105 |
106 | // Check input
107 | if (bitmap == null) {
108 | Log.e(TAG, "classify. Invalid Input bitmap");
109 | return ret;
110 | }
111 |
112 | storeBitmap(bitmap);
113 |
114 | float[] propArray = jniClassifyBitmap(_handler);
115 | if (propArray != null) {
116 | Map sortedmap = Utils.sortPrediction(mSynsets, propArray);
117 | int kSize = 10;
118 | for (Map.Entry sortedMapEntry : sortedmap.entrySet()) {
119 | VisionDetRet det = new VisionDetRet(sortedMapEntry.getKey(), sortedMapEntry.getValue(), 0, 0, 0, 0);
120 | ret.add(det);
121 | if (kSize == ret.size())
122 | break;
123 | }
124 | }
125 |
126 | freeBitmap();
127 | return ret;
128 | }
129 |
130 | @Override
131 | public void init(int imgWidth, int imgHeight) {
132 | super.init(imgWidth, imgHeight);
133 | jniLoadModel(mModelPath, mWeightsPath);
134 | jniSetInputModelDim(MODEL_DIM, MODEL_DIM);
135 | }
136 |
137 | @Override
138 | public void deInit() {
139 | super.deInit();
140 | jniRelease();
141 | }
142 |
143 | private void storeBitmap(final Bitmap bitmap) {
144 | if (_handler != null)
145 | freeBitmap();
146 | _handler = jniStoreBitmapData(bitmap);
147 | }
148 |
149 | private void freeBitmap() {
150 | if (_handler == null)
151 | return;
152 | jniFreeBitmapData(_handler);
153 | _handler = null;
154 | }
155 |
156 | protected native int jniLoadModel(String modelPath, String weightsPath);
157 |
158 | protected native int jniSetInputModelDim(int width, int height);
159 |
160 | protected native int jniRelease();
161 |
162 | protected native float[] jniClassifyImgByPath(String imgPath);
163 |
164 | private native float[] jniClassifyBitmap(ByteBuffer handler);
165 |
166 | // Bitmap
167 | private native ByteBuffer jniStoreBitmapData(Bitmap bitmap);
168 |
169 | private native void jniFreeBitmapData(ByteBuffer handler);
170 |
171 | private native Bitmap jniGetBitmapFromStoredBitmapData(ByteBuffer handler);
172 | }
173 |
--------------------------------------------------------------------------------
/cnnlibs/src/main/java/com/tzutalin/vision/visionrecognition/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.tzutalin.vision.visionrecognition;
17 |
18 | import android.support.annotation.NonNull;
19 |
20 | import java.util.Collections;
21 | import java.util.Comparator;
22 | import java.util.HashMap;
23 | import java.util.LinkedHashMap;
24 | import java.util.LinkedList;
25 | import java.util.List;
26 | import java.util.Map;
27 | import java.util.TreeMap;
28 |
29 | /**
30 | * Created by darrenl on 2015/9/10.
31 | */
32 | public final class Utils {
33 |
34 | private Utils() throws InstantiationException {
35 | throw new InstantiationException("This class is not for initialization");
36 | }
37 |
38 | @NonNull
39 | public static Map sortPrediction(@NonNull String[] synsets, @NonNull float[] propArray) {
40 | HashMap map = new HashMap<>();
41 | if (propArray != null) {
42 | for (int i = 0; i != synsets.length; i++) {
43 | map.put(synsets[i], propArray[i]);
44 | }
45 | }
46 |
47 | return sortByValue(map);
48 |
49 | }
50 |
51 | public static > Map
52 | sortByValue(Map map) {
53 | List> list =
54 | new LinkedList<>(map.entrySet());
55 | Collections.sort(list, new Comparator>() {
56 | @Override
57 | public int compare(Map.Entry o1, Map.Entry o2) {
58 | return (o2.getValue()).compareTo(o1.getValue());
59 | }
60 | });
61 |
62 | Map result = new LinkedHashMap<>();
63 | for (Map.Entry entry : list) {
64 | result.put(entry.getKey(), entry.getValue());
65 | }
66 | return result;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/cnnlibs/src/main/java/com/tzutalin/vision/visionrecognition/VisionClassifierCreator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.tzutalin.vision.visionrecognition;
18 |
19 | import android.content.Context;
20 | import android.support.annotation.NonNull;
21 |
22 | import java.io.File;
23 |
24 | /**
25 | * Create an instance using default instances for vision recognition and detection
26 | */
27 | public final class VisionClassifierCreator {
28 | private final static String SCENE_MODEL_PATH = "/sdcard/phone_data/vision_scene/mit/deploy_places205_mem.protxt";
29 | private final static String SCENE_WIEGHTS_PATH = "/sdcard/phone_data/vision_scene/mit/googlelet_places205_train_iter_2400000.caffemodel";
30 | private final static String SCENE_MEAN_FILE = null;
31 | private final static String SCENE_SYNSET_FILE = "/sdcard/phone_data/vision_scene/mit/mit_category_table";
32 |
33 | private final static String DETECT_MODEL_PATH = "/sdcard/phone_data/fastrcnn/deploy.prototxt";
34 | private final static String DETECT_WIEGHTS_PATH = "/sdcard/phone_data/fastrcnn/caffenet_fast_rcnn_iter_40000.caffemodel";
35 | private final static String DETECT_MEAN_FILE = "/sdcard/phone_data/fastrcnn/imagenet_mean.binaryproto";
36 | private final static String DETECT_SYNSET_FILE = "/sdcard/phone_data/fastrcnn/fastrcnn_synset";
37 |
38 | private VisionClassifierCreator() throws InstantiationException {
39 | throw new InstantiationException("This class is not for instantiation");
40 | }
41 |
42 | /**
43 | * Create an instance using a default {@link SceneClassifier} instance
44 | * @return {@link SceneClassifier instance
45 | */
46 | @NonNull
47 | public static SceneClassifier createSceneClassifier(@NonNull Context context) throws IllegalAccessException {
48 | return new SceneClassifier(context, SCENE_MODEL_PATH, SCENE_WIEGHTS_PATH, SCENE_MEAN_FILE, SCENE_SYNSET_FILE);
49 | }
50 |
51 | /**
52 | * Create an instance using a default {@link ObjectDetector} instance
53 | * @return {@link ObjectDetector} instance
54 | */
55 | @NonNull
56 | public static ObjectDetector createObjectDetector(@NonNull Context context) throws IllegalAccessException {
57 | return new ObjectDetector(context, DETECT_MODEL_PATH, DETECT_WIEGHTS_PATH, DETECT_MEAN_FILE, DETECT_SYNSET_FILE);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/cnnlibs/src/main/java/com/tzutalin/vision/visionrecognition/VisionDetRet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 TzuTaLin
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.tzutalin.vision.visionrecognition;
18 |
19 | /**
20 | * A VisionDetRet contains all the information identifying the location and confidence value of the detected object in a bitmap.
21 | */
22 | public final class VisionDetRet {
23 | private String mLabel;
24 | private float mConfidence;
25 | private int mLeft;
26 | private int mTop;
27 | private int mRight;
28 | private int mBottom;
29 |
30 | VisionDetRet() {
31 | }
32 |
33 | /**
34 | *
35 | * @param label Label name
36 | * @param confidence A confidence factor between 0 and 1. This indicates how certain what has been found is actually the label.
37 | * @param l The X coordinate of the left side of the result
38 | * @param t The Y coordinate of the top of the result
39 | * @param r The X coordinate of the right side of the result
40 | * @param b The Y coordinate of the bottom of the result
41 | */
42 | public VisionDetRet(String label, float confidence, int l, int t, int r, int b) {
43 | mLabel = label;
44 | mLeft = l;
45 | mTop = t;
46 | mRight = r;
47 | mBottom = b;
48 | mConfidence = confidence;
49 | }
50 |
51 | /**
52 | * @return The X coordinate of the left side of the result
53 | */
54 | public int getLeft() {
55 | return mLeft;
56 | }
57 |
58 | /**
59 | * @return The Y coordinate of the top of the result
60 | */
61 | public int getTop() {
62 | return mTop;
63 | }
64 |
65 | /**
66 | * @return The X coordinate of the right side of the result
67 | */
68 | public int getRight() {
69 | return mRight;
70 | }
71 |
72 | /**
73 | * @return The Y coordinate of the bottom of the result
74 | */
75 | public int getBottom() {
76 | return mBottom;
77 | }
78 |
79 | /**
80 | * @return A confidence factor between 0 and 1. This indicates how certain what has been found is actually the label.
81 | */
82 | public float getConfidence() {
83 | return mConfidence;
84 | }
85 |
86 | /**
87 | *
88 | * @return The label of the result
89 | */
90 | public String getLabel() {
91 | return mLabel;
92 | }
93 |
94 | @Override
95 | public String toString() {
96 | return new StringBuilder()
97 | .append("Left:")
98 | .append(mLeft)
99 | .append(", Top:")
100 | .append(mTop)
101 | .append(", Right:")
102 | .append(mRight)
103 | .append(", Bottom:")
104 | .append(mBottom)
105 | .append(", Label:")
106 | .append(mLabel).toString();
107 | }
108 | }
--------------------------------------------------------------------------------
/cnnlibs/src/main/jniLibs/armeabi-v7a/libobjrek.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/cnnlibs/src/main/jniLibs/armeabi-v7a/libobjrek.so
--------------------------------------------------------------------------------
/cnnlibs/src/main/jniLibs/armeabi-v7a/libobjrek_jni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/cnnlibs/src/main/jniLibs/armeabi-v7a/libobjrek_jni.so
--------------------------------------------------------------------------------
/cnnlibs/src/main/jniLibs/x86/libobjrek.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/cnnlibs/src/main/jniLibs/x86/libobjrek.so
--------------------------------------------------------------------------------
/cnnlibs/src/main/jniLibs/x86/libobjrek_jni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/cnnlibs/src/main/jniLibs/x86/libobjrek_jni.so
--------------------------------------------------------------------------------
/cnnlibs/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CNNLibs
3 |
4 |
--------------------------------------------------------------------------------
/contributors.txt:
--------------------------------------------------------------------------------
1 | TzuTa Lin
2 |
--------------------------------------------------------------------------------
/demo/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/demo/1.png
--------------------------------------------------------------------------------
/demo/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/demo/2.png
--------------------------------------------------------------------------------
/demo/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/demo/3.png
--------------------------------------------------------------------------------
/demo/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/demo/4.png
--------------------------------------------------------------------------------
/demo/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/demo/5.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Mar 21 14:55:14 CST 2017
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-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':cnnlibs'
2 |
--------------------------------------------------------------------------------
/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | if [ -d phone_data/ ]
4 | then
5 | echo ".. model exists already ..."
6 | else
7 | echo ".. Try to download the model ..."
8 | ./tools/get_model.py
9 | fi
10 |
11 | rm phone_data.tar > /dev/null 2>&1
12 | echo "--- Try to push data to sdcard ---"
13 | adb wait-for-device
14 | echo "--- start pushing ---"
15 | adb push phone_data/ /sdcard/
16 |
17 |
--------------------------------------------------------------------------------
/tools/get_model.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 | import os
4 | import time
5 | import tarfile
6 |
7 | if sys.version_info >= (3,):
8 | import urllib.request as urllib2
9 | import urllib.parse as urlparse
10 | else:
11 | import urllib2
12 | import urlparse
13 | import urllib
14 |
15 | def download_file(url, desc=None, renamed_file=None):
16 | u = urllib2.urlopen(url)
17 | scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
18 | filename = os.path.basename(path)
19 | if not filename:
20 | filename = 'downloaded.file'
21 |
22 | if not renamed_file is None:
23 | filename = renamed_file
24 |
25 | if desc:
26 | filename = os.path.join(desc, filename)
27 |
28 | with open(filename, 'wb') as f:
29 | meta = u.info()
30 | meta_func = meta.getheaders if hasattr(meta, 'getheaders') else meta.get_all
31 | meta_length = meta_func("Content-Length")
32 | file_size = None
33 | if meta_length:
34 | file_size = int(meta_length[0])
35 | print("Downloading: {0} Bytes: {1}".format(url, file_size))
36 |
37 | file_size_dl = 0
38 | block_sz = 8192
39 | while True:
40 | buffer = u.read(block_sz)
41 | if not buffer:
42 | break
43 |
44 | file_size_dl += len(buffer)
45 | f.write(buffer)
46 |
47 | status = "{0:16}".format(file_size_dl)
48 | if file_size:
49 | status += " [{0:6.2f}%]".format(file_size_dl * 100 / file_size)
50 | status += chr(13)
51 |
52 | return filename
53 |
54 | def extractTarfile(filename):
55 | tar = tarfile.open(filename)
56 | tar.extractall()
57 | tar.close()
58 |
59 | if __name__== '__main__':
60 | download_url = 'https://www.dropbox.com/s/0i2fr9krb8wv8mp/phone_data.tar?dl=1'
61 | target_name = 'phone_data.tar'
62 | download_file(download_url, renamed_file=target_name)
63 | extractTarfile(target_name)
64 |
--------------------------------------------------------------------------------
/tools/testcar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzutalin/Android-Object-Detection/ff0319803e382cb9b7037bc49e38d7e33369d568/tools/testcar.jpg
--------------------------------------------------------------------------------