diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 6cbf4c39..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-language: android
-branches:
- except:
- - legacy
- - experimental
-
-# whitelist
-branches:
- only:
- - master
- - develop
-
-before_install:
- - date
- - ./envsetup 1> /dev/null 2%>1
- - cd $TRAVIS_BUILD_DIR
- - cd tools/travis-ci
- - sh setupNDK.sh
- - export PATH=`pwd`/android-ndk:$PATH
- - echo $PATH
- - cd $TRAVIS_BUILD_DIR
-script:
- - cd $TRAVIS_BUILD_DIR
- - ndk-build -j8
-after_script:
- - date
diff --git a/README.md b/README.md
index a5d061c7..acc597ef 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
* You can build it to dynamic or static library for Android. You can also build dlib's sample to Android executable file.
-* You can refer to [dlib-android-app](https://github.com/tzutalin/dlib-android-app) which demonstrates dlib-android features
+* This demonstrates dlib-android features, building with JNI.
### Grab the source
@@ -34,35 +34,15 @@
### Build JNI code and shared library for Android application
* You can change the compiler architecture in dlib-android/jni/Application.mk
-* The way to build the shared library for Android application
+* Android Studio build JNI code and move to libs folder to use them, but if you don't compile the ndk run in command line to build and see warnings:
```sh
- $ cd [dlib-android]
- $ python build.py
-```
-
-Alternative way to build native code and copy to the Android Studio's project manually:
-```sh
- $ cd [dlib-android]
- $ ndk-build -j 2
- $ cp -r libs/* androidstudio-examples/dlib-android-app/dlib/src/main/jniLibs
+ $ cd [dlib-android]/app/src/main/jni
+ $ ndk-build
```
### Run Android application
-* Open Android Studio's projects in androidstudio-examples/dlib-android-app to run face detection, face landmark, and so on
-
-### Folder structure
-
-```
-├── data # Test data or the models for detection and landmarks
-├── dlib # Source files of dlib. It is a submodule
-├── jni # Source files of JNI codes and their make files
-├── androidstudio-examples # Android Studio's projects use the shared library built by this repo
-├── tools # Tools and utilities
-├── third_party # Like OpenCV and [miniglog](https://github.com/tzutalin/miniglog)
-├── CMakeLists.txt # Use CMake to build instead of using Android.mk
-├── LICENSE
-└── README.md
+* Open Android Studio's project dlib-android to run face detection, face landmark, and so on
```
### Do you want to contribute
diff --git a/androidstudio-examples/dlib-android-app b/androidstudio-examples/dlib-android-app
deleted file mode 160000
index d0170613..00000000
--- a/androidstudio-examples/dlib-android-app
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit d0170613f36046b8e122a5de651029ecb1af947e
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/app.iml b/app/app.iml
new file mode 100644
index 00000000..3296fb58
--- /dev/null
+++ b/app/app.iml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 00000000..50b73d9f
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,74 @@
+apply plugin: 'com.android.application'
+import org.apache.tools.ant.taskdefs.condition.Os
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.0"
+
+ defaultConfig {
+ applicationId "com.tzutalin.dlibtest"
+ minSdkVersion 21
+ targetSdkVersion 25
+ versionCode 1
+ versionName "${rootProject.ext.releaseVersionName}"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ sourceSets.main {
+ jniLibs.srcDir 'src/main/libs'
+ jni.srcDirs = [] //disable automatic ndk-build call
+ }
+
+ // call regular ndk-build(.cmd) script from app directory
+ task ndkBuild(type: Exec) {
+ if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+ commandLine 'ndk-build.cmd', '-C', file('src/main/jni').absolutePath
+ } else {
+ commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath
+ }
+ }
+
+ tasks.withType(JavaCompile) {
+ compileTask -> compileTask.dependsOn ndkBuild
+ }
+}
+
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
+ }
+}
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+apply plugin: 'com.neenbedankt.android-apt'
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile "com.android.support:appcompat-v7:25.1.0"
+ compile 'com.android.support:design:25.1.0'
+ compile 'com.github.dexafree:materiallist:3.0.1'
+ apt "org.androidannotations:androidannotations:4.0.0"
+ compile "org.androidannotations:androidannotations-api:4.0.0"
+
+ // Add AndroidJUnit
+ androidTestCompile "com.android.support:support-annotations:25.1.0"
+ androidTestCompile 'com.android.support.test:runner:0.5'
+ androidTestCompile 'com.android.support.test:rules:0.5'
+ // Optional -- Hamcrest library
+ androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
+}
+apply plugin: 'com.jakewharton.hugo'
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 00000000..acfa448f
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/darrenl/tools/android-sdk-linux/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/app/src/androidTest/java/DLibFunctionsTest.java b/app/src/androidTest/java/DLibFunctionsTest.java
new file mode 100644
index 00000000..2ea7f18e
--- /dev/null
+++ b/app/src/androidTest/java/DLibFunctionsTest.java
@@ -0,0 +1,38 @@
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.tzutalin.dlib.PedestrianDet;
+import com.tzutalin.dlib.VisionDetRet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DLibFunctionsTest {
+
+ private Context mInstrumantationCtx;
+
+ @Before
+ public void setup() {
+ mInstrumantationCtx = InstrumentationRegistry.getTargetContext();
+ }
+
+ @Test
+ public void testFacialLandmark() {
+ PedestrianDet peopleDet = new PedestrianDet();
+ List results = peopleDet.detect("/sdcard/test.bmp");
+ for (final VisionDetRet ret : results) {
+ String label = ret.getLabel();
+ int rectLeft = ret.getLeft();
+ int rectTop= ret.getTop();
+ int rectRight = ret.getRight();
+ int rectBottom = ret.getBottom();
+ }
+ }
+}
diff --git a/app/src/androidTest/java/FaceDetTest.java b/app/src/androidTest/java/FaceDetTest.java
new file mode 100644
index 00000000..42f1a38c
--- /dev/null
+++ b/app/src/androidTest/java/FaceDetTest.java
@@ -0,0 +1,113 @@
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.tzutalin.dlib.Constants;
+import com.tzutalin.dlib.FaceDet;
+import com.tzutalin.dlib.VisionDetRet;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Created by houzhi on 16-10-20.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class FaceDetTest {
+
+ @Before
+ public void setup() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ @Test
+ public void testDetBitmapFace() {
+ FaceDet faceDet = new FaceDet(Constants.getFaceShapeModelPath());
+ Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.jpg");
+ assertThat(bitmap, notNullValue());
+ List results = faceDet.detect(bitmap);
+ for (final VisionDetRet ret : results) {
+ String label = ret.getLabel();
+ int rectLeft = ret.getLeft();
+ int rectTop = ret.getTop();
+ int rectRight = ret.getRight();
+ int rectBottom = ret.getBottom();
+ assertThat(label, is("face"));
+ Assert.assertTrue(rectLeft > 0);
+ }
+ faceDet.release();
+ }
+
+ @Test
+ public void testDetFace() {
+ Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.jpg");
+ assertThat(bitmap, notNullValue());
+ FaceDet faceDet = new FaceDet(Constants.getFaceShapeModelPath());
+ List results = faceDet.detect("/sdcard/test.jpg");
+ for (final VisionDetRet ret : results) {
+ String label = ret.getLabel();
+ int rectLeft = ret.getLeft();
+ int rectTop = ret.getTop();
+ int rectRight = ret.getRight();
+ int rectBottom = ret.getBottom();
+ assertThat(label, is("face"));
+ Assert.assertTrue(rectLeft > 0);
+ }
+ faceDet.release();
+ }
+
+ @Test
+ public void testDetBitmapFaceLandmarkDect() {
+ Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.jpg");
+ assertThat(bitmap, notNullValue());
+ FaceDet faceDet = new FaceDet(Constants.getFaceShapeModelPath());
+ List results = faceDet.detect(bitmap);
+ for (final VisionDetRet ret : results) {
+ String label = ret.getLabel();
+ int rectLeft = ret.getLeft();
+ int rectTop = ret.getTop();
+ int rectRight = ret.getRight();
+ int rectBottom = ret.getBottom();
+ ArrayList landmarks = ret.getFaceLandmarks();
+ assertThat(label, is("face"));
+ Assert.assertTrue(landmarks.size() > 0);
+ Assert.assertTrue(rectLeft > 0);
+ }
+ faceDet.release();
+ }
+
+ @Test
+ public void testDetFaceLandmark() {
+ FaceDet faceDet = new FaceDet(Constants.getFaceShapeModelPath());
+ List results = faceDet.detect("/sdcard/test.jpg");
+ for (final VisionDetRet ret : results) {
+ String label = ret.getLabel();
+ int rectLeft = ret.getLeft();
+ int rectTop = ret.getTop();
+ int rectRight = ret.getRight();
+ int rectBottom = ret.getBottom();
+ ArrayList landmarks = ret.getFaceLandmarks();
+ assertThat(label, is("face"));
+ Assert.assertTrue(landmarks.size() > 0);
+ Assert.assertTrue(rectLeft > 0);
+ }
+ faceDet.release();
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..b866d37f
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/tzutalin/dlib/Constants.java b/app/src/main/java/com/tzutalin/dlib/Constants.java
new file mode 100644
index 00000000..8d8abe81
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlib/Constants.java
@@ -0,0 +1,24 @@
+package com.tzutalin.dlib;
+
+import android.os.Environment;
+
+import java.io.File;
+
+/**
+ * Created by darrenl on 2016/4/22.
+ */
+public final class Constants {
+ private Constants() {
+ // Constants should be prive
+ }
+
+ /**
+ * getFaceShapeModelPath
+ * @return default face shape model path
+ */
+ public static String getFaceShapeModelPath() {
+ File sdcard = Environment.getExternalStorageDirectory();
+ String targetPath = sdcard.getAbsolutePath() + File.separator + "shape_predictor_68_face_landmarks.dat";
+ return targetPath;
+ }
+}
diff --git a/app/src/main/java/com/tzutalin/dlib/FaceDet.java b/app/src/main/java/com/tzutalin/dlib/FaceDet.java
new file mode 100644
index 00000000..a8227a81
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlib/FaceDet.java
@@ -0,0 +1,83 @@
+package com.tzutalin.dlib;
+
+import android.graphics.Bitmap;
+import android.support.annotation.Keep;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by houzhi on 16-10-20.
+ * Modified by tzutalin on 16-11-15
+ */
+public class FaceDet {
+ private static final String TAG = "dlib";
+
+ // accessed by native methods
+ @SuppressWarnings("unused")
+ private long mNativeFaceDetContext;
+ private String mLandMarkPath = "";
+
+ static {
+ try {
+ System.loadLibrary("android_dlib");
+ jniNativeClassInit();
+ Log.d(TAG, "jniNativeClassInit success");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "library not found");
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public FaceDet() {
+ jniInit(mLandMarkPath);
+ }
+
+ public FaceDet(String landMarkPath) {
+ mLandMarkPath = landMarkPath;
+ jniInit(mLandMarkPath);
+ }
+
+ @Nullable
+ @WorkerThread
+ public List detect(@NonNull String path) {
+ VisionDetRet[] detRets = jniDetect(path);
+ return Arrays.asList(detRets);
+ }
+
+ @Nullable
+ @WorkerThread
+ public List detect(@NonNull Bitmap bitmap) {
+ VisionDetRet[] detRets = jniBitmapDetect(bitmap);
+ return Arrays.asList(detRets);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ release();
+ }
+
+ public void release() {
+ jniDeInit();
+ }
+
+ @Keep
+ private native static void jniNativeClassInit();
+
+ @Keep
+ private synchronized native int jniInit(String landmarkModelPath);
+
+ @Keep
+ private synchronized native int jniDeInit();
+
+ @Keep
+ private synchronized native VisionDetRet[] jniBitmapDetect(Bitmap bitmap);
+
+ @Keep
+ private synchronized native VisionDetRet[] jniDetect(String path);
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tzutalin/dlib/PedestrianDet.java b/app/src/main/java/com/tzutalin/dlib/PedestrianDet.java
new file mode 100644
index 00000000..fc801236
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlib/PedestrianDet.java
@@ -0,0 +1,95 @@
+/*
+* Copyright (C) 2015 TzuTaLin
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.tzutalin.dlib;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.support.annotation.Keep;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static android.R.attr.path;
+
+/**
+ * Created by Tzutalin on 2015/10/20.
+ */
+public class PedestrianDet {
+
+ // accessed by native methods
+ @SuppressWarnings("unused")
+ private long mNativeDetContext;
+ private static final String TAG = "dlib";
+
+ static {
+ try {
+ System.loadLibrary("android_dlib");
+ Log.d(TAG, "jniNativeClassInit success");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "library not found!");
+ }
+ }
+
+ public PedestrianDet() {
+ jniInit();
+ }
+
+ @Nullable
+ @WorkerThread
+ public List detect(@NonNull Bitmap bitmap) {
+ VisionDetRet[] detRets = jniBitmapDetect(bitmap);
+ return Arrays.asList(detRets);
+ }
+
+ @Nullable
+ @WorkerThread
+ public List detect(@NonNull final String path) {
+ VisionDetRet[] detRets = jniDetect(path);
+ return Arrays.asList(detRets);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ release();
+ }
+
+ public void release() {
+ jniDeInit();
+ }
+
+ @Keep
+ private native int jniInit();
+
+ @Keep
+ private synchronized native int jniDeInit();
+
+ @Keep
+ private synchronized native VisionDetRet[] jniDetect(String path);
+
+ @Keep
+ private synchronized native VisionDetRet[] jniBitmapDetect(Bitmap bitmap);
+
+}
diff --git a/app/src/main/java/com/tzutalin/dlib/VisionDetRet.java b/app/src/main/java/com/tzutalin/dlib/VisionDetRet.java
new file mode 100644
index 00000000..02ef03c6
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlib/VisionDetRet.java
@@ -0,0 +1,134 @@
+/*
+* Copyright (C) 2015 TzuTaLin
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.tzutalin.dlib;
+
+/**
+ * Created by Tzutalin on 2015/10/20.
+ */
+
+import android.graphics.Point;
+
+import java.util.ArrayList;
+
+/**
+ * A VisionDetRet contains all the information identifying the location and confidence value of the detected object in a bitmap.
+ */
+public final class VisionDetRet {
+ private String mLabel;
+ private float mConfidence;
+ private int mLeft;
+ private int mTop;
+ private int mRight;
+ private int mBottom;
+ private ArrayList mLandmarkPoints = new ArrayList<>();
+
+ VisionDetRet() {
+ }
+
+ /**
+ * @param label Label name
+ * @param confidence A confidence factor between 0 and 1. This indicates how certain what has been found is actually the label.
+ * @param l The X coordinate of the left side of the result
+ * @param t The Y coordinate of the top of the result
+ * @param r The X coordinate of the right side of the result
+ * @param b The Y coordinate of the bottom of the result
+ */
+ public VisionDetRet(String label, float confidence, int l, int t, int r, int b) {
+ mLabel = label;
+ mLeft = l;
+ mTop = t;
+ mRight = r;
+ mBottom = b;
+ mConfidence = confidence;
+ }
+
+ /**
+ * @return The X coordinate of the left side of the result
+ */
+ public int getLeft() {
+ return mLeft;
+ }
+
+ /**
+ * @return The Y coordinate of the top of the result
+ */
+ public int getTop() {
+ return mTop;
+ }
+
+ /**
+ * @return The X coordinate of the right side of the result
+ */
+ public int getRight() {
+ return mRight;
+ }
+
+ /**
+ * @return The Y coordinate of the bottom of the result
+ */
+ public int getBottom() {
+ return mBottom;
+ }
+
+ /**
+ * @return A confidence factor between 0 and 1. This indicates how certain what has been found is actually the label.
+ */
+ public float getConfidence() {
+ return mConfidence;
+ }
+
+ /**
+ * @return The label of the result
+ */
+ public String getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * Add landmark to the list. Usually, call by jni
+ * @param x Point x
+ * @param y Point y
+ * @return true if adding landmark successfully
+ */
+ public boolean addLandmark(int x, int y) {
+ return mLandmarkPoints.add(new Point(x, y));
+ }
+
+ /**
+ * Return the list of landmark points
+ * @return ArrayList of android.graphics.Point
+ */
+ public ArrayList getFaceLandmarks() {
+ return mLandmarkPoints;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Left:");
+ sb.append(mLabel);
+ sb.append(", Top:");
+ sb.append(mTop);
+ sb.append(", Right:");
+ sb.append(mRight);
+ sb.append(", Bottom:");
+ sb.append(mBottom);
+ sb.append(", Label:");
+ sb.append(mLabel);
+ return sb.toString();
+ }
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/AutoFitTextureView.java b/app/src/main/java/com/tzutalin/dlibtest/AutoFitTextureView.java
new file mode 100644
index 00000000..25456035
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/AutoFitTextureView.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Tzutalin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.TextureView;
+
+/**
+ * A {@link TextureView} that can be adjusted to a specified aspect ratio.
+ */
+public class AutoFitTextureView extends TextureView {
+ private int mRatioWidth = 0;
+ private int mRatioHeight = 0;
+
+ public AutoFitTextureView(final Context context) {
+ this(context, null);
+ }
+
+ public AutoFitTextureView(final Context context, final AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AutoFitTextureView(final Context context, final AttributeSet attrs, final int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
+ * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
+ * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
+ *
+ * @param width Relative horizontal size
+ * @param height Relative vertical size
+ */
+ public void setAspectRatio(final int width, final int height) {
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException("Size cannot be negative.");
+ }
+ mRatioWidth = width;
+ mRatioHeight = height;
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ final int height = MeasureSpec.getSize(heightMeasureSpec);
+ if (0 == mRatioWidth || 0 == mRatioHeight) {
+ setMeasuredDimension(width, height);
+ } else {
+ if (width < height * mRatioWidth / mRatioHeight) {
+ setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
+ } else {
+ setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/CameraActivity.java b/app/src/main/java/com/tzutalin/dlibtest/CameraActivity.java
new file mode 100644
index 00000000..92fc0a43
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/CameraActivity.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 Tzutalin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+/**
+ * Created by darrenl on 2016/5/20.
+ */
+public class CameraActivity extends Activity {
+
+ private static int OVERLAY_PERMISSION_REQ_CODE = 1;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ setContentView(R.layout.activity_camera);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this.getApplicationContext())) {
+ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
+ startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
+ }
+ }
+
+ if (null == savedInstanceState) {
+ getFragmentManager()
+ .beginTransaction()
+ .replace(R.id.container, CameraConnectionFragment.newInstance())
+ .commit();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(this.getApplicationContext())) {
+ Toast.makeText(CameraActivity.this, "CameraActivity\", \"SYSTEM_ALERT_WINDOW, permission not granted...", Toast.LENGTH_SHORT).show();
+ } else {
+ Intent intent = getIntent();
+ finish();
+ startActivity(intent);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tzutalin/dlibtest/CameraConnectionFragment.java b/app/src/main/java/com/tzutalin/dlibtest/CameraConnectionFragment.java
new file mode 100644
index 00000000..c5c57d9e
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/CameraConnectionFragment.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright 2016 Tzutalin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.v4.app.ActivityCompat;
+import android.util.Log;
+import android.util.Size;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.LayoutInflater;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import hugo.weaving.DebugLog;
+
+public class CameraConnectionFragment extends Fragment {
+
+ /**
+ * The camera preview size will be chosen to be the smallest frame by pixel size capable of
+ * containing a DESIRED_SIZE x DESIRED_SIZE square.
+ */
+ private static final int MINIMUM_PREVIEW_SIZE = 320;
+ private static final String TAG = "CameraConnectionFragment";
+
+ private TrasparentTitleView mScoreView;
+
+ /**
+ * Conversion from screen rotation to JPEG orientation.
+ */
+ private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
+ private static final String FRAGMENT_DIALOG = "dialog";
+
+ static {
+ ORIENTATIONS.append(Surface.ROTATION_0, 90);
+ ORIENTATIONS.append(Surface.ROTATION_90, 0);
+ ORIENTATIONS.append(Surface.ROTATION_180, 270);
+ ORIENTATIONS.append(Surface.ROTATION_270, 180);
+ }
+
+ /**
+ * {@link android.view.TextureView.SurfaceTextureListener} handles several lifecycle events on a
+ * {@link TextureView}.
+ */
+ private final TextureView.SurfaceTextureListener surfaceTextureListener =
+ new TextureView.SurfaceTextureListener() {
+ @Override
+ public void onSurfaceTextureAvailable(
+ final SurfaceTexture texture, final int width, final int height) {
+ openCamera(width, height);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(
+ final SurfaceTexture texture, final int width, final int height) {
+ configureTransform(width, height);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(final SurfaceTexture texture) {
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(final SurfaceTexture texture) {
+ }
+ };
+
+ /**
+ * ID of the current {@link CameraDevice}.
+ */
+ private String cameraId;
+
+ /**
+ * An {@link AutoFitTextureView} for camera preview.
+ */
+ private AutoFitTextureView textureView;
+
+ /**
+ * A {@link CameraCaptureSession } for camera preview.
+ */
+ private CameraCaptureSession captureSession;
+
+ /**
+ * A reference to the opened {@link CameraDevice}.
+ */
+ private CameraDevice cameraDevice;
+
+ /**
+ * The {@link android.util.Size} of camera preview.
+ */
+ private Size previewSize;
+
+ /**
+ * {@link android.hardware.camera2.CameraDevice.StateCallback}
+ * is called when {@link CameraDevice} changes its state.
+ */
+ private final CameraDevice.StateCallback stateCallback =
+ new CameraDevice.StateCallback() {
+ @Override
+ public void onOpened(final CameraDevice cd) {
+ // This method is called when the camera is opened. We start camera preview here.
+ cameraOpenCloseLock.release();
+ cameraDevice = cd;
+ createCameraPreviewSession();
+ }
+
+ @Override
+ public void onDisconnected(final CameraDevice cd) {
+ cameraOpenCloseLock.release();
+ cd.close();
+ cameraDevice = null;
+
+ if (mOnGetPreviewListener != null) {
+ mOnGetPreviewListener.deInitialize();
+ }
+ }
+
+ @Override
+ public void onError(final CameraDevice cd, final int error) {
+ cameraOpenCloseLock.release();
+ cd.close();
+ cameraDevice = null;
+ final Activity activity = getActivity();
+ if (null != activity) {
+ activity.finish();
+ }
+
+ if (mOnGetPreviewListener != null) {
+ mOnGetPreviewListener.deInitialize();
+ }
+ }
+ };
+
+ /**
+ * An additional thread for running tasks that shouldn't block the UI.
+ */
+ private HandlerThread backgroundThread;
+
+ /**
+ * A {@link Handler} for running tasks in the background.
+ */
+ private Handler backgroundHandler;
+
+ /**
+ * An additional thread for running inference so as not to block the camera.
+ */
+ private HandlerThread inferenceThread;
+
+ /**
+ * A {@link Handler} for running tasks in the background.
+ */
+ private Handler inferenceHandler;
+
+ /**
+ * An {@link ImageReader} that handles preview frame capture.
+ */
+ private ImageReader previewReader;
+
+ /**
+ * {@link android.hardware.camera2.CaptureRequest.Builder} for the camera preview
+ */
+ private CaptureRequest.Builder previewRequestBuilder;
+
+ /**
+ * {@link CaptureRequest} generated by {@link #previewRequestBuilder}
+ */
+ private CaptureRequest previewRequest;
+
+ /**
+ * A {@link Semaphore} to prevent the app from exiting before closing the camera.
+ */
+ private final Semaphore cameraOpenCloseLock = new Semaphore(1);
+
+ /**
+ * Shows a {@link Toast} on the UI thread.
+ *
+ * @param text The message to show
+ */
+ private void showToast(final String text) {
+ final Activity activity = getActivity();
+ if (activity != null) {
+ activity.runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+
+ /**
+ * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
+ * width and height are at least as large as the respective requested values, and whose aspect
+ * ratio matches with the specified value.
+ *
+ * @param choices The list of sizes that the camera supports for the intended output class
+ * @param width The minimum desired width
+ * @param height The minimum desired height
+ * @param aspectRatio The aspect ratio
+ * @return The optimal {@code Size}, or an arbitrary one if none were big enough
+ */
+ @SuppressLint("LongLogTag")
+ @DebugLog
+ private static Size chooseOptimalSize(
+ final Size[] choices, final int width, final int height, final Size aspectRatio) {
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ final List bigEnough = new ArrayList();
+ for (final Size option : choices) {
+ if (option.getHeight() >= MINIMUM_PREVIEW_SIZE && option.getWidth() >= MINIMUM_PREVIEW_SIZE) {
+ Log.i(TAG, "Adding size: " + option.getWidth() + "x" + option.getHeight());
+ bigEnough.add(option);
+ } else {
+ Log.i(TAG, "Not adding size: " + option.getWidth() + "x" + option.getHeight());
+ }
+ }
+
+ // Pick the smallest of those, assuming we found any
+ if (bigEnough.size() > 0) {
+ final Size chosenSize = Collections.min(bigEnough, new CompareSizesByArea());
+ Log.i(TAG, "Chosen size: " + chosenSize.getWidth() + "x" + chosenSize.getHeight());
+ return chosenSize;
+ } else {
+ Log.e(TAG, "Couldn't find any suitable preview size");
+ return choices[0];
+ }
+ }
+
+ public static CameraConnectionFragment newInstance() {
+ return new CameraConnectionFragment();
+ }
+
+ @Override
+ public View onCreateView(
+ final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.camera_connection_fragment, container, false);
+ }
+
+ @Override
+ public void onViewCreated(final View view, final Bundle savedInstanceState) {
+ textureView = (AutoFitTextureView) view.findViewById(R.id.texture);
+ mScoreView = (TrasparentTitleView) view.findViewById(R.id.results);
+ }
+
+ @Override
+ public void onActivityCreated(final Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startBackgroundThread();
+
+ // When the screen is turned off and turned back on, the SurfaceTexture is already
+ // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
+ // a camera and start preview from here (otherwise, we wait until the surface is ready in
+ // the SurfaceTextureListener).
+ if (textureView.isAvailable()) {
+ openCamera(textureView.getWidth(), textureView.getHeight());
+ } else {
+ textureView.setSurfaceTextureListener(surfaceTextureListener);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ closeCamera();
+ stopBackgroundThread();
+ super.onPause();
+ }
+
+ /**
+ * Sets up member variables related to camera.
+ *
+ * @param width The width of available size for camera preview
+ * @param height The height of available size for camera preview
+ */
+ @DebugLog
+ @SuppressLint("LongLogTag")
+ private void setUpCameraOutputs(final int width, final int height) {
+ final Activity activity = getActivity();
+ final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ SparseArray cameraFaceTypeMap = new SparseArray<>();
+ // Check the facing types of camera devices
+ for (final String cameraId : manager.getCameraIdList()) {
+ final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
+ final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+ if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
+ if (cameraFaceTypeMap.get(CameraCharacteristics.LENS_FACING_FRONT) != null) {
+ cameraFaceTypeMap.append(CameraCharacteristics.LENS_FACING_FRONT, cameraFaceTypeMap.get(CameraCharacteristics.LENS_FACING_FRONT) + 1);
+ } else {
+ cameraFaceTypeMap.append(CameraCharacteristics.LENS_FACING_FRONT, 1);
+ }
+ }
+
+ if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
+ if (cameraFaceTypeMap.get(CameraCharacteristics.LENS_FACING_FRONT) != null) {
+ cameraFaceTypeMap.append(CameraCharacteristics.LENS_FACING_BACK, cameraFaceTypeMap.get(CameraCharacteristics.LENS_FACING_BACK) + 1);
+ } else {
+ cameraFaceTypeMap.append(CameraCharacteristics.LENS_FACING_BACK, 1);
+ }
+ }
+ }
+
+ Integer num_facing_back_camera = cameraFaceTypeMap.get(CameraCharacteristics.LENS_FACING_BACK);
+ for (final String cameraId : manager.getCameraIdList()) {
+ final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
+ final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+ // If facing back camera or facing external camera exist, we won't use facing front camera
+ if (num_facing_back_camera != null && num_facing_back_camera > 0) {
+ // We don't use a front facing camera in this sample if there are other camera device facing types
+ if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
+ continue;
+ }
+ }
+
+ final StreamConfigurationMap map =
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ if (map == null) {
+ continue;
+ }
+
+ // For still image captures, we use the largest available size.
+ final Size largest =
+ Collections.max(
+ Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)),
+ new CompareSizesByArea());
+
+ // Danger, W.R.! Attempting to use too large a preview size could exceed the camera
+ // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
+ // garbage capture data.
+ previewSize =
+ chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, largest);
+
+ // We fit the aspect ratio of TextureView to the size of preview we picked.
+ final int orientation = getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ textureView.setAspectRatio(previewSize.getWidth(), previewSize.getHeight());
+ } else {
+ textureView.setAspectRatio(previewSize.getHeight(), previewSize.getWidth());
+ }
+
+ CameraConnectionFragment.this.cameraId = cameraId;
+ return;
+ }
+ } catch (final CameraAccessException e) {
+ Log.e(TAG, "Exception!", e);
+ } catch (final NullPointerException e) {
+ // Currently an NPE is thrown when the Camera2API is used but not supported on the
+ // device this code runs.
+ ErrorDialog.newInstance(getString(R.string.camera_error))
+ .show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ }
+ }
+
+ /**
+ * Opens the camera specified by {@link CameraConnectionFragment#cameraId}.
+ */
+ @SuppressLint("LongLogTag")
+ @DebugLog
+ private void openCamera(final int width, final int height) {
+ setUpCameraOutputs(width, height);
+ configureTransform(width, height);
+ final Activity activity = getActivity();
+ final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+ throw new RuntimeException("Time out waiting to lock camera opening.");
+ }
+ if (ActivityCompat.checkSelfPermission(this.getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ Log.w(TAG, "checkSelfPermission CAMERA");
+ }
+ manager.openCamera(cameraId, stateCallback, backgroundHandler);
+ Log.d(TAG, "open Camera");
+ } catch (final CameraAccessException e) {
+ Log.e(TAG, "Exception!", e);
+ } catch (final InterruptedException e) {
+ throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
+ }
+ }
+
+ /**
+ * Closes the current {@link CameraDevice}.
+ */
+ @DebugLog
+ private void closeCamera() {
+ try {
+ cameraOpenCloseLock.acquire();
+ if (null != captureSession) {
+ captureSession.close();
+ captureSession = null;
+ }
+ if (null != cameraDevice) {
+ cameraDevice.close();
+ cameraDevice = null;
+ }
+ if (null != previewReader) {
+ previewReader.close();
+ previewReader = null;
+ }
+ if (null != mOnGetPreviewListener) {
+ mOnGetPreviewListener.deInitialize();
+ }
+ } catch (final InterruptedException e) {
+ throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
+ } finally {
+ cameraOpenCloseLock.release();
+ }
+ }
+
+ /**
+ * Starts a background thread and its {@link Handler}.
+ */
+ @DebugLog
+ private void startBackgroundThread() {
+ backgroundThread = new HandlerThread("ImageListener");
+ backgroundThread.start();
+ backgroundHandler = new Handler(backgroundThread.getLooper());
+
+ inferenceThread = new HandlerThread("InferenceThread");
+ inferenceThread.start();
+ inferenceHandler = new Handler(inferenceThread.getLooper());
+ }
+
+ /**
+ * Stops the background thread and its {@link Handler}.
+ */
+ @SuppressLint("LongLogTag")
+ @DebugLog
+ private void stopBackgroundThread() {
+ backgroundThread.quitSafely();
+ inferenceThread.quitSafely();
+ try {
+ backgroundThread.join();
+ backgroundThread = null;
+ backgroundHandler = null;
+
+ inferenceThread.join();
+ inferenceThread = null;
+ inferenceThread = null;
+ } catch (final InterruptedException e) {
+ Log.e(TAG, "error" ,e );
+ }
+ }
+
+ private final OnGetImageListener mOnGetPreviewListener = new OnGetImageListener();
+
+ private final CameraCaptureSession.CaptureCallback captureCallback =
+ new CameraCaptureSession.CaptureCallback() {
+ @Override
+ public void onCaptureProgressed(
+ final CameraCaptureSession session,
+ final CaptureRequest request,
+ final CaptureResult partialResult) {}
+
+ @Override
+ public void onCaptureCompleted(
+ final CameraCaptureSession session,
+ final CaptureRequest request,
+ final TotalCaptureResult result) {}
+ };
+
+ /**
+ * Creates a new {@link CameraCaptureSession} for camera preview.
+ */
+ @SuppressLint("LongLogTag")
+ @DebugLog
+ private void createCameraPreviewSession() {
+ try {
+ final SurfaceTexture texture = textureView.getSurfaceTexture();
+ assert texture != null;
+
+ // We configure the size of default buffer to be the size of camera preview we want.
+ texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
+
+ // This is the output Surface we need to start preview.
+ final Surface surface = new Surface(texture);
+
+ // We set up a CaptureRequest.Builder with the output Surface.
+ previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ previewRequestBuilder.addTarget(surface);
+
+ Log.i(TAG, "Opening camera preview: " + previewSize.getWidth() + "x" + previewSize.getHeight());
+
+ // Create the reader for the preview frames.
+ previewReader =
+ ImageReader.newInstance(
+ previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
+
+ previewReader.setOnImageAvailableListener(mOnGetPreviewListener, backgroundHandler);
+ previewRequestBuilder.addTarget(previewReader.getSurface());
+
+ // Here, we create a CameraCaptureSession for camera preview.
+ cameraDevice.createCaptureSession(
+ Arrays.asList(surface, previewReader.getSurface()),
+ new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(final CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == cameraDevice) {
+ return;
+ }
+
+ // When the session is ready, we start displaying the preview.
+ captureSession = cameraCaptureSession;
+ try {
+ // Auto focus should be continuous for camera preview.
+ previewRequestBuilder.set(
+ CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ // Flash is automatically enabled when necessary.
+ previewRequestBuilder.set(
+ CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
+
+ // Finally, we start displaying the camera preview.
+ previewRequest = previewRequestBuilder.build();
+ captureSession.setRepeatingRequest(
+ previewRequest, captureCallback, backgroundHandler);
+ } catch (final CameraAccessException e) {
+ Log.e(TAG, "Exception!", e);
+ }
+ }
+
+ @Override
+ public void onConfigureFailed(final CameraCaptureSession cameraCaptureSession) {
+ showToast("Failed");
+ }
+ },
+ null);
+ } catch (final CameraAccessException e) {
+ Log.e(TAG, "Exception!", e);
+ }
+
+ Log.i(TAG, "Getting assets.");
+ mOnGetPreviewListener.initialize(getActivity().getApplicationContext(), getActivity().getAssets(), mScoreView, inferenceHandler);
+ }
+
+ /**
+ * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
+ * This method should be called after the camera preview size is determined in
+ * setUpCameraOutputs and also the size of `mTextureView` is fixed.
+ *
+ * @param viewWidth The width of `mTextureView`
+ * @param viewHeight The height of `mTextureView`
+ */
+ @DebugLog
+ private void configureTransform(final int viewWidth, final int viewHeight) {
+ final Activity activity = getActivity();
+ if (null == textureView || null == previewSize || null == activity) {
+ return;
+ }
+ final int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
+ final Matrix matrix = new Matrix();
+ final RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ final RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
+ final float centerX = viewRect.centerX();
+ final float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ final float scale =
+ Math.max(
+ (float) viewHeight / previewSize.getHeight(),
+ (float) viewWidth / previewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate(90 * (rotation - 2), centerX, centerY);
+ } else if (Surface.ROTATION_180 == rotation) {
+ matrix.postRotate(180, centerX, centerY);
+ }
+ textureView.setTransform(matrix);
+ }
+
+ /**
+ * Compares two {@code Size}s based on their areas.
+ */
+ static class CompareSizesByArea implements Comparator {
+ @Override
+ public int compare(final Size lhs, final Size rhs) {
+ // We cast here to ensure the multiplications won't overflow
+ return Long.signum(
+ (long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
+ }
+ }
+
+ /**
+ * Shows an error message dialog.
+ */
+ public static class ErrorDialog extends DialogFragment {
+ private static final String ARG_MESSAGE = "message";
+
+ public static ErrorDialog newInstance(final String message) {
+ final ErrorDialog dialog = new ErrorDialog();
+ final Bundle args = new Bundle();
+ args.putString(ARG_MESSAGE, message);
+ dialog.setArguments(args);
+ return dialog;
+ }
+
+ @Override
+ public Dialog onCreateDialog(final Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+ return new AlertDialog.Builder(activity)
+ .setMessage(getArguments().getString(ARG_MESSAGE))
+ .setPositiveButton(
+ android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialogInterface, final int i) {
+ activity.finish();
+ }
+ })
+ .create();
+ }
+ }
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/FileUtils.java b/app/src/main/java/com/tzutalin/dlibtest/FileUtils.java
new file mode 100644
index 00000000..316369c7
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/FileUtils.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Tzutalin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.RawRes;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Created by darrenl on 2016/3/30.
+ */
+public class FileUtils {
+ @NonNull
+ public static final void copyFileFromRawToOthers(@NonNull final Context context, @RawRes int id, @NonNull final String targetPath) {
+ InputStream in = context.getResources().openRawResource(id);
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(targetPath);
+ byte[] buff = new byte[1024];
+ int read = 0;
+ while ((read = in.read(buff)) > 0) {
+ out.write(buff, 0, read);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/FloatingCameraWindow.java b/app/src/main/java/com/tzutalin/dlibtest/FloatingCameraWindow.java
new file mode 100644
index 00000000..8dd1a516
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/FloatingCameraWindow.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 Tzuta Lin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.UiThread;
+import android.util.Log;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by Tzutalin on 2016/5/25
+ */
+public class FloatingCameraWindow {
+ private static final String TAG = "FloatingCameraWindow";
+ private Context mContext;
+ private WindowManager.LayoutParams mWindowParam;
+ private WindowManager mWindowManager;
+ private FloatCamView mRootView;
+ private Handler mUIHandler;
+
+ private int mWindowWidth;
+ private int mWindowHeight;
+
+ private int mScreenMaxWidth;
+ private int mScreenMaxHeight;
+
+ private float mScaleWidthRatio = 1.0f;
+ private float mScaleHeightRatio = 1.0f;
+
+ private static final boolean DEBUG = true;
+
+ public FloatingCameraWindow(Context context) {
+ mContext = context;
+ mUIHandler = new Handler(Looper.getMainLooper());
+
+ // Get screen max size
+ Point size = new Point();
+ Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ display.getSize(size);
+ mScreenMaxWidth = size.x;
+ mScreenMaxHeight = size.y;
+ } else {
+ mScreenMaxWidth = display.getWidth();
+ mScreenMaxHeight = display.getHeight();
+ }
+ // Default window size
+ mWindowWidth = mScreenMaxWidth / 2;
+ mWindowHeight = mScreenMaxHeight / 2;
+
+ mWindowWidth = mWindowWidth > 0 && mWindowWidth < mScreenMaxWidth ? mWindowWidth : mScreenMaxWidth;
+ mWindowHeight = mWindowHeight > 0 && mWindowHeight < mScreenMaxHeight ? mWindowHeight : mScreenMaxHeight;
+ }
+
+ public FloatingCameraWindow(Context context, int windowWidth, int windowHeight) {
+ this(context);
+
+ if (windowWidth < 0 || windowWidth > mScreenMaxWidth || windowHeight < 0 || windowHeight > mScreenMaxHeight) {
+ throw new IllegalArgumentException("Window size is illegal");
+ }
+
+ mScaleWidthRatio = (float) windowWidth / mWindowHeight;
+ mScaleHeightRatio = (float) windowHeight / mWindowHeight;
+
+ if (DEBUG) {
+ Log.d(TAG, "mScaleWidthRatio: " + mScaleWidthRatio);
+ Log.d(TAG, "mScaleHeightRatio: " + mScaleHeightRatio);
+ }
+
+ mWindowWidth = windowWidth;
+ mWindowHeight = windowHeight;
+ }
+
+ private void init() {
+ mUIHandler.postAtFrontOfQueue(new Runnable() {
+ @Override
+ public void run() {
+ if (mWindowManager == null || mRootView == null) {
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ mRootView = new FloatCamView(FloatingCameraWindow.this);
+ mWindowManager.addView(mRootView, initWindowParameter());
+ }
+ }
+ });
+ }
+
+ public void release() {
+ mUIHandler.postAtFrontOfQueue(new Runnable() {
+ @Override
+ public void run() {
+ if (mWindowManager != null) {
+ mWindowManager.removeViewImmediate(mRootView);
+ mRootView = null;
+ }
+ mUIHandler.removeCallbacksAndMessages(null);
+ }
+ });
+ }
+
+ private WindowManager.LayoutParams initWindowParameter() {
+ mWindowParam = new WindowManager.LayoutParams();
+
+ mWindowParam.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+ mWindowParam.format = 1;
+ mWindowParam.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ mWindowParam.flags = mWindowParam.flags | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+ mWindowParam.flags = mWindowParam.flags | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+
+ mWindowParam.alpha = 1.0f;
+
+ mWindowParam.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+ mWindowParam.x = 0;
+ mWindowParam.y = 0;
+ mWindowParam.width = mWindowWidth;
+ mWindowParam.height = mWindowHeight;
+ return mWindowParam;
+ }
+
+ public void setRGBBitmap(final Bitmap rgb) {
+ checkInit();
+ mUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mRootView.setRGBImageView(rgb);
+ }
+ });
+ }
+
+ public void setFPS(final float fps) {
+ checkInit();
+ mUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ checkInit();
+ mRootView.setFPS(fps);
+ }
+ });
+ }
+
+ public void setMoreInformation(final String info) {
+ checkInit();
+ mUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ checkInit();
+ mRootView.setMoreInformation(info);
+ }
+ });
+ }
+
+ private void checkInit() {
+ if (mRootView == null) {
+ init();
+ }
+ }
+
+ @UiThread
+ private final class FloatCamView extends FrameLayout {
+ private WeakReference mWeakRef;
+ private static final int MOVE_THRESHOLD = 10;
+ private int mLastX;
+ private int mLastY;
+ private int mFirstX;
+ private int mFirstY;
+ private LayoutInflater mLayoutInflater;
+ private ImageView mColorView;
+ private TextView mFPSText;
+ private TextView mInfoText;
+ private boolean mIsMoving = false;
+
+ public FloatCamView(FloatingCameraWindow window) {
+ super(window.mContext);
+ mWeakRef = new WeakReference(window);
+ // mLayoutInflater = LayoutInflater.from(context);
+ mLayoutInflater = (LayoutInflater) window.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ FrameLayout body = (FrameLayout) this;
+ body.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return false;
+ }
+ });
+
+ View floatView = mLayoutInflater.inflate(R.layout.cam_window_view, body, true);
+ mColorView = (ImageView) findViewById(R.id.imageView_c);
+ mFPSText = (TextView) findViewById(R.id.fps_textview);
+ mInfoText = (TextView) findViewById(R.id.info_textview);
+ mFPSText.setVisibility(View.GONE);
+ mInfoText.setVisibility(View.GONE);
+
+ int colorMaxWidth = (int) (mWindowWidth* window.mScaleWidthRatio);
+ int colorMaxHeight = (int) (mWindowHeight * window.mScaleHeightRatio);
+
+ mColorView.getLayoutParams().width = colorMaxWidth;
+ mColorView.getLayoutParams().height = colorMaxHeight;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mLastX = (int) event.getRawX();
+ mLastY = (int) event.getRawY();
+ mFirstX = mLastX;
+ mFirstY = mLastY;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ int deltaX = (int) event.getRawX() - mLastX;
+ int deltaY = (int) event.getRawY() - mLastY;
+ mLastX = (int) event.getRawX();
+ mLastY = (int) event.getRawY();
+ int totalDeltaX = mLastX - mFirstX;
+ int totalDeltaY = mLastY - mFirstY;
+
+ if (mIsMoving
+ || Math.abs(totalDeltaX) >= MOVE_THRESHOLD
+ || Math.abs(totalDeltaY) >= MOVE_THRESHOLD) {
+ mIsMoving = true;
+ WindowManager windowMgr = mWeakRef.get().mWindowManager;
+ WindowManager.LayoutParams parm = mWeakRef.get().mWindowParam;
+ if (event.getPointerCount() == 1 && windowMgr != null) {
+ parm.x -= deltaX;
+ parm.y -= deltaY;
+ windowMgr.updateViewLayout(this, parm);
+ }
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ mIsMoving = false;
+ break;
+ }
+ return true;
+ }
+
+ public void setRGBImageView(Bitmap rgb) {
+ if (rgb != null && !rgb.isRecycled()) {
+ mColorView.setImageBitmap(rgb);
+ }
+ }
+
+ public void setFPS(float fps) {
+ if (mFPSText != null) {
+ if (mFPSText.getVisibility() == View.GONE) {
+ mFPSText.setVisibility(View.VISIBLE);
+ }
+ mFPSText.setText(String.format("FPS: %.2f", fps));
+ }
+ }
+
+ public void setMoreInformation(String info) {
+ if (mInfoText != null) {
+ if (mInfoText.getVisibility() == View.GONE) {
+ mInfoText.setVisibility(View.VISIBLE);
+ }
+ mInfoText.setText(info);
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/ImageUtils.java b/app/src/main/java/com/tzutalin/dlibtest/ImageUtils.java
new file mode 100644
index 00000000..3311842d
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/ImageUtils.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2016 Tzutalin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.graphics.Bitmap;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+/**
+ * Utility class for manipulating images.
+ **/
+public class ImageUtils {
+ private static final String TAG = ImageUtils.class.getSimpleName();
+
+ /**
+ * Utility method to compute the allocated size in bytes of a YUV420SP image
+ * of the given dimensions.
+ */
+ public static int getYUVByteSize(final int width, final int height) {
+ // The luminance plane requires 1 byte per pixel.
+ final int ySize = width * height;
+
+ // The UV plane works on 2x2 blocks, so dimensions with odd size must be rounded up.
+ // Each 2x2 block takes 2 bytes to encode, one each for U and V.
+ final int uvSize = ((width + 1) / 2) * ((height + 1) / 2) * 2;
+
+ return ySize + uvSize;
+ }
+
+ /**
+ * Saves a Bitmap object to disk for analysis.
+ *
+ * @param bitmap The bitmap to save.
+ */
+ public static void saveBitmap(final Bitmap bitmap) {
+ final String root =
+ Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dlib";
+ Log.i(TAG, String.format("Saving %dx%d bitmap to %s.", bitmap.getWidth(), bitmap.getHeight(), root));
+ final File myDir = new File(root);
+
+ if (!myDir.mkdirs()) {
+ Log.i(TAG, "Make dir failed");
+ }
+
+ final String fname = "preview.png";
+ final File file = new File(myDir, fname);
+ if (file.exists()) {
+ file.delete();
+ }
+ try {
+ final FileOutputStream out = new FileOutputStream(file);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 99, out);
+ out.flush();
+ out.close();
+ } catch (final Exception e) {
+ Log.e(TAG, "Exception!", e);
+ }
+ }
+
+ /**
+ * Converts YUV420 semi-planar data to ARGB 8888 data using the supplied width
+ * and height. The input and output must already be allocated and non-null.
+ * For efficiency, no error checking is performed.
+ *
+ * @param input The array of YUV 4:2:0 input data.
+ * @param output A pre-allocated array for the ARGB 8:8:8:8 output data.
+ * @param width The width of the input image.
+ * @param height The height of the input image.
+ * @param halfSize If true, downsample to 50% in each dimension, otherwise not.
+ */
+ public static native void convertYUV420SPToARGB8888(
+ byte[] input, int[] output, int width, int height, boolean halfSize);
+
+ /**
+ * Converts YUV420 semi-planar data to ARGB 8888 data using the supplied width
+ * and height. The input and output must already be allocated and non-null.
+ * For efficiency, no error checking is performed.
+ *
+ * @param y
+ * @param u
+ * @param v
+ * @param uvPixelStride
+ * @param width The width of the input image.
+ * @param height The height of the input image.
+ * @param halfSize If true, downsample to 50% in each dimension, otherwise not.
+ * @param output A pre-allocated array for the ARGB 8:8:8:8 output data.
+ */
+ public static native void convertYUV420ToARGB8888(
+ byte[] y,
+ byte[] u,
+ byte[] v,
+ int[] output,
+ int width,
+ int height,
+ int yRowStride,
+ int uvRowStride,
+ int uvPixelStride,
+ boolean halfSize);
+
+ /**
+ * Converts YUV420 semi-planar data to RGB 565 data using the supplied width
+ * and height. The input and output must already be allocated and non-null.
+ * For efficiency, no error checking is performed.
+ *
+ * @param input The array of YUV 4:2:0 input data.
+ * @param output A pre-allocated array for the RGB 5:6:5 output data.
+ * @param width The width of the input image.
+ * @param height The height of the input image.
+ */
+ public static native void convertYUV420SPToRGB565(
+ byte[] input, byte[] output, int width, int height);
+
+ /**
+ * Converts 32-bit ARGB8888 image data to YUV420SP data. This is useful, for
+ * instance, in creating data to feed the classes that rely on raw camera
+ * preview frames.
+ *
+ * @param input An array of input pixels in ARGB8888 format.
+ * @param output A pre-allocated array for the YUV420SP output data.
+ * @param width The width of the input image.
+ * @param height The height of the input image.
+ */
+ public static native void convertARGB8888ToYUV420SP(
+ int[] input, byte[] output, int width, int height);
+
+ /**
+ * Converts 16-bit RGB565 image data to YUV420SP data. This is useful, for
+ * instance, in creating data to feed the classes that rely on raw camera
+ * preview frames.
+ *
+ * @param input An array of input pixels in RGB565 format.
+ * @param output A pre-allocated array for the YUV420SP output data.
+ * @param width The width of the input image.
+ * @param height The height of the input image.
+ */
+ public static native void convertRGB565ToYUV420SP(
+ byte[] input, byte[] output, int width, int height);
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/MainActivity.java b/app/src/main/java/com/tzutalin/dlibtest/MainActivity.java
new file mode 100644
index 00000000..16acfcfa
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/MainActivity.java
@@ -0,0 +1,366 @@
+/*
+* Copyright (C) 2015 TzuTaLin
+*/
+
+package com.tzutalin.dlibtest;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.support.annotation.NonNull;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.dexafree.materialList.card.Card;
+import com.dexafree.materialList.card.provider.BigImageCardProvider;
+import com.dexafree.materialList.view.MaterialListView;
+import com.tzutalin.dlib.Constants;
+import com.tzutalin.dlib.FaceDet;
+import com.tzutalin.dlib.PedestrianDet;
+import com.tzutalin.dlib.VisionDetRet;
+
+import org.androidannotations.annotations.AfterViews;
+import org.androidannotations.annotations.Background;
+import org.androidannotations.annotations.Click;
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.UiThread;
+import org.androidannotations.annotations.ViewById;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import hugo.weaving.DebugLog;
+
+@EActivity(R.layout.activity_main)
+public class MainActivity extends AppCompatActivity {
+ private static final int RESULT_LOAD_IMG = 1;
+ private static final int REQUEST_CODE_PERMISSION = 2;
+
+ private static final String TAG = "MainActivity";
+
+ // Storage Permissions
+ private static String[] PERMISSIONS_REQ = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.CAMERA
+ };
+
+ protected String mTestImgPath;
+ // UI
+ @ViewById(R.id.material_listview)
+ protected MaterialListView mListView;
+ @ViewById(R.id.fab)
+ protected FloatingActionButton mFabActionBt;
+ @ViewById(R.id.fab_cam)
+ protected FloatingActionButton mFabCamActionBt;
+ @ViewById(R.id.toolbar)
+ protected Toolbar mToolbar;
+
+ FaceDet mFaceDet;
+ PedestrianDet mPersonDet;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mListView = (MaterialListView) findViewById(R.id.material_listview);
+ setSupportActionBar(mToolbar);
+ // Just use hugo to print log
+ isExternalStorageWritable();
+ isExternalStorageReadable();
+
+ // For API 23+ you need to request the read/write permissions even if they are already in your manifest.
+ int currentapiVersion = android.os.Build.VERSION.SDK_INT;
+
+ if (currentapiVersion >= Build.VERSION_CODES.M) {
+ verifyPermissions(this);
+ }
+ }
+
+ @AfterViews
+ protected void setupUI() {
+ mToolbar.setTitle(getString(R.string.app_name));
+ Toast.makeText(MainActivity.this, getString(R.string.description_info), Toast.LENGTH_LONG).show();
+ }
+
+ @Click({R.id.fab})
+ protected void launchGallery() {
+ Toast.makeText(MainActivity.this, "Pick one image", Toast.LENGTH_SHORT).show();
+ Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+ startActivityForResult(galleryIntent, RESULT_LOAD_IMG);
+ }
+
+ @Click({R.id.fab_cam})
+ protected void launchCameraPreview() {
+ startActivity(new Intent(this, CameraActivity.class));
+ }
+
+ /**
+ * Checks if the app has permission to write to device storage or open camera
+ * If the app does not has permission then the user will be prompted to grant permissions
+ *
+ * @param activity
+ */
+ @DebugLog
+ private static boolean verifyPermissions(Activity activity) {
+ // Check if we have write permission
+ int write_permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ int read_persmission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ int camera_permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
+
+ if (write_permission != PackageManager.PERMISSION_GRANTED ||
+ read_persmission != PackageManager.PERMISSION_GRANTED ||
+ camera_permission != PackageManager.PERMISSION_GRANTED) {
+ // We don't have permission so prompt the user
+ ActivityCompat.requestPermissions(
+ activity,
+ PERMISSIONS_REQ,
+ REQUEST_CODE_PERMISSION
+ );
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /* Checks if external storage is available for read and write */
+ @DebugLog
+ private boolean isExternalStorageWritable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ return true;
+ }
+ return false;
+ }
+
+ /* Checks if external storage is available to at least read */
+ @DebugLog
+ private boolean isExternalStorageReadable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state) ||
+ Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ return true;
+ }
+ return false;
+ }
+
+ @DebugLog
+ protected void demoStaticImage() {
+ if (mTestImgPath != null) {
+ Log.d(TAG, "demoStaticImage() launch a task to det");
+ runDetectAsync(mTestImgPath);
+ } else {
+ Log.d(TAG, "demoStaticImage() mTestImgPath is null, go to gallery");
+ Toast.makeText(MainActivity.this, "Pick an image to run algorithms", Toast.LENGTH_SHORT).show();
+ // Create intent to Open Image applications like Gallery, Google Photos
+ Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+ startActivityForResult(galleryIntent, RESULT_LOAD_IMG);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ if (requestCode == REQUEST_CODE_PERMISSION) {
+ Toast.makeText(MainActivity.this, "Demo using static images", Toast.LENGTH_SHORT).show();
+ demoStaticImage();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ try {
+ // When an Image is picked
+ if (requestCode == RESULT_LOAD_IMG && resultCode == RESULT_OK && null != data) {
+ // Get the Image from data
+ Uri selectedImage = data.getData();
+ String[] filePathColumn = {MediaStore.Images.Media.DATA};
+ // Get the cursor
+ Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
+ cursor.moveToFirst();
+ int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
+ mTestImgPath = cursor.getString(columnIndex);
+ cursor.close();
+ if (mTestImgPath != null) {
+ runDetectAsync(mTestImgPath);
+ Toast.makeText(this, "Img Path:" + mTestImgPath, Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ Toast.makeText(this, "You haven't picked Image", Toast.LENGTH_LONG).show();
+ }
+ } catch (Exception e) {
+ Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG).show();
+ }
+ }
+
+ // ==========================================================
+ // Tasks inner class
+ // ==========================================================
+ private ProgressDialog mDialog;
+
+ @Background
+ @NonNull
+ protected void runDetectAsync(@NonNull String imgPath) {
+ showDiaglog();
+
+ final String targetPath = Constants.getFaceShapeModelPath();
+ if (!new File(targetPath).exists()) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(MainActivity.this, "Copy landmark model to " + targetPath, Toast.LENGTH_SHORT).show();
+ }
+ });
+ FileUtils.copyFileFromRawToOthers(getApplicationContext(), R.raw.shape_predictor_68_face_landmarks, targetPath);
+ }
+ // Init
+ if (mPersonDet == null) {
+ mPersonDet = new PedestrianDet();
+ }
+ if (mFaceDet == null) {
+ mFaceDet = new FaceDet(Constants.getFaceShapeModelPath());
+ }
+
+ Log.d(TAG, "Image path: " + imgPath);
+ List cardrets = new ArrayList<>();
+ List faceList = mFaceDet.detect(imgPath);
+ if (faceList.size() > 0) {
+ Card card = new Card.Builder(MainActivity.this)
+ .withProvider(BigImageCardProvider.class)
+ .setDrawable(drawRect(imgPath, faceList, Color.GREEN))
+ .setTitle("Face det")
+ .endConfig()
+ .build();
+ cardrets.add(card);
+ } else {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(getApplicationContext(), "No face", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ List personList = mPersonDet.detect(imgPath);
+ if (personList.size() > 0) {
+ Card card = new Card.Builder(MainActivity.this)
+ .withProvider(BigImageCardProvider.class)
+ .setDrawable(drawRect(imgPath, personList, Color.BLUE))
+ .setTitle("Person det")
+ .endConfig()
+ .build();
+ cardrets.add(card);
+ } else {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(getApplicationContext(), "No person", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ addCardListView(cardrets);
+ dismissDialog();
+ }
+
+ @UiThread
+ protected void addCardListView(List cardrets) {
+ for (Card each : cardrets) {
+ mListView.add(each);
+ }
+ }
+
+ @UiThread
+ protected void showDiaglog() {
+ mDialog = ProgressDialog.show(MainActivity.this, "Wait", "Person and face detection", true);
+ }
+
+ @UiThread
+ protected void dismissDialog() {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
+ }
+
+ @DebugLog
+ protected BitmapDrawable drawRect(String path, List results, int color) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inSampleSize = 1;
+ Bitmap bm = BitmapFactory.decodeFile(path, options);
+ android.graphics.Bitmap.Config bitmapConfig = bm.getConfig();
+ // set default bitmap config if none
+ if (bitmapConfig == null) {
+ bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
+ }
+ // resource bitmaps are imutable,
+ // so we need to convert it to mutable one
+ bm = bm.copy(bitmapConfig, true);
+ int width = bm.getWidth();
+ int height = bm.getHeight();
+ // By ratio scale
+ float aspectRatio = bm.getWidth() / (float) bm.getHeight();
+
+ final int MAX_SIZE = 512;
+ int newWidth = MAX_SIZE;
+ int newHeight = MAX_SIZE;
+ float resizeRatio = 1;
+ newHeight = Math.round(newWidth / aspectRatio);
+ if (bm.getWidth() > MAX_SIZE && bm.getHeight() > MAX_SIZE) {
+ Log.d(TAG, "Resize Bitmap");
+ bm = getResizedBitmap(bm, newWidth, newHeight);
+ resizeRatio = (float) bm.getWidth() / (float) width;
+ Log.d(TAG, "resizeRatio " + resizeRatio);
+ }
+
+ // Create canvas to draw
+ Canvas canvas = new Canvas(bm);
+ Paint paint = new Paint();
+ paint.setColor(color);
+ paint.setStrokeWidth(2);
+ paint.setStyle(Paint.Style.STROKE);
+ // Loop result list
+ for (VisionDetRet ret : results) {
+ Rect bounds = new Rect();
+ bounds.left = (int) (ret.getLeft() * resizeRatio);
+ bounds.top = (int) (ret.getTop() * resizeRatio);
+ bounds.right = (int) (ret.getRight() * resizeRatio);
+ bounds.bottom = (int) (ret.getBottom() * resizeRatio);
+ canvas.drawRect(bounds, paint);
+ // Get landmark
+ ArrayList landmarks = ret.getFaceLandmarks();
+ for (Point point : landmarks) {
+ int pointX = (int) (point.x * resizeRatio);
+ int pointY = (int) (point.y * resizeRatio);
+ canvas.drawCircle(pointX, pointY, 2, paint);
+ }
+ }
+
+ return new BitmapDrawable(getResources(), bm);
+ }
+
+ @DebugLog
+ protected Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
+ Bitmap resizedBitmap = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
+ return resizedBitmap;
+ }
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/OnGetImageListener.java b/app/src/main/java/com/tzutalin/dlibtest/OnGetImageListener.java
new file mode 100644
index 00000000..aeb74c89
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/OnGetImageListener.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2016 Tzutalin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
+import android.media.ImageReader.OnImageAvailableListener;
+import android.os.Handler;
+import android.os.Trace;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+import com.tzutalin.dlib.Constants;
+import com.tzutalin.dlib.FaceDet;
+import com.tzutalin.dlib.VisionDetRet;
+
+import junit.framework.Assert;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class that takes in preview frames and converts the image to Bitmaps to process with dlib lib.
+ */
+public class OnGetImageListener implements OnImageAvailableListener {
+ private static final boolean SAVE_PREVIEW_BITMAP = false;
+
+ private static final int NUM_CLASSES = 1001;
+ private static final int INPUT_SIZE = 224;
+ private static final int IMAGE_MEAN = 117;
+ private static final String TAG = "OnGetImageListener";
+
+ private int mScreenRotation = 90;
+
+ private int mPreviewWdith = 0;
+ private int mPreviewHeight = 0;
+ private byte[][] mYUVBytes;
+ private int[] mRGBBytes = null;
+ private Bitmap mRGBframeBitmap = null;
+ private Bitmap mCroppedBitmap = null;
+
+ private boolean mIsComputing = false;
+ private Handler mInferenceHandler;
+
+ private Context mContext;
+ private FaceDet mFaceDet;
+ private TrasparentTitleView mTransparentTitleView;
+ private FloatingCameraWindow mWindow;
+ private Paint mFaceLandmardkPaint;
+
+ public void initialize(
+ final Context context,
+ final AssetManager assetManager,
+ final TrasparentTitleView scoreView,
+ final Handler handler) {
+ this.mContext = context;
+ this.mTransparentTitleView = scoreView;
+ this.mInferenceHandler = handler;
+ mFaceDet = new FaceDet(Constants.getFaceShapeModelPath());
+ mWindow = new FloatingCameraWindow(mContext);
+
+ mFaceLandmardkPaint = new Paint();
+ mFaceLandmardkPaint.setColor(Color.GREEN);
+ mFaceLandmardkPaint.setStrokeWidth(2);
+ mFaceLandmardkPaint.setStyle(Paint.Style.STROKE);
+ }
+
+ public void deInitialize() {
+ synchronized (OnGetImageListener.this) {
+ if (mFaceDet != null) {
+ mFaceDet.release();
+ }
+
+ if (mWindow != null) {
+ mWindow.release();
+ }
+ }
+ }
+
+ private void drawResizedBitmap(final Bitmap src, final Bitmap dst) {
+
+ Display getOrient = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ int orientation = Configuration.ORIENTATION_UNDEFINED;
+ Point point = new Point();
+ getOrient.getSize(point);
+ int screen_width = point.x;
+ int screen_height = point.y;
+ Log.d(TAG, String.format("screen size (%d,%d)", screen_width, screen_height));
+ if (screen_width < screen_height) {
+ orientation = Configuration.ORIENTATION_PORTRAIT;
+ mScreenRotation = 90;
+ } else {
+ orientation = Configuration.ORIENTATION_LANDSCAPE;
+ mScreenRotation = 0;
+ }
+
+ Assert.assertEquals(dst.getWidth(), dst.getHeight());
+ final float minDim = Math.min(src.getWidth(), src.getHeight());
+
+ final Matrix matrix = new Matrix();
+
+ // We only want the center square out of the original rectangle.
+ final float translateX = -Math.max(0, (src.getWidth() - minDim) / 2);
+ final float translateY = -Math.max(0, (src.getHeight() - minDim) / 2);
+ matrix.preTranslate(translateX, translateY);
+
+ final float scaleFactor = dst.getHeight() / minDim;
+ matrix.postScale(scaleFactor, scaleFactor);
+
+ // Rotate around the center if necessary.
+ if (mScreenRotation != 0) {
+ matrix.postTranslate(-dst.getWidth() / 2.0f, -dst.getHeight() / 2.0f);
+ matrix.postRotate(mScreenRotation);
+ matrix.postTranslate(dst.getWidth() / 2.0f, dst.getHeight() / 2.0f);
+ }
+
+ final Canvas canvas = new Canvas(dst);
+ canvas.drawBitmap(src, matrix, null);
+ }
+
+ @Override
+ public void onImageAvailable(final ImageReader reader) {
+ Image image = null;
+ try {
+ image = reader.acquireLatestImage();
+
+ if (image == null) {
+ return;
+ }
+
+ // No mutex needed as this method is not reentrant.
+ if (mIsComputing) {
+ image.close();
+ return;
+ }
+ mIsComputing = true;
+
+ Trace.beginSection("imageAvailable");
+
+ final Plane[] planes = image.getPlanes();
+
+ // Initialize the storage bitmaps once when the resolution is known.
+ if (mPreviewWdith != image.getWidth() || mPreviewHeight != image.getHeight()) {
+ mPreviewWdith = image.getWidth();
+ mPreviewHeight = image.getHeight();
+
+ Log.d(TAG, String.format("Initializing at size %dx%d", mPreviewWdith, mPreviewHeight));
+ mRGBBytes = new int[mPreviewWdith * mPreviewHeight];
+ mRGBframeBitmap = Bitmap.createBitmap(mPreviewWdith, mPreviewHeight, Config.ARGB_8888);
+ mCroppedBitmap = Bitmap.createBitmap(INPUT_SIZE, INPUT_SIZE, Config.ARGB_8888);
+
+ mYUVBytes = new byte[planes.length][];
+ for (int i = 0; i < planes.length; ++i) {
+ mYUVBytes[i] = new byte[planes[i].getBuffer().capacity()];
+ }
+ }
+
+ for (int i = 0; i < planes.length; ++i) {
+ planes[i].getBuffer().get(mYUVBytes[i]);
+ }
+
+ final int yRowStride = planes[0].getRowStride();
+ final int uvRowStride = planes[1].getRowStride();
+ final int uvPixelStride = planes[1].getPixelStride();
+ ImageUtils.convertYUV420ToARGB8888(
+ mYUVBytes[0],
+ mYUVBytes[1],
+ mYUVBytes[2],
+ mRGBBytes,
+ mPreviewWdith,
+ mPreviewHeight,
+ yRowStride,
+ uvRowStride,
+ uvPixelStride,
+ false);
+
+ image.close();
+ } catch (final Exception e) {
+ if (image != null) {
+ image.close();
+ }
+ Log.e(TAG, "Exception!", e);
+ Trace.endSection();
+ return;
+ }
+
+ mRGBframeBitmap.setPixels(mRGBBytes, 0, mPreviewWdith, 0, 0, mPreviewWdith, mPreviewHeight);
+ drawResizedBitmap(mRGBframeBitmap, mCroppedBitmap);
+
+ if (SAVE_PREVIEW_BITMAP) {
+ ImageUtils.saveBitmap(mCroppedBitmap);
+ }
+
+ mInferenceHandler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (!new File(Constants.getFaceShapeModelPath()).exists()) {
+ mTransparentTitleView.setText("Copying landmark model to " + Constants.getFaceShapeModelPath());
+ FileUtils.copyFileFromRawToOthers(mContext, R.raw.shape_predictor_68_face_landmarks, Constants.getFaceShapeModelPath());
+ }
+
+ long startTime = System.currentTimeMillis();
+ List results;
+ synchronized (OnGetImageListener.this) {
+ results = mFaceDet.detect(mCroppedBitmap);
+ }
+ long endTime = System.currentTimeMillis();
+ mTransparentTitleView.setText("Time cost: " + String.valueOf((endTime - startTime) / 1000f) + " sec");
+ // Draw on bitmap
+ if (results != null) {
+ for (final VisionDetRet ret : results) {
+ float resizeRatio = 1.0f;
+ Rect bounds = new Rect();
+ bounds.left = (int) (ret.getLeft() * resizeRatio);
+ bounds.top = (int) (ret.getTop() * resizeRatio);
+ bounds.right = (int) (ret.getRight() * resizeRatio);
+ bounds.bottom = (int) (ret.getBottom() * resizeRatio);
+ Canvas canvas = new Canvas(mCroppedBitmap);
+ canvas.drawRect(bounds, mFaceLandmardkPaint);
+
+ // Draw landmark
+ ArrayList landmarks = ret.getFaceLandmarks();
+ for (Point point : landmarks) {
+ int pointX = (int) (point.x * resizeRatio);
+ int pointY = (int) (point.y * resizeRatio);
+ canvas.drawCircle(pointX, pointY, 2, mFaceLandmardkPaint);
+ }
+ }
+ }
+
+ mWindow.setRGBBitmap(mCroppedBitmap);
+ mIsComputing = false;
+ }
+ });
+
+ Trace.endSection();
+ }
+}
diff --git a/app/src/main/java/com/tzutalin/dlibtest/TrasparentTitleView.java b/app/src/main/java/com/tzutalin/dlibtest/TrasparentTitleView.java
new file mode 100644
index 00000000..4bcc4206
--- /dev/null
+++ b/app/src/main/java/com/tzutalin/dlibtest/TrasparentTitleView.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Tzutalin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzutalin.dlibtest;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.support.annotation.NonNull;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+
+public class TrasparentTitleView extends View {
+ private static final float TEXT_SIZE_DIP = 24;
+ private static final String TAG = "RecognitionScoreView";
+ private String mShowText;
+ private final float mTextSizePx;
+ private final Paint mFgPaint;
+ private final Paint mBgPaint;
+
+ public TrasparentTitleView(final Context context, final AttributeSet set) {
+ super(context, set);
+
+ mTextSizePx =
+ TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, TEXT_SIZE_DIP, getResources().getDisplayMetrics());
+ mFgPaint = new Paint();
+ mFgPaint.setTextSize(mTextSizePx);
+
+ mBgPaint = new Paint();
+ mBgPaint.setColor(0xcc4285f4);
+ }
+
+ @NonNull
+ public void setText(@NonNull String text) {
+ this.mShowText = text;
+ postInvalidate();
+ }
+
+ @Override
+ public void onDraw(final Canvas canvas) {
+ final int x = 10;
+ int y = (int) (mFgPaint.getTextSize() * 1.5f);
+
+ canvas.drawPaint(mBgPaint);
+
+ if (mShowText != null) {
+ canvas.drawText(mShowText, x, y, mFgPaint);
+ }
+ }
+}
diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk
new file mode 100644
index 00000000..e3a69f0d
--- /dev/null
+++ b/app/src/main/jni/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH := $(call my-dir)
+SUB_MK_FILES := $(call all-subdir-makefiles)
+
+## Build dlib to static library
+include $(CLEAR_VARS)
+LOCAL_MODULE := dlib
+LOCAL_C_INCLUDES := dlib
+
+LOCAL_SRC_FILES += \
+ dlib/dlib/threads/threads_kernel_shared.cpp \
+ dlib/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp \
+ dlib/dlib/base64/base64_kernel_1.cpp \
+ dlib/dlib/threads/threads_kernel_1.cpp \
+ dlib/dlib/threads/threads_kernel_2.cpp
+
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
+include $(BUILD_STATIC_LIBRARY)
+
+EXT_INSTALL_PATH = third_party
+
+OPENCV_PATH := $(LOCAL_PATH)/$(EXT_INSTALL_PATH)/OpenCV-android-sdk/sdk/native/jni
+OPENCV_INCLUDE_DIR = $(OPENCV_PATH)/include
+
+MINIGLOG_LIB_TYPE := STATIC
+MINI_GLOG_PATH = $(EXT_INSTALL_PATH)/miniglog
+include $(MINI_GLOG_PATH)/Android.mk
+
+include $(SUB_MK_FILES)
diff --git a/jni/Application.mk b/app/src/main/jni/Application.mk
similarity index 100%
rename from jni/Application.mk
rename to app/src/main/jni/Application.mk
diff --git a/app/src/main/jni/dlib/.gitignore b/app/src/main/jni/dlib/.gitignore
new file mode 100644
index 00000000..235fff57
--- /dev/null
+++ b/app/src/main/jni/dlib/.gitignore
@@ -0,0 +1,9 @@
+**/.idea
+*~
+*.swp
+*.o
+*.so
+build
+dist
+*.egg-info/
+
diff --git a/app/src/main/jni/dlib/.hgignore b/app/src/main/jni/dlib/.hgignore
new file mode 100644
index 00000000..2b462fa0
--- /dev/null
+++ b/app/src/main/jni/dlib/.hgignore
@@ -0,0 +1,31 @@
+/build/
+/build2/
+/build_clang/
+\.swp$
+\.swo$
+\.o$
+\.a$
+\.orig$
+\.obj$
+\.pyc$
+^build/
+^docs/release/
+^docs/docs/web/
+^docs/docs/chm/
+^docs/docs/cache/
+^docs/docs/log.txt$
+^docs/docs/old_log.txt$
+^dlib/test/debug.txt$
+^dlib/test/test$
+^dlib/test/makefile.bak$
+python_examples/.*.so$
+python_examples/.*.pyd$
+python_examples/.*.dll$
+python_examples/.*.lib$
+docs/docs/python/classes.txt
+docs/docs/python/functions.txt
+syntax: glob
+dlib/test/build64/*
+*.svm
+dlib/test/build_python
+dlib/test/test_log.txt
diff --git a/app/src/main/jni/dlib/.hgtags b/app/src/main/jni/dlib/.hgtags
new file mode 100644
index 00000000..3c860951
--- /dev/null
+++ b/app/src/main/jni/dlib/.hgtags
@@ -0,0 +1,32 @@
+7f7ffcda900ae3c8de0a562cc7e9d3f51e523a39 v17.39
+43cbb1c92eaeba09bd0e9c72bb0783044492e651 v17.40
+f6c79ee4083449640e45cc7e48ef2e7636687d90 v17.41
+e516e232b94254db264e34b61458e0eabd78bea8 v17.42
+43d280b34aa9dd68c62208d72f3b8e48ed047684 v17.43
+9ed76e89b6644208d4536b3396c7664445bd4520 v17.44
+d20f5ce805d53b5fec9d5dd250159d28480041cf v17.45
+cfbd4102b1ee25ca3531819abbbe93971d6dc65a v17.46
+f58ff52144bddbccb5a372e6c4befb4b6ad98021 v17.47
+b90ab60d8a18fc8616fb895b0d059c1cf07db3ce v17.48
+4312a45be8b45634f8ffafcb2b5a425bd426642b v17.49
+df60c7686f3982791e218977edb64d638151ca3b v18.0
+8d0762ab49b9ee8d1d3fc1fc02926c6bde6d5542 v18.1
+5de237bc41c1c2e63d0731731eee231a4213a31b v18.2
+7f21bd92812d2d08fe9a881a401cbf0f6b104081 v18.3
+78be73b57b829adb20a452ad910f7039a09c9474 v18.4
+3026cfaf82c5a878b2c81ee4d6445237d453e372 v18.5
+6a929c3ad782f17e34d364665e6e277e3ff99912 v18.6
+5a3fb1f81041978948e6148a1f56ab56cf678c69 v18.7
+a6c2b16111b8023dbded7299dcc7e6acd26671b8 v18.8
+4de62892e10850e8f0205b4857cf48b31fd730c8 v18.9
+5a14394843c04628990857e5db94ff6bc43c2da0 v18.10
+dd8e950033d5026373acce9ed4b2ffb85908d3b5 v18.11
+4e3941b13ca859f788853cfcef9973ac4b161e65 v18.12
+67c3ad208aae9537cf16f64936dd62e2210caa96 v18.13
+cae7fcc9e6a9b28b44a703e4598f44286fec734d v18.14
+feaff82884ded598bde93c635eb3ded9c0933a07 v18.15
+42a25c606cf924a8d41d2fc96b9c85f839d21a04 v18.16
+ce6f364987865b19bdb1b4730ac5403e2bb55dc4 v18.17
+7ae1775f61a44b7f07866050b50ad3ade581f019 v18.18
+4d6b102506bb9e2f195c7ddf984cc2d86b8643e7 before_dnn_serialization_cleanup
+7210589728f6d83f6cb7d21cd24d114a5364d9e2 v19.0
diff --git a/app/src/main/jni/dlib/CMakeLists.txt b/app/src/main/jni/dlib/CMakeLists.txt
new file mode 100644
index 00000000..3f9c43e6
--- /dev/null
+++ b/app/src/main/jni/dlib/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.4)
+add_subdirectory(dlib)
diff --git a/app/src/main/jni/dlib/MANIFEST.in b/app/src/main/jni/dlib/MANIFEST.in
new file mode 100644
index 00000000..53ed6697
--- /dev/null
+++ b/app/src/main/jni/dlib/MANIFEST.in
@@ -0,0 +1,22 @@
+#
+# MANIFEST.in
+#
+# Manifest template for creating the dlib source distribution.
+
+include MANIFEST.in
+include setup.py
+include README.txt
+
+# sources
+recursive-include dlib **
+recursive-exclude dlib/test **
+recursive-exclude dlib/build **
+recursive-include docs **
+recursive-include python_examples *.txt *.py *.bat
+recursive-exclude python_examples/build **
+recursive-include tools/python **
+recursive-exclude tools/python/build **
+
+# dlib package
+recursive-include dist/dlib **
+
diff --git a/app/src/main/jni/dlib/README.txt b/app/src/main/jni/dlib/README.txt
new file mode 100644
index 00000000..67fb2aaa
--- /dev/null
+++ b/app/src/main/jni/dlib/README.txt
@@ -0,0 +1,51 @@
+
+ dlib C++ library
+
+Dlib is a modern C++ toolkit containing machine learning algorithms and tools
+for creating complex software in C++ to solve real world problems. See
+http://dlib.net for the main project documentation and API reference.
+
+
+
+COMPILING DLIB C++ EXAMPLE PROGRAMS
+ Go into the examples folder and type:
+ mkdir build; cd build; cmake .. ; cmake --build .
+ That will build all the examples. If you have a CPU that supports AVX
+ instructions then turn them on like this:
+ mkdir build; cd build; cmake .. -DUSE_AVX_INSTRUCTIONS=1; cmake --build .
+ Doing so will make some things run faster.
+
+COMPILING DLIB Python API
+ Before you can run the Python example programs you must compile dlib. Type:
+ python setup.py install
+ or type
+ python setup.py install --yes USE_AVX_INSTRUCTIONS
+ if you have a CPU that supports AVX instructions, since this makes some
+ things run faster.
+
+RUNNING THE UNIT TEST SUITE
+ Type the following to compile and run the dlib unit test suite:
+ cd dlib/test
+ mkdir build
+ cd build
+ cmake ..
+ cmake --build . --config Release
+ ./dtest --runall
+
+ Note that on windows your compiler might put the test executable in a
+ subfolder called Release. If that's the case then you have to go to that
+ folder before running the test.
+
+This library is licensed under the Boost Software License, which can be found
+in dlib/LICENSE.txt. The long and short of the license is that you can use
+dlib however you like, even in closed source commercial software.
+
+Dlib Sponsors:
+ This research is based in part upon work supported by the Office of the
+ Director of National Intelligence (ODNI), Intelligence Advanced Research
+ Projects Activity (IARPA) under contract number 2014-14071600010. The
+ views and conclusions contained herein are those of the authors and
+ should not be interpreted as necessarily representing the official policies
+ or endorsements, either expressed or implied, of ODNI, IARPA, or the U.S.
+ Government.
+
diff --git a/app/src/main/jni/dlib/dlib/CMakeLists.txt b/app/src/main/jni/dlib/dlib/CMakeLists.txt
new file mode 100644
index 00000000..92255761
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/CMakeLists.txt
@@ -0,0 +1,637 @@
+#
+# This is a CMake makefile. You can find the cmake utility and
+# information about it at http://www.cmake.org
+#
+
+
+cmake_minimum_required(VERSION 2.8.4)
+project(dlib)
+
+# default to a Release build (except if CMAKE_BUILD_TYPE is set)
+include(cmake_utils/release_build_by_default)
+include(cmake_utils/use_cpp_11.cmake)
+
+
+set(CPACK_PACKAGE_VERSION_MAJOR "19")
+set(CPACK_PACKAGE_VERSION_MINOR "1")
+set(CPACK_PACKAGE_VERSION_PATCH "0")
+set(VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
+# Set DLIB_VERSION in the including CMake file so they can use it to do whatever they want.
+get_directory_property(has_parent PARENT_DIRECTORY)
+if(has_parent)
+ set(DLIB_VERSION ${VERSION} PARENT_SCOPE)
+endif()
+
+set(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
+# Suppress cmake warnings about changes in new versions.
+if(COMMAND cmake_policy)
+ cmake_policy(SET CMP0003 NEW)
+ if (POLICY CMP0054)
+ cmake_policy(SET CMP0054 NEW)
+ endif()
+endif()
+
+include(cmake_utils/add_global_compiler_switch.cmake)
+
+
+# Make sure ENABLE_ASSERTS is defined for debug builds
+if (NOT CMAKE_CXX_FLAGS_DEBUG MATCHES "-DENABLE_ASSERTS")
+ set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLE_ASSERTS"
+ CACHE STRING "Flags used by the compiler during C++ debug builds."
+ FORCE)
+endif ()
+macro (toggle_preprocessor_switch option_name)
+ if (${option_name})
+ add_global_define(${option_name})
+ else()
+ remove_global_define(${option_name})
+ endif()
+endmacro()
+
+# Don't try to call add_library(dlib) and setup dlib's stuff if it has already
+# been done by some other part of the current cmake project. We do this
+# because it avoids getting warnings/errors about cmake policy CMP0002. This
+# happens when a project tries to call add_subdirectory() on dlib more than
+# once. This most often happens when the top level of a project depends on two
+# or more other things which both depend on dlib.
+if (NOT TARGET dlib)
+
+ set (DLIB_ISO_CPP_ONLY_STR
+ "Enable this if you don't want to compile any non-ISO C++ code (i.e. you don't use any of the API Wrappers)" )
+ set (DLIB_NO_GUI_SUPPORT_STR
+ "Enable this if you don't want to compile any of the dlib GUI code" )
+ set (DLIB_ENABLE_STACK_TRACE_STR
+ "Enable this if you want to turn on the DLIB_STACK_TRACE macros" )
+ set (DLIB_ENABLE_ASSERTS_STR
+ "Enable this if you want to turn on the DLIB_ASSERT macro" )
+ set (DLIB_USE_BLAS_STR
+ "Disable this if you don't want to use a BLAS library" )
+ set (DLIB_USE_LAPACK_STR
+ "Disable this if you don't want to use a LAPACK library" )
+ set (DLIB_USE_CUDA_STR
+ "Disable this if you don't want to use NVIDIA CUDA" )
+ set (DLIB_PNG_SUPPORT_STR
+ "Disable this if you don't want to link against libpng" )
+ set (DLIB_GIF_SUPPORT_STR
+ "Disable this if you don't want to link against libgif" )
+ set (DLIB_JPEG_SUPPORT_STR
+ "Disable this if you don't want to link against libjpeg" )
+ set (DLIB_LINK_WITH_SQLITE3_STR
+ "Disable this if you don't want to link against sqlite3" )
+ #set (DLIB_USE_FFTW_STR "Disable this if you don't want to link against fftw" )
+
+ option(DLIB_ISO_CPP_ONLY ${DLIB_ISO_CPP_ONLY_STR} OFF)
+ toggle_preprocessor_switch(DLIB_ISO_CPP_ONLY)
+ option(DLIB_NO_GUI_SUPPORT ${DLIB_NO_GUI_SUPPORT_STR} OFF)
+ toggle_preprocessor_switch(DLIB_NO_GUI_SUPPORT)
+ option(DLIB_ENABLE_STACK_TRACE ${DLIB_ENABLE_STACK_TRACE_STR} OFF)
+ toggle_preprocessor_switch(DLIB_ENABLE_STACK_TRACE)
+
+ option(DLIB_ENABLE_ASSERTS ${DLIB_ENABLE_ASSERTS_STR} OFF)
+ if(DLIB_ENABLE_ASSERTS)
+ # Set these variables so they are set in the config.h.in file when dlib
+ # is installed.
+ set (DLIB_DISABLE_ASSERTS false)
+ set (ENABLE_ASSERTS true)
+ add_global_define(ENABLE_ASSERTS)
+ else()
+ # Set these variables so they are set in the config.h.in file when dlib
+ # is installed.
+ set (DLIB_DISABLE_ASSERTS true)
+ set (ENABLE_ASSERTS false)
+ remove_global_define(ENABLE_ASSERTS)
+ endif()
+
+ if (DLIB_ISO_CPP_ONLY)
+ option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} OFF)
+ option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} OFF)
+ option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} OFF)
+ option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} OFF)
+ option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} OFF)
+ option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} OFF)
+ option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} OFF)
+ #option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} OFF)
+ else()
+ option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} ON)
+ option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} ON)
+ option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} ON)
+ option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} ON)
+ option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} ON)
+ option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} ON)
+ option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} ON)
+ #option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} ON)
+ endif()
+ toggle_preprocessor_switch(DLIB_JPEG_SUPPORT)
+ toggle_preprocessor_switch(DLIB_USE_BLAS)
+ toggle_preprocessor_switch(DLIB_USE_LAPACK)
+ toggle_preprocessor_switch(DLIB_USE_CUDA)
+ toggle_preprocessor_switch(DLIB_PNG_SUPPORT)
+ toggle_preprocessor_switch(DLIB_GIF_SUPPORT)
+ #toggle_preprocessor_switch(DLIB_USE_FFTW)
+
+
+ set(source_files
+ base64/base64_kernel_1.cpp
+ bigint/bigint_kernel_1.cpp
+ bigint/bigint_kernel_2.cpp
+ bit_stream/bit_stream_kernel_1.cpp
+ entropy_decoder/entropy_decoder_kernel_1.cpp
+ entropy_decoder/entropy_decoder_kernel_2.cpp
+ entropy_encoder/entropy_encoder_kernel_1.cpp
+ entropy_encoder/entropy_encoder_kernel_2.cpp
+ md5/md5_kernel_1.cpp
+ tokenizer/tokenizer_kernel_1.cpp
+ unicode/unicode.cpp
+ data_io/image_dataset_metadata.cpp
+ data_io/mnist.cpp)
+
+ if (COMPILER_CAN_DO_CPP_11)
+ set(source_files ${source_files}
+ dnn/cpu_dlib.cpp
+ dnn/tensor_tools.cpp
+ )
+ endif()
+
+ if (DLIB_ISO_CPP_ONLY)
+ add_library(dlib STATIC ${source_files} )
+ if (UNIX AND NOT DLIB_IN_PROJECT_BUILD)
+ add_library(dlib_shared SHARED ${source_files} )
+ endif()
+ else()
+
+ set(source_files ${source_files}
+ sockets/sockets_kernel_1.cpp
+ bsp/bsp.cpp
+ dir_nav/dir_nav_kernel_1.cpp
+ dir_nav/dir_nav_kernel_2.cpp
+ dir_nav/dir_nav_extensions.cpp
+ linker/linker_kernel_1.cpp
+ logger/extra_logger_headers.cpp
+ logger/logger_kernel_1.cpp
+ logger/logger_config_file.cpp
+ misc_api/misc_api_kernel_1.cpp
+ misc_api/misc_api_kernel_2.cpp
+ sockets/sockets_extensions.cpp
+ sockets/sockets_kernel_2.cpp
+ sockstreambuf/sockstreambuf.cpp
+ sockstreambuf/sockstreambuf_unbuffered.cpp
+ server/server_kernel.cpp
+ server/server_iostream.cpp
+ server/server_http.cpp
+ threads/multithreaded_object_extension.cpp
+ threads/threaded_object_extension.cpp
+ threads/threads_kernel_1.cpp
+ threads/threads_kernel_2.cpp
+ threads/threads_kernel_shared.cpp
+ threads/thread_pool_extension.cpp
+ threads/async.cpp
+ timer/timer.cpp
+ stack_trace.cpp
+ )
+
+ set(dlib_needed_libraries)
+ if(UNIX)
+ set(CMAKE_THREAD_PREFER_PTHREAD ON)
+ find_package(Threads REQUIRED)
+ set(dlib_needed_libraries ${dlib_needed_libraries} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+
+ # we want to link to the right stuff depending on our platform.
+ if (WIN32 AND NOT CYGWIN) ###############################################################################
+ if (DLIB_NO_GUI_SUPPORT)
+ set (dlib_needed_libraries ws2_32 winmm)
+ else()
+ set (dlib_needed_libraries ws2_32 winmm comctl32 gdi32 imm32)
+ endif()
+ elseif(APPLE) ############################################################################
+ if (NOT DLIB_NO_GUI_SUPPORT)
+ find_package(X11 QUIET)
+ if (X11_FOUND)
+ include_directories(${X11_INCLUDE_DIR})
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${X11_LIBRARIES})
+ else()
+ find_library(xlib X11)
+ # Make sure X11 is in the include path. Note that we look for
+ # Xlocale.h rather than Xlib.h because it avoids finding a partial
+ # copy of the X11 headers on systems with anaconda installed.
+ find_path(xlib_path Xlocale.h
+ PATHS
+ /Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include
+ /opt/local/include
+ PATH_SUFFIXES X11
+ )
+ if (xlib AND xlib_path)
+ get_filename_component(x11_path ${xlib_path} PATH CACHE)
+ include_directories(${x11_path})
+ set(dlib_needed_libraries ${dlib_needed_libraries} ${xlib} )
+ set(X11_FOUND 1)
+ endif()
+ endif()
+ if (NOT X11_FOUND)
+ message(" *****************************************************************************")
+ message(" *** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ***")
+ message(" *** Make sure XQuartz is installed if you want GUI support. ***")
+ message(" *** You can download XQuartz from: http://xquartz.macosforge.org/landing/ ***")
+ message(" *****************************************************************************")
+ set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE )
+ add_global_define(DLIB_NO_GUI_SUPPORT)
+ endif()
+ endif()
+
+ mark_as_advanced(pthreadlib xlib xlib_path x11_path)
+ else () ##################################################################################
+ # link to the nsl library if it exists. this is something you need sometimes
+ find_library(nsllib nsl)
+ if (nsllib)
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${nsllib})
+ endif ()
+
+ # link to the socket library if it exists. this is something you need on solaris
+ find_library(socketlib socket)
+ if (socketlib)
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${socketlib})
+ endif ()
+
+ if (NOT DLIB_NO_GUI_SUPPORT)
+ include(FindX11)
+ if (X11_FOUND)
+ include_directories(${X11_INCLUDE_DIR})
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${X11_LIBRARIES})
+ else()
+ message(" *****************************************************************************")
+ message(" *** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ***")
+ message(" *** Make sure libx11-dev is installed if you want GUI support. ***")
+ message(" *** On Ubuntu run: sudo apt-get install libx11-dev ***")
+ message(" *****************************************************************************")
+ set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE )
+ add_global_define(DLIB_NO_GUI_SUPPORT)
+ endif()
+ endif()
+
+ mark_as_advanced(nsllib pthreadlib socketlib)
+ endif () ##################################################################################
+
+ if (NOT DLIB_NO_GUI_SUPPORT)
+ set(source_files ${source_files}
+ gui_widgets/fonts.cpp
+ gui_widgets/widgets.cpp
+ gui_widgets/drawable.cpp
+ gui_widgets/canvas_drawing.cpp
+ gui_widgets/style.cpp
+ gui_widgets/base_widgets.cpp
+ gui_core/gui_core_kernel_1.cpp
+ gui_core/gui_core_kernel_2.cpp
+ )
+ endif()
+
+ INCLUDE (CheckFunctionExists)
+
+ if (DLIB_GIF_SUPPORT)
+ find_package(GIF QUIET)
+ if (GIF_FOUND)
+ include_directories(${GIF_INCLUDE_DIR})
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${GIF_LIBRARY})
+ else()
+ set(DLIB_GIF_SUPPORT OFF CACHE STRING ${DLIB_GIF_SUPPORT_STR} FORCE )
+ toggle_preprocessor_switch(DLIB_GIF_SUPPORT)
+ endif()
+ endif()
+
+ if (DLIB_PNG_SUPPORT)
+ # try to find libpng
+ find_package(PNG QUIET)
+ # Make sure there isn't something wrong with the version of LIBPNG
+ # installed on this system.
+ if (PNG_FOUND)
+ set(CMAKE_REQUIRED_LIBRARIES ${PNG_LIBRARY})
+ CHECK_FUNCTION_EXISTS(png_create_read_struct LIBPNG_IS_GOOD)
+ endif()
+ if (PNG_FOUND AND LIBPNG_IS_GOOD)
+ include_directories(${PNG_INCLUDE_DIR})
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${PNG_LIBRARY})
+ set(REQUIRES_LIBS " libpng")
+ else()
+ # If we can't find libpng then statically compile it in.
+ include_directories(external/libpng external/zlib)
+ set(source_files ${source_files}
+ external/libpng/png.c
+ external/libpng/pngerror.c
+ external/libpng/pngget.c
+ external/libpng/pngmem.c
+ external/libpng/pngpread.c
+ external/libpng/pngread.c
+ external/libpng/pngrio.c
+ external/libpng/pngrtran.c
+ external/libpng/pngrutil.c
+ external/libpng/pngset.c
+ external/libpng/pngtrans.c
+ external/libpng/pngwio.c
+ external/libpng/pngwrite.c
+ external/libpng/pngwtran.c
+ external/libpng/pngwutil.c
+ external/zlib/adler32.c
+ external/zlib/compress.c
+ external/zlib/crc32.c
+ external/zlib/deflate.c
+ external/zlib/gzclose.c
+ external/zlib/gzlib.c
+ external/zlib/gzread.c
+ external/zlib/gzwrite.c
+ external/zlib/infback.c
+ external/zlib/inffast.c
+ external/zlib/inflate.c
+ external/zlib/inftrees.c
+ external/zlib/trees.c
+ external/zlib/uncompr.c
+ external/zlib/zutil.c
+ )
+ set(REQUIRES_LIBS "")
+ endif()
+ set(source_files ${source_files}
+ image_loader/png_loader.cpp
+ image_saver/save_png.cpp
+ )
+ endif()
+
+ if (DLIB_JPEG_SUPPORT)
+ # try to find libjpeg
+ find_package(JPEG QUIET)
+ # Make sure there isn't something wrong with the version of libjpeg
+ # installed on this system. Also don't use the installed libjpeg
+ # if this is an APPLE system because apparently it's broken (as of 2015/01/01).
+ if (JPEG_FOUND)
+ set(CMAKE_REQUIRED_LIBRARIES ${JPEG_LIBRARY})
+ CHECK_FUNCTION_EXISTS(jpeg_read_header LIBJPEG_IS_GOOD)
+ endif()
+ if (JPEG_FOUND AND LIBJPEG_IS_GOOD AND NOT APPLE)
+ include_directories(${JPEG_INCLUDE_DIR})
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${JPEG_LIBRARY})
+ else()
+ # If we can't find libjpeg then statically compile it in.
+ add_definitions(-DDLIB_JPEG_STATIC)
+ set(source_files ${source_files}
+ external/libjpeg/jcomapi.cpp
+ external/libjpeg/jdapimin.cpp
+ external/libjpeg/jdapistd.cpp
+ external/libjpeg/jdatasrc.cpp
+ external/libjpeg/jdcoefct.cpp
+ external/libjpeg/jdcolor.cpp
+ external/libjpeg/jddctmgr.cpp
+ external/libjpeg/jdhuff.cpp
+ external/libjpeg/jdinput.cpp
+ external/libjpeg/jdmainct.cpp
+ external/libjpeg/jdmarker.cpp
+ external/libjpeg/jdmaster.cpp
+ external/libjpeg/jdmerge.cpp
+ external/libjpeg/jdphuff.cpp
+ external/libjpeg/jdpostct.cpp
+ external/libjpeg/jdsample.cpp
+ external/libjpeg/jerror.cpp
+ external/libjpeg/jidctflt.cpp
+ external/libjpeg/jidctfst.cpp
+ external/libjpeg/jidctint.cpp
+ external/libjpeg/jidctred.cpp
+ external/libjpeg/jmemmgr.cpp
+ external/libjpeg/jmemnobs.cpp
+ external/libjpeg/jquant1.cpp
+ external/libjpeg/jquant2.cpp
+ external/libjpeg/jutils.cpp
+ external/libjpeg/jcapimin.cpp
+ external/libjpeg/jdatadst.cpp
+ external/libjpeg/jcparam.cpp
+ external/libjpeg/jcapistd.cpp
+ external/libjpeg/jcmarker.cpp
+ external/libjpeg/jcinit.cpp
+ external/libjpeg/jcmaster.cpp
+ external/libjpeg/jcdctmgr.cpp
+ external/libjpeg/jccoefct.cpp
+ external/libjpeg/jccolor.cpp
+ external/libjpeg/jchuff.cpp
+ external/libjpeg/jcmainct.cpp
+ external/libjpeg/jcphuff.cpp
+ external/libjpeg/jcprepct.cpp
+ external/libjpeg/jcsample.cpp
+ external/libjpeg/jfdctint.cpp
+ external/libjpeg/jfdctflt.cpp
+ external/libjpeg/jfdctfst.cpp
+ )
+ endif()
+ set(source_files ${source_files}
+ image_loader/jpeg_loader.cpp
+ image_saver/save_jpeg.cpp
+ )
+ endif()
+
+
+ if (DLIB_USE_BLAS OR DLIB_USE_LAPACK)
+ # Try to find BLAS and LAPACK
+ include(cmake_utils/cmake_find_blas.txt)
+
+ if (DLIB_USE_BLAS)
+ if (blas_found)
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${blas_libraries})
+ else()
+ set(DLIB_USE_BLAS OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE )
+ toggle_preprocessor_switch(DLIB_USE_BLAS)
+ endif()
+ endif()
+
+ if (DLIB_USE_LAPACK)
+ if (lapack_found)
+ set (dlib_needed_libraries ${dlib_needed_libraries} ${lapack_libraries})
+ else()
+ set(DLIB_USE_LAPACK OFF CACHE STRING ${DLIB_USE_LAPACK_STR} FORCE )
+ toggle_preprocessor_switch(DLIB_USE_LAPACK)
+ endif()
+ endif()
+ endif()
+
+
+ if (DLIB_USE_CUDA)
+ find_package(CUDA 7.5)
+
+
+ if (CUDA_FOUND AND COMPILER_CAN_DO_CPP_11)
+
+ set(CUDA_HOST_COMPILATION_CPP ON)
+ # Note that we add __STRICT_ANSI__ to avoid freaking out nvcc with gcc specific
+ # magic in the standard C++ header files (since nvcc uses gcc headers on
+ # linux).
+ list(APPEND CUDA_NVCC_FLAGS "-arch=sm_30;-std=c++11;-D__STRICT_ANSI__;-D_MWAITXINTRIN_H_INCLUDED;-D_FORCE_INLINES")
+
+ include(cmake_utils/test_for_cudnn/find_cudnn.txt)
+
+ if (cudnn AND NOT DEFINED cuda_test_compile_worked AND NOT DEFINED cudnn_test_compile_worked)
+ # make sure cuda is really working by doing a test compile
+ message(STATUS "Building a CUDA test project to see if your compiler is compatible with CUDA...")
+ try_compile(cuda_test_compile_worked ${PROJECT_BINARY_DIR}/cuda_test_build
+ ${PROJECT_SOURCE_DIR}/cmake_utils/test_for_cuda cuda_test
+ CMAKE_FLAGS "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
+ "-DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}"
+ "-DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}"
+ )
+ if (NOT cuda_test_compile_worked)
+ message(STATUS "*** CUDA was found but your compiler failed to compile a simple CUDA program so dlib isn't going to use CUDA. ***")
+ else()
+ message(STATUS "Checking if you have the right version of cuDNN installed.")
+ try_compile(cudnn_test_compile_worked ${PROJECT_BINARY_DIR}/cudnn_test_build
+ ${PROJECT_SOURCE_DIR}/cmake_utils/test_for_cudnn cudnn_test
+ CMAKE_FLAGS "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
+ "-DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}"
+ "-DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}"
+ )
+ if (cudnn_test_compile_worked)
+ message(STATUS "Found cuDNN: " ${cudnn})
+ else()
+ message(STATUS "*** Found cuDNN, but it looks like the wrong version so dlib will not use it. ***")
+ endif()
+ endif()
+ endif()
+ endif()
+
+
+ if (CUDA_FOUND AND cudnn AND cudnn_include AND COMPILER_CAN_DO_CPP_11 AND cuda_test_compile_worked AND cudnn_test_compile_worked)
+ set(source_files ${source_files}
+ dnn/cuda_dlib.cu
+ dnn/cudnn_dlibapi.cpp
+ dnn/cublas_dlibapi.cpp
+ dnn/curand_dlibapi.cpp
+ dnn/gpu_data.cpp
+ )
+ set(dlib_needed_libraries ${dlib_needed_libraries}
+ ${CUDA_CUBLAS_LIBRARIES}
+ ${cudnn}
+ ${CUDA_curand_LIBRARY}
+ )
+ include_directories(${cudnn_include})
+ else()
+ set(DLIB_USE_CUDA OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE )
+ toggle_preprocessor_switch(DLIB_USE_CUDA)
+ if (COMPILER_CAN_DO_CPP_11)
+ if (NOT cudnn OR NOT cudnn_include OR NOT cudnn_test_compile_worked)
+ message(STATUS "*** cuDNN V5.0 OR GREATER NOT FOUND. DLIB WILL NOT USE CUDA. ***")
+ message(STATUS "*** If you have cuDNN then set CMAKE_PREFIX_PATH to include cuDNN's folder.")
+ endif()
+ else ()
+ message(STATUS "*** Dlib CUDA support requires C++11 but your compiler doesn't support it. ***")
+ endif()
+ endif()
+ endif()
+
+
+ if (DLIB_LINK_WITH_SQLITE3)
+ find_library(sqlite sqlite3)
+ # make sure sqlite3.h is in the include path
+ find_path(sqlite_path sqlite3.h)
+ if (sqlite AND sqlite_path)
+ get_filename_component(sqlite_path2 ${sqlite_path} PATH CACHE)
+ include_directories(${sqlite_path2})
+ set(dlib_needed_libraries ${dlib_needed_libraries} ${sqlite} )
+ else()
+ set(DLIB_LINK_WITH_SQLITE3 OFF CACHE STRING ${DLIB_LINK_WITH_SQLITE3_STR} FORCE )
+ endif()
+ mark_as_advanced(sqlite sqlite_path sqlite_path2)
+ endif()
+
+
+
+ if (DLIB_USE_FFTW)
+ find_library(fftw fftw3)
+ # make sure fftw3.h is in the include path
+ find_path(fftw_path fftw3.h)
+ if (fftw AND fftw_path)
+ include_directories(${fftw_path})
+ set(dlib_needed_libraries ${dlib_needed_libraries} ${fftw} )
+ else()
+ set(DLIB_USE_FFTW OFF CACHE STRING ${DLIB_USE_FFTW_STR} FORCE )
+ toggle_preprocessor_switch(DLIB_USE_FFTW)
+ endif()
+ mark_as_advanced(fftw fftw_path)
+ endif()
+
+
+
+ # Tell CMake to build dlib via add_library()/cuda_add_library()
+ if (DLIB_USE_CUDA)
+ cuda_add_library(dlib STATIC ${source_files} )
+ else()
+ add_library(dlib STATIC ${source_files} )
+ endif()
+ target_link_libraries(dlib ${dlib_needed_libraries} )
+ if (UNIX AND NOT DLIB_IN_PROJECT_BUILD)
+ if (DLIB_USE_CUDA)
+ cuda_add_library(dlib_shared SHARED ${source_files} )
+ else()
+ add_library(dlib_shared SHARED ${source_files} )
+ endif()
+ target_link_libraries(dlib_shared ${dlib_needed_libraries} )
+ endif()
+
+ endif () ##### end of if NOT DLIB_ISO_CPP_ONLY ##########################################################
+
+ # Install the library
+ if (NOT DLIB_IN_PROJECT_BUILD)
+ set (LIB_INSTALL_DIR lib CACHE STRING "Install location of libraries (e.g. lib32 or lib64 for multilib installations)")
+ cmake_minimum_required(VERSION 2.8.8)
+ if(UNIX)
+ set_target_properties(dlib_shared PROPERTIES
+ OUTPUT_NAME dlib
+ VERSION ${VERSION})
+ install(TARGETS dlib dlib_shared
+ EXPORT dlib
+ RUNTIME DESTINATION bin # Windows (including cygwin) considers .dll to be runtime artifacts
+ LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+ ARCHIVE DESTINATION "${LIB_INSTALL_DIR}")
+ else()
+ install(TARGETS dlib
+ EXPORT dlib
+ RUNTIME DESTINATION bin # Windows considers .dll to be runtime artifacts
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+ endif()
+
+ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION include/dlib
+ FILES_MATCHING PATTERN "*.h"
+ REGEX "${CMAKE_CURRENT_BINARY_DIR}" EXCLUDE)
+
+
+ configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+ # overwrite config.h with the configured one
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h DESTINATION include/dlib)
+
+ configure_file(${PROJECT_SOURCE_DIR}/revision.h.in ${CMAKE_CURRENT_BINARY_DIR}/revision.h)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/revision.h DESTINATION include/dlib)
+
+ install(FILES "LICENSE.txt" DESTINATION share/doc/dlib)
+
+ ## Config.cmake generation and installation
+
+ set(ConfigPackageLocation "${LIB_INSTALL_DIR}/cmake/dlib")
+ install(EXPORT dlib
+ NAMESPACE dlib::
+ DESTINATION ${ConfigPackageLocation})
+
+ set(CONF_INSTALL_PATH "\${dlib_CMAKE_DIR}/../../../")
+ configure_file(cmake_utils/dlibConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfig.cmake" @ONLY)
+
+ include(CMakePackageConfigHelpers)
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfigVersion.cmake"
+ VERSION ${VERSION}
+ COMPATIBILITY AnyNewerVersion
+ )
+
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfigVersion.cmake"
+ DESTINATION ${ConfigPackageLocation})
+
+ ## dlib-1.pc generation and installation
+
+ configure_file("cmake_utils/dlib.pc.in" "dlib-1.pc" @ONLY)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/dlib-1.pc"
+ DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
+
+ endif()
+
+endif()
diff --git a/app/src/main/jni/dlib/dlib/LICENSE.txt b/app/src/main/jni/dlib/dlib/LICENSE.txt
new file mode 100644
index 00000000..127a5bc3
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/LICENSE.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/app/src/main/jni/dlib/dlib/algs.h b/app/src/main/jni/dlib/dlib/algs.h
new file mode 100644
index 00000000..3a7fa5e4
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/algs.h
@@ -0,0 +1,1048 @@
+// Copyright (C) 2003 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+
+#ifdef DLIB_ALL_SOURCE_END
+#include "dlib_basic_cpp_build_tutorial.txt"
+#endif
+
+#ifndef DLIB_ALGs_
+#define DLIB_ALGs_
+
+// this file contains miscellaneous stuff
+
+
+#ifdef _MSC_VER
+// Disable the following warnings for Visual Studio
+
+// this is to disable the "'this' : used in base member initializer list"
+// warning you get from some of the GUI objects since all the objects
+// require that their parent class be passed into their constructor.
+// In this case though it is totally safe so it is ok to disable this warning.
+#pragma warning(disable : 4355)
+
+// This is a warning you get sometimes when Visual Studio performs a Koenig Lookup.
+// This is a bug in visual studio. It is a totally legitimate thing to
+// expect from a compiler.
+#pragma warning(disable : 4675)
+
+// This is a warning you get from visual studio 2005 about things in the standard C++
+// library being "deprecated." I checked the C++ standard and it doesn't say jack
+// about any of them (I checked the searchable PDF). So this warning is total Bunk.
+#pragma warning(disable : 4996)
+
+// This is a warning you get from visual studio 2003:
+// warning C4345: behavior change: an object of POD type constructed with an initializer
+// of the form () will be default-initialized.
+// I love it when this compiler gives warnings about bugs in previous versions of itself.
+#pragma warning(disable : 4345)
+
+
+// Disable warnings about conversion from size_t to unsigned long and long.
+#pragma warning(disable : 4267)
+
+// Disable warnings about conversion from double to float
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+
+// Disable "warning C4180: qualifier applied to function type has no meaning; ignored".
+// This warning happens often in generic code that works with functions and isn't useful.
+#pragma warning(disable : 4180)
+
+// Disable "warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)"
+#pragma warning(disable : 4290)
+
+#endif
+
+#ifdef __BORLANDC__
+// Disable the following warnings for the Borland Compilers
+//
+// These warnings just say that the compiler is refusing to inline functions with
+// loops or try blocks in them.
+//
+#pragma option -w-8027
+#pragma option -w-8026
+#endif
+
+#include // for the exceptions
+
+#ifdef __CYGWIN__
+namespace std
+{
+ typedef std::basic_string wstring;
+}
+#endif
+
+#include "platform.h"
+#include "windows_magic.h"
+
+
+#include // for std::swap
+#include // for std::bad_alloc
+#include
+#include // for std::numeric_limits for is_finite()
+#include "assert.h"
+#include "error.h"
+#include "noncopyable.h"
+#include "enable_if.h"
+#include "uintn.h"
+#include "numeric_constants.h"
+#include "memory_manager_stateless/memory_manager_stateless_kernel_1.h" // for the default memory manager
+
+
+
+// ----------------------------------------------------------------------------------------
+/*!A _dT !*/
+
+template
+inline charT _dTcast (const char a, const wchar_t b);
+template <>
+inline char _dTcast (const char a, const wchar_t ) { return a; }
+template <>
+inline wchar_t _dTcast (const char , const wchar_t b) { return b; }
+
+template
+inline const charT* _dTcast ( const char* a, const wchar_t* b);
+template <>
+inline const char* _dTcast ( const char* a, const wchar_t* ) { return a; }
+template <>
+inline const wchar_t* _dTcast ( const char* , const wchar_t* b) { return b; }
+
+
+#define _dT(charT,str) _dTcast(str,L##str)
+/*!
+ requires
+ - charT == char or wchar_t
+ - str == a string or character literal
+ ensures
+ - returns the literal in the form of a charT type literal.
+!*/
+
+// ----------------------------------------------------------------------------------------
+
+
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A default_memory_manager
+
+ This memory manager just calls new and delete directly.
+
+ !*/
+ typedef memory_manager_stateless_kernel_1 default_memory_manager;
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A swap !*/
+ // make swap available in the dlib namespace
+ using std::swap;
+
+// ----------------------------------------------------------------------------------------
+
+ /*!
+ Here is where I define my return codes. It is
+ important that they all be < 0.
+ !*/
+
+ enum general_return_codes
+ {
+ TIMEOUT = -1,
+ WOULDBLOCK = -2,
+ OTHER_ERROR = -3,
+ SHUTDOWN = -4,
+ PORTINUSE = -5
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ inline unsigned long square_root (
+ unsigned long value
+ )
+ /*!
+ requires
+ - value <= 2^32 - 1
+ ensures
+ - returns the square root of value. if the square root is not an
+ integer then it will be rounded up to the nearest integer.
+ !*/
+ {
+ unsigned long x;
+
+ // set the initial guess for what the root is depending on
+ // how big value is
+ if (value < 3)
+ return value;
+ else if (value < 4096) // 12
+ x = 45;
+ else if (value < 65536) // 16
+ x = 179;
+ else if (value < 1048576) // 20
+ x = 717;
+ else if (value < 16777216) // 24
+ x = 2867;
+ else if (value < 268435456) // 28
+ x = 11469;
+ else // 32
+ x = 45875;
+
+
+
+ // find the root
+ x = (x + value/x)>>1;
+ x = (x + value/x)>>1;
+ x = (x + value/x)>>1;
+ x = (x + value/x)>>1;
+
+
+
+ if (x*x < value)
+ return x+1;
+ else
+ return x;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ void median (
+ T& one,
+ T& two,
+ T& three
+ );
+ /*!
+ requires
+ - T implements operator<
+ - T is swappable by a global swap()
+ ensures
+ - #one is the median
+ - #one, #two, and #three is some permutation of one, two, and three.
+ !*/
+
+
+ template <
+ typename T
+ >
+ void median (
+ T& one,
+ T& two,
+ T& three
+ )
+ {
+ using std::swap;
+ using dlib::swap;
+
+ if ( one < two )
+ {
+ // one < two
+ if ( two < three )
+ {
+ // one < two < three : two
+ swap(one,two);
+
+ }
+ else
+ {
+ // one < two >= three
+ if ( one < three)
+ {
+ // three
+ swap(three,one);
+ }
+ }
+
+ }
+ else
+ {
+ // one >= two
+ if ( three < one )
+ {
+ // three <= one >= two
+ if ( three < two )
+ {
+ // two
+ swap(two,one);
+ }
+ else
+ {
+ // three
+ swap(three,one);
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ namespace relational_operators
+ {
+ template <
+ typename A,
+ typename B
+ >
+ bool operator> (
+ const A& a,
+ const B& b
+ ) { return b < a; }
+
+ // ---------------------------------
+
+ template <
+ typename A,
+ typename B
+ >
+ bool operator!= (
+ const A& a,
+ const B& b
+ ) { return !(a == b); }
+
+ // ---------------------------------
+
+ template <
+ typename A,
+ typename B
+ >
+ bool operator<= (
+ const A& a,
+ const B& b
+ ) { return !(b < a); }
+
+ // ---------------------------------
+
+ template <
+ typename A,
+ typename B
+ >
+ bool operator>= (
+ const A& a,
+ const B& b
+ ) { return !(a < b); }
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ void exchange (
+ T& a,
+ T& b
+ )
+ /*!
+ This function does the exact same thing that global swap does and it does it by
+ just calling swap. But a lot of compilers have problems doing a Koenig Lookup
+ and the fact that this has a different name (global swap has the same name as
+ the member functions called swap) makes them compile right.
+
+ So this is a workaround but not too ugly of one. But hopefully I get get
+ rid of this in a few years. So this function is already deprecated.
+
+ This also means you should NOT use this function in your own code unless
+ you have to support an old buggy compiler that benefits from this hack.
+ !*/
+ {
+ using std::swap;
+ using dlib::swap;
+ swap(a,b);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_pointer_type
+
+ This is a template where is_pointer_type::value == true when T is a pointer
+ type and false otherwise.
+ !*/
+
+ template <
+ typename T
+ >
+ class is_pointer_type
+ {
+ public:
+ enum { value = false };
+ private:
+ is_pointer_type();
+ };
+
+ template <
+ typename T
+ >
+ class is_pointer_type
+ {
+ public:
+ enum { value = true };
+ private:
+ is_pointer_type();
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_const_type
+
+ This is a template where is_const_type::value == true when T is a const
+ type and false otherwise.
+ !*/
+
+ template
+ struct is_const_type
+ {
+ static const bool value = false;
+ };
+ template
+ struct is_const_type
+ {
+ static const bool value = true;
+ };
+ template
+ struct is_const_type
+ {
+ static const bool value = true;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_reference_type
+
+ This is a template where is_reference_type::value == true when T is a reference
+ type and false otherwise.
+ !*/
+
+ template
+ struct is_reference_type
+ {
+ static const bool value = false;
+ };
+
+ template struct is_reference_type { static const bool value = true; };
+ template struct is_reference_type { static const bool value = true; };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_same_type
+
+ This is a template where is_same_type::value == true when T and U are the
+ same type and false otherwise.
+ !*/
+
+ template <
+ typename T,
+ typename U
+ >
+ class is_same_type
+ {
+ public:
+ enum {value = false};
+ private:
+ is_same_type();
+ };
+
+ template
+ class is_same_type
+ {
+ public:
+ enum {value = true};
+ private:
+ is_same_type();
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_float_type
+
+ This is a template that can be used to determine if a type is one of the built
+ int floating point types (i.e. float, double, or long double).
+ !*/
+
+ template < typename T > struct is_float_type { const static bool value = false; };
+ template <> struct is_float_type { const static bool value = true; };
+ template <> struct is_float_type { const static bool value = true; };
+ template <> struct is_float_type { const static bool value = true; };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_convertible
+
+ This is a template that can be used to determine if one type is convertible
+ into another type.
+
+ For example:
+ is_convertible::value == true // because ints are convertible to floats
+ is_convertible::value == false // because int pointers are NOT convertible to floats
+ !*/
+
+ template
+ struct is_convertible
+ {
+ struct yes_type { char a; };
+ struct no_type { yes_type a[2]; };
+ static const from& from_helper();
+ static yes_type test(to);
+ static no_type test(...);
+ const static bool value = sizeof(test(from_helper())) == sizeof(yes_type);
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ struct general_ {};
+ struct special_ : general_ {};
+ template struct int_ { typedef int type; };
+
+// ----------------------------------------------------------------------------------------
+
+
+ /*!A is_same_object
+
+ This is a templated function which checks if both of its arguments are actually
+ references to the same object. It returns true if they are and false otherwise.
+
+ !*/
+
+ // handle the case where T and U are unrelated types.
+ template < typename T, typename U >
+ typename disable_if_c::value || is_convertible::value, bool>::type
+ is_same_object (
+ const T& a,
+ const U& b
+ )
+ {
+ return ((void*)&a == (void*)&b);
+ }
+
+ // handle the case where T and U are related types because their pointers can be
+ // implicitly converted into one or the other. E.g. a derived class and its base class.
+ // Or where both T and U are just the same type. This way we make sure that if there is a
+ // valid way to convert between these two pointer types then we will take that route rather
+ // than the void* approach used otherwise.
+ template < typename T, typename U >
+ typename enable_if_c::value || is_convertible::value, bool>::type
+ is_same_object (
+ const T& a,
+ const U& b
+ )
+ {
+ return (&a == &b);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_unsigned_type
+
+ This is a template where is_unsigned_type::value == true when T is an unsigned
+ scalar type and false when T is a signed scalar type.
+ !*/
+ template <
+ typename T
+ >
+ struct is_unsigned_type
+ {
+ static const bool value = static_cast((static_cast(0)-static_cast(1))) > 0;
+ };
+ template <> struct is_unsigned_type { static const bool value = false; };
+ template <> struct is_unsigned_type { static const bool value = false; };
+ template <> struct is_unsigned_type { static const bool value = false; };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_signed_type
+
+ This is a template where is_signed_type::value == true when T is a signed
+ scalar type and false when T is an unsigned scalar type.
+ !*/
+ template <
+ typename T
+ >
+ struct is_signed_type
+ {
+ static const bool value = !is_unsigned_type::value;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ class copy_functor
+ {
+ public:
+ void operator() (
+ const T& source,
+ T& destination
+ ) const
+ {
+ destination = source;
+ }
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A static_switch
+
+ To use this template you give it some number of boolean expressions and it
+ tells you which one of them is true. If more than one of them is true then
+ it causes a compile time error.
+
+ for example:
+ static_switch<1 + 1 == 2, 4 - 1 == 4>::value == 1 // because the first expression is true
+ static_switch<1 + 1 == 3, 4 == 4>::value == 2 // because the second expression is true
+ static_switch<1 + 1 == 3, 4 == 5>::value == 0 // 0 here because none of them are true
+ static_switch<1 + 1 == 2, 4 == 4>::value == compiler error // because more than one expression is true
+ !*/
+
+ template < bool v1 = 0, bool v2 = 0, bool v3 = 0, bool v4 = 0, bool v5 = 0,
+ bool v6 = 0, bool v7 = 0, bool v8 = 0, bool v9 = 0, bool v10 = 0,
+ bool v11 = 0, bool v12 = 0, bool v13 = 0, bool v14 = 0, bool v15 = 0 >
+ struct static_switch;
+
+ template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 0; };
+ template <> struct static_switch<1,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 1; };
+ template <> struct static_switch<0,1,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 2; };
+ template <> struct static_switch<0,0,1,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 3; };
+ template <> struct static_switch<0,0,0,1,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 4; };
+ template <> struct static_switch<0,0,0,0,1,0,0,0,0,0,0,0,0,0,0> { const static int value = 5; };
+ template <> struct static_switch<0,0,0,0,0,1,0,0,0,0,0,0,0,0,0> { const static int value = 6; };
+ template <> struct static_switch<0,0,0,0,0,0,1,0,0,0,0,0,0,0,0> { const static int value = 7; };
+ template <> struct static_switch<0,0,0,0,0,0,0,1,0,0,0,0,0,0,0> { const static int value = 8; };
+ template <> struct static_switch<0,0,0,0,0,0,0,0,1,0,0,0,0,0,0> { const static int value = 9; };
+ template <> struct static_switch<0,0,0,0,0,0,0,0,0,1,0,0,0,0,0> { const static int value = 10; };
+ template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,1,0,0,0,0> { const static int value = 11; };
+ template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,1,0,0,0> { const static int value = 12; };
+ template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,1,0,0> { const static int value = 13; };
+ template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,1,0> { const static int value = 14; };
+ template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,1> { const static int value = 15; };
+
+// ----------------------------------------------------------------------------------------
+ /*!A is_built_in_scalar_type
+
+ This is a template that allows you to determine if the given type is a built
+ in scalar type such as an int, char, float, short, etc.
+
+ For example, is_built_in_scalar_type::value == true
+ For example, is_built_in_scalar_type::value == false
+ !*/
+
+ template struct is_built_in_scalar_type { const static bool value = false; };
+
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+ // Don't define one for wchar_t when using a version of visual studio
+ // older than 8.0 (visual studio 2005) since before then they improperly set
+ // wchar_t to be a typedef rather than its own type as required by the C++
+ // standard.
+#if !defined(_MSC_VER) || _NATIVE_WCHAR_T_DEFINED
+ template <> struct is_built_in_scalar_type { const static bool value = true; };
+#endif
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ typename enable_if,bool>::type is_finite (
+ const T& value
+ )
+ /*!
+ requires
+ - value must be some kind of scalar type such as int or double
+ ensures
+ - returns true if value is a finite value (e.g. not infinity or NaN) and false
+ otherwise.
+ !*/
+ {
+ if (is_float_type::value)
+ return -std::numeric_limits::infinity() < value && value < std::numeric_limits::infinity();
+ else
+ return true;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A promote
+
+ This is a template that takes one of the built in scalar types and gives you another
+ scalar type that should be big enough to hold sums of values from the original scalar
+ type. The new scalar type will also always be signed.
+
+ For example, promote::type == int32
+ !*/
+
+ template struct promote;
+ template struct promote { typedef int32 type; };
+ template struct promote { typedef int32 type; };
+ template struct promote { typedef int64 type; };
+ template struct promote { typedef int64 type; };
+
+ template <> struct promote { typedef double type; };
+ template <> struct promote { typedef double type; };
+ template <> struct promote { typedef long double type; };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A assign_zero_if_built_in_scalar_type
+
+ This function assigns its argument the value of 0 if it is a built in scalar
+ type according to the is_built_in_scalar_type<> template. If it isn't a
+ built in scalar type then it does nothing.
+ !*/
+
+ template inline typename disable_if,void>::type assign_zero_if_built_in_scalar_type (T&){}
+ template inline typename enable_if,void>::type assign_zero_if_built_in_scalar_type (T& a){a=0;}
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A basic_type
+
+ This is a template that takes a type and strips off any const, volatile, or reference
+ qualifiers and gives you back the basic underlying type. So for example:
+
+ basic_type::type == int
+ !*/
+
+ template struct basic_type { typedef T type; };
+ template struct basic_type { typedef T type; };
+ template struct basic_type { typedef T type; };
+ template struct basic_type { typedef T type; };
+ template struct basic_type { typedef T type; };
+ template struct basic_type { typedef T type; };
+ template struct basic_type { typedef T type; };
+ template struct basic_type { typedef T type; };
+
+// ----------------------------------------------------------------------------------------
+
+ template
+ T put_in_range (
+ const T& a,
+ const T& b,
+ const T& val
+ )
+ /*!
+ requires
+ - T is a type that looks like double, float, int, or so forth
+ ensures
+ - if (val is within the range [a,b]) then
+ - returns val
+ - else
+ - returns the end of the range [a,b] that is closest to val
+ !*/
+ {
+ if (a < b)
+ {
+ if (val < a)
+ return a;
+ else if (val > b)
+ return b;
+ }
+ else
+ {
+ if (val < b)
+ return b;
+ else if (val > a)
+ return a;
+ }
+
+ return val;
+ }
+
+ // overload for double
+ inline double put_in_range(const double& a, const double& b, const double& val)
+ { return put_in_range(a,b,val); }
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A tabs
+
+ This is a template to compute the absolute value a number at compile time.
+
+ For example,
+ abs<-4>::value == 4
+ abs<4>::value == 4
+ !*/
+
+ template
+ struct tabs { const static long value = x; };
+ template
+ struct tabs::type> { const static long value = -x; };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A tmax
+
+ This is a template to compute the max of two values at compile time
+
+ For example,
+ abs<4,7>::value == 7
+ !*/
+
+ template
+ struct tmax { const static long value = x; };
+ template
+ struct tmax x)>::type> { const static long value = y; };
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A tmin
+
+ This is a template to compute the min of two values at compile time
+
+ For example,
+ abs<4,7>::value == 4
+ !*/
+
+ template
+ struct tmin { const static long value = x; };
+ template
+ struct tmin::type> { const static long value = y; };
+
+ // ----------------------------------------------------------------------------------------
+
+#define DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(testname, returnT, funct_name, args) \
+ struct _two_bytes_##testname { char a[2]; }; \
+ template < typename T, returnT (T::*funct)args > \
+ struct _helper_##testname { typedef char type; }; \
+ template \
+ static char _has_##testname##_helper( typename _helper_##testname::type ) { return 0;} \
+ template \
+ static _two_bytes_##testname _has_##testname##_helper(int) { return _two_bytes_##testname();} \
+ template struct _##testname##workaroundbug { \
+ const static unsigned long U = sizeof(_has_##testname##_helper('a')); }; \
+ template ::U > \
+ struct testname { static const bool value = false; }; \
+ template \
+ struct testname { static const bool value = true; };
+ /*!A DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST
+
+ The DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST() macro is used to define traits templates
+ that tell you if a class has a certain member function. For example, to make a
+ test to see if a class has a public method with the signature void print(int) you
+ would say:
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, (int))
+
+ Then you can check if a class, T, has this method by looking at the boolean value:
+ has_print::value
+ which will be true if the member function is in the T class.
+
+ Note that you can test for member functions taking no arguments by simply passing
+ in empty () like so:
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ())
+ This would test for a member of the form:
+ void print().
+
+ To test for const member functions you would use a statement such as this:
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ()const)
+ This would test for a member of the form:
+ void print() const.
+
+ To test for const templated member functions you would use a statement such as this:
+ DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, template print, ())
+ This would test for a member of the form:
+ template void print().
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ /*!A is_function
+
+ This is a template that allows you to determine if the given type is a function.
+
+ For example,
+ void funct();
+
+ is_built_in_scalar_type::value == true
+ is_built_in_scalar_type::value == false
+ !*/
+
+ template struct is_function { static const bool value = false; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+ template
+ struct is_function { static const bool value = true; };
+
+
+ template class funct_wrap0
+ {
+ public:
+ funct_wrap0(T (&f_)()):f(f_){}
+ T operator()() const { return f(); }
+ private:
+ T (&f)();
+ };
+ template class funct_wrap1
+ {
+ public:
+ funct_wrap1(T (&f_)(A0)):f(f_){}
+ T operator()(A0 a0) const { return f(a0); }
+ private:
+ T (&f)(A0);
+ };
+ template class funct_wrap2
+ {
+ public:
+ funct_wrap2(T (&f_)(A0,A1)):f(f_){}
+ T operator()(A0 a0, A1 a1) const { return f(a0,a1); }
+ private:
+ T (&f)(A0,A1);
+ };
+ template class funct_wrap3
+ {
+ public:
+ funct_wrap3(T (&f_)(A0,A1,A2)):f(f_){}
+ T operator()(A0 a0, A1 a1, A2 a2) const { return f(a0,a1,a2); }
+ private:
+ T (&f)(A0,A1,A2);
+ };
+ template class funct_wrap4
+ {
+ public:
+ funct_wrap4(T (&f_)(A0,A1,A2,A3)):f(f_){}
+ T operator()(A0 a0, A1 a1, A2 a2, A3 a3) const { return f(a0,a1,a2,a3); }
+ private:
+ T (&f)(A0,A1,A2,A3);
+ };
+ template class funct_wrap5
+ {
+ public:
+ funct_wrap5(T (&f_)(A0,A1,A2,A3,A4)):f(f_){}
+ T operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { return f(a0,a1,a2,a3,a4); }
+ private:
+ T (&f)(A0,A1,A2,A3,A4);
+ };
+
+ /*!A wrap_function
+
+ This is a template that allows you to turn a global function into a
+ function object. The reason for this template's existance is so you can
+ do stuff like this:
+
+ template
+ void call_funct(const T& funct)
+ { cout << funct(); }
+
+ std::string test() { return "asdfasf"; }
+
+ int main()
+ {
+ call_funct(wrap_function(test));
+ }
+
+ The above code doesn't work right on some compilers if you don't
+ use wrap_function.
+ !*/
+
+ template
+ funct_wrap0 wrap_function(T (&f)()) { return funct_wrap0(f); }
+ template
+ funct_wrap1 wrap_function(T (&f)(A0)) { return funct_wrap1(f); }
+ template
+ funct_wrap2 wrap_function(T (&f)(A0, A1)) { return funct_wrap2(f); }
+ template
+ funct_wrap3 wrap_function(T (&f)(A0, A1, A2)) { return funct_wrap3(f); }
+ template
+ funct_wrap4 wrap_function(T (&f)(A0, A1, A2, A3)) { return funct_wrap4(f); }
+ template
+ funct_wrap5 wrap_function(T (&f)(A0, A1, A2, A3, A4)) { return funct_wrap5(f); }
+
+// ----------------------------------------------------------------------------------------
+
+ template
+ class stack_based_memory_block : noncopyable
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object is a simple container for a block of memory
+ of bSIZE bytes. This memory block is located on the stack
+ and properly aligned to hold any kind of object.
+ !*/
+ public:
+ static const unsigned long size = bSIZE;
+
+ stack_based_memory_block(): data(mem.data) {}
+
+ void* get () { return data; }
+ /*!
+ ensures
+ - returns a pointer to the block of memory contained in this object
+ !*/
+
+ const void* get () const { return data; }
+ /*!
+ ensures
+ - returns a pointer to the block of memory contained in this object
+ !*/
+
+ private:
+
+ // You obviously can't have a block of memory that has zero bytes in it.
+ COMPILE_TIME_ASSERT(bSIZE > 0);
+
+ union mem_block
+ {
+ // All of this garbage is to make sure this union is properly aligned
+ // (a union is always aligned such that everything in it would be properly
+ // aligned. So the assumption here is that one of these objects has
+ // a large enough alignment requirement to satisfy any object this
+ // block of memory might be cast into).
+ void* void_ptr;
+ int integer;
+ struct {
+ void (stack_based_memory_block::*callback)();
+ stack_based_memory_block* o;
+ } stuff;
+ long double more_stuff;
+
+ uint64 var1;
+ uint32 var2;
+ double var3;
+
+ char data[size];
+ } mem;
+
+ // The reason for having this variable is that doing it this way avoids
+ // warnings from gcc about violations of strict-aliasing rules.
+ void* const data;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_ALGs_
+
diff --git a/app/src/main/jni/dlib/dlib/all/source.cpp b/app/src/main/jni/dlib/dlib/all/source.cpp
new file mode 100644
index 00000000..0413b21b
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/all/source.cpp
@@ -0,0 +1,92 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_ALL_SOURCe_
+#define DLIB_ALL_SOURCe_
+
+#if defined(DLIB_ALGs_) || defined(DLIB_PLATFORm_)
+#include "../dlib_basic_cpp_build_tutorial.txt"
+#endif
+
+// ISO C++ code
+#include "../base64/base64_kernel_1.cpp"
+#include "../bigint/bigint_kernel_1.cpp"
+#include "../bigint/bigint_kernel_2.cpp"
+#include "../bit_stream/bit_stream_kernel_1.cpp"
+#include "../entropy_decoder/entropy_decoder_kernel_1.cpp"
+#include "../entropy_decoder/entropy_decoder_kernel_2.cpp"
+#include "../entropy_encoder/entropy_encoder_kernel_1.cpp"
+#include "../entropy_encoder/entropy_encoder_kernel_2.cpp"
+#include "../md5/md5_kernel_1.cpp"
+#include "../tokenizer/tokenizer_kernel_1.cpp"
+#include "../unicode/unicode.cpp"
+#include "../data_io/image_dataset_metadata.cpp"
+#include "../data_io/mnist.cpp"
+
+// Stuff that requires C++11
+#if __cplusplus >= 201103
+#include "../dnn/cpu_dlib.cpp"
+#include "../dnn/tensor_tools.cpp"
+#endif
+
+#ifndef DLIB_ISO_CPP_ONLY
+// Code that depends on OS specific APIs
+
+// include this first so that it can disable the older version
+// of the winsock API when compiled in windows.
+#include "../sockets/sockets_kernel_1.cpp"
+#include "../bsp/bsp.cpp"
+
+#include "../dir_nav/dir_nav_kernel_1.cpp"
+#include "../dir_nav/dir_nav_kernel_2.cpp"
+#include "../dir_nav/dir_nav_extensions.cpp"
+#include "../linker/linker_kernel_1.cpp"
+#include "../logger/extra_logger_headers.cpp"
+#include "../logger/logger_kernel_1.cpp"
+#include "../logger/logger_config_file.cpp"
+#include "../misc_api/misc_api_kernel_1.cpp"
+#include "../misc_api/misc_api_kernel_2.cpp"
+#include "../sockets/sockets_extensions.cpp"
+#include "../sockets/sockets_kernel_2.cpp"
+#include "../sockstreambuf/sockstreambuf.cpp"
+#include "../sockstreambuf/sockstreambuf_unbuffered.cpp"
+#include "../server/server_kernel.cpp"
+#include "../server/server_iostream.cpp"
+#include "../server/server_http.cpp"
+#include "../threads/multithreaded_object_extension.cpp"
+#include "../threads/threaded_object_extension.cpp"
+#include "../threads/threads_kernel_1.cpp"
+#include "../threads/threads_kernel_2.cpp"
+#include "../threads/threads_kernel_shared.cpp"
+#include "../threads/thread_pool_extension.cpp"
+#include "../threads/async.cpp"
+#include "../timer/timer.cpp"
+#include "../stack_trace.cpp"
+
+#ifdef DLIB_PNG_SUPPORT
+#include "../image_loader/png_loader.cpp"
+#include "../image_saver/save_png.cpp"
+#endif
+
+#ifdef DLIB_JPEG_SUPPORT
+#include "../image_loader/jpeg_loader.cpp"
+#include "../image_saver/save_jpeg.cpp"
+#endif
+
+#ifndef DLIB_NO_GUI_SUPPORT
+#include "../gui_widgets/fonts.cpp"
+#include "../gui_widgets/widgets.cpp"
+#include "../gui_widgets/drawable.cpp"
+#include "../gui_widgets/canvas_drawing.cpp"
+#include "../gui_widgets/style.cpp"
+#include "../gui_widgets/base_widgets.cpp"
+#include "../gui_core/gui_core_kernel_1.cpp"
+#include "../gui_core/gui_core_kernel_2.cpp"
+#endif // DLIB_NO_GUI_SUPPORT
+
+#endif // DLIB_ISO_CPP_ONLY
+
+
+#define DLIB_ALL_SOURCE_END
+
+#endif // DLIB_ALL_SOURCe_
+
diff --git a/app/src/main/jni/dlib/dlib/all_console.cpp b/app/src/main/jni/dlib/dlib/all_console.cpp
new file mode 100644
index 00000000..556983be
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/all_console.cpp
@@ -0,0 +1,9 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_ALL_CONSOLe_
+#define DLIB_ALL_CONSOLe_
+
+#error "This file has been replaced. Instead you should add dlib/all/source.cpp to your project"
+
+#endif // DLIB_ALL_CONSOLe_
+
diff --git a/app/src/main/jni/dlib/dlib/all_gui.cpp b/app/src/main/jni/dlib/dlib/all_gui.cpp
new file mode 100644
index 00000000..cd397dbf
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/all_gui.cpp
@@ -0,0 +1,9 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_ALL_GUi_
+#define DLIB_ALL_GUi_
+
+#error "This file has been replaced. Instead you should add dlib/all/source.cpp to your project"
+
+#endif // DLIB_ALL_GUi_
+
diff --git a/app/src/main/jni/dlib/dlib/any.h b/app/src/main/jni/dlib/dlib/any.h
new file mode 100644
index 00000000..01f04706
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/any.h
@@ -0,0 +1,13 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_AnY_
+#define DLIB_AnY_
+
+#include "any/any.h"
+#include "any/any_trainer.h"
+#include "any/any_decision_function.h"
+#include "any/any_function.h"
+
+#endif // DLIB_AnY_
+
+
diff --git a/app/src/main/jni/dlib/dlib/any/any.h b/app/src/main/jni/dlib/dlib/any/any.h
new file mode 100644
index 00000000..6d9938d6
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/any/any.h
@@ -0,0 +1,181 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_AnY_H_
+#define DLIB_AnY_H_
+
+#include "any_abstract.h"
+#include "../smart_pointers.h"
+#include
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ class bad_any_cast : public std::bad_cast
+ {
+ public:
+ virtual const char * what() const throw()
+ {
+ return "bad_any_cast";
+ }
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class any
+ {
+
+ public:
+
+ any()
+ {
+ }
+
+ any (
+ const any& item
+ )
+ {
+ if (item.data)
+ {
+ item.data->copy_to(data);
+ }
+ }
+
+ template
+ any (
+ const T& item
+ )
+ {
+ typedef typename basic_type::type U;
+ data.reset(new derived(item));
+ }
+
+ void clear (
+ )
+ {
+ data.reset();
+ }
+
+ template
+ bool contains (
+ ) const
+ {
+ typedef typename basic_type::type U;
+ return dynamic_cast*>(data.get()) != 0;
+ }
+
+ bool is_empty(
+ ) const
+ {
+ return data.get() == 0;
+ }
+
+ template
+ T& cast_to(
+ )
+ {
+ typedef typename basic_type::type U;
+ derived* d = dynamic_cast*>(data.get());
+ if (d == 0)
+ {
+ throw bad_any_cast();
+ }
+
+ return d->item;
+ }
+
+ template
+ const T& cast_to(
+ ) const
+ {
+ typedef typename basic_type::type U;
+ derived* d = dynamic_cast*>(data.get());
+ if (d == 0)
+ {
+ throw bad_any_cast();
+ }
+
+ return d->item;
+ }
+
+ template
+ T& get(
+ )
+ {
+ typedef typename basic_type::type U;
+ derived* d = dynamic_cast*>(data.get());
+ if (d == 0)
+ {
+ d = new derived();
+ data.reset(d);
+ }
+
+ return d->item;
+ }
+
+ any& operator= (
+ const any& item
+ )
+ {
+ any(item).swap(*this);
+ return *this;
+ }
+
+ void swap (
+ any& item
+ )
+ {
+ data.swap(item.data);
+ }
+
+ private:
+
+ struct base
+ {
+ virtual ~base() {}
+
+ virtual void copy_to (
+ scoped_ptr& dest
+ ) const = 0;
+ };
+
+ template
+ struct derived : public base
+ {
+ T item;
+ derived() {}
+ derived(const T& val) : item(val) {}
+
+ virtual void copy_to (
+ scoped_ptr& dest
+ ) const
+ {
+ dest.reset(new derived(item));
+ }
+ };
+
+ scoped_ptr data;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ inline void swap (
+ any& a,
+ any& b
+ ) { a.swap(b); }
+
+// ----------------------------------------------------------------------------------------
+
+ template T& any_cast(any& a) { return a.cast_to(); }
+ template const T& any_cast(const any& a) { return a.cast_to(); }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+
+#endif // DLIB_AnY_H_
+
+
+
diff --git a/app/src/main/jni/dlib/dlib/any/any_abstract.h b/app/src/main/jni/dlib/dlib/any/any_abstract.h
new file mode 100644
index 00000000..2fea9638
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/any/any_abstract.h
@@ -0,0 +1,210 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#undef DLIB_AnY_ABSTRACT_H_
+#ifdef DLIB_AnY_ABSTRACT_H_
+
+#include
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ class bad_any_cast : public std::bad_cast
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This object is the exception class used by the any object.
+ It is used to indicate when someone attempts to cast an any
+ object into a type which isn't contained in the any object.
+ !*/
+
+ public:
+ virtual const char* what() const throw() { return "bad_any_cast"; }
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ class any
+ {
+ /*!
+ INITIAL VALUE
+ - is_empty() == true
+ - for all T: contains() == false
+
+ WHAT THIS OBJECT REPRESENTS
+ This object is basically a type-safe version of a void*. In particular,
+ it is a container which can contain only one object but the object may
+ be of any type.
+
+ It is somewhat like the type_safe_union except you don't have to declare
+ the set of possible content types beforehand. So in some sense this is
+ like a less type-strict version of the type_safe_union.
+ !*/
+
+ public:
+
+ any(
+ );
+ /*!
+ ensures
+ - this object is properly initialized
+ !*/
+
+ any (
+ const any& item
+ );
+ /*!
+ ensures
+ - copies the state of item into *this.
+ - Note that *this and item will contain independent copies of the
+ contents of item. That is, this function performs a deep
+ copy and therefore does not result in *this containing
+ any kind of reference to item.
+ !*/
+
+ template < typename T >
+ any (
+ const T& item
+ );
+ /*!
+ ensures
+ - #contains() == true
+ - #cast_to() == item
+ (i.e. a copy of item will be stored in *this)
+ !*/
+
+ void clear (
+ );
+ /*!
+ ensures
+ - #*this will have its default value. I.e. #is_empty() == true
+ !*/
+
+ template
+ bool contains (
+ ) const;
+ /*!
+ ensures
+ - if (this object currently contains an object of type T) then
+ - returns true
+ - else
+ - returns false
+ !*/
+
+ bool is_empty(
+ ) const;
+ /*!
+ ensures
+ - if (this object contains any kind of object) then
+ - returns false
+ - else
+ - returns true
+ !*/
+
+ template
+ T& cast_to(
+ );
+ /*!
+ ensures
+ - if (contains() == true) then
+ - returns a non-const reference to the object contained within *this
+ - else
+ - throws bad_any_cast
+ !*/
+
+ template
+ const T& cast_to(
+ ) const;
+ /*!
+ ensures
+ - if (contains() == true) then
+ - returns a const reference to the object contained within *this
+ - else
+ - throws bad_any_cast
+ !*/
+
+ template
+ T& get(
+ );
+ /*!
+ ensures
+ - #is_empty() == false
+ - #contains() == true
+ - if (contains() == true)
+ - returns a non-const reference to the object contained in *this.
+ - else
+ - Constructs an object of type T inside *this
+ - Any previous object stored in this any object is destructed and its
+ state is lost.
+ - returns a non-const reference to the newly created T object.
+ !*/
+
+ any& operator= (
+ const any& item
+ );
+ /*!
+ ensures
+ - copies the state of item into *this.
+ - Note that *this and item will contain independent copies of the
+ contents of item. That is, this function performs a deep
+ copy and therefore does not result in *this containing
+ any kind of reference to item.
+ !*/
+
+ void swap (
+ any& item
+ );
+ /*!
+ ensures
+ - swaps *this and item
+ - does not invalidate pointers or references to the object contained
+ inside *this or item. Moreover, a pointer or reference to the object in
+ *this will now refer to the contents of #item and vice versa.
+ !*/
+
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ inline void swap (
+ any& a,
+ any& b
+ ) { a.swap(b); }
+ /*!
+ provides a global swap function
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ T& any_cast(
+ any& a
+ ) { return a.cast_to(); }
+ /*!
+ ensures
+ - returns a.cast_to()
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ const T& any_cast(
+ const any& a
+ ) { return a.cast_to(); }
+ /*!
+ ensures
+ - returns a.cast_to()
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_AnY_ABSTRACT_H_
+
+
diff --git a/app/src/main/jni/dlib/dlib/any/any_decision_function.h b/app/src/main/jni/dlib/dlib/any/any_decision_function.h
new file mode 100644
index 00000000..d165fcca
--- /dev/null
+++ b/app/src/main/jni/dlib/dlib/any/any_decision_function.h
@@ -0,0 +1,210 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_AnY_DECISION_FUNCTION_Hh_
+#define DLIB_AnY_DECISION_FUNCTION_Hh_
+
+#include "any.h"
+#include "../smart_pointers.h"
+
+#include "any_decision_function_abstract.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename sample_type_,
+ typename result_type_ = double
+ >
+ class any_decision_function
+ {
+
+ public:
+
+ typedef sample_type_ sample_type;
+ typedef result_type_ result_type;
+ typedef default_memory_manager mem_manager_type;
+
+ any_decision_function()
+ {
+ }
+
+ any_decision_function (
+ const any_decision_function& item
+ )
+ {
+ if (item.data)
+ {
+ item.data->copy_to(data);
+ }
+ }
+
+ template
+ any_decision_function (
+ const T& item
+ )
+ {
+ typedef typename basic_type::type U;
+ data.reset(new derived(item));
+ }
+
+ void clear (
+ )
+ {
+ data.reset();
+ }
+
+ template
+ bool contains (
+ ) const
+ {
+ typedef typename basic_type::type U;
+ return dynamic_cast*>(data.get()) != 0;
+ }
+
+ bool is_empty(
+ ) const
+ {
+ return data.get() == 0;
+ }
+
+ result_type operator() (
+ const sample_type& item
+ ) const
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(is_empty() == false,
+ "\t result_type any_decision_function::operator()"
+ << "\n\t You can't call operator() on an empty any_decision_function"
+ << "\n\t this: " << this
+ );
+
+ return data->evaluate(item);
+ }
+
+ template