├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── libraries
│ ├── animated_vector_drawable_25_0_1.xml
│ ├── appcompat_v7_25_0_1.xml
│ ├── design_25_0_1.xml
│ ├── espresso_core_2_2_2.xml
│ ├── espresso_idling_resource_2_2_2.xml
│ ├── exposed_instrumentation_api_publish_0_5.xml
│ ├── hamcrest_core_1_3.xml
│ ├── hamcrest_integration_1_3.xml
│ ├── hamcrest_library_1_3.xml
│ ├── javassist_3_16_1_GA.xml
│ ├── javawriter_2_1_1.xml
│ ├── javax_annotation_api_1_2.xml
│ ├── javax_inject_1.xml
│ ├── json_simple_1_1_1.xml
│ ├── jsr305_2_0_1.xml
│ ├── junit_4_12.xml
│ ├── junit_4_8_2.xml
│ ├── msgpack_0_6_8.xml
│ ├── recyclerview_v7_25_0_1.xml
│ ├── rules_0_5.xml
│ ├── runner_0_5.xml
│ ├── support_annotations_25_2_0.xml
│ ├── support_compat_25_2_0.xml
│ ├── support_core_ui_25_2_0.xml
│ ├── support_core_utils_25_2_0.xml
│ ├── support_fragment_25_2_0.xml
│ ├── support_media_compat_25_2_0.xml
│ ├── support_v13_25_2_0.xml
│ ├── support_v4_25_2_0.xml
│ ├── support_vector_drawable_25_0_1.xml
│ └── transition_25_0_1.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── CMakeLists.txt
├── build.gradle
├── libs
│ ├── javassist-3.16.1-GA.jar
│ ├── json-simple-1.1.1.jar
│ ├── junit-4.8.2.jar
│ └── msgpack-0.6.8.jar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── de
│ │ └── hpi
│ │ └── xnor_mxnet
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ ├── de
│ │ │ └── hpi
│ │ │ │ └── xnor_mxnet
│ │ │ │ ├── AutoFitTextureView.java
│ │ │ │ ├── BorderedText.java
│ │ │ │ ├── CameraConnectionFragment.java
│ │ │ │ ├── CameraFrameCapture.java
│ │ │ │ ├── CameraLiveViewActivity.java
│ │ │ │ ├── GPSTracker.java
│ │ │ │ ├── GetWiki.java
│ │ │ │ ├── HttpHandler.java
│ │ │ │ ├── ImageClassificationTask.java
│ │ │ │ ├── ImageUtils.java
│ │ │ │ ├── LocationDetails.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── OverlayView.java
│ │ │ │ └── imageclassification
│ │ │ │ ├── AbstractClassifier.java
│ │ │ │ ├── Classification.java
│ │ │ │ ├── ImageClassifier.java
│ │ │ │ ├── ImageNetClassifier.java
│ │ │ │ └── ModelPreparationTask.java
│ │ └── org
│ │ │ └── dmlc
│ │ │ └── mxnet
│ │ │ ├── MxnetException.java
│ │ │ └── Predictor.java
│ ├── jniLibs
│ │ └── arm64-v8a
│ │ │ ├── libc++_shared.so
│ │ │ ├── libmxnet_predict.so
│ │ │ └── libopenblas.so
│ ├── native-image-utils
│ │ ├── imageutils_jni.cc
│ │ ├── yuv2rgb.cc
│ │ └── yuv2rgb.h
│ └── res
│ │ ├── layout
│ │ ├── activity_gpslogger.xml
│ │ ├── content_gpslogger.xml
│ │ ├── main_activity.xml
│ │ └── placerecognizer_ui.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── raw
│ │ ├── binarized_densenet_28_params
│ │ ├── binarized_densenet_28_symbol
│ │ ├── binarized_resnet_e_18_params
│ │ ├── binarized_resnet_e_18_symbol
│ │ └── synset.txt
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ ├── de
│ └── hpi
│ │ └── xnor_mxnet
│ │ └── ExampleUnitTest.java
│ └── mxnet
│ ├── MxnetException.java
│ └── Predictor.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | *.gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/workspace.xml
38 |
39 | # Keystore files
40 | *.jks
41 |
42 | app/.externalNativeBuild/
43 | app/src/main/jniLibs
44 | app/src/main/res/raw
45 |
46 | .idea
47 | .cxx
48 |
--------------------------------------------------------------------------------
/.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/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/libraries/animated_vector_drawable_25_0_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/appcompat_v7_25_0_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/design_25_0_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/espresso_core_2_2_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/espresso_idling_resource_2_2_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/exposed_instrumentation_api_publish_0_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/hamcrest_core_1_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/libraries/hamcrest_integration_1_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/hamcrest_library_1_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/javassist_3_16_1_GA.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/javawriter_2_1_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/javax_annotation_api_1_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/javax_inject_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/json_simple_1_1_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/jsr305_2_0_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/junit_4_12.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/libraries/junit_4_8_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/msgpack_0_6_8.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/libraries/recyclerview_v7_25_0_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/rules_0_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/runner_0_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/support_annotations_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/libraries/support_compat_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/support_core_ui_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/support_core_utils_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/support_fragment_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/support_media_compat_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/support_v13_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/support_v4_25_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/libraries/support_vector_drawable_25_0_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/libraries/transition_25_0_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android Image Classification
2 | ============================
3 |
4 | This is an example project capable of performing image classification on a live camera feed, using a binarized neural network on Android.
5 |
6 | Requirements
7 | ------------
8 |
9 | * android device (minimum required Android version is 4.2 (API level 21))
10 |
11 | Usage
12 | -----
13 |
14 | Clone the repository, open and compile the project with Android Studio. Tested to work with Android Studio 4.0 and SDK 29.
15 | If you want to use the library on an device that does not have a armv7 or armv8 processor, you have to recompile the BMXNet library as described [here](https://github.com/hpi-xnor/BMXNet-v2/tree/master/amalgamation), using the correct toolchain.
16 |
17 | Please take care when recompiling the library to set the definition of `BINARY_WORD_32` or `BINARY_WORD_64` according to your target architecture and also to convert the model to the right `BINARY_WORD` using the model converter supplied with BMXNet.
18 |
19 | If you want to use any model other than the two provided (`DenseNet-28` and `ResNetE-18`), you'll have to make sure that
20 | the `symbol` file contains a `softmax` as output op. And that the id of the output layer is set correctly in the symbol json file.
21 | You can find the symbol and model files in `app/src/main/res/raw`.
22 |
23 | If you want to change the used default model (from `DensetNet-28` to `ResNetE-18` or vice versa), you'll have to
24 | change [these two](https://github.com/hpi-xnor/android-image-classification/blob/master/app/src/main/java/de/hpi/xnor_mxnet/imageclassification/ImageNetClassifier.java#L56-L57)
25 | lines.
26 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | set(SourceLocation src/main/native-image-utils)
4 |
5 | add_library(native-image-utils SHARED "${SourceLocation}/imageutils_jni.cc" "${SourceLocation}/yuv2rgb.cc")
6 | include_directories(${SOURCE})
7 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.3"
6 | defaultConfig {
7 | applicationId "de.hpi.xnor_mxnet"
8 | minSdkVersion 21
9 | targetSdkVersion 29
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | externalNativeBuild {
21 | cmake {
22 | path 'CMakeLists.txt'
23 | }
24 | }
25 | ndkVersion '21.0.6113669'
26 | }
27 |
28 | dependencies {
29 | compile fileTree(include: ['*.jar', '*.so'], dir: 'libs')
30 | androidTestCompile('androidx.test.espresso:espresso-core:3.1.0', {
31 | exclude group: 'com.android.support', module: 'support-annotations'
32 | })
33 | compile 'androidx.appcompat:appcompat:1.0.2'
34 | compile 'com.google.android.material:material:1.0.0'
35 | testCompile 'junit:junit:4.12'
36 | compile 'androidx.legacy:legacy-support-v13:1.0.0'
37 | }
38 |
--------------------------------------------------------------------------------
/app/libs/javassist-3.16.1-GA.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/libs/javassist-3.16.1-GA.jar
--------------------------------------------------------------------------------
/app/libs/json-simple-1.1.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/libs/json-simple-1.1.1.jar
--------------------------------------------------------------------------------
/app/libs/junit-4.8.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/libs/junit-4.8.2.jar
--------------------------------------------------------------------------------
/app/libs/msgpack-0.6.8.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/libs/msgpack-0.6.8.jar
--------------------------------------------------------------------------------
/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 /Users/timoesterreich/Library/Android/sdk/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/androidTest/java/de/hpi/xnor_mxnet/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("de.hpi.placerecognizer", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/AutoFitTextureView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 The Android Open Source Project
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 de.hpi.xnor_mxnet;
18 |
19 | import android.content.Context;
20 | import android.util.AttributeSet;
21 | import android.util.Size;
22 | import android.view.TextureView;
23 |
24 | /**
25 | * A {@link TextureView} that can be adjusted to a specified aspect ratio.
26 | */
27 | public class AutoFitTextureView extends TextureView {
28 |
29 | private int mRatioWidth = 0;
30 | private int mRatioHeight = 0;
31 |
32 | public AutoFitTextureView(Context context) {
33 | this(context, null);
34 | }
35 |
36 | public AutoFitTextureView(Context context, AttributeSet attrs) {
37 | this(context, attrs, 0);
38 | }
39 |
40 | public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
41 | super(context, attrs, defStyle);
42 | }
43 |
44 | /**
45 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
46 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
47 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
48 | *
49 | * @param width Relative horizontal size
50 | * @param height Relative vertical size
51 | */
52 | public void setAspectRatio(int width, int height) {
53 | if (width < 0 || height < 0) {
54 | throw new IllegalArgumentException("Size cannot be negative.");
55 | }
56 | mRatioWidth = width;
57 | mRatioHeight = height;
58 | requestLayout();
59 | }
60 |
61 | @Override
62 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
63 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
64 |
65 | int width = MeasureSpec.getSize(widthMeasureSpec);
66 | int height = MeasureSpec.getSize(heightMeasureSpec);
67 | if (0 == mRatioWidth || 0 == mRatioHeight) {
68 | setMeasuredDimension(width, height);
69 | } else {
70 | if (width < height * mRatioWidth / mRatioHeight) {
71 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
72 | } else {
73 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
74 | }
75 | }
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/BorderedText.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | ==============================================================================*/
15 |
16 | package de.hpi.xnor_mxnet;
17 |
18 | import android.graphics.Canvas;
19 | import android.graphics.Color;
20 | import android.graphics.Paint;
21 | import android.graphics.Paint.Align;
22 | import android.graphics.Paint.Style;
23 | import android.graphics.Rect;
24 | import android.graphics.Typeface;
25 | import java.util.Vector;
26 |
27 | /**
28 | * A class that encapsulates the tedious bits of rendering legible, bordered text onto a canvas.
29 | */
30 | public class BorderedText {
31 | private final Paint interiorPaint;
32 | private final Paint exteriorPaint;
33 |
34 | private final float textSize;
35 |
36 | /**
37 | * Creates a left-aligned bordered text object with a white interior, and a black exterior with
38 | * the specified text size.
39 | *
40 | * @param textSize text size in pixels
41 | */
42 | public BorderedText(final float textSize) {
43 | this(Color.WHITE, Color.BLACK, textSize);
44 | }
45 |
46 | /**
47 | * Create a bordered text object with the specified interior and exterior colors, text size and
48 | * alignment.
49 | *
50 | * @param interiorColor the interior text color
51 | * @param exteriorColor the exterior text color
52 | * @param textSize text size in pixels
53 | */
54 | public BorderedText(final int interiorColor, final int exteriorColor, final float textSize) {
55 | interiorPaint = new Paint();
56 | interiorPaint.setTextSize(textSize);
57 | interiorPaint.setColor(interiorColor);
58 | interiorPaint.setStyle(Style.FILL);
59 | interiorPaint.setAntiAlias(false);
60 | interiorPaint.setAlpha(255);
61 |
62 | exteriorPaint = new Paint();
63 | exteriorPaint.setTextSize(textSize);
64 | exteriorPaint.setColor(exteriorColor);
65 | exteriorPaint.setStyle(Style.FILL_AND_STROKE);
66 | exteriorPaint.setStrokeWidth(textSize / 8);
67 | exteriorPaint.setAntiAlias(false);
68 | exteriorPaint.setAlpha(255);
69 |
70 | this.textSize = textSize;
71 | }
72 |
73 | public void setTypeface(Typeface typeface) {
74 | interiorPaint.setTypeface(typeface);
75 | exteriorPaint.setTypeface(typeface);
76 | }
77 |
78 | public void drawText(final Canvas canvas, final float posX, final float posY, final String text) {
79 | canvas.drawText(text, posX, posY, exteriorPaint);
80 | canvas.drawText(text, posX, posY, interiorPaint);
81 | }
82 |
83 | public void drawLines(Canvas canvas, final float posX, final float posY, Vector lines) {
84 | int lineNum = 0;
85 | for (final String line : lines) {
86 | drawText(canvas, posX, posY - getTextSize() * (lines.size() - lineNum - 1), line);
87 | ++lineNum;
88 | }
89 | }
90 |
91 | public void setInteriorColor(final int color) {
92 | interiorPaint.setColor(color);
93 | }
94 |
95 | public void setExteriorColor(final int color) {
96 | exteriorPaint.setColor(color);
97 | }
98 |
99 | public float getTextSize() {
100 | return textSize;
101 | }
102 |
103 | public void setAlpha(final int alpha) {
104 | interiorPaint.setAlpha(alpha);
105 | exteriorPaint.setAlpha(alpha);
106 | }
107 |
108 | public void getTextBounds(
109 | final String line, final int index, final int count, final Rect lineBounds) {
110 | interiorPaint.getTextBounds(line, index, count, lineBounds);
111 | }
112 |
113 | public void setTextAlign(final Align align) {
114 | interiorPaint.setTextAlign(align);
115 | exteriorPaint.setTextAlign(align);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/CameraConnectionFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 The TensorFlow Authors. All Rights Reserved.
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 de.hpi.xnor_mxnet;
18 |
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.res.Configuration;
27 | import android.graphics.ImageFormat;
28 | import android.graphics.Matrix;
29 | import android.graphics.RectF;
30 | import android.graphics.SurfaceTexture;
31 | import android.hardware.camera2.CameraAccessException;
32 | import android.hardware.camera2.CameraCaptureSession;
33 | import android.hardware.camera2.CameraCharacteristics;
34 | import android.hardware.camera2.CameraDevice;
35 | import android.hardware.camera2.CameraManager;
36 | import android.hardware.camera2.CaptureRequest;
37 | import android.hardware.camera2.CaptureResult;
38 | import android.hardware.camera2.TotalCaptureResult;
39 | import android.hardware.camera2.params.StreamConfigurationMap;
40 | import android.media.ImageReader;
41 | import android.media.ImageReader.OnImageAvailableListener;
42 | import android.os.Bundle;
43 | import android.os.Handler;
44 | import android.os.HandlerThread;
45 | import android.text.TextUtils;
46 | import android.util.Size;
47 | import android.util.SparseIntArray;
48 | import android.view.LayoutInflater;
49 | import android.view.Surface;
50 | import android.view.TextureView;
51 | import android.view.View;
52 | import android.view.ViewGroup;
53 | import android.view.ViewGroup.LayoutParams;
54 | import android.widget.Toast;
55 | import java.util.ArrayList;
56 | import java.util.Arrays;
57 | import java.util.Collections;
58 | import java.util.Comparator;
59 | import java.util.List;
60 | import java.util.concurrent.Semaphore;
61 | import java.util.concurrent.TimeUnit;
62 | import java.util.stream.Stream;
63 |
64 | public class CameraConnectionFragment extends Fragment {
65 |
66 | /**
67 | * The camera preview size will be chosen to be the smallest frame by pixel size capable of
68 | * containing a DESIRED_SIZE x DESIRED_SIZE square.
69 | */
70 | private static final int MINIMUM_PREVIEW_SIZE = 320;
71 |
72 | /**
73 | * Conversion from screen rotation to JPEG orientation.
74 | */
75 | private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
76 | private static final String FRAGMENT_DIALOG = "dialog";
77 |
78 | static {
79 | ORIENTATIONS.append(Surface.ROTATION_0, 90);
80 | ORIENTATIONS.append(Surface.ROTATION_90, 0);
81 | ORIENTATIONS.append(Surface.ROTATION_180, 270);
82 | ORIENTATIONS.append(Surface.ROTATION_270, 180);
83 | }
84 | /**
85 | * {@link android.view.TextureView.SurfaceTextureListener} handles several lifecycle events on a
86 | * {@link TextureView}.
87 | */
88 | private final TextureView.SurfaceTextureListener surfaceTextureListener =
89 | new TextureView.SurfaceTextureListener() {
90 | @Override
91 | public void onSurfaceTextureAvailable(
92 | final SurfaceTexture texture, final int width, final int height) {
93 | openCamera(width, height);
94 | }
95 |
96 | @Override
97 | public void onSurfaceTextureSizeChanged(
98 | final SurfaceTexture texture, final int width, final int height) {
99 | configureTransform(width, height);
100 | }
101 |
102 | @Override
103 | public boolean onSurfaceTextureDestroyed(final SurfaceTexture texture) {
104 | return true;
105 | }
106 |
107 | @Override
108 | public void onSurfaceTextureUpdated(final SurfaceTexture texture) {}
109 | };
110 |
111 | /**
112 | * Callback for Activities to use to initialize their data once the
113 | * selected preview size is known.
114 | */
115 | public interface ConnectionCallback {
116 | void onPreviewSizeChosen(Size size, int cameraRotation);
117 | }
118 |
119 | /**
120 | * ID of the current {@link CameraDevice}.
121 | */
122 | private String cameraId;
123 |
124 | /**
125 | * An {@link AutoFitTextureView} for camera preview.
126 | */
127 | private AutoFitTextureView textureView;
128 |
129 | /**
130 | * A {@link CameraCaptureSession } for camera preview.
131 | */
132 | private CameraCaptureSession captureSession;
133 |
134 | /**
135 | * A reference to the opened {@link CameraDevice}.
136 | */
137 | private CameraDevice cameraDevice;
138 |
139 | /**
140 | * The rotation in degrees of the camera sensor from the display.
141 | */
142 | private Integer sensorOrientation;
143 |
144 | /**
145 | * The {@link android.util.Size} of camera preview.
146 | */
147 | private Size previewSize;
148 |
149 | /**
150 | * {@link android.hardware.camera2.CameraDevice.StateCallback}
151 | * is called when {@link CameraDevice} changes its state.
152 | */
153 | private final CameraDevice.StateCallback stateCallback =
154 | new CameraDevice.StateCallback() {
155 | @Override
156 | public void onOpened(final CameraDevice cd) {
157 | // This method is called when the camera is opened. We start camera preview here.
158 | cameraOpenCloseLock.release();
159 | cameraDevice = cd;
160 | createCameraPreviewSession();
161 | }
162 |
163 | @Override
164 | public void onDisconnected(final CameraDevice cd) {
165 | cameraOpenCloseLock.release();
166 | cd.close();
167 | cameraDevice = null;
168 | }
169 |
170 | @Override
171 | public void onError(final CameraDevice cd, final int error) {
172 | cameraOpenCloseLock.release();
173 | cd.close();
174 | cameraDevice = null;
175 | final Activity activity = getActivity();
176 | if (null != activity) {
177 | activity.finish();
178 | }
179 | }
180 | };
181 |
182 | /**
183 | * An additional thread for running tasks that shouldn't block the UI.
184 | */
185 | private HandlerThread backgroundThread;
186 |
187 | /**
188 | * A {@link Handler} for running tasks in the background.
189 | */
190 | private Handler backgroundHandler;
191 |
192 | /**
193 | * An {@link ImageReader} that handles preview frame capture.
194 | */
195 | private ImageReader previewReader;
196 |
197 | /**
198 | * {@link android.hardware.camera2.CaptureRequest.Builder} for the camera preview
199 | */
200 | private CaptureRequest.Builder previewRequestBuilder;
201 |
202 | /**
203 | * {@link CaptureRequest} generated by {@link #previewRequestBuilder}
204 | */
205 | private CaptureRequest previewRequest;
206 |
207 | /**
208 | * A {@link Semaphore} to prevent the app from exiting before closing the camera.
209 | */
210 | private final Semaphore cameraOpenCloseLock = new Semaphore(1);
211 |
212 | /**
213 | * A {@link OnImageAvailableListener} to receive frames as they are available.
214 | */
215 | private final OnImageAvailableListener imageListener;
216 |
217 | /** The input size in pixels desired by TensorFlow (width and height of a square bitmap). */
218 | private final Size inputSize;
219 |
220 | /**
221 | * The layout identifier to inflate for this Fragment.
222 | */
223 | private final int layout;
224 |
225 |
226 | private final ConnectionCallback cameraConnectionCallback;
227 |
228 | private CameraConnectionFragment(
229 | final ConnectionCallback connectionCallback,
230 | final OnImageAvailableListener imageListener,
231 | final int layout,
232 | final Size inputSize) {
233 | this.cameraConnectionCallback = connectionCallback;
234 | this.imageListener = imageListener;
235 | this.layout = layout;
236 | this.inputSize = inputSize;
237 | }
238 |
239 | /**
240 | * Shows a {@link Toast} on the UI thread.
241 | *
242 | * @param text The message to show
243 | */
244 | private void showToast(final String text) {
245 | final Activity activity = getActivity();
246 | if (activity != null) {
247 | activity.runOnUiThread(
248 | new Runnable() {
249 | @Override
250 | public void run() {
251 | Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
252 | }
253 | });
254 | }
255 | }
256 |
257 | /**
258 | * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
259 | * width and height are at least as large as the minimum of both, or an exact match if possible.
260 | *
261 | * @param choices The list of sizes that the camera supports for the intended output class
262 | * @param width The minimum desired width
263 | * @param height The minimum desired height
264 | * @return The optimal {@code Size}, or an arbitrary one if none were big enough
265 | */
266 | private static Size chooseOptimalSize(final Size[] choices, final int width, final int height) {
267 | final int minSize = Math.max(Math.min(width, height), MINIMUM_PREVIEW_SIZE);
268 | final Size desiredSize = new Size(width, height);
269 |
270 | // Collect the supported resolutions that are at least as big as the preview Surface
271 | boolean exactSizeFound = false;
272 | final List bigEnough = new ArrayList();
273 | final List tooSmall = new ArrayList();
274 | for (final Size option : choices) {
275 | if (option.equals(desiredSize)) {
276 | // Set the size but don't return yet so that remaining sizes will still be logged.
277 | exactSizeFound = true;
278 | }
279 |
280 | if (option.getHeight() >= minSize && option.getWidth() >= minSize) {
281 | bigEnough.add(option);
282 | } else {
283 | tooSmall.add(option);
284 | }
285 | }
286 |
287 | if (exactSizeFound) {
288 | return desiredSize;
289 | }
290 |
291 | // Pick the smallest of those, assuming we found any
292 | if (bigEnough.size() > 0) {
293 | final Size chosenSize = Collections.min(bigEnough, new CompareSizesByArea());
294 | return chosenSize;
295 | } else {
296 | return choices[0];
297 | }
298 | }
299 |
300 | public static CameraConnectionFragment newInstance(
301 | final ConnectionCallback callback,
302 | final OnImageAvailableListener imageListener,
303 | final int layout,
304 | final Size inputSize) {
305 | return new CameraConnectionFragment(callback, imageListener, layout, inputSize);
306 | }
307 |
308 | @Override
309 | public View onCreateView(
310 | final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
311 | return inflater.inflate(layout, container, false);
312 | }
313 |
314 | @Override
315 | public void onViewCreated(final View view, final Bundle savedInstanceState) {
316 | textureView = (AutoFitTextureView) view.findViewById(R.id.texture);
317 | }
318 |
319 | @Override
320 | public void onActivityCreated(final Bundle savedInstanceState) {
321 | super.onActivityCreated(savedInstanceState);
322 | }
323 |
324 | @Override
325 | public void onResume() {
326 | super.onResume();
327 | startBackgroundThread();
328 |
329 | // When the screen is turned off and turned back on, the SurfaceTexture is already
330 | // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
331 | // a camera and start preview from here (otherwise, we wait until the surface is ready in
332 | // the SurfaceTextureListener).
333 | if (textureView.isAvailable()) {
334 | openCamera(textureView.getWidth(), textureView.getHeight());
335 | } else {
336 | textureView.setSurfaceTextureListener(surfaceTextureListener);
337 | }
338 | }
339 |
340 | @Override
341 | public void onPause() {
342 | closeCamera();
343 | stopBackgroundThread();
344 | super.onPause();
345 | }
346 |
347 | /**
348 | * Sets up member variables related to camera.
349 | *
350 | * @param width The width of available size for camera preview
351 | * @param height The height of available size for camera preview
352 | */
353 | private void setUpCameraOutputs(final int width, final int height) {
354 | final Activity activity = getActivity();
355 | final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
356 | try {
357 | for (final String cameraId : manager.getCameraIdList()) {
358 | final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
359 |
360 | // We don't use a front facing camera in this sample.
361 | final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
362 | if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
363 | continue;
364 | }
365 |
366 | final StreamConfigurationMap map =
367 | characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
368 |
369 | if (map == null) {
370 | continue;
371 | }
372 | sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
373 |
374 | // Danger, W.R.! Attempting to use too large a preview size could exceed the camera
375 | // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
376 | // garbage capture data.
377 | previewSize =
378 | chooseOptimalSize(
379 | map.getOutputSizes(SurfaceTexture.class),
380 | inputSize.getWidth(),
381 | inputSize.getHeight());
382 |
383 | // We fit the aspect ratio of TextureView to the size of preview we picked.
384 | final int orientation = getResources().getConfiguration().orientation;
385 | if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
386 | textureView.setAspectRatio(previewSize.getWidth(), previewSize.getHeight());
387 | } else {
388 | textureView.setAspectRatio(previewSize.getHeight(), previewSize.getWidth());
389 | }
390 |
391 | CameraConnectionFragment.this.cameraId = cameraId;
392 | }
393 | } catch (final CameraAccessException e) {
394 | e.printStackTrace();
395 | } catch (final NullPointerException e) {
396 | // Currently an NPE is thrown when the Camera2API is used but not supported on the
397 | // device this code runs.
398 | // TODO(andrewharp): abstract ErrorDialog/RuntimeException handling out into new method and
399 | // reuse throughout app.
400 | ErrorDialog.newInstance(getString(R.string.camera_error))
401 | .show(getChildFragmentManager(), FRAGMENT_DIALOG);
402 | throw new RuntimeException(getString(R.string.camera_error));
403 | }
404 |
405 | cameraConnectionCallback.onPreviewSizeChosen(previewSize, sensorOrientation);
406 | }
407 |
408 | /**
409 | * Opens the camera specified by {@link CameraConnectionFragment#cameraId}.
410 | */
411 | private void openCamera(final int width, final int height) {
412 | setUpCameraOutputs(width, height);
413 | configureTransform(width, height);
414 |
415 | final Activity activity = getActivity();
416 | final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
417 | try {
418 | if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
419 | throw new RuntimeException("Time out waiting to lock camera opening.");
420 | }
421 | manager.openCamera(cameraId, stateCallback, backgroundHandler);
422 | } catch (final CameraAccessException e) {
423 | e.printStackTrace();
424 | } catch (final InterruptedException e) {
425 | throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
426 | }
427 | }
428 |
429 | /**
430 | * Closes the current {@link CameraDevice}.
431 | */
432 | private void closeCamera() {
433 | try {
434 | cameraOpenCloseLock.acquire();
435 | if (null != captureSession) {
436 | captureSession.close();
437 | captureSession = null;
438 | }
439 | if (null != cameraDevice) {
440 | cameraDevice.close();
441 | cameraDevice = null;
442 | }
443 | if (null != previewReader) {
444 | previewReader.close();
445 | previewReader = null;
446 | }
447 | } catch (final InterruptedException e) {
448 | throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
449 | } finally {
450 | cameraOpenCloseLock.release();
451 | }
452 | }
453 |
454 | /**
455 | * Starts a background thread and its {@link Handler}.
456 | */
457 | private void startBackgroundThread() {
458 | backgroundThread = new HandlerThread("ImageListener");
459 | backgroundThread.start();
460 | backgroundHandler = new Handler(backgroundThread.getLooper());
461 | }
462 |
463 | /**
464 | * Stops the background thread and its {@link Handler}.
465 | */
466 | private void stopBackgroundThread() {
467 | backgroundThread.quitSafely();
468 | try {
469 | backgroundThread.join();
470 | backgroundThread = null;
471 | backgroundHandler = null;
472 | } catch (final InterruptedException e) {
473 | e.printStackTrace();
474 | }
475 | }
476 |
477 | private final CameraCaptureSession.CaptureCallback captureCallback =
478 | new CameraCaptureSession.CaptureCallback() {
479 | @Override
480 | public void onCaptureProgressed(
481 | final CameraCaptureSession session,
482 | final CaptureRequest request,
483 | final CaptureResult partialResult) {}
484 |
485 | @Override
486 | public void onCaptureCompleted(
487 | final CameraCaptureSession session,
488 | final CaptureRequest request,
489 | final TotalCaptureResult result) {}
490 | };
491 |
492 | /**
493 | * Creates a new {@link CameraCaptureSession} for camera preview.
494 | */
495 | private void createCameraPreviewSession() {
496 | try {
497 | final SurfaceTexture texture = textureView.getSurfaceTexture();
498 | assert texture != null;
499 |
500 | // We configure the size of default buffer to be the size of camera preview we want.
501 | texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
502 |
503 | // This is the output Surface we need to start preview.
504 | final Surface surface = new Surface(texture);
505 |
506 | // We set up a CaptureRequest.Builder with the output Surface.
507 | previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
508 | previewRequestBuilder.addTarget(surface);
509 |
510 | // Create the reader for the preview frames
511 | previewReader =
512 | ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
513 |
514 | previewReader.setOnImageAvailableListener(imageListener, backgroundHandler);
515 | previewRequestBuilder.addTarget(previewReader.getSurface());
516 |
517 | // Here, we create a CameraCaptureSession for camera preview.
518 | cameraDevice.createCaptureSession(
519 | Arrays.asList(surface, previewReader.getSurface()),
520 | // Arrays.asList(surface),
521 | new CameraCaptureSession.StateCallback() {
522 |
523 | @Override
524 | public void onConfigured(final CameraCaptureSession cameraCaptureSession) {
525 | // The camera is already closed
526 | if (null == cameraDevice) {
527 | return;
528 | }
529 |
530 | // When the session is ready, we start displaying the preview.
531 | captureSession = cameraCaptureSession;
532 | try {
533 | // Auto focus should be continuous for camera preview.
534 | previewRequestBuilder.set(
535 | CaptureRequest.CONTROL_AF_MODE,
536 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
537 | // Flash is automatically enabled when necessary.
538 | previewRequestBuilder.set(
539 | CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
540 |
541 | // Finally, we start displaying the camera preview.
542 | previewRequest = previewRequestBuilder.build();
543 | captureSession.setRepeatingRequest(
544 | previewRequest, captureCallback, backgroundHandler);
545 | } catch (final CameraAccessException e) {
546 | e.printStackTrace();
547 | }
548 | }
549 |
550 | @Override
551 | public void onConfigureFailed(final CameraCaptureSession cameraCaptureSession) {
552 | showToast("Failed");
553 | }
554 | },
555 | null);
556 | } catch (final CameraAccessException e) {
557 | e.printStackTrace();
558 | }
559 | }
560 |
561 | /**
562 | * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
563 | * This method should be called after the camera preview size is determined in
564 | * setUpCameraOutputs and also the size of `mTextureView` is fixed.
565 | *
566 | * @param viewWidth The width of `mTextureView`
567 | * @param viewHeight The height of `mTextureView`
568 | */
569 | private void configureTransform(final int viewWidth, final int viewHeight) {
570 | final Activity activity = getActivity();
571 | if (null == textureView || null == previewSize || null == activity) {
572 | return;
573 | }
574 | final int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
575 | final Matrix matrix = new Matrix();
576 | final RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
577 | final RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
578 | final float centerX = viewRect.centerX();
579 | final float centerY = viewRect.centerY();
580 | if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
581 | bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
582 | matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
583 | final float scale =
584 | Math.max(
585 | (float) viewHeight / previewSize.getHeight(),
586 | (float) viewWidth / previewSize.getWidth());
587 | matrix.postScale(scale, scale, centerX, centerY);
588 | matrix.postRotate(90 * (rotation - 2), centerX, centerY);
589 | } else if (Surface.ROTATION_180 == rotation) {
590 | matrix.postRotate(180, centerX, centerY);
591 | }
592 | textureView.setTransform(matrix);
593 | }
594 |
595 | /**
596 | * Compares two {@code Size}s based on their areas.
597 | */
598 | static class CompareSizesByArea implements Comparator {
599 | @Override
600 | public int compare(final Size lhs, final Size rhs) {
601 | // We cast here to ensure the multiplications won't overflow
602 | return Long.signum(
603 | (long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
604 | }
605 | }
606 |
607 | /**
608 | * Shows an error message dialog.
609 | */
610 | public static class ErrorDialog extends DialogFragment {
611 | private static final String ARG_MESSAGE = "message";
612 |
613 | public static ErrorDialog newInstance(final String message) {
614 | final ErrorDialog dialog = new ErrorDialog();
615 | final Bundle args = new Bundle();
616 | args.putString(ARG_MESSAGE, message);
617 | dialog.setArguments(args);
618 | return dialog;
619 | }
620 |
621 | @Override
622 | public Dialog onCreateDialog(final Bundle savedInstanceState) {
623 | final Activity activity = getActivity();
624 | return new AlertDialog.Builder(activity)
625 | .setMessage(getArguments().getString(ARG_MESSAGE))
626 | .setPositiveButton(
627 | android.R.string.ok,
628 | new DialogInterface.OnClickListener() {
629 | @Override
630 | public void onClick(final DialogInterface dialogInterface, final int i) {
631 | activity.finish();
632 | }
633 | })
634 | .create();
635 | }
636 | }
637 | }
638 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/CameraFrameCapture.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.app.AlertDialog;
6 | import android.app.Dialog;
7 | import android.app.DialogFragment;
8 | import android.app.Fragment;
9 | import android.content.Context;
10 | import android.content.DialogInterface;
11 | import android.content.pm.PackageManager;
12 | import android.content.res.Configuration;
13 | import android.graphics.ImageFormat;
14 | import android.graphics.Matrix;
15 | import android.graphics.Point;
16 | import android.graphics.Rect;
17 | import android.graphics.RectF;
18 | import android.graphics.SurfaceTexture;
19 | import android.graphics.YuvImage;
20 | import android.hardware.camera2.CameraAccessException;
21 | import android.hardware.camera2.CameraCaptureSession;
22 | import android.hardware.camera2.CameraCharacteristics;
23 | import android.hardware.camera2.CameraDevice;
24 | import android.hardware.camera2.CameraManager;
25 | import android.hardware.camera2.CaptureRequest;
26 | import android.hardware.camera2.params.StreamConfigurationMap;
27 | import android.media.Image;
28 | import android.media.ImageReader;
29 | import android.os.Bundle;
30 | import android.os.Handler;
31 | import android.os.HandlerThread;
32 | import androidx.annotation.NonNull;
33 | import androidx.core.content.ContextCompat;
34 | import androidx.legacy.app.FragmentCompat;
35 |
36 | import android.util.Size;
37 | import android.util.SparseIntArray;
38 | import android.view.LayoutInflater;
39 | import android.view.Surface;
40 | import android.view.TextureView;
41 | import android.view.View;
42 | import android.view.ViewGroup;
43 |
44 | import java.io.ByteArrayOutputStream;
45 | import java.nio.ByteBuffer;
46 | import java.util.ArrayList;
47 | import java.util.Arrays;
48 | import java.util.Collections;
49 | import java.util.Comparator;
50 | import java.util.List;
51 | import java.util.concurrent.Semaphore;
52 | import java.util.concurrent.TimeUnit;
53 |
54 |
55 | public class CameraFrameCapture extends Fragment
56 | implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
57 |
58 | private static final int REQUEST_CAMERA_PERMISSION = 2;
59 | private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
60 | private static final int MAX_PREVIEW_WIDTH = 1080;
61 | private static final int MAX_PREVIEW_HEIGHT = 1920;
62 | private static final String FRAGMENT_DIALOG = "";
63 |
64 | static {
65 | ORIENTATIONS.append(Surface.ROTATION_0, 90);
66 | ORIENTATIONS.append(Surface.ROTATION_90, 0);
67 | ORIENTATIONS.append(Surface.ROTATION_180, 270);
68 | ORIENTATIONS.append(Surface.ROTATION_270, 180);
69 | }
70 |
71 | private final TextureView.SurfaceTextureListener mSurfaceTextureListener
72 | = new TextureView.SurfaceTextureListener() {
73 |
74 | @Override
75 | public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
76 | openCamera(width, height);
77 | }
78 |
79 | @Override
80 | public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
81 | configureTransform(width, height);
82 | }
83 |
84 | @Override
85 | public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
86 | return true;
87 | }
88 |
89 | @Override
90 | public void onSurfaceTextureUpdated(SurfaceTexture texture) {
91 |
92 | }
93 |
94 | };
95 |
96 | /**
97 | * ID of the current {@link CameraDevice}.
98 | */
99 | private String mCameraId;
100 |
101 | /**
102 | * An {@link AutoFitTextureView} for camera preview.
103 | */
104 | private AutoFitTextureView mTextureView;
105 |
106 | /**
107 | * A {@link CameraCaptureSession } for camera preview.
108 | */
109 | private CameraCaptureSession mCaptureSession;
110 |
111 | /**
112 | * A reference to the opened {@link CameraDevice}.
113 | */
114 | private CameraDevice mCameraDevice;
115 |
116 | /**
117 | * The {@link android.util.Size} of camera preview.
118 | */
119 | private Size mPreviewSize;
120 |
121 | /**
122 | * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
123 | */
124 | private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
125 |
126 | @Override
127 | public void onOpened(@NonNull CameraDevice cameraDevice) {
128 | // This method is called when the camera is opened. We start camera preview here.
129 | mCameraOpenCloseLock.release();
130 | mCameraDevice = cameraDevice;
131 | createCameraPreviewSession();
132 | }
133 |
134 | @Override
135 | public void onDisconnected(@NonNull CameraDevice cameraDevice) {
136 | mCameraOpenCloseLock.release();
137 | cameraDevice.close();
138 | mCameraDevice = null;
139 | }
140 |
141 | @Override
142 | public void onError(@NonNull CameraDevice cameraDevice, int error) {
143 | mCameraOpenCloseLock.release();
144 | cameraDevice.close();
145 | mCameraDevice = null;
146 | Activity activity = getActivity();
147 | if (null != activity) {
148 | activity.finish();
149 | }
150 | }
151 | };
152 |
153 | /**
154 | * An additional thread for running tasks that shouldn't block the UI.
155 | */
156 | private HandlerThread mBackgroundThread;
157 |
158 | /**
159 | * A {@link Handler} for running tasks in the background.
160 | */
161 | private Handler mBackgroundHandler;
162 |
163 | /**
164 | * An {@link ImageReader} that handles still image capture.
165 | */
166 | private ImageReader mImageReader;
167 |
168 | /**
169 | * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
170 | * still image is ready to be saved.
171 | */
172 | private ImageReader.OnImageAvailableListener mOnImageAvailableListener;
173 |
174 | /**
175 | * {@link CaptureRequest.Builder} for the camera preview
176 | */
177 | private CaptureRequest.Builder mPreviewRequestBuilder;
178 |
179 | /**
180 | * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
181 | */
182 | private CaptureRequest mPreviewRequest;
183 |
184 | /**
185 | * A {@link Semaphore} to prevent the app from exiting before closing the camera.
186 | */
187 | private Semaphore mCameraOpenCloseLock = new Semaphore(1);
188 |
189 | /**
190 | * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
191 | */
192 | private CameraCaptureSession.CaptureCallback mCaptureCallback
193 | = new CameraCaptureSession.CaptureCallback() {
194 | };
195 |
196 | private final ConnectionCallback mCameraConnectionCallback;
197 |
198 | public interface ConnectionCallback {
199 | void onPreviewSizeChosen(Size size);
200 | }
201 |
202 | private CameraFrameCapture(ConnectionCallback connectionCallback, ImageReader.OnImageAvailableListener imageListener) {
203 | this.mCameraConnectionCallback = connectionCallback;
204 | this.mOnImageAvailableListener = imageListener;
205 | }
206 |
207 | public static CameraFrameCapture newInstance(
208 | final ConnectionCallback connectionCallback,
209 | final ImageReader.OnImageAvailableListener imageListener) {
210 | return new CameraFrameCapture(connectionCallback, imageListener);
211 | }
212 |
213 | /**
214 | * Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
215 | * is at least as large as the respective texture view size, and that is at most as large as the
216 | * respective max size, and whose aspect ratio matches with the specified value. If such size
217 | * doesn't exist, choose the largest one that is at most as large as the respective max size,
218 | * and whose aspect ratio matches with the specified value.
219 | *
220 | * @param choices The list of sizes that the camera supports for the intended output
221 | * class
222 | * @param textureViewWidth The width of the texture view relative to sensor coordinate
223 | * @param textureViewHeight The height of the texture view relative to sensor coordinate
224 | * @param maxWidth The maximum width that can be chosen
225 | * @param maxHeight The maximum height that can be chosen
226 | * @param aspectRatio The aspect ratio
227 | * @return The optimal {@code Size}, or an arbitrary one if none were big enough
228 | */
229 | private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
230 | int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
231 |
232 | // Collect the supported resolutions that are at least as big as the preview Surface
233 | List bigEnough = new ArrayList<>();
234 | // Collect the supported resolutions that are smaller than the preview Surface
235 | List notBigEnough = new ArrayList<>();
236 | int w = aspectRatio.getWidth();
237 | int h = aspectRatio.getHeight();
238 | for (Size option : choices) {
239 | if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
240 | option.getHeight() == option.getWidth() * h / w) {
241 | if (option.getWidth() >= textureViewWidth &&
242 | option.getHeight() >= textureViewHeight) {
243 | bigEnough.add(option);
244 | } else {
245 | notBigEnough.add(option);
246 | }
247 | }
248 | }
249 |
250 | // Pick the smallest of those big enough. If there is no one big enough, pick the
251 | // largest of those not big enough.
252 | if (bigEnough.size() > 0) {
253 | return Collections.min(bigEnough, new CompareSizesByArea());
254 | } else if (notBigEnough.size() > 0) {
255 | return Collections.max(notBigEnough, new CompareSizesByArea());
256 | } else {
257 | return choices[0];
258 | }
259 | }
260 |
261 |
262 |
263 | @Override
264 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
265 | Bundle savedInstanceState) {
266 | return inflater.inflate(R.layout.placerecognizer_ui, container, false);
267 | }
268 |
269 | @Override
270 | public void onViewCreated(final View view, Bundle savedInstanceState) {
271 | mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
272 | }
273 |
274 | @Override
275 | public void onActivityCreated(Bundle savedInstanceState) {
276 | super.onActivityCreated(savedInstanceState);
277 | }
278 |
279 | @Override
280 | public void onResume() {
281 | super.onResume();
282 | startBackgroundThread();
283 |
284 | // When the screen is turned off and turned back on, the SurfaceTexture is already
285 | // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
286 | // a camera and start preview from here (otherwise, we wait until the surface is ready in
287 | // the SurfaceTextureListener).
288 | if (mTextureView.isAvailable()) {
289 | openCamera(mTextureView.getWidth(), mTextureView.getHeight());
290 | } else {
291 | mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
292 | }
293 | }
294 |
295 | @Override
296 | public void onPause() {
297 | closeCamera();
298 | stopBackgroundThread();
299 | super.onPause();
300 | }
301 |
302 | private void requestCameraPermission() {
303 | if (FragmentCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
304 | new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
305 | } else {
306 | FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
307 | REQUEST_CAMERA_PERMISSION);
308 | }
309 | }
310 |
311 | @Override
312 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
313 | @NonNull int[] grantResults) {
314 | if (requestCode != REQUEST_CAMERA_PERMISSION) {
315 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
316 | }
317 | }
318 |
319 | /**
320 | * Sets up member variables related to camera.
321 | *
322 | * @param width The width of available size for camera preview
323 | * @param height The height of available size for camera preview
324 | */
325 | private void setUpCameraOutputs(int width, int height) {
326 | Activity activity = getActivity();
327 | int mSensorOrientation;
328 | CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
329 | try {
330 | for (String cameraId : manager.getCameraIdList()) {
331 | CameraCharacteristics characteristics
332 | = manager.getCameraCharacteristics(cameraId);
333 |
334 | StreamConfigurationMap map = characteristics.get(
335 | CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
336 | if (map == null) {
337 | continue;
338 | }
339 |
340 | // For still image captures, we use the largest available size.
341 | Size largest = Collections.max(
342 | Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
343 | new CompareSizesByArea());
344 | mImageReader =
345 | ImageReader.newInstance(
346 | mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.YUV_420_888, /*maxImages*/2);
347 | // mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
348 | mImageReader.setOnImageAvailableListener(
349 | mOnImageAvailableListener, mBackgroundHandler);
350 |
351 | // Find out if we need to swap dimension to get the preview size relative to sensor
352 | // coordinate.
353 | int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
354 | //noinspection ConstantConditions
355 | mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
356 | boolean swappedDimensions = false;
357 | switch (displayRotation) {
358 | case Surface.ROTATION_0:
359 | case Surface.ROTATION_180:
360 | if (mSensorOrientation == 90 || mSensorOrientation == 270) {
361 | swappedDimensions = true;
362 | }
363 | break;
364 | case Surface.ROTATION_90:
365 | case Surface.ROTATION_270:
366 | if (mSensorOrientation == 0 || mSensorOrientation == 180) {
367 | swappedDimensions = true;
368 | }
369 | break;
370 | default:
371 | }
372 |
373 | Point displaySize = new Point();
374 | activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
375 | int rotatedPreviewWidth = width;
376 | int rotatedPreviewHeight = height;
377 | int maxPreviewWidth = displaySize.x;
378 | int maxPreviewHeight = displaySize.y;
379 |
380 | if (swappedDimensions) {
381 | //noinspection SuspiciousNameCombination
382 | rotatedPreviewWidth = height;
383 | //noinspection SuspiciousNameCombination
384 | rotatedPreviewHeight = width;
385 | //noinspection SuspiciousNameCombination
386 | maxPreviewWidth = displaySize.y;
387 | //noinspection SuspiciousNameCombination
388 | maxPreviewHeight = displaySize.x;
389 | }
390 |
391 | if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
392 | maxPreviewWidth = MAX_PREVIEW_WIDTH;
393 | }
394 |
395 | if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
396 | maxPreviewHeight = MAX_PREVIEW_HEIGHT;
397 | }
398 |
399 | // Danger, W.R.! Attempting to use too large a preview size could exceed the camera
400 | // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
401 | // garbage capture data.
402 | mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
403 | rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
404 | maxPreviewHeight, largest);
405 |
406 | // We fit the aspect ratio of TextureView to the size of preview we picked.
407 | int orientation = getResources().getConfiguration().orientation;
408 | if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
409 | mTextureView.setAspectRatio(
410 | mPreviewSize.getWidth(), mPreviewSize.getHeight());
411 | } else {
412 | mTextureView.setAspectRatio(
413 | mPreviewSize.getHeight(), mPreviewSize.getWidth());
414 | }
415 | mCameraId = cameraId;
416 | return;
417 | }
418 | } catch (Exception e) {
419 | e.printStackTrace();
420 | }
421 | }
422 |
423 | /**
424 | * Opens the camera specified by {@link CameraFrameCapture#mCameraId}.
425 | */
426 | private void openCamera(int width, int height) {
427 | if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
428 | != PackageManager.PERMISSION_GRANTED) {
429 | requestCameraPermission();
430 | return;
431 | }
432 | setUpCameraOutputs(width, height);
433 | configureTransform(width, height);
434 | Activity activity = getActivity();
435 | CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
436 | try {
437 | if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
438 | throw new RuntimeException("Time out waiting to lock camera opening.");
439 | }
440 | manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
441 | mCameraConnectionCallback.onPreviewSizeChosen(mPreviewSize);
442 | } catch (CameraAccessException e) {
443 | e.printStackTrace();
444 | } catch (InterruptedException e) {
445 | throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
446 | }
447 | }
448 |
449 | /**
450 | * Closes the current {@link CameraDevice}.
451 | */
452 | private void closeCamera() {
453 | try {
454 | mCameraOpenCloseLock.acquire();
455 | if (null != mCaptureSession) {
456 | mCaptureSession.close();
457 | mCaptureSession = null;
458 | }
459 | if (null != mCameraDevice) {
460 | mCameraDevice.close();
461 | mCameraDevice = null;
462 | }
463 | if (null != mImageReader) {
464 | mImageReader.close();
465 | mImageReader = null;
466 | }
467 | } catch (InterruptedException e) {
468 | throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
469 | } finally {
470 | mCameraOpenCloseLock.release();
471 | }
472 | }
473 |
474 | /**
475 | * Starts a background thread and its {@link Handler}.
476 | */
477 | private void startBackgroundThread() {
478 | mBackgroundThread = new HandlerThread("CameraBackground");
479 | mBackgroundThread.start();
480 | mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
481 | }
482 |
483 | /**
484 | * Stops the background thread and its {@link Handler}.
485 | */
486 | private void stopBackgroundThread() {
487 | mBackgroundThread.quitSafely();
488 | try {
489 | mBackgroundThread.join();
490 | mBackgroundThread = null;
491 | mBackgroundHandler = null;
492 | } catch (InterruptedException e) {
493 | e.printStackTrace();
494 | }
495 | }
496 |
497 | /**
498 | * Creates a new {@link CameraCaptureSession} for camera preview.
499 | */
500 | private void createCameraPreviewSession() {
501 | try {
502 | SurfaceTexture texture = mTextureView.getSurfaceTexture();
503 | assert texture != null;
504 |
505 | // We configure the size of default buffer to be the size of camera preview we want.
506 | texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
507 |
508 | // This is the output Surface we need to start preview.
509 | Surface surface = new Surface(texture);
510 |
511 | // We set up a CaptureRequest.Builder with the output Surface.
512 | mPreviewRequestBuilder
513 | = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
514 | mPreviewRequestBuilder.addTarget(surface);
515 | mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
516 |
517 | // Here, we create a CameraCaptureSession for camera preview.
518 | mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
519 | new CameraCaptureSession.StateCallback() {
520 |
521 | @Override
522 | public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
523 | // The camera is already closed
524 | if (null == mCameraDevice) {
525 | return;
526 | }
527 |
528 | // When the session is ready, we start displaying the preview.
529 | mCaptureSession = cameraCaptureSession;
530 | try {
531 | // Auto focus should be continuous for camera preview.
532 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
533 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
534 |
535 | // Finally, we start displaying the camera preview.
536 | mPreviewRequest = mPreviewRequestBuilder.build();
537 | mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
538 | } catch (CameraAccessException e) {
539 | e.printStackTrace();
540 | }
541 | }
542 |
543 | @Override
544 | public void onConfigureFailed(
545 | @NonNull CameraCaptureSession cameraCaptureSession) {
546 | }
547 | }, null
548 | );
549 | } catch (CameraAccessException e) {
550 | e.printStackTrace();
551 | }
552 | }
553 |
554 | /**
555 | * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
556 | * This method should be called after the camera preview size is determined in
557 | * setUpCameraOutputs and also the size of `mTextureView` is fixed.
558 | *
559 | * @param viewWidth The width of `mTextureView`
560 | * @param viewHeight The height of `mTextureView`
561 | */
562 | private void configureTransform(int viewWidth, int viewHeight) {
563 | Activity activity = getActivity();
564 | if (null == mTextureView || null == mPreviewSize || null == activity) {
565 | return;
566 | }
567 | int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
568 | Matrix matrix = new Matrix();
569 | RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
570 | RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
571 | float centerX = viewRect.centerX();
572 | float centerY = viewRect.centerY();
573 | if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
574 | bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
575 | matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
576 | float scale = Math.max(
577 | (float) viewHeight / mPreviewSize.getHeight(),
578 | (float) viewWidth / mPreviewSize.getWidth());
579 | matrix.postScale(scale, scale, centerX, centerY);
580 | matrix.postRotate(90 * (rotation - 2), centerX, centerY);
581 | } else if (Surface.ROTATION_180 == rotation) {
582 | matrix.postRotate(180, centerX, centerY);
583 | }
584 | mTextureView.setTransform(matrix);
585 | }
586 |
587 | @Override
588 | public void onClick(View view) {
589 | }
590 |
591 | /**
592 | * Compares two {@code Size}s based on their areas.
593 | */
594 | static class CompareSizesByArea implements Comparator {
595 |
596 | @Override
597 | public int compare(Size lhs, Size rhs) {
598 | // We cast here to ensure the multiplications won't overflow
599 | return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
600 | (long) rhs.getWidth() * rhs.getHeight());
601 | }
602 |
603 | }
604 |
605 | /**
606 | * Shows OK/Cancel confirmation dialog about camera permission.
607 | */
608 | public static class ConfirmationDialog extends DialogFragment {
609 |
610 | @Override
611 | public Dialog onCreateDialog(Bundle savedInstanceState) {
612 | final Fragment parent = getParentFragment();
613 | return new AlertDialog.Builder(getActivity())
614 | .setMessage("CreateTest")//R.string.request_permission)
615 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
616 | @Override
617 | public void onClick(DialogInterface dialog, int which) {
618 | FragmentCompat.requestPermissions(parent,
619 | new String[]{Manifest.permission.CAMERA},
620 | REQUEST_CAMERA_PERMISSION);
621 | }
622 | })
623 | .setNegativeButton(android.R.string.cancel,
624 | new DialogInterface.OnClickListener() {
625 | @Override
626 | public void onClick(DialogInterface dialog, int which) {
627 | Activity activity = parent.getActivity();
628 | if (activity != null) {
629 | activity.finish();
630 | }
631 | }
632 | })
633 | .create();
634 | }
635 | }
636 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/CameraLiveViewActivity.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 |
4 | import android.app.Activity;
5 |
6 | public abstract class CameraLiveViewActivity extends Activity {
7 | protected boolean computing = false;
8 |
9 | abstract public void runCameraLiveView();
10 |
11 | public void setComputing(boolean computing) {
12 | this.computing = computing;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/GPSTracker.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import android.Manifest;
4 | import android.app.AlertDialog;
5 | import android.app.Service;
6 | import android.content.Context;
7 | import android.content.DialogInterface;
8 | import android.content.Intent;
9 | import android.content.pm.PackageManager;
10 | import android.location.Location;
11 | import android.location.LocationListener;
12 | import android.location.LocationManager;
13 | import android.os.Bundle;
14 | import android.os.IBinder;
15 | import android.provider.Settings;
16 | import androidx.annotation.Nullable;
17 | import androidx.core.app.ActivityCompat;
18 |
19 | import android.util.Log;
20 |
21 | public class GPSTracker extends Service implements LocationListener {
22 |
23 | private final Context mContext;
24 |
25 | // flag for GPS status
26 | boolean isGPSEnabled = false;
27 |
28 | // flag for network status
29 | boolean isNetworkEnabled = false;
30 |
31 | boolean canGetLocation = false;
32 |
33 | Location location;
34 | double latitude;
35 | double longitude;
36 |
37 | // The minimum distance to change Updates in meters
38 | private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
39 |
40 | // The minimum time between updates in milliseconds
41 | private static final long MIN_TIME_BW_UPDATES = 1000 * 60; // 1 minute
42 |
43 | // Declaring a Location Manager
44 | protected LocationManager locationManager;
45 |
46 | public GPSTracker(Context context) {
47 | this.mContext = context;
48 | getLocation();
49 | }
50 |
51 | public Location getLocation() {
52 | try {
53 | locationManager = (LocationManager) mContext
54 | .getSystemService(LOCATION_SERVICE);
55 |
56 | // getting GPS status
57 | isGPSEnabled = locationManager
58 | .isProviderEnabled(LocationManager.GPS_PROVIDER);
59 |
60 | // getting network status
61 | isNetworkEnabled = locationManager
62 | .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
63 |
64 | if (isGPSEnabled && isNetworkEnabled) {
65 | this.canGetLocation = true;
66 | if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
67 | ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
68 |
69 | AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
70 | alertDialog.setTitle("GPS permissions");
71 | alertDialog.setMessage("Please grant the App permissions to use GPS.");
72 | }
73 | if (isNetworkEnabled) {
74 | locationManager.requestLocationUpdates(
75 | LocationManager.NETWORK_PROVIDER,
76 | MIN_TIME_BW_UPDATES,
77 | MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
78 | Log.d("Network", "Network Enabled");
79 | if (locationManager != null) {
80 | location = locationManager
81 | .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
82 | if (location != null) {
83 | latitude = location.getLatitude();
84 | longitude = location.getLongitude();
85 | }
86 | }
87 | }
88 | // if GPS Enabled get lat/long using GPS Services
89 | if (isGPSEnabled) {
90 | if (location == null) {
91 | locationManager.requestLocationUpdates(
92 | LocationManager.GPS_PROVIDER,
93 | MIN_TIME_BW_UPDATES,
94 | MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
95 | Log.d("GPS", "GPS Enabled");
96 | if (locationManager != null) {
97 | location = locationManager
98 | .getLastKnownLocation(LocationManager.GPS_PROVIDER);
99 | if (location != null) {
100 | latitude = location.getLatitude();
101 | longitude = location.getLongitude();
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 | } catch (Exception e) {
109 | e.printStackTrace();
110 | }
111 |
112 | return location;
113 | }
114 |
115 | public double getLatitude() {
116 | if (location != null) {
117 | latitude = location.getLatitude();
118 | }
119 |
120 | return latitude;
121 | }
122 |
123 | public double getLongitude() {
124 | if (location != null) {
125 | longitude = location.getLongitude();
126 | }
127 |
128 | return longitude;
129 | }
130 |
131 | public void showSettingsAlert() {
132 | AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
133 |
134 | // Setting Dialog Title
135 | alertDialog.setTitle("GPS is settings");
136 |
137 | // Setting Dialog Message
138 | alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
139 |
140 | // On pressing Settings button
141 | alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
142 | public void onClick(DialogInterface dialog, int which) {
143 | Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
144 | mContext.startActivity(intent);
145 | }
146 | });
147 |
148 | // on pressing cancel button
149 | alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
150 | public void onClick(DialogInterface dialog, int which) {
151 | dialog.cancel();
152 | }
153 | });
154 |
155 | // Showing Alert Message
156 | alertDialog.show();
157 | }
158 |
159 | public boolean canGetLocation() {
160 | return this.canGetLocation;
161 | }
162 |
163 | @Nullable
164 | @Override
165 | public IBinder onBind(Intent intent) {
166 | return null;
167 | }
168 |
169 | @Override
170 | public void onLocationChanged(Location location) {
171 |
172 | }
173 |
174 | @Override
175 | public void onStatusChanged(String s, int i, Bundle bundle) {
176 |
177 | }
178 |
179 | @Override
180 | public void onProviderEnabled(String s) {
181 |
182 | }
183 |
184 | @Override
185 | public void onProviderDisabled(String s) {
186 |
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/GetWiki.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import android.os.AsyncTask;
4 | import android.util.Log;
5 |
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | import java.text.SimpleDateFormat;
10 | import java.util.Date;
11 | import java.util.Iterator;
12 |
13 | //Json parser for wikipedia
14 | class GetWiki extends AsyncTask {
15 |
16 | private static final String WIK = "WikiActivity";
17 |
18 | @Override
19 | protected void onPreExecute() {
20 | super.onPreExecute();
21 | }
22 |
23 | @Override
24 | protected LocationDetails doInBackground(String... strings) {
25 | String urlTitle = strings[0];
26 | String url = "https://en.wikipedia.org/w/api.php?format=json&action=query&redirects&exintro=&explaintext=&prop=extracts&titles=" + urlTitle;
27 | HttpHandler handler = new HttpHandler();
28 |
29 | // Making a request to url and getting response
30 | String jsonStr = handler.makeServiceCall(url);
31 |
32 | if (jsonStr != null) {
33 | try {
34 | JSONObject jsonObj = new JSONObject(jsonStr);
35 | JSONObject pages = jsonObj.getJSONObject("query").getJSONObject("pages");
36 | Iterator keys = pages.keys();
37 | String pageId= keys.next();
38 | JSONObject page = pages.getJSONObject(pageId);
39 |
40 | String title = page.getString("title");
41 | String extract = page.getString("extract");
42 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
43 | String date = sdf.format(new Date());
44 |
45 | return new LocationDetails(title,extract,date);
46 | } catch (JSONException e) {
47 | e.printStackTrace();
48 | }
49 | }
50 | return null;
51 | }
52 |
53 | @Override
54 | protected void onPostExecute(LocationDetails result) {
55 | super.onPostExecute(result);
56 | Log.i(WIK,"good");
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/HttpHandler.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.BufferedInputStream;
6 | import java.io.BufferedReader;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.io.InputStreamReader;
10 | import java.net.HttpURLConnection;
11 | import java.net.MalformedURLException;
12 | import java.net.ProtocolException;
13 | import java.net.URL;
14 |
15 | class HttpHandler {
16 |
17 | private static final String TAG = HttpHandler.class.getSimpleName();
18 |
19 | HttpHandler() {
20 | }
21 |
22 | String makeServiceCall(String reqUrl) {
23 | String response = null;
24 | try {
25 | URL url = new URL(reqUrl);
26 | HttpURLConnection conn = (HttpURLConnection) url.openConnection();
27 | conn.setRequestMethod("GET");
28 | // read the response
29 | InputStream in = new BufferedInputStream(conn.getInputStream());
30 | response = convertStreamToString(in);
31 | } catch (MalformedURLException e) {
32 | Log.e(TAG, "MalformedURLException: " + e.getMessage());
33 | } catch (ProtocolException e) {
34 | Log.e(TAG, "ProtocolException: " + e.getMessage());
35 | } catch (IOException e) {
36 | Log.e(TAG, "IOException: " + e.getMessage());
37 | } catch (Exception e) {
38 | Log.e(TAG, "Exception: " + e.getMessage());
39 | }
40 | return response;
41 | }
42 |
43 | private String convertStreamToString(InputStream is) {
44 | BufferedReader reader = new BufferedReader(new InputStreamReader(is));
45 | StringBuilder sb = new StringBuilder();
46 |
47 | String line;
48 | try {
49 | while ((line = reader.readLine()) != null) {
50 | sb.append(line).append('\n');
51 | }
52 | } catch (IOException e) {
53 | e.printStackTrace();
54 | } finally {
55 | try {
56 | is.close();
57 | } catch (IOException e) {
58 | e.printStackTrace();
59 | }
60 | }
61 | return sb.toString();
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/ImageClassificationTask.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.widget.TextView;
6 |
7 | import de.hpi.xnor_mxnet.imageclassification.Classification;
8 | import de.hpi.xnor_mxnet.imageclassification.ImageClassifier;
9 | import de.hpi.xnor_mxnet.imageclassification.ImageNetClassifier;
10 |
11 | class ImageClassificationTask implements Runnable {
12 |
13 | private final Bitmap mImage;
14 | private final ImageClassifier mClassifier;
15 | private final CameraLiveViewActivity mActivity;
16 |
17 | ImageClassificationTask(Bitmap image, CameraLiveViewActivity activity, ImageClassifier classifier) {
18 | mImage = image;
19 | mClassifier = classifier;
20 | mActivity = activity;
21 | }
22 |
23 | private String join(String delimiter, String[] s) {
24 | StringBuilder out = new StringBuilder();
25 | out.append(s[0]);
26 | for (int i = 1; i < s.length; ++i) {
27 | out.append(delimiter).append(s[i]);
28 | }
29 | return out.toString();
30 | }
31 |
32 | @Override
33 | public void run() {
34 | final Classification[] results = mClassifier.classifyImage(mImage);
35 | final String[] resultStrings = new String[results.length];
36 |
37 | for (int i = 0; i < results.length; ++i) {
38 | resultStrings[i] = String.format("%s, %.3f", results[i].get_label(), results[i].get_probability());
39 | }
40 |
41 | mActivity.runOnUiThread(new Runnable() {
42 | @Override
43 | public void run() {
44 | TextView textView = (TextView) mActivity.findViewById(R.id.classDisplay);
45 | String text = join("\n", resultStrings);
46 | if (textView != null) {
47 | textView.setText(text);
48 | }
49 | System.out.println(text);
50 | mActivity.setComputing(false);
51 | }
52 | });
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/ImageUtils.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | ==============================================================================*/
15 |
16 | package de.hpi.xnor_mxnet;
17 |
18 |
19 | import android.graphics.Matrix;
20 |
21 | public class ImageUtils {
22 | /**
23 | * Utility method to compute the allocated size in bytes of a YUV420SP image
24 | * of the given dimensions.
25 | */
26 | public static int getYUVByteSize(final int width, final int height) {
27 | // The luminance plane requires 1 byte per pixel.
28 | final int ySize = width * height;
29 |
30 | // The UV plane works on 2x2 blocks, so dimensions with odd size must be rounded up.
31 | // Each 2x2 block takes 2 bytes to encode, one each for U and V.
32 | final int uvSize = ((width + 1) / 2) * ((height + 1) / 2) * 2;
33 |
34 | return ySize + uvSize;
35 | }
36 |
37 | /**
38 | * Converts YUV420 semi-planar data to ARGB 8888 data using the supplied width
39 | * and height. The input and output must already be allocated and non-null.
40 | * For efficiency, no error checking is performed.
41 | *
42 | * @param input The array of YUV 4:2:0 input data.
43 | * @param output A pre-allocated array for the ARGB 8:8:8:8 output data.
44 | * @param width The width of the input image.
45 | * @param height The height of the input image.
46 | * @param halfSize If true, downsample to 50% in each dimension, otherwise not.
47 | */
48 | public static native void convertYUV420SPToARGB8888(
49 | byte[] input, int[] output, int width, int height, boolean halfSize);
50 |
51 | /**
52 | * Converts YUV420 semi-planar data to ARGB 8888 data using the supplied width
53 | * and height. The input and output must already be allocated and non-null.
54 | * For efficiency, no error checking is performed.
55 | *
56 | * @param y
57 | * @param u
58 | * @param v
59 | * @param uvPixelStride
60 | * @param width The width of the input image.
61 | * @param height The height of the input image.
62 | * @param halfSize If true, downsample to 50% in each dimension, otherwise not.
63 | * @param output A pre-allocated array for the ARGB 8:8:8:8 output data.
64 | */
65 | public static native void convertYUV420ToARGB8888(
66 | byte[] y,
67 | byte[] u,
68 | byte[] v,
69 | int[] output,
70 | int width,
71 | int height,
72 | int yRowStride,
73 | int uvRowStride,
74 | int uvPixelStride,
75 | boolean halfSize);
76 |
77 | /**
78 | * Converts YUV420 semi-planar data to RGB 565 data using the supplied width
79 | * and height. The input and output must already be allocated and non-null.
80 | * For efficiency, no error checking is performed.
81 | *
82 | * @param input The array of YUV 4:2:0 input data.
83 | * @param output A pre-allocated array for the RGB 5:6:5 output data.
84 | * @param width The width of the input image.
85 | * @param height The height of the input image.
86 | */
87 | public static native void convertYUV420SPToRGB565(
88 | byte[] input, byte[] output, int width, int height);
89 |
90 | /**
91 | * Returns a transformation matrix from one reference frame into another.
92 | * Handles cropping (if maintaining aspect ratio is desired) and rotation.
93 | *
94 | * @param srcWidth Width of source frame.
95 | * @param srcHeight Height of source frame.
96 | * @param dstWidth Width of destination frame.
97 | * @param dstHeight Height of destination frame.
98 | * @param applyRotation Amount of rotation to apply from one frame to another.
99 | * Must be a multiple of 90.
100 | * @param maintainAspectRatio If true, will ensure that scaling in x and y remains constant,
101 | * cropping the image if necessary.
102 | * @return The transformation fulfilling the desired requirements.
103 | */
104 | public static Matrix getTransformationMatrix(
105 | final int srcWidth,
106 | final int srcHeight,
107 | final int dstWidth,
108 | final int dstHeight,
109 | final int applyRotation,
110 | final boolean maintainAspectRatio) {
111 | final Matrix matrix = new Matrix();
112 |
113 | if (applyRotation != 0) {
114 | // Translate so center of image is at origin.
115 | matrix.postTranslate(-srcWidth / 2.0f, -srcHeight / 2.0f);
116 |
117 | // Rotate around origin.
118 | matrix.postRotate(applyRotation);
119 | }
120 |
121 | // Account for the already applied rotation, if any, and then determine how
122 | // much scaling is needed for each axis.
123 | final boolean transpose = (Math.abs(applyRotation) + 90) % 180 == 0;
124 |
125 | final int inWidth = transpose ? srcHeight : srcWidth;
126 | final int inHeight = transpose ? srcWidth : srcHeight;
127 |
128 | // Apply scaling if necessary.
129 | if (inWidth != dstWidth || inHeight != dstHeight) {
130 | final float scaleFactorX = dstWidth / (float) inWidth;
131 | final float scaleFactorY = dstHeight / (float) inHeight;
132 |
133 | if (maintainAspectRatio) {
134 | // Scale by minimum factor so that dst is filled completely while
135 | // maintaining the aspect ratio. Some image may fall off the edge.
136 | final float scaleFactor = Math.max(scaleFactorX, scaleFactorY);
137 | matrix.postScale(scaleFactor, scaleFactor);
138 | } else {
139 | // Scale exactly to fill dst from src.
140 | matrix.postScale(scaleFactorX, scaleFactorY);
141 | }
142 | }
143 |
144 | if (applyRotation != 0) {
145 | // Translate back from origin centered reference to destination frame.
146 | matrix.postTranslate(dstWidth / 2.0f, dstHeight / 2.0f);
147 | }
148 |
149 | return matrix;
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/LocationDetails.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | class LocationDetails {
7 |
8 | public String title;
9 | String descritpion;
10 | String date;
11 |
12 | LocationDetails(String title, String descritpion, String date) {
13 | this.title = title;
14 | this.descritpion = descritpion;
15 | this.date = date;
16 | }
17 |
18 | Map toMap() {
19 | HashMap result = new HashMap<>();
20 | result.put("title", title);
21 | result.put("description", descritpion);
22 | result.put("date", date);
23 |
24 | return result;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/MainActivity.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import android.Manifest;
4 | import android.app.Fragment;
5 | import android.content.pm.PackageManager;
6 | import android.graphics.Bitmap;
7 | import android.graphics.Canvas;
8 | import android.graphics.Matrix;
9 | import android.graphics.Paint;
10 | import android.graphics.Typeface;
11 | import android.media.Image;
12 | import android.media.ImageReader;
13 | import android.os.Build;
14 | import android.os.Bundle;
15 | import android.os.Handler;
16 | import android.os.HandlerThread;
17 | import android.os.Trace;
18 | import android.util.Log;
19 | import android.util.Size;
20 | import android.util.TypedValue;
21 | import android.view.KeyEvent;
22 | import android.view.WindowManager;
23 | import android.widget.Toast;
24 |
25 | import java.nio.ByteBuffer;
26 | import java.util.Vector;
27 |
28 | import de.hpi.xnor_mxnet.imageclassification.ImageClassifier;
29 | import de.hpi.xnor_mxnet.imageclassification.ImageNetClassifier;
30 |
31 |
32 | public class MainActivity extends CameraLiveViewActivity implements ImageReader.OnImageAvailableListener {
33 | static {
34 | System.loadLibrary("native-image-utils");
35 | }
36 | private static final int PERMISSIONS_REQUEST = 1;
37 |
38 | private static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
39 | private static final String PERMISSION_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;
40 | private static final float TEXT_SIZE_DIP = 10;
41 | private static String TAG;
42 |
43 | private Handler handler;
44 | private HandlerThread handlerThread;
45 |
46 |
47 | private ImageClassifier mImageClassifier;
48 | private byte[][] yuvBytes;
49 | private int[] rgbBytes;
50 | private int previewWidth;
51 | private int previewHeight;
52 | private Bitmap rgbFrameBitmap;
53 | private Bitmap croppedBitmap;
54 | private Matrix frameToCropTransform;
55 | private Matrix cropToFrameTransform;
56 | private boolean debug;
57 | private Bitmap cropCopyBitmap;
58 | private BorderedText borderedText;
59 | private long lasProcessingTimeMs;
60 | private boolean isFirstImage = true;
61 |
62 | private boolean hasPermission() {
63 | return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
64 | checkSelfPermission(PERMISSION_CAMERA) == PackageManager.PERMISSION_GRANTED &&
65 | checkSelfPermission(PERMISSION_STORAGE) == PackageManager.PERMISSION_GRANTED;
66 | }
67 |
68 | private void requestPermission() {
69 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
70 | if (shouldShowRequestPermissionRationale(PERMISSION_CAMERA) || shouldShowRequestPermissionRationale(PERMISSION_STORAGE)) {
71 | Toast.makeText(MainActivity.this, "Camera AND storage permission are required for this demo", Toast.LENGTH_LONG).show();
72 | }
73 | requestPermissions(new String[] {PERMISSION_CAMERA, PERMISSION_STORAGE}, PERMISSIONS_REQUEST);
74 | }
75 | }
76 |
77 | private void buildImageClassifier() {
78 | mImageClassifier = new ImageNetClassifier(this);
79 | }
80 |
81 | @Override
82 | protected void onCreate(Bundle savedInstanceState) {
83 | super.onCreate(savedInstanceState);
84 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
85 | TAG = getResources().getString(R.string.app_name);
86 |
87 | setContentView(R.layout.main_activity);
88 |
89 | if (hasPermission()) {
90 | buildImageClassifier();
91 | } else {
92 | requestPermission();
93 | }
94 | }
95 |
96 | @Override
97 | public synchronized void onResume() {
98 | super.onResume();
99 |
100 | handlerThread = new HandlerThread("inference");
101 | handlerThread.start();
102 | handler = new Handler(handlerThread.getLooper());
103 | }
104 |
105 | @Override
106 | public synchronized void onPause() {
107 | Log.d(TAG, "Pausing");
108 |
109 | if (!isFinishing()) {
110 | finish();
111 | }
112 |
113 | handlerThread.quitSafely();
114 | try {
115 | handlerThread.join();
116 | handlerThread = null;
117 | handler = null;
118 | } catch (final InterruptedException e) {
119 | Log.e(TAG, e.getMessage());
120 | }
121 |
122 | super.onPause();
123 | }
124 |
125 | public void runCameraLiveView() {
126 | final Fragment cameraView = CameraConnectionFragment.newInstance(
127 | new CameraConnectionFragment.ConnectionCallback() {
128 | @Override
129 | public void onPreviewSizeChosen(Size size, int rotation) {
130 | MainActivity.this.onPreviewSizeChosen(size);
131 | }
132 | },
133 | this,
134 | R.layout.placerecognizer_ui,
135 | new Size(mImageClassifier.getImageWidth(), mImageClassifier.getImageHeight())
136 | );
137 |
138 | getFragmentManager().beginTransaction()
139 | .replace(R.id.container, cameraView)
140 | .commit();
141 | }
142 |
143 | public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
144 | {
145 | switch (requestCode) {
146 | case PERMISSIONS_REQUEST: {
147 | if (grantResults.length > 0
148 | && grantResults[0] == PackageManager.PERMISSION_GRANTED
149 | && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
150 | buildImageClassifier();
151 | } else {
152 | requestPermission();
153 | }
154 | }
155 | }
156 | }
157 |
158 | public void onPreviewSizeChosen(final Size size) {
159 | final float textSizePx =
160 | TypedValue.applyDimension(
161 | TypedValue.COMPLEX_UNIT_DIP, TEXT_SIZE_DIP, getResources().getDisplayMetrics());
162 | borderedText = new BorderedText(textSizePx);
163 | borderedText.setTypeface(Typeface.MONOSPACE);
164 |
165 | previewWidth = size.getWidth();
166 | previewHeight = size.getHeight();
167 |
168 | Log.i(TAG, String.format("Initializing cameraPreview at size %dx%d", previewWidth, previewHeight));
169 | rgbBytes = new int[previewWidth * previewHeight];
170 | rgbFrameBitmap = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888);
171 | croppedBitmap = Bitmap.createBitmap(mImageClassifier.getImageWidth(), mImageClassifier.getImageHeight(), Bitmap.Config.ARGB_8888);
172 |
173 | frameToCropTransform =
174 | ImageUtils.getTransformationMatrix(
175 | previewWidth, previewHeight,
176 | mImageClassifier.getImageWidth(), mImageClassifier.getImageHeight(),
177 | 90, true);
178 |
179 | cropToFrameTransform = new Matrix();
180 | frameToCropTransform.invert(cropToFrameTransform);
181 |
182 | yuvBytes = new byte[3][];
183 |
184 | addCallback(
185 | new OverlayView.DrawCallback() {
186 | @Override
187 | public void drawCallback(final Canvas canvas) {
188 | renderDebug(canvas);
189 | }
190 | });
191 | }
192 |
193 | protected void fillBytes(final Image.Plane[] planes, final byte[][] yuvBytes) {
194 | // Because of the variable row stride it's not possible to know in
195 | // advance the actual necessary dimensions of the yuv planes.
196 | for (int i = 0; i < planes.length; ++i) {
197 | final ByteBuffer buffer = planes[i].getBuffer();
198 | if (yuvBytes[i] == null) {
199 | Log.d(TAG, String.format("Initializing buffer %d at size %d", i, buffer.capacity()));
200 | yuvBytes[i] = new byte[buffer.capacity()];
201 | }
202 | buffer.get(yuvBytes[i]);
203 | }
204 | }
205 |
206 | public void requestRender() {
207 | final OverlayView overlay = (OverlayView) findViewById(R.id.debug_overlay);
208 | if (overlay != null) {
209 | overlay.postInvalidate();
210 | }
211 | }
212 |
213 | public void addCallback(final OverlayView.DrawCallback callback) {
214 | final OverlayView overlay = (OverlayView) findViewById(R.id.debug_overlay);
215 | if (overlay != null) {
216 | overlay.addCallback(callback);
217 | }
218 | }
219 |
220 | @Override
221 | public boolean onKeyDown(final int keyCode, final KeyEvent event) {
222 | if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
223 | debug = !debug;
224 | requestRender();
225 | return true;
226 | }
227 | return super.onKeyDown(keyCode, event);
228 | }
229 |
230 | private void renderDebug(final Canvas canvas) {
231 | if (!debug) {
232 | return;
233 | }
234 | final Bitmap copy = cropCopyBitmap;
235 | if (copy != null) {
236 | final Matrix matrix = new Matrix();
237 | final float scaleFactor = 2;
238 | matrix.postScale(scaleFactor, scaleFactor);
239 | matrix.postTranslate(
240 | canvas.getWidth() - copy.getWidth() * scaleFactor,
241 | canvas.getHeight() - copy.getHeight() * scaleFactor);
242 | canvas.drawBitmap(copy, matrix, new Paint());
243 |
244 | final Vector lines = new Vector<>();
245 |
246 | lines.add("Frame: " + previewWidth + "x" + previewHeight);
247 | lines.add("Crop: " + copy.getWidth() + "x" + copy.getHeight());
248 | lines.add("View: " + canvas.getWidth() + "x" + canvas.getHeight());
249 | lines.add("Inference time: " + lasProcessingTimeMs + "ms");
250 |
251 | borderedText.drawLines(canvas, 10, canvas.getHeight() - 10, lines);
252 | }
253 | }
254 |
255 | @Override
256 | public void onImageAvailable(ImageReader imageReader) {
257 | Image image = null;
258 |
259 | try {
260 | image = imageReader.acquireLatestImage();
261 |
262 | if (image == null) {
263 | return;
264 | }
265 |
266 | if (computing || isFirstImage) {
267 | isFirstImage = false;
268 | image.close();
269 | return;
270 | }
271 | computing = true;
272 |
273 | Trace.beginSection("imageAvailable");
274 |
275 | final Image.Plane[] planes = image.getPlanes();
276 | fillBytes(planes, yuvBytes);
277 |
278 | final int yRowStride = planes[0].getRowStride();
279 | final int uvRowStride = planes[1].getRowStride();
280 | final int uvPixelStride = planes[1].getPixelStride();
281 | ImageUtils.convertYUV420ToARGB8888(
282 | yuvBytes[0],
283 | yuvBytes[1],
284 | yuvBytes[2],
285 | rgbBytes,
286 | previewWidth,
287 | previewHeight,
288 | yRowStride,
289 | uvRowStride,
290 | uvPixelStride,
291 | false);
292 | image.close();
293 | Trace.endSection();
294 | } catch (final Exception e) {
295 | if (image != null) {
296 | image.close();
297 | }
298 | Log.e(TAG, String.format("Exception in onImageAvailable: %s", e));
299 | Trace.endSection();
300 | return;
301 | }
302 |
303 | rgbFrameBitmap.setPixels(rgbBytes, 0, previewWidth, 0, 0, previewWidth, previewHeight);
304 | final Canvas canvas = new Canvas(croppedBitmap);
305 | canvas.drawBitmap(rgbFrameBitmap, frameToCropTransform, null);
306 | cropCopyBitmap = Bitmap.createBitmap(croppedBitmap);
307 |
308 | if (handler != null) {
309 | handler.post(new ImageClassificationTask(croppedBitmap, this, mImageClassifier));
310 | }
311 | }
312 |
313 | public void setLasProcessingTimeMs(long lasProcessingTimeMs) {
314 | this.lasProcessingTimeMs = lasProcessingTimeMs;
315 | }
316 | }
317 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/OverlayView.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | ==============================================================================*/
15 |
16 | package de.hpi.xnor_mxnet;
17 |
18 | import android.content.Context;
19 | import android.graphics.Canvas;
20 | import android.util.AttributeSet;
21 | import android.view.View;
22 | import java.util.LinkedList;
23 | import java.util.List;
24 |
25 | /**
26 | * A simple View providing a render callback to other classes.
27 | */
28 | public class OverlayView extends View {
29 | private final List callbacks = new LinkedList();
30 |
31 | public OverlayView(final Context context, final AttributeSet attrs) {
32 | super(context, attrs);
33 | }
34 |
35 | /**
36 | * Interface defining the callback for client classes.
37 | */
38 | public interface DrawCallback {
39 | public void drawCallback(final Canvas canvas);
40 | }
41 |
42 | public void addCallback(final DrawCallback callback) {
43 | callbacks.add(callback);
44 | }
45 |
46 | @Override
47 | public synchronized void draw(final Canvas canvas) {
48 | for (final DrawCallback callback : callbacks) {
49 | callback.drawCallback(canvas);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/imageclassification/AbstractClassifier.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet.imageclassification;
2 |
3 |
4 | import android.content.Context;
5 |
6 | import org.dmlc.mxnet.Predictor;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.io.InputStreamReader;
13 | import java.util.ArrayList;
14 | import java.util.Arrays;
15 | import java.util.List;
16 | import java.util.Map;
17 |
18 | import de.hpi.xnor_mxnet.BuildConfig;
19 | import de.hpi.xnor_mxnet.MainActivity;
20 |
21 | abstract class AbstractClassifier implements ImageClassifier {
22 | final MainActivity mActivity;
23 | Predictor mPredictor;
24 | List mLabels;
25 | Map mMean;
26 | Map mStdDev;
27 |
28 | int mImageWidth;
29 | int mImageHeight;
30 |
31 | protected final boolean modelNeedsMeanAdjust = true;
32 | protected final boolean modelNeedsStdAdjust = true;
33 |
34 | @Override
35 | public int getImageWidth() {
36 | return mImageWidth;
37 | }
38 |
39 | @Override
40 | public int getImageHeight() {
41 | return mImageHeight;
42 | }
43 |
44 | AbstractClassifier(MainActivity activity) {
45 | mActivity = activity;
46 | ModelPreparationTask preparationTask = new ModelPreparationTask();
47 | preparationTask.setContext(activity);
48 | preparationTask.execute(this);
49 | }
50 |
51 | static byte[] readRawFile(Context ctx, int resId)
52 | {
53 | ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
54 | int size = 0;
55 | byte[] buffer = new byte[1024];
56 | try (InputStream ins = ctx.getResources().openRawResource(resId)) {
57 | while((size=ins.read(buffer,0,1024))>=0){
58 | outputStream.write(buffer,0,size);
59 | }
60 | } catch (IOException e) {
61 | e.printStackTrace();
62 | }
63 | return outputStream.toByteArray();
64 | }
65 |
66 | static List readRawTextFile(Context ctx, int resId)
67 | {
68 | List result = new ArrayList<>();
69 | InputStream inputStream = ctx.getResources().openRawResource(resId);
70 |
71 | InputStreamReader inputreader = new InputStreamReader(inputStream);
72 | BufferedReader buffreader = new BufferedReader(inputreader);
73 | String line;
74 |
75 | try {
76 | while (( line = buffreader.readLine()) != null) {
77 | result.add(line);
78 | }
79 | } catch (IOException e) {
80 | return null;
81 | }
82 | return result;
83 | }
84 |
85 | Classification[] getTopKresults(float[] input_matrix, int k) {
86 | float[] sorted_values = input_matrix.clone();
87 | Arrays.sort(sorted_values);
88 |
89 | Classification[] topK = new Classification[k];
90 | List input_list = new ArrayList<>();
91 | for (float f: input_matrix) {
92 | input_list.add(f);
93 | }
94 |
95 | if (BuildConfig.DEBUG && sorted_values.length < k) {
96 | throw new RuntimeException("Too few predicted values for getting topK results!");
97 | }
98 |
99 | for (int i = 0; i < topK.length; ++i) {
100 | int classId = input_list.indexOf(sorted_values[sorted_values.length - i - 1]);
101 | String tag = mLabels.get(classId);
102 | String [] tagInfo = tag.split(" ", 2);
103 | topK[i] = new Classification(classId, tagInfo[1], input_matrix[classId]);
104 | }
105 | return topK;
106 | }
107 |
108 | float[] prepareInputImage(byte[] bytes) {
109 | float[] colors = new float[bytes.length / 4 * 3];
110 |
111 | // the R,G,B order has been tested (by HJ, 19.10.17), the R->G->B (1,2,3) got better results from prediction
112 | int imageOffset = mImageWidth * mImageHeight;
113 | for (int i = 0; i < bytes.length; i += 4) {
114 | int j = i / 4;
115 |
116 | int indexR = j;
117 | int indexG = imageOffset + j;
118 | int indexB = 2 * imageOffset + j;
119 |
120 | colors[indexR] = (float)(((int)(bytes[i + 1])) & 0xFF);
121 | colors[indexG] = (float)(((int)(bytes[i + 2])) & 0xFF);
122 | colors[indexB] = (float)(((int)(bytes[i + 3])) & 0xFF);
123 |
124 | if (modelNeedsMeanAdjust) {
125 | colors[indexR] -= mMean.get("r");
126 | colors[indexG] -= mMean.get("g");
127 | colors[indexB] -= mMean.get("b");
128 | }
129 |
130 | if (modelNeedsStdAdjust) {
131 | colors[indexR] /= mStdDev.get("r");
132 | colors[indexG] /= mStdDev.get("g");
133 | colors[indexB] /= mStdDev.get("b");
134 | }
135 | }
136 | return colors;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/imageclassification/Classification.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet.imageclassification;
2 |
3 | public class Classification {
4 | private String _id;
5 | private String _label;
6 | private float _probability;
7 |
8 | Classification(String id, String label, float probability) {
9 | _id = id; _label = label; _probability = probability;
10 | }
11 |
12 | public Classification(int id, String label, float probability) {
13 | _id = String.valueOf(id); _label = label; _probability = probability;
14 | }
15 |
16 | public String get_id() { return _id; }
17 | public String get_label() { return _label; }
18 | public float get_probability() { return _probability; }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/imageclassification/ImageClassifier.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet.imageclassification;
2 |
3 | import android.graphics.Bitmap;
4 |
5 | public interface ImageClassifier {
6 | int getImageWidth();
7 | int getImageHeight();
8 | Classification[] classifyImage(Bitmap bitmap);
9 | void loadModel();
10 | void loadLabels();
11 | void loadMean();
12 | void loadStdDev();
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/imageclassification/ImageNetClassifier.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet.imageclassification;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.SystemClock;
5 | import android.os.Trace;
6 |
7 | import org.dmlc.mxnet.Predictor;
8 |
9 | import java.nio.ByteBuffer;
10 | import java.util.HashMap;
11 |
12 | import de.hpi.xnor_mxnet.MainActivity;
13 | import de.hpi.xnor_mxnet.R;
14 |
15 | public class ImageNetClassifier extends AbstractClassifier {
16 | protected final boolean modelNeedsMeanAdjust = true;
17 | protected final boolean modelNeedsStdAdjust = true;
18 |
19 | public ImageNetClassifier(MainActivity activity) {
20 | super(activity);
21 | mImageWidth = 224;
22 | mImageHeight = 224;
23 | }
24 |
25 | public Classification[] classifyImage(Bitmap bitmap) {
26 | Trace.beginSection("create Image Buffer");
27 | ByteBuffer byteBuffer = ByteBuffer.allocate(bitmap.getByteCount());
28 | bitmap.copyPixelsToBuffer(byteBuffer);
29 | byte[] bytes = byteBuffer.array();
30 | Trace.endSection();
31 |
32 | Trace.beginSection("color adaption");
33 | float[] colors;
34 | colors = prepareInputImage(bytes);
35 |
36 | Trace.endSection();
37 | Trace.beginSection("Model execution");
38 |
39 | final long startTime = SystemClock.uptimeMillis();
40 | mPredictor.forward("data", colors);
41 | mActivity.setLasProcessingTimeMs(SystemClock.uptimeMillis() - startTime);
42 |
43 | final float[] result = mPredictor.getOutput(0);
44 | Trace.endSection();
45 |
46 | Trace.beginSection("gather top results");
47 | Classification[] results = getTopKresults(result, 5);
48 | Trace.endSection();
49 |
50 | mActivity.requestRender();
51 | return results;
52 | }
53 |
54 | @Override
55 | public void loadModel() {
56 | final byte[] symbol = readRawFile(mActivity, R.raw.binarized_densenet_28_symbol);
57 | final byte[] params = readRawFile(mActivity, R.raw.binarized_densenet_28_params);
58 | final Predictor.Device device = new Predictor.Device(Predictor.Device.Type.CPU, 0);
59 | final int[] shape = {1, 3, mImageHeight, mImageWidth};
60 | final String key = "data";
61 | final Predictor.InputNode node = new Predictor.InputNode(key, shape);
62 |
63 | mPredictor = new Predictor(symbol, params, device, new Predictor.InputNode[]{node});
64 | }
65 |
66 | @Override
67 | public void loadLabels() {
68 | mLabels = readRawTextFile(mActivity, R.raw.synset);
69 | }
70 |
71 | @Override
72 | public void loadMean() {
73 | mMean = new HashMap<>();
74 | if (modelNeedsMeanAdjust) {
75 | mMean.put("b", (float) 103.939);
76 | mMean.put("g", (float) 116.779);
77 | mMean.put("r", (float) 123.68);
78 | }
79 |
80 | }
81 |
82 | @Override
83 | public void loadStdDev() {
84 | mStdDev = new HashMap<>();
85 | if (modelNeedsStdAdjust) {
86 | mStdDev.put("b", (float) 57.375);
87 | mStdDev.put("g", (float) 57.12);
88 | mStdDev.put("r", (float) 58.393);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/de/hpi/xnor_mxnet/imageclassification/ModelPreparationTask.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet.imageclassification;
2 |
3 |
4 | import android.app.ProgressDialog;
5 | import android.os.AsyncTask;
6 |
7 | import de.hpi.xnor_mxnet.CameraLiveViewActivity;
8 | import de.hpi.xnor_mxnet.R;
9 |
10 |
11 | public class ModelPreparationTask extends AsyncTask {
12 | private ProgressDialog mProgressDialog;
13 | private CameraLiveViewActivity context;
14 |
15 | public void setContext(CameraLiveViewActivity context) {
16 | this.context = context;
17 | }
18 |
19 | @Override
20 | protected void onPreExecute() {
21 | mProgressDialog = new ProgressDialog(context);
22 | mProgressDialog.setTitle(R.string.loading_model);
23 | mProgressDialog.setCancelable(false);
24 | mProgressDialog.setIndeterminate(true);
25 | mProgressDialog.show();
26 | }
27 |
28 | @Override
29 | protected Void doInBackground(ImageClassifier... imageClassifiers) {
30 | for (ImageClassifier classifier: imageClassifiers) {
31 | classifier.loadModel();
32 | classifier.loadLabels();
33 | classifier.loadMean();
34 | classifier.loadStdDev();
35 | }
36 | return null;
37 | }
38 |
39 | @Override
40 | protected void onPostExecute(Void voids) {
41 | if (mProgressDialog != null) {
42 | mProgressDialog.dismiss();
43 | }
44 | context.runCameraLiveView();
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/org/dmlc/mxnet/MxnetException.java:
--------------------------------------------------------------------------------
1 | package org.dmlc.mxnet;
2 |
3 | public class MxnetException extends Exception {
4 | public MxnetException(){}
5 | public MxnetException(String txt) {
6 | super(txt);
7 | }
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/org/dmlc/mxnet/Predictor.java:
--------------------------------------------------------------------------------
1 | package org.dmlc.mxnet;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Color;
5 |
6 | public class Predictor {
7 | static {
8 | System.loadLibrary("mxnet_predict");
9 | }
10 |
11 | public static class InputNode {
12 | String key;
13 | int[] shape;
14 | public InputNode(String key, int[] shape) {
15 | this.key = key;
16 | this.shape = shape;
17 | }
18 | }
19 |
20 | public static class Device {
21 | public enum Type {
22 | CPU, GPU, CPU_PINNED
23 | }
24 |
25 | public Device(Type t, int i) {
26 | this.type = t;
27 | this.id = i;
28 | }
29 |
30 | Type type;
31 | int id;
32 | int ctype() {
33 | return this.type == Type.CPU? 1: this.type == Type.GPU? 2: 3;
34 | }
35 | }
36 |
37 | private long handle = 0;
38 |
39 | public Predictor(byte[] symbol, byte[] params, Device dev, InputNode[] input) {
40 | String[] keys = new String[input.length];
41 | int[][] shapes = new int[input.length][];
42 | for (int i=0; i
20 | #include
21 |
22 | #include "yuv2rgb.h"
23 |
24 | #define IMAGEUTILS_METHOD(METHOD_NAME) \
25 | Java_de_hpi_xnor_1mxnet_ImageUtils_##METHOD_NAME // NOLINT
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | JNIEXPORT void JNICALL
32 | IMAGEUTILS_METHOD(convertYUV420SPToARGB8888)(
33 | JNIEnv* env, jclass clazz, jbyteArray input, jintArray output,
34 | jint width, jint height, jboolean halfSize);
35 |
36 | JNIEXPORT void JNICALL IMAGEUTILS_METHOD(convertYUV420ToARGB8888)(
37 | JNIEnv* env, jclass clazz, jbyteArray y, jbyteArray u, jbyteArray v,
38 | jintArray output, jint width, jint height, jint y_row_stride,
39 | jint uv_row_stride, jint uv_pixel_stride, jboolean halfSize);
40 |
41 | JNIEXPORT void JNICALL IMAGEUTILS_METHOD(convertYUV420SPToRGB565)(
42 | JNIEnv* env, jclass clazz, jbyteArray input, jbyteArray output, jint width,
43 | jint height);
44 |
45 | #ifdef __cplusplus
46 | }
47 | #endif
48 |
49 | JNIEXPORT void JNICALL
50 | IMAGEUTILS_METHOD(convertYUV420SPToARGB8888)(
51 | JNIEnv* env, jclass clazz, jbyteArray input, jintArray output,
52 | jint width, jint height, jboolean halfSize) {
53 | jboolean inputCopy = JNI_FALSE;
54 | jbyte* const i = env->GetByteArrayElements(input, &inputCopy);
55 |
56 | jboolean outputCopy = JNI_FALSE;
57 | jint* const o = env->GetIntArrayElements(output, &outputCopy);
58 |
59 | if (halfSize) {
60 | ConvertYUV420SPToARGB8888HalfSize(reinterpret_cast(i),
61 | reinterpret_cast(o), width,
62 | height);
63 | } else {
64 | ConvertYUV420SPToARGB8888(reinterpret_cast(i),
65 | reinterpret_cast(i) + width * height,
66 | reinterpret_cast(o), width, height);
67 | }
68 |
69 | env->ReleaseByteArrayElements(input, i, JNI_ABORT);
70 | env->ReleaseIntArrayElements(output, o, 0);
71 | }
72 |
73 | JNIEXPORT void JNICALL IMAGEUTILS_METHOD(convertYUV420ToARGB8888)(
74 | JNIEnv* env, jclass clazz, jbyteArray y, jbyteArray u, jbyteArray v,
75 | jintArray output, jint width, jint height, jint y_row_stride,
76 | jint uv_row_stride, jint uv_pixel_stride, jboolean halfSize) {
77 | jboolean inputCopy = JNI_FALSE;
78 | jbyte* const y_buff = env->GetByteArrayElements(y, &inputCopy);
79 | jboolean outputCopy = JNI_FALSE;
80 | jint* const o = env->GetIntArrayElements(output, &outputCopy);
81 |
82 | if (halfSize) {
83 | ConvertYUV420SPToARGB8888HalfSize(reinterpret_cast(y_buff),
84 | reinterpret_cast(o), width,
85 | height);
86 | } else {
87 | jbyte* const u_buff = env->GetByteArrayElements(u, &inputCopy);
88 | jbyte* const v_buff = env->GetByteArrayElements(v, &inputCopy);
89 |
90 | ConvertYUV420ToARGB8888(
91 | reinterpret_cast(y_buff), reinterpret_cast(u_buff),
92 | reinterpret_cast(v_buff), reinterpret_cast(o),
93 | width, height, y_row_stride, uv_row_stride, uv_pixel_stride);
94 |
95 | env->ReleaseByteArrayElements(u, u_buff, JNI_ABORT);
96 | env->ReleaseByteArrayElements(v, v_buff, JNI_ABORT);
97 | }
98 |
99 | env->ReleaseByteArrayElements(y, y_buff, JNI_ABORT);
100 | env->ReleaseIntArrayElements(output, o, 0);
101 | }
102 |
103 | JNIEXPORT void JNICALL IMAGEUTILS_METHOD(convertYUV420SPToRGB565)(
104 | JNIEnv* env, jclass clazz, jbyteArray input, jbyteArray output, jint width,
105 | jint height) {
106 | jboolean inputCopy = JNI_FALSE;
107 | jbyte* const i = env->GetByteArrayElements(input, &inputCopy);
108 |
109 | jboolean outputCopy = JNI_FALSE;
110 | jbyte* const o = env->GetByteArrayElements(output, &outputCopy);
111 |
112 | ConvertYUV420SPToRGB565(reinterpret_cast(i),
113 | reinterpret_cast(o), width, height);
114 |
115 | env->ReleaseByteArrayElements(input, i, JNI_ABORT);
116 | env->ReleaseByteArrayElements(output, o, 0);
117 | }
118 |
--------------------------------------------------------------------------------
/app/src/main/native-image-utils/yuv2rgb.cc:
--------------------------------------------------------------------------------
1 | /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | ==============================================================================*/
15 |
16 | // This is a collection of routines which converts various YUV image formats
17 | // to ARGB.
18 |
19 | #include "yuv2rgb.h"
20 |
21 | #ifndef MAX
22 | #define MAX(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b); _a > _b ? _a : _b; })
23 | #define MIN(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b); _a < _b ? _a : _b; })
24 | #endif
25 |
26 | // This value is 2 ^ 18 - 1, and is used to clamp the RGB values before their ranges
27 | // are normalized to eight bits.
28 | static const int kMaxChannelValue = 262143;
29 |
30 | static inline uint32_t YUV2RGB(int nY, int nU, int nV) {
31 | nY -= 16;
32 | nU -= 128;
33 | nV -= 128;
34 | if (nY < 0) nY = 0;
35 |
36 | // This is the floating point equivalent. We do the conversion in integer
37 | // because some Android devices do not have floating point in hardware.
38 | // nR = (int)(1.164 * nY + 2.018 * nU);
39 | // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
40 | // nB = (int)(1.164 * nY + 1.596 * nV);
41 |
42 | int nR = (int)(1192 * nY + 1634 * nV);
43 | int nG = (int)(1192 * nY - 833 * nV - 400 * nU);
44 | int nB = (int)(1192 * nY + 2066 * nU);
45 |
46 | nR = MIN(kMaxChannelValue, MAX(0, nR));
47 | nG = MIN(kMaxChannelValue, MAX(0, nG));
48 | nB = MIN(kMaxChannelValue, MAX(0, nB));
49 |
50 | nR = (nR >> 10) & 0xff;
51 | nG = (nG >> 10) & 0xff;
52 | nB = (nB >> 10) & 0xff;
53 |
54 | return 0xff000000 | (nR << 16) | (nG << 8) | nB;
55 | }
56 |
57 | // Accepts a YUV 4:2:0 image with a plane of 8 bit Y samples followed by
58 | // separate u and v planes with arbitrary row and column strides,
59 | // containing 8 bit 2x2 subsampled chroma samples.
60 | // Converts to a packed ARGB 32 bit output of the same pixel dimensions.
61 | void ConvertYUV420ToARGB8888(const uint8_t* const yData,
62 | const uint8_t* const uData,
63 | const uint8_t* const vData, uint32_t* const output,
64 | const int width, const int height,
65 | const int y_row_stride, const int uv_row_stride,
66 | const int uv_pixel_stride) {
67 | uint32_t* out = output;
68 |
69 | for (int y = 0; y < height; y++) {
70 | const uint8_t* pY = yData + y_row_stride * y;
71 |
72 | const int uv_row_start = uv_row_stride * (y >> 1);
73 | const uint8_t* pU = uData + uv_row_start;
74 | const uint8_t* pV = vData + uv_row_start;
75 |
76 | for (int x = 0; x < width; x++) {
77 | const int uv_offset = (x >> 1) * uv_pixel_stride;
78 | *out++ = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]);
79 | }
80 | }
81 | }
82 |
83 | // Accepts a YUV 4:2:0 image with a plane of 8 bit Y samples followed by an
84 | // interleaved U/V plane containing 8 bit 2x2 subsampled chroma samples,
85 | // except the interleave order of U and V is reversed. Converts to a packed
86 | // ARGB 32 bit output of the same pixel dimensions.
87 | void ConvertYUV420SPToARGB8888(const uint8_t* const yData,
88 | const uint8_t* const uvData,
89 | uint32_t* const output, const int width,
90 | const int height) {
91 | const uint8_t* pY = yData;
92 | const uint8_t* pUV = uvData;
93 | uint32_t* out = output;
94 |
95 | for (int y = 0; y < height; y++) {
96 | for (int x = 0; x < width; x++) {
97 | int nY = *pY++;
98 | int offset = (y >> 1) * width + 2 * (x >> 1);
99 | #ifdef __APPLE__
100 | int nU = pUV[offset];
101 | int nV = pUV[offset + 1];
102 | #else
103 | int nV = pUV[offset];
104 | int nU = pUV[offset + 1];
105 | #endif
106 |
107 | *out++ = YUV2RGB(nY, nU, nV);
108 | }
109 | }
110 | }
111 |
112 | // The same as above, but downsamples each dimension to half size.
113 | void ConvertYUV420SPToARGB8888HalfSize(const uint8_t* const input,
114 | uint32_t* const output, int width,
115 | int height) {
116 | const uint8_t* pY = input;
117 | const uint8_t* pUV = input + (width * height);
118 | uint32_t* out = output;
119 | int stride = width;
120 | width >>= 1;
121 | height >>= 1;
122 |
123 | for (int y = 0; y < height; y++) {
124 | for (int x = 0; x < width; x++) {
125 | int nY = (pY[0] + pY[1] + pY[stride] + pY[stride + 1]) >> 2;
126 | pY += 2;
127 | #ifdef __APPLE__
128 | int nU = *pUV++;
129 | int nV = *pUV++;
130 | #else
131 | int nV = *pUV++;
132 | int nU = *pUV++;
133 | #endif
134 |
135 | *out++ = YUV2RGB(nY, nU, nV);
136 | }
137 | pY += stride;
138 | }
139 | }
140 |
141 | // Accepts a YUV 4:2:0 image with a plane of 8 bit Y samples followed by an
142 | // interleaved U/V plane containing 8 bit 2x2 subsampled chroma samples,
143 | // except the interleave order of U and V is reversed. Converts to a packed
144 | // RGB 565 bit output of the same pixel dimensions.
145 | void ConvertYUV420SPToRGB565(const uint8_t* const input, uint16_t* const output,
146 | const int width, const int height) {
147 | const uint8_t* pY = input;
148 | const uint8_t* pUV = input + (width * height);
149 | uint16_t* out = output;
150 |
151 | for (int y = 0; y < height; y++) {
152 | for (int x = 0; x < width; x++) {
153 | int nY = *pY++;
154 | int offset = (y >> 1) * width + 2 * (x >> 1);
155 | #ifdef __APPLE__
156 | int nU = pUV[offset];
157 | int nV = pUV[offset + 1];
158 | #else
159 | int nV = pUV[offset];
160 | int nU = pUV[offset + 1];
161 | #endif
162 |
163 | nY -= 16;
164 | nU -= 128;
165 | nV -= 128;
166 | if (nY < 0) nY = 0;
167 |
168 | // This is the floating point equivalent. We do the conversion in integer
169 | // because some Android devices do not have floating point in hardware.
170 | // nR = (int)(1.164 * nY + 2.018 * nU);
171 | // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
172 | // nB = (int)(1.164 * nY + 1.596 * nV);
173 |
174 | int nR = (int)(1192 * nY + 1634 * nV);
175 | int nG = (int)(1192 * nY - 833 * nV - 400 * nU);
176 | int nB = (int)(1192 * nY + 2066 * nU);
177 |
178 | nR = MIN(kMaxChannelValue, MAX(0, nR));
179 | nG = MIN(kMaxChannelValue, MAX(0, nG));
180 | nB = MIN(kMaxChannelValue, MAX(0, nB));
181 |
182 | // Shift more than for ARGB8888 and apply appropriate bitmask.
183 | nR = (nR >> 13) & 0x1f;
184 | nG = (nG >> 12) & 0x3f;
185 | nB = (nB >> 13) & 0x1f;
186 |
187 | // R is high 5 bits, G is middle 6 bits, and B is low 5 bits.
188 | *out++ = (nR << 11) | (nG << 5) | nB;
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/app/src/main/native-image-utils/yuv2rgb.h:
--------------------------------------------------------------------------------
1 | /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | ==============================================================================*/
15 |
16 | // This is a collection of routines which converts various YUV image formats
17 | // to (A)RGB.
18 |
19 | #ifndef ORG_TENSORFLOW_JNI_IMAGEUTILS_YUV2RGB_H_
20 | #define ORG_TENSORFLOW_JNI_IMAGEUTILS_YUV2RGB_H_
21 |
22 | #include
23 |
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 | void ConvertYUV420ToARGB8888(const uint8_t* const yData,
29 | const uint8_t* const uData,
30 | const uint8_t* const vData, uint32_t* const output,
31 | const int width, const int height,
32 | const int y_row_stride, const int uv_row_stride,
33 | const int uv_pixel_stride);
34 |
35 | // Converts YUV420 semi-planar data to ARGB 8888 data using the supplied width
36 | // and height. The input and output must already be allocated and non-null.
37 | // For efficiency, no error checking is performed.
38 | void ConvertYUV420SPToARGB8888(const uint8_t* const pY,
39 | const uint8_t* const pUV, uint32_t* const output,
40 | const int width, const int height);
41 |
42 | // The same as above, but downsamples each dimension to half size.
43 | void ConvertYUV420SPToARGB8888HalfSize(const uint8_t* const input,
44 | uint32_t* const output, int width,
45 | int height);
46 |
47 | // Converts YUV420 semi-planar data to RGB 565 data using the supplied width
48 | // and height. The input and output must already be allocated and non-null.
49 | // For efficiency, no error checking is performed.
50 | void ConvertYUV420SPToRGB565(const uint8_t* const input, uint16_t* const output,
51 | const int width, const int height);
52 |
53 | #ifdef __cplusplus
54 | }
55 | #endif
56 |
57 | #endif // ORG_TENSORFLOW_JNI_IMAGEUTILS_YUV2RGB_H_
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_gpslogger.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
22 |
23 |
24 |
25 |
33 |
34 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_gpslogger.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/main_activity.xml:
--------------------------------------------------------------------------------
1 |
16 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/placerecognizer_ui.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
21 |
22 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/binarized_densenet_28_params:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/src/main/res/raw/binarized_densenet_28_params
--------------------------------------------------------------------------------
/app/src/main/res/raw/binarized_resnet_e_18_params:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpi-xnor/android-image-classification/5013eba9e212a5ba8e98e4bc3f8c9d58d1df46f6/app/src/main/res/raw/binarized_resnet_e_18_params
--------------------------------------------------------------------------------
/app/src/main/res/raw/synset.txt:
--------------------------------------------------------------------------------
1 | n01440764 tench, Tinca tinca
2 | n01443537 goldfish, Carassius auratus
3 | n01484850 great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias
4 | n01491361 tiger shark, Galeocerdo cuvieri
5 | n01494475 hammerhead, hammerhead shark
6 | n01496331 electric ray, crampfish, numbfish, torpedo
7 | n01498041 stingray
8 | n01514668 cock
9 | n01514859 hen
10 | n01518878 ostrich, Struthio camelus
11 | n01530575 brambling, Fringilla montifringilla
12 | n01531178 goldfinch, Carduelis carduelis
13 | n01532829 house finch, linnet, Carpodacus mexicanus
14 | n01534433 junco, snowbird
15 | n01537544 indigo bunting, indigo finch, indigo bird, Passerina cyanea
16 | n01558993 robin, American robin, Turdus migratorius
17 | n01560419 bulbul
18 | n01580077 jay
19 | n01582220 magpie
20 | n01592084 chickadee
21 | n01601694 water ouzel, dipper
22 | n01608432 kite
23 | n01614925 bald eagle, American eagle, Haliaeetus leucocephalus
24 | n01616318 vulture
25 | n01622779 great grey owl, great gray owl, Strix nebulosa
26 | n01629819 European fire salamander, Salamandra salamandra
27 | n01630670 common newt, Triturus vulgaris
28 | n01631663 eft
29 | n01632458 spotted salamander, Ambystoma maculatum
30 | n01632777 axolotl, mud puppy, Ambystoma mexicanum
31 | n01641577 bullfrog, Rana catesbeiana
32 | n01644373 tree frog, tree-frog
33 | n01644900 tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui
34 | n01664065 loggerhead, loggerhead turtle, Caretta caretta
35 | n01665541 leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea
36 | n01667114 mud turtle
37 | n01667778 terrapin
38 | n01669191 box turtle, box tortoise
39 | n01675722 banded gecko
40 | n01677366 common iguana, iguana, Iguana iguana
41 | n01682714 American chameleon, anole, Anolis carolinensis
42 | n01685808 whiptail, whiptail lizard
43 | n01687978 agama
44 | n01688243 frilled lizard, Chlamydosaurus kingi
45 | n01689811 alligator lizard
46 | n01692333 Gila monster, Heloderma suspectum
47 | n01693334 green lizard, Lacerta viridis
48 | n01694178 African chameleon, Chamaeleo chamaeleon
49 | n01695060 Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis
50 | n01697457 African crocodile, Nile crocodile, Crocodylus niloticus
51 | n01698640 American alligator, Alligator mississipiensis
52 | n01704323 triceratops
53 | n01728572 thunder snake, worm snake, Carphophis amoenus
54 | n01728920 ringneck snake, ring-necked snake, ring snake
55 | n01729322 hognose snake, puff adder, sand viper
56 | n01729977 green snake, grass snake
57 | n01734418 king snake, kingsnake
58 | n01735189 garter snake, grass snake
59 | n01737021 water snake
60 | n01739381 vine snake
61 | n01740131 night snake, Hypsiglena torquata
62 | n01742172 boa constrictor, Constrictor constrictor
63 | n01744401 rock python, rock snake, Python sebae
64 | n01748264 Indian cobra, Naja naja
65 | n01749939 green mamba
66 | n01751748 sea snake
67 | n01753488 horned viper, cerastes, sand viper, horned asp, Cerastes cornutus
68 | n01755581 diamondback, diamondback rattlesnake, Crotalus adamanteus
69 | n01756291 sidewinder, horned rattlesnake, Crotalus cerastes
70 | n01768244 trilobite
71 | n01770081 harvestman, daddy longlegs, Phalangium opilio
72 | n01770393 scorpion
73 | n01773157 black and gold garden spider, Argiope aurantia
74 | n01773549 barn spider, Araneus cavaticus
75 | n01773797 garden spider, Aranea diademata
76 | n01774384 black widow, Latrodectus mactans
77 | n01774750 tarantula
78 | n01775062 wolf spider, hunting spider
79 | n01776313 tick
80 | n01784675 centipede
81 | n01795545 black grouse
82 | n01796340 ptarmigan
83 | n01797886 ruffed grouse, partridge, Bonasa umbellus
84 | n01798484 prairie chicken, prairie grouse, prairie fowl
85 | n01806143 peacock
86 | n01806567 quail
87 | n01807496 partridge
88 | n01817953 African grey, African gray, Psittacus erithacus
89 | n01818515 macaw
90 | n01819313 sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita
91 | n01820546 lorikeet
92 | n01824575 coucal
93 | n01828970 bee eater
94 | n01829413 hornbill
95 | n01833805 hummingbird
96 | n01843065 jacamar
97 | n01843383 toucan
98 | n01847000 drake
99 | n01855032 red-breasted merganser, Mergus serrator
100 | n01855672 goose
101 | n01860187 black swan, Cygnus atratus
102 | n01871265 tusker
103 | n01872401 echidna, spiny anteater, anteater
104 | n01873310 platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus
105 | n01877812 wallaby, brush kangaroo
106 | n01882714 koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus
107 | n01883070 wombat
108 | n01910747 jellyfish
109 | n01914609 sea anemone, anemone
110 | n01917289 brain coral
111 | n01924916 flatworm, platyhelminth
112 | n01930112 nematode, nematode worm, roundworm
113 | n01943899 conch
114 | n01944390 snail
115 | n01945685 slug
116 | n01950731 sea slug, nudibranch
117 | n01955084 chiton, coat-of-mail shell, sea cradle, polyplacophore
118 | n01968897 chambered nautilus, pearly nautilus, nautilus
119 | n01978287 Dungeness crab, Cancer magister
120 | n01978455 rock crab, Cancer irroratus
121 | n01980166 fiddler crab
122 | n01981276 king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica
123 | n01983481 American lobster, Northern lobster, Maine lobster, Homarus americanus
124 | n01984695 spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish
125 | n01985128 crayfish, crawfish, crawdad, crawdaddy
126 | n01986214 hermit crab
127 | n01990800 isopod
128 | n02002556 white stork, Ciconia ciconia
129 | n02002724 black stork, Ciconia nigra
130 | n02006656 spoonbill
131 | n02007558 flamingo
132 | n02009229 little blue heron, Egretta caerulea
133 | n02009912 American egret, great white heron, Egretta albus
134 | n02011460 bittern
135 | n02012849 crane
136 | n02013706 limpkin, Aramus pictus
137 | n02017213 European gallinule, Porphyrio porphyrio
138 | n02018207 American coot, marsh hen, mud hen, water hen, Fulica americana
139 | n02018795 bustard
140 | n02025239 ruddy turnstone, Arenaria interpres
141 | n02027492 red-backed sandpiper, dunlin, Erolia alpina
142 | n02028035 redshank, Tringa totanus
143 | n02033041 dowitcher
144 | n02037110 oystercatcher, oyster catcher
145 | n02051845 pelican
146 | n02056570 king penguin, Aptenodytes patagonica
147 | n02058221 albatross, mollymawk
148 | n02066245 grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus
149 | n02071294 killer whale, killer, orca, grampus, sea wolf, Orcinus orca
150 | n02074367 dugong, Dugong dugon
151 | n02077923 sea lion
152 | n02085620 Chihuahua
153 | n02085782 Japanese spaniel
154 | n02085936 Maltese dog, Maltese terrier, Maltese
155 | n02086079 Pekinese, Pekingese, Peke
156 | n02086240 Shih-Tzu
157 | n02086646 Blenheim spaniel
158 | n02086910 papillon
159 | n02087046 toy terrier
160 | n02087394 Rhodesian ridgeback
161 | n02088094 Afghan hound, Afghan
162 | n02088238 basset, basset hound
163 | n02088364 beagle
164 | n02088466 bloodhound, sleuthhound
165 | n02088632 bluetick
166 | n02089078 black-and-tan coonhound
167 | n02089867 Walker hound, Walker foxhound
168 | n02089973 English foxhound
169 | n02090379 redbone
170 | n02090622 borzoi, Russian wolfhound
171 | n02090721 Irish wolfhound
172 | n02091032 Italian greyhound
173 | n02091134 whippet
174 | n02091244 Ibizan hound, Ibizan Podenco
175 | n02091467 Norwegian elkhound, elkhound
176 | n02091635 otterhound, otter hound
177 | n02091831 Saluki, gazelle hound
178 | n02092002 Scottish deerhound, deerhound
179 | n02092339 Weimaraner
180 | n02093256 Staffordshire bullterrier, Staffordshire bull terrier
181 | n02093428 American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier
182 | n02093647 Bedlington terrier
183 | n02093754 Border terrier
184 | n02093859 Kerry blue terrier
185 | n02093991 Irish terrier
186 | n02094114 Norfolk terrier
187 | n02094258 Norwich terrier
188 | n02094433 Yorkshire terrier
189 | n02095314 wire-haired fox terrier
190 | n02095570 Lakeland terrier
191 | n02095889 Sealyham terrier, Sealyham
192 | n02096051 Airedale, Airedale terrier
193 | n02096177 cairn, cairn terrier
194 | n02096294 Australian terrier
195 | n02096437 Dandie Dinmont, Dandie Dinmont terrier
196 | n02096585 Boston bull, Boston terrier
197 | n02097047 miniature schnauzer
198 | n02097130 giant schnauzer
199 | n02097209 standard schnauzer
200 | n02097298 Scotch terrier, Scottish terrier, Scottie
201 | n02097474 Tibetan terrier, chrysanthemum dog
202 | n02097658 silky terrier, Sydney silky
203 | n02098105 soft-coated wheaten terrier
204 | n02098286 West Highland white terrier
205 | n02098413 Lhasa, Lhasa apso
206 | n02099267 flat-coated retriever
207 | n02099429 curly-coated retriever
208 | n02099601 golden retriever
209 | n02099712 Labrador retriever
210 | n02099849 Chesapeake Bay retriever
211 | n02100236 German short-haired pointer
212 | n02100583 vizsla, Hungarian pointer
213 | n02100735 English setter
214 | n02100877 Irish setter, red setter
215 | n02101006 Gordon setter
216 | n02101388 Brittany spaniel
217 | n02101556 clumber, clumber spaniel
218 | n02102040 English springer, English springer spaniel
219 | n02102177 Welsh springer spaniel
220 | n02102318 cocker spaniel, English cocker spaniel, cocker
221 | n02102480 Sussex spaniel
222 | n02102973 Irish water spaniel
223 | n02104029 kuvasz
224 | n02104365 schipperke
225 | n02105056 groenendael
226 | n02105162 malinois
227 | n02105251 briard
228 | n02105412 kelpie
229 | n02105505 komondor
230 | n02105641 Old English sheepdog, bobtail
231 | n02105855 Shetland sheepdog, Shetland sheep dog, Shetland
232 | n02106030 collie
233 | n02106166 Border collie
234 | n02106382 Bouvier des Flandres, Bouviers des Flandres
235 | n02106550 Rottweiler
236 | n02106662 German shepherd, German shepherd dog, German police dog, alsatian
237 | n02107142 Doberman, Doberman pinscher
238 | n02107312 miniature pinscher
239 | n02107574 Greater Swiss Mountain dog
240 | n02107683 Bernese mountain dog
241 | n02107908 Appenzeller
242 | n02108000 EntleBucher
243 | n02108089 boxer
244 | n02108422 bull mastiff
245 | n02108551 Tibetan mastiff
246 | n02108915 French bulldog
247 | n02109047 Great Dane
248 | n02109525 Saint Bernard, St Bernard
249 | n02109961 Eskimo dog, husky
250 | n02110063 malamute, malemute, Alaskan malamute
251 | n02110185 Siberian husky
252 | n02110341 dalmatian, coach dog, carriage dog
253 | n02110627 affenpinscher, monkey pinscher, monkey dog
254 | n02110806 basenji
255 | n02110958 pug, pug-dog
256 | n02111129 Leonberg
257 | n02111277 Newfoundland, Newfoundland dog
258 | n02111500 Great Pyrenees
259 | n02111889 Samoyed, Samoyede
260 | n02112018 Pomeranian
261 | n02112137 chow, chow chow
262 | n02112350 keeshond
263 | n02112706 Brabancon griffon
264 | n02113023 Pembroke, Pembroke Welsh corgi
265 | n02113186 Cardigan, Cardigan Welsh corgi
266 | n02113624 toy poodle
267 | n02113712 miniature poodle
268 | n02113799 standard poodle
269 | n02113978 Mexican hairless
270 | n02114367 timber wolf, grey wolf, gray wolf, Canis lupus
271 | n02114548 white wolf, Arctic wolf, Canis lupus tundrarum
272 | n02114712 red wolf, maned wolf, Canis rufus, Canis niger
273 | n02114855 coyote, prairie wolf, brush wolf, Canis latrans
274 | n02115641 dingo, warrigal, warragal, Canis dingo
275 | n02115913 dhole, Cuon alpinus
276 | n02116738 African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus
277 | n02117135 hyena, hyaena
278 | n02119022 red fox, Vulpes vulpes
279 | n02119789 kit fox, Vulpes macrotis
280 | n02120079 Arctic fox, white fox, Alopex lagopus
281 | n02120505 grey fox, gray fox, Urocyon cinereoargenteus
282 | n02123045 tabby, tabby cat
283 | n02123159 tiger cat
284 | n02123394 Persian cat
285 | n02123597 Siamese cat, Siamese
286 | n02124075 Egyptian cat
287 | n02125311 cougar, puma, catamount, mountain lion, painter, panther, Felis concolor
288 | n02127052 lynx, catamount
289 | n02128385 leopard, Panthera pardus
290 | n02128757 snow leopard, ounce, Panthera uncia
291 | n02128925 jaguar, panther, Panthera onca, Felis onca
292 | n02129165 lion, king of beasts, Panthera leo
293 | n02129604 tiger, Panthera tigris
294 | n02130308 cheetah, chetah, Acinonyx jubatus
295 | n02132136 brown bear, bruin, Ursus arctos
296 | n02133161 American black bear, black bear, Ursus americanus, Euarctos americanus
297 | n02134084 ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus
298 | n02134418 sloth bear, Melursus ursinus, Ursus ursinus
299 | n02137549 mongoose
300 | n02138441 meerkat, mierkat
301 | n02165105 tiger beetle
302 | n02165456 ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle
303 | n02167151 ground beetle, carabid beetle
304 | n02168699 long-horned beetle, longicorn, longicorn beetle
305 | n02169497 leaf beetle, chrysomelid
306 | n02172182 dung beetle
307 | n02174001 rhinoceros beetle
308 | n02177972 weevil
309 | n02190166 fly
310 | n02206856 bee
311 | n02219486 ant, emmet, pismire
312 | n02226429 grasshopper, hopper
313 | n02229544 cricket
314 | n02231487 walking stick, walkingstick, stick insect
315 | n02233338 cockroach, roach
316 | n02236044 mantis, mantid
317 | n02256656 cicada, cicala
318 | n02259212 leafhopper
319 | n02264363 lacewing, lacewing fly
320 | n02268443 dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk
321 | n02268853 damselfly
322 | n02276258 admiral
323 | n02277742 ringlet, ringlet butterfly
324 | n02279972 monarch, monarch butterfly, milkweed butterfly, Danaus plexippus
325 | n02280649 cabbage butterfly
326 | n02281406 sulphur butterfly, sulfur butterfly
327 | n02281787 lycaenid, lycaenid butterfly
328 | n02317335 starfish, sea star
329 | n02319095 sea urchin
330 | n02321529 sea cucumber, holothurian
331 | n02325366 wood rabbit, cottontail, cottontail rabbit
332 | n02326432 hare
333 | n02328150 Angora, Angora rabbit
334 | n02342885 hamster
335 | n02346627 porcupine, hedgehog
336 | n02356798 fox squirrel, eastern fox squirrel, Sciurus niger
337 | n02361337 marmot
338 | n02363005 beaver
339 | n02364673 guinea pig, Cavia cobaya
340 | n02389026 sorrel
341 | n02391049 zebra
342 | n02395406 hog, pig, grunter, squealer, Sus scrofa
343 | n02396427 wild boar, boar, Sus scrofa
344 | n02397096 warthog
345 | n02398521 hippopotamus, hippo, river horse, Hippopotamus amphibius
346 | n02403003 ox
347 | n02408429 water buffalo, water ox, Asiatic buffalo, Bubalus bubalis
348 | n02410509 bison
349 | n02412080 ram, tup
350 | n02415577 bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis
351 | n02417914 ibex, Capra ibex
352 | n02422106 hartebeest
353 | n02422699 impala, Aepyceros melampus
354 | n02423022 gazelle
355 | n02437312 Arabian camel, dromedary, Camelus dromedarius
356 | n02437616 llama
357 | n02441942 weasel
358 | n02442845 mink
359 | n02443114 polecat, fitch, foulmart, foumart, Mustela putorius
360 | n02443484 black-footed ferret, ferret, Mustela nigripes
361 | n02444819 otter
362 | n02445715 skunk, polecat, wood pussy
363 | n02447366 badger
364 | n02454379 armadillo
365 | n02457408 three-toed sloth, ai, Bradypus tridactylus
366 | n02480495 orangutan, orang, orangutang, Pongo pygmaeus
367 | n02480855 gorilla, Gorilla gorilla
368 | n02481823 chimpanzee, chimp, Pan troglodytes
369 | n02483362 gibbon, Hylobates lar
370 | n02483708 siamang, Hylobates syndactylus, Symphalangus syndactylus
371 | n02484975 guenon, guenon monkey
372 | n02486261 patas, hussar monkey, Erythrocebus patas
373 | n02486410 baboon
374 | n02487347 macaque
375 | n02488291 langur
376 | n02488702 colobus, colobus monkey
377 | n02489166 proboscis monkey, Nasalis larvatus
378 | n02490219 marmoset
379 | n02492035 capuchin, ringtail, Cebus capucinus
380 | n02492660 howler monkey, howler
381 | n02493509 titi, titi monkey
382 | n02493793 spider monkey, Ateles geoffroyi
383 | n02494079 squirrel monkey, Saimiri sciureus
384 | n02497673 Madagascar cat, ring-tailed lemur, Lemur catta
385 | n02500267 indri, indris, Indri indri, Indri brevicaudatus
386 | n02504013 Indian elephant, Elephas maximus
387 | n02504458 African elephant, Loxodonta africana
388 | n02509815 lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens
389 | n02510455 giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca
390 | n02514041 barracouta, snoek
391 | n02526121 eel
392 | n02536864 coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch
393 | n02606052 rock beauty, Holocanthus tricolor
394 | n02607072 anemone fish
395 | n02640242 sturgeon
396 | n02641379 gar, garfish, garpike, billfish, Lepisosteus osseus
397 | n02643566 lionfish
398 | n02655020 puffer, pufferfish, blowfish, globefish
399 | n02666196 abacus
400 | n02667093 abaya
401 | n02669723 academic gown, academic robe, judge's robe
402 | n02672831 accordion, piano accordion, squeeze box
403 | n02676566 acoustic guitar
404 | n02687172 aircraft carrier, carrier, flattop, attack aircraft carrier
405 | n02690373 airliner
406 | n02692877 airship, dirigible
407 | n02699494 altar
408 | n02701002 ambulance
409 | n02704792 amphibian, amphibious vehicle
410 | n02708093 analog clock
411 | n02727426 apiary, bee house
412 | n02730930 apron
413 | n02747177 ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin
414 | n02749479 assault rifle, assault gun
415 | n02769748 backpack, back pack, knapsack, packsack, rucksack, haversack
416 | n02776631 bakery, bakeshop, bakehouse
417 | n02777292 balance beam, beam
418 | n02782093 balloon
419 | n02783161 ballpoint, ballpoint pen, ballpen, Biro
420 | n02786058 Band Aid
421 | n02787622 banjo
422 | n02788148 bannister, banister, balustrade, balusters, handrail
423 | n02790996 barbell
424 | n02791124 barber chair
425 | n02791270 barbershop
426 | n02793495 barn
427 | n02794156 barometer
428 | n02795169 barrel, cask
429 | n02797295 barrow, garden cart, lawn cart, wheelbarrow
430 | n02799071 baseball
431 | n02802426 basketball
432 | n02804414 bassinet
433 | n02804610 bassoon
434 | n02807133 bathing cap, swimming cap
435 | n02808304 bath towel
436 | n02808440 bathtub, bathing tub, bath, tub
437 | n02814533 beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon
438 | n02814860 beacon, lighthouse, beacon light, pharos
439 | n02815834 beaker
440 | n02817516 bearskin, busby, shako
441 | n02823428 beer bottle
442 | n02823750 beer glass
443 | n02825657 bell cote, bell cot
444 | n02834397 bib
445 | n02835271 bicycle-built-for-two, tandem bicycle, tandem
446 | n02837789 bikini, two-piece
447 | n02840245 binder, ring-binder
448 | n02841315 binoculars, field glasses, opera glasses
449 | n02843684 birdhouse
450 | n02859443 boathouse
451 | n02860847 bobsled, bobsleigh, bob
452 | n02865351 bolo tie, bolo, bola tie, bola
453 | n02869837 bonnet, poke bonnet
454 | n02870880 bookcase
455 | n02871525 bookshop, bookstore, bookstall
456 | n02877765 bottlecap
457 | n02879718 bow
458 | n02883205 bow tie, bow-tie, bowtie
459 | n02892201 brass, memorial tablet, plaque
460 | n02892767 brassiere, bra, bandeau
461 | n02894605 breakwater, groin, groyne, mole, bulwark, seawall, jetty
462 | n02895154 breastplate, aegis, egis
463 | n02906734 broom
464 | n02909870 bucket, pail
465 | n02910353 buckle
466 | n02916936 bulletproof vest
467 | n02917067 bullet train, bullet
468 | n02927161 butcher shop, meat market
469 | n02930766 cab, hack, taxi, taxicab
470 | n02939185 caldron, cauldron
471 | n02948072 candle, taper, wax light
472 | n02950826 cannon
473 | n02951358 canoe
474 | n02951585 can opener, tin opener
475 | n02963159 cardigan
476 | n02965783 car mirror
477 | n02966193 carousel, carrousel, merry-go-round, roundabout, whirligig
478 | n02966687 carpenter's kit, tool kit
479 | n02971356 carton
480 | n02974003 car wheel
481 | n02977058 cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM
482 | n02978881 cassette
483 | n02979186 cassette player
484 | n02980441 castle
485 | n02981792 catamaran
486 | n02988304 CD player
487 | n02992211 cello, violoncello
488 | n02992529 cellular telephone, cellular phone, cellphone, cell, mobile phone
489 | n02999410 chain
490 | n03000134 chainlink fence
491 | n03000247 chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour
492 | n03000684 chain saw, chainsaw
493 | n03014705 chest
494 | n03016953 chiffonier, commode
495 | n03017168 chime, bell, gong
496 | n03018349 china cabinet, china closet
497 | n03026506 Christmas stocking
498 | n03028079 church, church building
499 | n03032252 cinema, movie theater, movie theatre, movie house, picture palace
500 | n03041632 cleaver, meat cleaver, chopper
501 | n03042490 cliff dwelling
502 | n03045698 cloak
503 | n03047690 clog, geta, patten, sabot
504 | n03062245 cocktail shaker
505 | n03063599 coffee mug
506 | n03063689 coffeepot
507 | n03065424 coil, spiral, volute, whorl, helix
508 | n03075370 combination lock
509 | n03085013 computer keyboard, keypad
510 | n03089624 confectionery, confectionary, candy store
511 | n03095699 container ship, containership, container vessel
512 | n03100240 convertible
513 | n03109150 corkscrew, bottle screw
514 | n03110669 cornet, horn, trumpet, trump
515 | n03124043 cowboy boot
516 | n03124170 cowboy hat, ten-gallon hat
517 | n03125729 cradle
518 | n03126707 crane
519 | n03127747 crash helmet
520 | n03127925 crate
521 | n03131574 crib, cot
522 | n03133878 Crock Pot
523 | n03134739 croquet ball
524 | n03141823 crutch
525 | n03146219 cuirass
526 | n03160309 dam, dike, dyke
527 | n03179701 desk
528 | n03180011 desktop computer
529 | n03187595 dial telephone, dial phone
530 | n03188531 diaper, nappy, napkin
531 | n03196217 digital clock
532 | n03197337 digital watch
533 | n03201208 dining table, board
534 | n03207743 dishrag, dishcloth
535 | n03207941 dishwasher, dish washer, dishwashing machine
536 | n03208938 disk brake, disc brake
537 | n03216828 dock, dockage, docking facility
538 | n03218198 dogsled, dog sled, dog sleigh
539 | n03220513 dome
540 | n03223299 doormat, welcome mat
541 | n03240683 drilling platform, offshore rig
542 | n03249569 drum, membranophone, tympan
543 | n03250847 drumstick
544 | n03255030 dumbbell
545 | n03259280 Dutch oven
546 | n03271574 electric fan, blower
547 | n03272010 electric guitar
548 | n03272562 electric locomotive
549 | n03290653 entertainment center
550 | n03291819 envelope
551 | n03297495 espresso maker
552 | n03314780 face powder
553 | n03325584 feather boa, boa
554 | n03337140 file, file cabinet, filing cabinet
555 | n03344393 fireboat
556 | n03345487 fire engine, fire truck
557 | n03347037 fire screen, fireguard
558 | n03355925 flagpole, flagstaff
559 | n03372029 flute, transverse flute
560 | n03376595 folding chair
561 | n03379051 football helmet
562 | n03384352 forklift
563 | n03388043 fountain
564 | n03388183 fountain pen
565 | n03388549 four-poster
566 | n03393912 freight car
567 | n03394916 French horn, horn
568 | n03400231 frying pan, frypan, skillet
569 | n03404251 fur coat
570 | n03417042 garbage truck, dustcart
571 | n03424325 gasmask, respirator, gas helmet
572 | n03425413 gas pump, gasoline pump, petrol pump, island dispenser
573 | n03443371 goblet
574 | n03444034 go-kart
575 | n03445777 golf ball
576 | n03445924 golfcart, golf cart
577 | n03447447 gondola
578 | n03447721 gong, tam-tam
579 | n03450230 gown
580 | n03452741 grand piano, grand
581 | n03457902 greenhouse, nursery, glasshouse
582 | n03459775 grille, radiator grille
583 | n03461385 grocery store, grocery, food market, market
584 | n03467068 guillotine
585 | n03476684 hair slide
586 | n03476991 hair spray
587 | n03478589 half track
588 | n03481172 hammer
589 | n03482405 hamper
590 | n03483316 hand blower, blow dryer, blow drier, hair dryer, hair drier
591 | n03485407 hand-held computer, hand-held microcomputer
592 | n03485794 handkerchief, hankie, hanky, hankey
593 | n03492542 hard disc, hard disk, fixed disk
594 | n03494278 harmonica, mouth organ, harp, mouth harp
595 | n03495258 harp
596 | n03496892 harvester, reaper
597 | n03498962 hatchet
598 | n03527444 holster
599 | n03529860 home theater, home theatre
600 | n03530642 honeycomb
601 | n03532672 hook, claw
602 | n03534580 hoopskirt, crinoline
603 | n03535780 horizontal bar, high bar
604 | n03538406 horse cart, horse-cart
605 | n03544143 hourglass
606 | n03584254 iPod
607 | n03584829 iron, smoothing iron
608 | n03590841 jack-o'-lantern
609 | n03594734 jean, blue jean, denim
610 | n03594945 jeep, landrover
611 | n03595614 jersey, T-shirt, tee shirt
612 | n03598930 jigsaw puzzle
613 | n03599486 jinrikisha, ricksha, rickshaw
614 | n03602883 joystick
615 | n03617480 kimono
616 | n03623198 knee pad
617 | n03627232 knot
618 | n03630383 lab coat, laboratory coat
619 | n03633091 ladle
620 | n03637318 lampshade, lamp shade
621 | n03642806 laptop, laptop computer
622 | n03649909 lawn mower, mower
623 | n03657121 lens cap, lens cover
624 | n03658185 letter opener, paper knife, paperknife
625 | n03661043 library
626 | n03662601 lifeboat
627 | n03666591 lighter, light, igniter, ignitor
628 | n03670208 limousine, limo
629 | n03673027 liner, ocean liner
630 | n03676483 lipstick, lip rouge
631 | n03680355 Loafer
632 | n03690938 lotion
633 | n03691459 loudspeaker, speaker, speaker unit, loudspeaker system, speaker system
634 | n03692522 loupe, jeweler's loupe
635 | n03697007 lumbermill, sawmill
636 | n03706229 magnetic compass
637 | n03709823 mailbag, postbag
638 | n03710193 mailbox, letter box
639 | n03710637 maillot
640 | n03710721 maillot, tank suit
641 | n03717622 manhole cover
642 | n03720891 maraca
643 | n03721384 marimba, xylophone
644 | n03724870 mask
645 | n03729826 matchstick
646 | n03733131 maypole
647 | n03733281 maze, labyrinth
648 | n03733805 measuring cup
649 | n03742115 medicine chest, medicine cabinet
650 | n03743016 megalith, megalithic structure
651 | n03759954 microphone, mike
652 | n03761084 microwave, microwave oven
653 | n03763968 military uniform
654 | n03764736 milk can
655 | n03769881 minibus
656 | n03770439 miniskirt, mini
657 | n03770679 minivan
658 | n03773504 missile
659 | n03775071 mitten
660 | n03775546 mixing bowl
661 | n03776460 mobile home, manufactured home
662 | n03777568 Model T
663 | n03777754 modem
664 | n03781244 monastery
665 | n03782006 monitor
666 | n03785016 moped
667 | n03786901 mortar
668 | n03787032 mortarboard
669 | n03788195 mosque
670 | n03788365 mosquito net
671 | n03791053 motor scooter, scooter
672 | n03792782 mountain bike, all-terrain bike, off-roader
673 | n03792972 mountain tent
674 | n03793489 mouse, computer mouse
675 | n03794056 mousetrap
676 | n03796401 moving van
677 | n03803284 muzzle
678 | n03804744 nail
679 | n03814639 neck brace
680 | n03814906 necklace
681 | n03825788 nipple
682 | n03832673 notebook, notebook computer
683 | n03837869 obelisk
684 | n03838899 oboe, hautboy, hautbois
685 | n03840681 ocarina, sweet potato
686 | n03841143 odometer, hodometer, mileometer, milometer
687 | n03843555 oil filter
688 | n03854065 organ, pipe organ
689 | n03857828 oscilloscope, scope, cathode-ray oscilloscope, CRO
690 | n03866082 overskirt
691 | n03868242 oxcart
692 | n03868863 oxygen mask
693 | n03871628 packet
694 | n03873416 paddle, boat paddle
695 | n03874293 paddlewheel, paddle wheel
696 | n03874599 padlock
697 | n03876231 paintbrush
698 | n03877472 pajama, pyjama, pj's, jammies
699 | n03877845 palace
700 | n03884397 panpipe, pandean pipe, syrinx
701 | n03887697 paper towel
702 | n03888257 parachute, chute
703 | n03888605 parallel bars, bars
704 | n03891251 park bench
705 | n03891332 parking meter
706 | n03895866 passenger car, coach, carriage
707 | n03899768 patio, terrace
708 | n03902125 pay-phone, pay-station
709 | n03903868 pedestal, plinth, footstall
710 | n03908618 pencil box, pencil case
711 | n03908714 pencil sharpener
712 | n03916031 perfume, essence
713 | n03920288 Petri dish
714 | n03924679 photocopier
715 | n03929660 pick, plectrum, plectron
716 | n03929855 pickelhaube
717 | n03930313 picket fence, paling
718 | n03930630 pickup, pickup truck
719 | n03933933 pier
720 | n03935335 piggy bank, penny bank
721 | n03937543 pill bottle
722 | n03938244 pillow
723 | n03942813 ping-pong ball
724 | n03944341 pinwheel
725 | n03947888 pirate, pirate ship
726 | n03950228 pitcher, ewer
727 | n03954731 plane, carpenter's plane, woodworking plane
728 | n03956157 planetarium
729 | n03958227 plastic bag
730 | n03961711 plate rack
731 | n03967562 plow, plough
732 | n03970156 plunger, plumber's helper
733 | n03976467 Polaroid camera, Polaroid Land camera
734 | n03976657 pole
735 | n03977966 police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria
736 | n03980874 poncho
737 | n03982430 pool table, billiard table, snooker table
738 | n03983396 pop bottle, soda bottle
739 | n03991062 pot, flowerpot
740 | n03992509 potter's wheel
741 | n03995372 power drill
742 | n03998194 prayer rug, prayer mat
743 | n04004767 printer
744 | n04005630 prison, prison house
745 | n04008634 projectile, missile
746 | n04009552 projector
747 | n04019541 puck, hockey puck
748 | n04023962 punching bag, punch bag, punching ball, punchball
749 | n04026417 purse
750 | n04033901 quill, quill pen
751 | n04033995 quilt, comforter, comfort, puff
752 | n04037443 racer, race car, racing car
753 | n04039381 racket, racquet
754 | n04040759 radiator
755 | n04041544 radio, wireless
756 | n04044716 radio telescope, radio reflector
757 | n04049303 rain barrel
758 | n04065272 recreational vehicle, RV, R.V.
759 | n04067472 reel
760 | n04069434 reflex camera
761 | n04070727 refrigerator, icebox
762 | n04074963 remote control, remote
763 | n04081281 restaurant, eating house, eating place, eatery
764 | n04086273 revolver, six-gun, six-shooter
765 | n04090263 rifle
766 | n04099969 rocking chair, rocker
767 | n04111531 rotisserie
768 | n04116512 rubber eraser, rubber, pencil eraser
769 | n04118538 rugby ball
770 | n04118776 rule, ruler
771 | n04120489 running shoe
772 | n04125021 safe
773 | n04127249 safety pin
774 | n04131690 saltshaker, salt shaker
775 | n04133789 sandal
776 | n04136333 sarong
777 | n04141076 sax, saxophone
778 | n04141327 scabbard
779 | n04141975 scale, weighing machine
780 | n04146614 school bus
781 | n04147183 schooner
782 | n04149813 scoreboard
783 | n04152593 screen, CRT screen
784 | n04153751 screw
785 | n04154565 screwdriver
786 | n04162706 seat belt, seatbelt
787 | n04179913 sewing machine
788 | n04192698 shield, buckler
789 | n04200800 shoe shop, shoe-shop, shoe store
790 | n04201297 shoji
791 | n04204238 shopping basket
792 | n04204347 shopping cart
793 | n04208210 shovel
794 | n04209133 shower cap
795 | n04209239 shower curtain
796 | n04228054 ski
797 | n04229816 ski mask
798 | n04235860 sleeping bag
799 | n04238763 slide rule, slipstick
800 | n04239074 sliding door
801 | n04243546 slot, one-armed bandit
802 | n04251144 snorkel
803 | n04252077 snowmobile
804 | n04252225 snowplow, snowplough
805 | n04254120 soap dispenser
806 | n04254680 soccer ball
807 | n04254777 sock
808 | n04258138 solar dish, solar collector, solar furnace
809 | n04259630 sombrero
810 | n04263257 soup bowl
811 | n04264628 space bar
812 | n04265275 space heater
813 | n04266014 space shuttle
814 | n04270147 spatula
815 | n04273569 speedboat
816 | n04275548 spider web, spider's web
817 | n04277352 spindle
818 | n04285008 sports car, sport car
819 | n04286575 spotlight, spot
820 | n04296562 stage
821 | n04310018 steam locomotive
822 | n04311004 steel arch bridge
823 | n04311174 steel drum
824 | n04317175 stethoscope
825 | n04325704 stole
826 | n04326547 stone wall
827 | n04328186 stopwatch, stop watch
828 | n04330267 stove
829 | n04332243 strainer
830 | n04335435 streetcar, tram, tramcar, trolley, trolley car
831 | n04336792 stretcher
832 | n04344873 studio couch, day bed
833 | n04346328 stupa, tope
834 | n04347754 submarine, pigboat, sub, U-boat
835 | n04350905 suit, suit of clothes
836 | n04355338 sundial
837 | n04355933 sunglass
838 | n04356056 sunglasses, dark glasses, shades
839 | n04357314 sunscreen, sunblock, sun blocker
840 | n04366367 suspension bridge
841 | n04367480 swab, swob, mop
842 | n04370456 sweatshirt
843 | n04371430 swimming trunks, bathing trunks
844 | n04371774 swing
845 | n04372370 switch, electric switch, electrical switch
846 | n04376876 syringe
847 | n04380533 table lamp
848 | n04389033 tank, army tank, armored combat vehicle, armoured combat vehicle
849 | n04392985 tape player
850 | n04398044 teapot
851 | n04399382 teddy, teddy bear
852 | n04404412 television, television system
853 | n04409515 tennis ball
854 | n04417672 thatch, thatched roof
855 | n04418357 theater curtain, theatre curtain
856 | n04423845 thimble
857 | n04428191 thresher, thrasher, threshing machine
858 | n04429376 throne
859 | n04435653 tile roof
860 | n04442312 toaster
861 | n04443257 tobacco shop, tobacconist shop, tobacconist
862 | n04447861 toilet seat
863 | n04456115 torch
864 | n04458633 totem pole
865 | n04461696 tow truck, tow car, wrecker
866 | n04462240 toyshop
867 | n04465501 tractor
868 | n04467665 trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi
869 | n04476259 tray
870 | n04479046 trench coat
871 | n04482393 tricycle, trike, velocipede
872 | n04483307 trimaran
873 | n04485082 tripod
874 | n04486054 triumphal arch
875 | n04487081 trolleybus, trolley coach, trackless trolley
876 | n04487394 trombone
877 | n04493381 tub, vat
878 | n04501370 turnstile
879 | n04505470 typewriter keyboard
880 | n04507155 umbrella
881 | n04509417 unicycle, monocycle
882 | n04515003 upright, upright piano
883 | n04517823 vacuum, vacuum cleaner
884 | n04522168 vase
885 | n04523525 vault
886 | n04525038 velvet
887 | n04525305 vending machine
888 | n04532106 vestment
889 | n04532670 viaduct
890 | n04536866 violin, fiddle
891 | n04540053 volleyball
892 | n04542943 waffle iron
893 | n04548280 wall clock
894 | n04548362 wallet, billfold, notecase, pocketbook
895 | n04550184 wardrobe, closet, press
896 | n04552348 warplane, military plane
897 | n04553703 washbasin, handbasin, washbowl, lavabo, wash-hand basin
898 | n04554684 washer, automatic washer, washing machine
899 | n04557648 water bottle
900 | n04560804 water jug
901 | n04562935 water tower
902 | n04579145 whiskey jug
903 | n04579432 whistle
904 | n04584207 wig
905 | n04589890 window screen
906 | n04590129 window shade
907 | n04591157 Windsor tie
908 | n04591713 wine bottle
909 | n04592741 wing
910 | n04596742 wok
911 | n04597913 wooden spoon
912 | n04599235 wool, woolen, woollen
913 | n04604644 worm fence, snake fence, snake-rail fence, Virginia fence
914 | n04606251 wreck
915 | n04612504 yawl
916 | n04613696 yurt
917 | n06359193 web site, website, internet site, site
918 | n06596364 comic book
919 | n06785654 crossword puzzle, crossword
920 | n06794110 street sign
921 | n06874185 traffic light, traffic signal, stoplight
922 | n07248320 book jacket, dust cover, dust jacket, dust wrapper
923 | n07565083 menu
924 | n07579787 plate
925 | n07583066 guacamole
926 | n07584110 consomme
927 | n07590611 hot pot, hotpot
928 | n07613480 trifle
929 | n07614500 ice cream, icecream
930 | n07615774 ice lolly, lolly, lollipop, popsicle
931 | n07684084 French loaf
932 | n07693725 bagel, beigel
933 | n07695742 pretzel
934 | n07697313 cheeseburger
935 | n07697537 hotdog, hot dog, red hot
936 | n07711569 mashed potato
937 | n07714571 head cabbage
938 | n07714990 broccoli
939 | n07715103 cauliflower
940 | n07716358 zucchini, courgette
941 | n07716906 spaghetti squash
942 | n07717410 acorn squash
943 | n07717556 butternut squash
944 | n07718472 cucumber, cuke
945 | n07718747 artichoke, globe artichoke
946 | n07720875 bell pepper
947 | n07730033 cardoon
948 | n07734744 mushroom
949 | n07742313 Granny Smith
950 | n07745940 strawberry
951 | n07747607 orange
952 | n07749582 lemon
953 | n07753113 fig
954 | n07753275 pineapple, ananas
955 | n07753592 banana
956 | n07754684 jackfruit, jak, jack
957 | n07760859 custard apple
958 | n07768694 pomegranate
959 | n07802026 hay
960 | n07831146 carbonara
961 | n07836838 chocolate sauce, chocolate syrup
962 | n07860988 dough
963 | n07871810 meat loaf, meatloaf
964 | n07873807 pizza, pizza pie
965 | n07875152 potpie
966 | n07880968 burrito
967 | n07892512 red wine
968 | n07920052 espresso
969 | n07930864 cup
970 | n07932039 eggnog
971 | n09193705 alp
972 | n09229709 bubble
973 | n09246464 cliff, drop, drop-off
974 | n09256479 coral reef
975 | n09288635 geyser
976 | n09332890 lakeside, lakeshore
977 | n09399592 promontory, headland, head, foreland
978 | n09421951 sandbar, sand bar
979 | n09428293 seashore, coast, seacoast, sea-coast
980 | n09468604 valley, vale
981 | n09472597 volcano
982 | n09835506 ballplayer, baseball player
983 | n10148035 groom, bridegroom
984 | n10565667 scuba diver
985 | n11879895 rapeseed
986 | n11939491 daisy
987 | n12057211 yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum
988 | n12144580 corn
989 | n12267677 acorn
990 | n12620546 hip, rose hip, rosehip
991 | n12768682 buckeye, horse chestnut, conker
992 | n12985857 coral fungus
993 | n12998815 agaric
994 | n13037406 gyromitra
995 | n13040303 stinkhorn, carrion fungus
996 | n13044778 earthstar
997 | n13052670 hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa
998 | n13054560 bolete
999 | n13133613 ear, spike, capitulum
1000 | n15075141 toilet tissue, toilet paper, bathroom tissue
1001 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | XNOR MXNET
3 | Please Wait
4 | Loading Model
5 | This device doesn\'t support Camera2 API.
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/test/java/de/hpi/xnor_mxnet/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package de.hpi.xnor_mxnet;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/test/java/mxnet/MxnetException.java:
--------------------------------------------------------------------------------
1 | package mxnet;
2 |
3 | public class MxnetException extends Exception {
4 | public MxnetException(){}
5 | public MxnetException(String txt) {
6 | super(txt);
7 | }
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/app/src/test/java/mxnet/Predictor.java:
--------------------------------------------------------------------------------
1 | package mxnet;
2 |
3 | public class Predictor {
4 | static {
5 | System.loadLibrary("mxnet_predict");
6 | }
7 |
8 | public static class InputNode {
9 | String key;
10 | int[] shape;
11 | public InputNode(String key, int[] shape) {
12 | this.key = key;
13 | this.shape = shape;
14 | }
15 | }
16 |
17 | public static class Device {
18 | public enum Type {
19 | CPU, GPU, CPU_PINNED
20 | }
21 |
22 | public Device(Type t, int i) {
23 | this.type = t;
24 | this.id = i;
25 | }
26 |
27 | Type type;
28 | int id;
29 | int ctype() {
30 | return this.type == Type.CPU? 1: this.type == Type.GPU? 2: 3;
31 | }
32 | }
33 |
34 | private long handle = 0;
35 |
36 | public Predictor(byte[] symbol, byte[] params, Device dev, InputNode[] input) {
37 | String[] keys = new String[input.length];
38 | int[][] shapes = new int[input.length][];
39 | for (int i=0; i \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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'
2 |
--------------------------------------------------------------------------------