diff --git a/deploy/lite/android/demo/.gitignore b/deploy/lite/android/demo/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2b75303ac58f551de0a327638a60b909c6d33ece
--- /dev/null
+++ b/deploy/lite/android/demo/.gitignore
@@ -0,0 +1,13 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/deploy/lite/android/demo/app/.gitignore b/deploy/lite/android/demo/app/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9
--- /dev/null
+++ b/deploy/lite/android/demo/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/deploy/lite/android/demo/app/build.gradle b/deploy/lite/android/demo/app/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..f743f1d23905566772c4e572e9700df5ad779ca0
--- /dev/null
+++ b/deploy/lite/android/demo/app/build.gradle
@@ -0,0 +1,119 @@
+import java.security.MessageDigest
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "com.baidu.paddlex.lite.demo"
+ minSdkVersion 15
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(include: ['*.aar'], dir: 'libs')
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ implementation 'com.android.support:design:28.0.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+}
+
+
+def paddlexAndroidSdk = 'https://bj.bcebos.com/paddlex/deploy/lite/paddlex_lite_11cbd50e.tar.gz'
+
+task downloadAndExtractPaddleXAndroidSdk(type: DefaultTask) {
+ doFirst {
+ println "Downloading and extracting PaddleX Android SDK"}
+ doLast {
+ // Prepare cache folder for sdk
+ if (!file("cache").exists()) {
+ mkdir "cache"
+ }
+ // Generate cache name for sdk
+ MessageDigest messageDigest = MessageDigest.getInstance('MD5')
+ messageDigest.update(paddlexAndroidSdk.bytes)
+ String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
+ // Download sdk
+ if (!file("cache/${cacheName}.tar.gz").exists()) {
+ ant.get(src: paddlexAndroidSdk, dest: file("cache/${cacheName}.tar.gz"))
+ }
+ // Unpack sdk
+ copy {
+ from tarTree("cache/${cacheName}.tar.gz")
+ into "cache/${cacheName}"
+ }
+ // Copy sdk
+ if (!file("libs/paddlex.aar").exists()) {
+ copy {
+ from "cache/${cacheName}/paddlex.aar"
+ into "libs"
+ }
+ }
+ }
+}
+
+preBuild.dependsOn downloadAndExtractPaddleXAndroidSdk
+
+def paddleXLiteModel = 'https://bj.bcebos.com/paddlex/deploy/lite/mobilenetv2_imagenet_lite2.6.1.tar.gz'
+task downloadAndExtractPaddleXLiteModel(type: DefaultTask) {
+ doFirst {
+ println "Downloading and extracting PaddleX Android SDK"}
+
+ doLast {
+ // Prepare cache folder for model
+ if (!file("cache").exists()) {
+ mkdir "cache"
+ }
+ // Generate cache name for model
+ MessageDigest messageDigest = MessageDigest.getInstance('MD5')
+ messageDigest.update(paddleXLiteModel.bytes)
+ String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
+ // Download sdk
+ if (!file("cache/${cacheName}.tar.gz").exists()) {
+ ant.get(src: paddleXLiteModel, dest: file("cache/${cacheName}.tar.gz"))
+ }
+
+ // Unpack model
+ copy {
+ from tarTree("cache/${cacheName}.tar.gz")
+ into "cache/${cacheName}"
+ }
+
+ // Copy model.nb
+ if (!file("src/main/assets/model/model.nb").exists()) {
+ copy {
+ from "cache/${cacheName}/model.nb"
+ into "src/main/assets/model/"
+ }
+ }
+ // Copy config file model.yml
+ if (!file("src/main/assets/config/model.yml").exists()) {
+ copy {
+ from "cache/${cacheName}/model.yml"
+ into "src/main/assets/config/"
+ }
+ }
+ // Copy config file model.yml
+ if (!file("src/main/assets/images/test.jpg").exists()) {
+ copy {
+ from "cache/${cacheName}/test.jpg"
+ into "src/main/assets/images/"
+ }
+ }
+ }
+
+}
+
+preBuild.dependsOn downloadAndExtractPaddleXLiteModel
diff --git a/deploy/lite/android/demo/app/proguard-rules.pro b/deploy/lite/android/demo/app/proguard-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f1b424510da51fd82143bc74a0a801ae5a1e2fcd
--- /dev/null
+++ b/deploy/lite/android/demo/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/deploy/lite/android/demo/app/src/androidTest/java/com/baidu/paddlex/lite/demo/ExampleInstrumentedTest.java b/deploy/lite/android/demo/app/src/androidTest/java/com/baidu/paddlex/lite/demo/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b58dec6f5dd8bfa083ec951d659dd0690f67221
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/androidTest/java/com/baidu/paddlex/lite/demo/ExampleInstrumentedTest.java
@@ -0,0 +1,32 @@
+package com.baidu.paddlex.lite.demo;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.baidu.paddlex.config.ConfigParser;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws IOException {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+ AssetManager ass = appContext.getAssets();
+ assertEquals("com.baidu.paddlex.lite.demo", appContext.getPackageName());
+ }
+}
diff --git a/deploy/lite/android/demo/app/src/main/AndroidManifest.xml b/deploy/lite/android/demo/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..940c9692fcf6fdfe6b07e8f4641fe7e9a9e5ff5f
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/AppCompatPreferenceActivity.java b/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/AppCompatPreferenceActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6f4eff8e736278c71ef2c34783dd3e1b3659495
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/AppCompatPreferenceActivity.java
@@ -0,0 +1,126 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.lite.demo;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatDelegate;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
+ * to be used with AppCompat.
+ *
+ * This technique can be used with an {@link android.app.Activity} class, not just
+ * {@link android.preference.PreferenceActivity}.
+ */
+
+public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
+ private AppCompatDelegate mDelegate;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ getDelegate().installViewFactory();
+ getDelegate().onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ getDelegate().onPostCreate(savedInstanceState);
+ }
+
+ public ActionBar getSupportActionBar() {
+ return getDelegate().getSupportActionBar();
+ }
+
+ public void setSupportActionBar(@Nullable Toolbar toolbar) {
+ getDelegate().setSupportActionBar(toolbar);
+ }
+
+ @Override
+ public MenuInflater getMenuInflater() {
+ return getDelegate().getMenuInflater();
+ }
+
+ @Override
+ public void setContentView(@LayoutRes int layoutResID) {
+ getDelegate().setContentView(layoutResID);
+ }
+
+ @Override
+ public void setContentView(View view) {
+ getDelegate().setContentView(view);
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ getDelegate().setContentView(view, params);
+ }
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ getDelegate().addContentView(view, params);
+ }
+
+ @Override
+ protected void onPostResume() {
+ super.onPostResume();
+ getDelegate().onPostResume();
+ }
+
+ @Override
+ protected void onTitleChanged(CharSequence title, int color) {
+ super.onTitleChanged(title, color);
+ getDelegate().setTitle(title);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ getDelegate().onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ getDelegate().onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ getDelegate().onDestroy();
+ }
+
+ public void invalidateOptionsMenu() {
+ getDelegate().invalidateOptionsMenu();
+ }
+
+ private AppCompatDelegate getDelegate() {
+ if (mDelegate == null) {
+ mDelegate = AppCompatDelegate.create(this, null);
+ }
+ return mDelegate;
+ }
+}
diff --git a/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/MainActivity.java b/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/MainActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..62e47214fc80a40fbfa173967f61e490eab92e47
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/MainActivity.java
@@ -0,0 +1,466 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.lite.demo;
+
+import android.Manifest;
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.preference.PreferenceManager;
+import android.provider.MediaStore;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.baidu.paddlex.Predictor;
+import com.baidu.paddlex.Utils;
+import com.baidu.paddlex.config.ConfigParser;
+import com.baidu.paddlex.postprocess.ClsResult;
+import com.baidu.paddlex.postprocess.DetResult;
+import com.baidu.paddlex.postprocess.SegResult;
+import com.baidu.paddlex.visual.Visualize;
+import org.opencv.core.Mat;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class MainActivity extends AppCompatActivity {
+ public static final int OPEN_GALLERY_REQUEST_CODE = 0;
+ public static final int TAKE_PHOTO_REQUEST_CODE = 1;
+ public static final int REQUEST_LOAD_MODEL = 0;
+ public static final int REQUEST_RUN_MODEL = 1;
+ public static final int RESPONSE_LOAD_MODEL_SUCCESSED = 0;
+ public static final int RESPONSE_LOAD_MODEL_FAILED = 1;
+ public static final int RESPONSE_RUN_MODEL_SUCCESSED = 2;
+ public static final int RESPONSE_RUN_MODEL_FAILED = 3;
+ private static final String TAG = MainActivity.class.getSimpleName();
+ protected ProgressDialog pbLoadModel = null;
+ protected ProgressDialog pbRunModel = null;
+
+ protected Handler receiver = null; // receive messages from worker thread
+ protected Handler sender = null; // send command to worker thread
+ protected HandlerThread worker = null; // worker thread to load&run model
+
+ protected TextView tvInputSetting;
+ protected ImageView ivInputImage;
+ protected TextView tvOutputResult;
+ protected TextView tvInferenceTime;
+ private Button predictButton;
+ protected String testImagePathFromAsset;
+ protected String testYamlPathFromAsset;
+ protected String testModelPathFromAsset;
+
+ // Predictor
+ protected Predictor predictor = new Predictor();
+ // model config
+ protected ConfigParser configParser = new ConfigParser();
+ // Visualize
+ protected Visualize visualize = new Visualize();
+ // Predict Mat of Opencv
+ protected Mat predictMat;
+
+
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ receiver = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case RESPONSE_LOAD_MODEL_SUCCESSED:
+ pbLoadModel.dismiss();
+ Toast.makeText(MainActivity.this, "Load model successfully!", Toast.LENGTH_SHORT).show();
+ break;
+ case RESPONSE_LOAD_MODEL_FAILED:
+ pbLoadModel.dismiss();
+ Toast.makeText(MainActivity.this, "Load model failed!", Toast.LENGTH_SHORT).show();
+ break;
+ case RESPONSE_RUN_MODEL_SUCCESSED:
+ pbRunModel.dismiss();
+ onRunModelSuccessed();
+ break;
+ case RESPONSE_RUN_MODEL_FAILED:
+ pbRunModel.dismiss();
+ Toast.makeText(MainActivity.this, "Run model failed!", Toast.LENGTH_SHORT).show();
+ onRunModelFailed();
+ break;
+ default:
+ break;
+ }
+ }
+ };
+ worker = new HandlerThread("Predictor Worker");
+ worker.start();
+ sender = new Handler(worker.getLooper()) {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case REQUEST_LOAD_MODEL:
+ // load model and reload test image
+ if (onLoadModel()) {
+ receiver.sendEmptyMessage(RESPONSE_LOAD_MODEL_SUCCESSED);
+ } else {
+ receiver.sendEmptyMessage(RESPONSE_LOAD_MODEL_FAILED);
+ }
+ break;
+ case REQUEST_RUN_MODEL:
+ // run model if model is loaded
+ if (onRunModel()) {
+ receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_SUCCESSED);
+ } else {
+ receiver.sendEmptyMessage(RESPONSE_RUN_MODEL_FAILED);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ tvInputSetting = findViewById(R.id.tv_input_setting);
+ ivInputImage = findViewById(R.id.iv_input_image);
+ predictButton = findViewById(R.id.iv_predict_button);
+ tvInferenceTime = findViewById(R.id.tv_inference_time);
+ tvOutputResult = findViewById(R.id.tv_output_result);
+ tvInputSetting.setMovementMethod(ScrollingMovementMethod.getInstance());
+ tvOutputResult.setMovementMethod(ScrollingMovementMethod.getInstance());
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ String image_path = sharedPreferences.getString(getString(R.string.IMAGE_PATH_KEY),
+ getString(R.string.IMAGE_PATH_DEFAULT));
+ Utils.initialOpencv();
+ loadTestImageFromAsset(image_path);
+ predictButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(predictor.isLoaded()){
+ onLoadModelSuccessed();
+ }
+ }
+ });
+
+ }
+
+ public boolean onLoadModel() {
+ return predictor.init(configParser);
+ }
+
+ public boolean onRunModel() {
+ return predictor.isLoaded() && predictor.predict();
+ }
+
+ public void onRunModelFailed() {
+ }
+
+ public void loadModel() {
+ pbLoadModel = ProgressDialog.show(this, "", "Loading model...", false, false);
+ sender.sendEmptyMessage(REQUEST_LOAD_MODEL);
+ }
+
+ public void runModel() {
+ pbRunModel = ProgressDialog.show(this, "", "Running model...", false, false);
+ sender.sendEmptyMessage(REQUEST_RUN_MODEL);
+ }
+
+ public void onLoadModelSuccessed() {
+ if (predictMat != null && predictor.isLoaded()) {
+ int w = predictMat.width();
+ int h = predictMat.height();
+ int c = predictMat.channels();
+ predictor.setInputMat(predictMat);
+ runModel();
+ }
+ }
+
+ public void onRunModelSuccessed() {
+ // obtain results and update UI
+ tvInferenceTime.setText("Inference time: " + predictor.getInferenceTime() + " ms");
+
+ if (configParser.getModelType().equalsIgnoreCase("segmenter")) {
+ SegResult segResult = predictor.getSegResult();
+ Mat maskMat = visualize.draw(segResult, predictMat.clone(), predictor.getImageBlob(), 1);
+ Imgproc.cvtColor(maskMat, maskMat, Imgproc.COLOR_BGRA2RGBA);
+ Bitmap outputImage = Bitmap.createBitmap(maskMat.width(), maskMat.height(), Bitmap.Config.ARGB_8888);
+ org.opencv.android.Utils.matToBitmap(maskMat, outputImage);
+ if (outputImage != null) {
+ ivInputImage.setImageBitmap(outputImage);
+ }
+ } else if (configParser.getModelType().equalsIgnoreCase("detector")) {
+ DetResult detResult = predictor.getDetResult();
+ Mat roiMat = visualize.draw(detResult, predictMat.clone());
+ Imgproc.cvtColor(roiMat, roiMat, Imgproc.COLOR_BGR2RGB);
+ Bitmap outputImage = Bitmap.createBitmap(roiMat.width(),roiMat.height(), Bitmap.Config.ARGB_8888);
+ org.opencv.android.Utils.matToBitmap(roiMat,outputImage);
+ if (outputImage != null) {
+ ivInputImage.setImageBitmap(outputImage);
+ }
+ } else if (configParser.getModelType().equalsIgnoreCase("classifier")) {
+ ClsResult clsResult = predictor.getClsResult();
+ if (configParser.getLabeList().size() > 0) {
+ String outputResult = "Top1: " + clsResult.getCategory() + " - " + String.format("%.3f", clsResult.getScore());
+ tvOutputResult.setText(outputResult);
+ tvOutputResult.scrollTo(0, 0);
+ }
+ }
+ }
+
+ public void onMatChanged(Mat mat) {
+ this.predictMat = mat.clone();
+ }
+
+ public void onImageChanged(Bitmap image) {
+ ivInputImage.setImageBitmap(image);
+ tvOutputResult.setText("");
+ tvInferenceTime.setText("Inference time: -- ms");
+ }
+
+ public void onSettingsClicked() {
+ startActivity(new Intent(MainActivity.this, SettingsActivity.class));
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.menu_action_options, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ break;
+ case R.id.open_gallery:
+ if (requestAllPermissions()) {
+ openGallery();
+ }
+ break;
+ case R.id.take_photo:
+ if (requestAllPermissions()) {
+ takePhoto();
+ }
+ break;
+ case R.id.settings:
+ if (requestAllPermissions()) {
+ // make sure we have SDCard r&w permissions to load model from SDCard
+ onSettingsClicked();
+ }
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK && data != null) {
+ switch (requestCode) {
+ case OPEN_GALLERY_REQUEST_CODE:
+ try {
+ ContentResolver resolver = getContentResolver();
+ Uri uri = data.getData();
+ Bitmap image = MediaStore.Images.Media.getBitmap(resolver, uri);
+ String[] proj = {MediaStore.Images.Media.DATA};
+ Cursor cursor = managedQuery(uri, proj, null, null, null);
+ cursor.moveToFirst();
+ int columnIndex = cursor.getColumnIndex(proj[0]);
+ String imgDecodableString = cursor.getString(columnIndex);
+ File file = new File(imgDecodableString);
+ Mat mat = Imgcodecs.imread(file.getAbsolutePath(),Imgcodecs.IMREAD_COLOR);
+ onImageChanged(image);
+ onMatChanged(mat);
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ }
+ break;
+ case TAKE_PHOTO_REQUEST_CODE:
+ Bitmap image = (Bitmap) data.getParcelableExtra("data");
+ Mat mat = new Mat();
+ org.opencv.android.Utils.bitmapToMat(image, mat);
+ Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGBA2BGR);
+ onImageChanged(image);
+ onMatChanged(mat);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private boolean requestAllPermissions() {
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,
+ Manifest.permission.CAMERA)
+ != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.CAMERA},
+ 0);
+ return false;
+ }
+ return true;
+ }
+
+ private void openGallery() {
+ Intent intent = new Intent(Intent.ACTION_PICK, null);
+ intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
+ startActivityForResult(intent, OPEN_GALLERY_REQUEST_CODE);
+ }
+
+ private void takePhoto() {
+ Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ if (takePhotoIntent.resolveActivity(getPackageManager()) != null) {
+ startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST_CODE);
+ }
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ boolean isLoaded = predictor.isLoaded();
+ menu.findItem(R.id.open_gallery).setEnabled(isLoaded);
+ menu.findItem(R.id.take_photo).setEnabled(isLoaded);
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ protected void onResume() {
+ Log.i(TAG, "begin onResume");
+ super.onResume();
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+ boolean settingsChanged = false;
+ boolean testImageChanged = false;
+ String modelPath = sharedPreferences.getString(getString(R.string.MODEL_PATH_KEY),
+ getString(R.string.MODEL_PATH_DEFAULT));
+ settingsChanged |= !modelPath.equalsIgnoreCase(testModelPathFromAsset);
+ String yamlPath = sharedPreferences.getString(getString(R.string.YAML_PATH_KEY),
+ getString(R.string.YAML_PATH_DEFAULT));
+ settingsChanged |= !yamlPath.equalsIgnoreCase(testYamlPathFromAsset);
+ int cpuThreadNum = Integer.parseInt(sharedPreferences.getString(getString(R.string.CPU_THREAD_NUM_KEY),
+ getString(R.string.CPU_THREAD_NUM_DEFAULT)));
+ settingsChanged |= cpuThreadNum != configParser.getCpuThreadNum();
+ String cpuPowerMode = sharedPreferences.getString(getString(R.string.CPU_POWER_MODE_KEY),
+ getString(R.string.CPU_POWER_MODE_DEFAULT));
+ settingsChanged |= !cpuPowerMode.equalsIgnoreCase(configParser.getCpuPowerMode());
+ String imagePath = sharedPreferences.getString(getString(R.string.IMAGE_PATH_KEY),
+ getString(R.string.IMAGE_PATH_DEFAULT));
+ testImageChanged |= !imagePath.equalsIgnoreCase(testImagePathFromAsset);
+
+ testYamlPathFromAsset = yamlPath;
+ testModelPathFromAsset = modelPath;
+ if (settingsChanged) {
+ try {
+ String realModelPath = modelPath;
+ if (!modelPath.substring(0, 1).equals("/")) {
+ String modelFileName = Utils.getFileNameFromString(modelPath);
+ realModelPath = this.getCacheDir() + File.separator + modelFileName;
+ Utils.copyFileFromAssets(this, modelPath, realModelPath);
+ }
+ String realYamlPath = yamlPath;
+ if (!yamlPath.substring(0, 1).equals("/")) {
+ String yamlFileName = Utils.getFileNameFromString(yamlPath);
+ realYamlPath = this.getCacheDir() + File.separator + yamlFileName;
+ Utils.copyFileFromAssets(this, yamlPath, realYamlPath);
+ }
+ configParser.init(realModelPath, realYamlPath, cpuThreadNum, cpuPowerMode);
+ visualize.init(configParser.getNumClasses());
+ } catch (IOException e) {
+ e.printStackTrace();
+ Toast.makeText(MainActivity.this, "Load config failed!", Toast.LENGTH_SHORT).show();
+ }
+ // update UI
+ tvInputSetting.setText("Model: " + configParser.getModel()+ "\n" + "CPU" +
+ " Thread Num: " + Integer.toString(configParser.getCpuThreadNum()) + "\n" + "CPU Power Mode: " + configParser.getCpuPowerMode());
+ tvInputSetting.scrollTo(0, 0);
+ // reload model if configure has been changed
+ loadModel();
+ }
+
+ if (testImageChanged){
+ loadTestImageFromAsset(imagePath);
+ }
+ }
+
+ public void loadTestImageFromAsset(String imagePath){
+ if (imagePath.isEmpty()) {
+ return;
+ }
+ // read test image file from custom file_paths if the first character of mode file_paths is '/', otherwise read test
+ // image file from assets
+ testImagePathFromAsset = imagePath;
+ if (!imagePath.substring(0, 1).equals("/")) {
+ InputStream imageStream = null;
+ try {
+ imageStream = getAssets().open(imagePath);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ onImageChanged(BitmapFactory.decodeStream(imageStream));
+ String realPath;
+ String imageFileName = Utils.getFileNameFromString(imagePath);
+ realPath = this.getCacheDir() + File.separator + imageFileName;
+ Utils.copyFileFromAssets(this, imagePath, realPath);
+ onMatChanged(Imgcodecs.imread(realPath, Imgcodecs.IMREAD_COLOR));
+ } else {
+ if (!new File(imagePath).exists()) {
+ return;
+ }
+ onMatChanged(Imgcodecs.imread(imagePath, Imgcodecs.IMREAD_COLOR));
+ onImageChanged( BitmapFactory.decodeFile(imagePath));
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (predictor != null) {
+ predictor.releaseModel();
+ }
+ worker.quit();
+ super.onDestroy();
+ }
+}
\ No newline at end of file
diff --git a/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/SettingsActivity.java b/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/SettingsActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..271343ff5a626ba5d8a224dfe832738ae4ede123
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/java/com/baidu/paddlex/lite/demo/SettingsActivity.java
@@ -0,0 +1,158 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.lite.demo;
+
+import com.baidu.paddlex.Utils;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
+import android.support.v7.app.ActionBar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SettingsActivity extends AppCompatPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
+ ListPreference lpChoosePreInstalledModel = null;
+ CheckBoxPreference cbEnableCustomSettings = null;
+ EditTextPreference etModelPath = null;
+ EditTextPreference etYamlPath = null;
+ EditTextPreference etImagePath = null;
+ ListPreference lpCPUThreadNum = null;
+ ListPreference lpCPUPowerMode = null;
+
+ List preInstalledModelPaths = null;
+ List preInstalledYamlPaths = null;
+ List preInstalledImagePaths = null;
+ List preInstalledCPUThreadNums = null;
+ List preInstalledCPUPowerModes = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.settings);
+ ActionBar supportActionBar = getSupportActionBar();
+ if (supportActionBar != null) {
+ supportActionBar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ // initialized pre-installed models
+ preInstalledModelPaths = new ArrayList();
+ preInstalledYamlPaths = new ArrayList();
+ preInstalledImagePaths = new ArrayList();
+ preInstalledCPUThreadNums = new ArrayList();
+ preInstalledCPUPowerModes = new ArrayList();
+ preInstalledModelPaths.add(getString(R.string.MODEL_PATH_DEFAULT));
+ preInstalledYamlPaths.add(getString(R.string.YAML_PATH_DEFAULT));
+ preInstalledImagePaths.add(getString(R.string.IMAGE_PATH_DEFAULT));
+ preInstalledCPUThreadNums.add(getString(R.string.CPU_THREAD_NUM_DEFAULT));
+ preInstalledCPUPowerModes.add(getString(R.string.CPU_POWER_MODE_DEFAULT));
+ // initialize UI components
+ lpChoosePreInstalledModel =
+ (ListPreference) findPreference(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY));
+ String[] preInstalledModelNames = new String[preInstalledModelPaths.size()];
+ for (int i = 0; i < preInstalledModelPaths.size(); i++) {
+ preInstalledModelNames[i] =
+ preInstalledModelPaths.get(i).substring(preInstalledModelPaths.get(i).lastIndexOf("/") + 1);
+ }
+ lpChoosePreInstalledModel.setEntries(preInstalledModelNames);
+ lpChoosePreInstalledModel.setEntryValues(preInstalledModelPaths.toArray(new String[preInstalledModelPaths.size()]));
+ cbEnableCustomSettings =
+ (CheckBoxPreference) findPreference(getString(R.string.ENABLE_CUSTOM_SETTINGS_KEY));
+ etModelPath = (EditTextPreference) findPreference(getString(R.string.MODEL_PATH_KEY));
+ etModelPath.setTitle("Model Path (SDCard: " + Utils.getSDCardDirectory() + ")");
+ etYamlPath = (EditTextPreference) findPreference(getString(R.string.YAML_PATH_KEY));
+ etImagePath = (EditTextPreference) findPreference(getString(R.string.IMAGE_PATH_KEY));
+ lpCPUThreadNum =
+ (ListPreference) findPreference(getString(R.string.CPU_THREAD_NUM_KEY));
+ lpCPUPowerMode =
+ (ListPreference) findPreference(getString(R.string.CPU_POWER_MODE_KEY));
+ }
+
+ private void reloadPreferenceAndUpdateUI() {
+ SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
+ boolean enableCustomSettings =
+ sharedPreferences.getBoolean(getString(R.string.ENABLE_CUSTOM_SETTINGS_KEY), false);
+ String modelPath = sharedPreferences.getString(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY),
+ getString(R.string.MODEL_PATH_DEFAULT));
+ int modelIdx = lpChoosePreInstalledModel.findIndexOfValue(modelPath);
+ if (modelIdx >= 0 && modelIdx < preInstalledModelPaths.size()) {
+ if (!enableCustomSettings) {
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putString(getString(R.string.MODEL_PATH_KEY), preInstalledModelPaths.get(modelIdx));
+ editor.putString(getString(R.string.YAML_PATH_KEY), preInstalledYamlPaths.get(modelIdx));
+ editor.putString(getString(R.string.IMAGE_PATH_KEY), preInstalledImagePaths.get(modelIdx));
+ editor.putString(getString(R.string.CPU_THREAD_NUM_KEY), preInstalledCPUThreadNums.get(modelIdx));
+ editor.putString(getString(R.string.CPU_POWER_MODE_KEY), preInstalledCPUPowerModes.get(modelIdx));
+ editor.commit();
+ }
+ lpChoosePreInstalledModel.setSummary(modelPath);
+ }
+
+ cbEnableCustomSettings.setChecked(enableCustomSettings);
+ etModelPath.setEnabled(enableCustomSettings);
+ etYamlPath.setEnabled(enableCustomSettings);
+ etImagePath.setEnabled(enableCustomSettings);
+ lpCPUThreadNum.setEnabled(enableCustomSettings);
+ lpCPUPowerMode.setEnabled(enableCustomSettings);
+ modelPath = sharedPreferences.getString(getString(R.string.MODEL_PATH_KEY),
+ getString(R.string.MODEL_PATH_DEFAULT));
+ String YamlPath = sharedPreferences.getString(getString(R.string.YAML_PATH_KEY),
+ getString(R.string.YAML_PATH_DEFAULT));
+ String imagePath = sharedPreferences.getString(getString(R.string.IMAGE_PATH_KEY),
+ getString(R.string.IMAGE_PATH_DEFAULT));
+ String cpuThreadNum = sharedPreferences.getString(getString(R.string.CPU_THREAD_NUM_KEY),
+ getString(R.string.CPU_THREAD_NUM_DEFAULT));
+ String cpuPowerMode = sharedPreferences.getString(getString(R.string.CPU_POWER_MODE_KEY),
+ getString(R.string.CPU_POWER_MODE_DEFAULT));
+
+ etModelPath.setSummary(modelPath);
+ etModelPath.setText(modelPath);
+ etYamlPath.setSummary(YamlPath);
+ etYamlPath.setText(YamlPath);
+ etImagePath.setSummary(imagePath);
+ etImagePath.setText(imagePath);
+ lpCPUThreadNum.setValue(cpuThreadNum);
+ lpCPUThreadNum.setSummary(cpuThreadNum);
+ lpCPUPowerMode.setValue(cpuPowerMode);
+ lpCPUPowerMode.setSummary(cpuPowerMode);
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+ reloadPreferenceAndUpdateUI();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY))) {
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putBoolean(getString(R.string.ENABLE_CUSTOM_SETTINGS_KEY), false);
+ editor.commit();
+ }
+ reloadPreferenceAndUpdateUI();
+ }
+}
diff --git a/deploy/lite/android/demo/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/deploy/lite/android/demo/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1f6bb290603d7caa16c5fb6f61bbfdc750622f5c
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/deploy/lite/android/demo/app/src/main/res/drawable/face.jpg b/deploy/lite/android/demo/app/src/main/res/drawable/face.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8963ae3db05894cd4bf3ea17957297363db73171
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/drawable/face.jpg differ
diff --git a/deploy/lite/android/demo/app/src/main/res/drawable/ic_launcher_background.xml b/deploy/lite/android/demo/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0d025f9bf6b67c63044a36a9ff44fbc69e5c5822
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/deploy/lite/android/demo/app/src/main/res/layout/activity_main.xml b/deploy/lite/android/demo/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000000000000000000000000000000000000..97c79f86dbedee3b71ef4b787b05352f70a428fd
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ />
+
+
+
+
+
+
\ No newline at end of file
diff --git a/deploy/lite/android/demo/app/src/main/res/menu/menu_action_options.xml b/deploy/lite/android/demo/app/src/main/res/menu/menu_action_options.xml
new file mode 100644
index 0000000000000000000000000000000000000000..34757f7d68cfae3b45cade0900dc507d205a018e
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/menu/menu_action_options.xml
@@ -0,0 +1,21 @@
+
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/deploy/lite/android/demo/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eca70cfe52eac1ba66ba280a68ca7be8fcf88a16
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/deploy/lite/android/demo/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eca70cfe52eac1ba66ba280a68ca7be8fcf88a16
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-hdpi/ic_launcher.png b/deploy/lite/android/demo/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..898f3ed59ac9f3248734a00e5902736c9367d455
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/deploy/lite/android/demo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..dffca3601eba7bf5f409bdd520820e2eb5122c75
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-mdpi/ic_launcher.png b/deploy/lite/android/demo/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..64ba76f75e9ce021aa3d95c213491f73bcacb597
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/deploy/lite/android/demo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..dae5e082342fcdeee5db8a6e0b27028e2d2808f5
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/deploy/lite/android/demo/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..e5ed46597ea8447d91ab1786a34e30f1c26b18bd
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/deploy/lite/android/demo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..14ed0af35023e4f1901cf03487b6c524257b8483
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/deploy/lite/android/demo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..b0907cac3bfd8fbfdc46e1108247f0a1055387ec
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/deploy/lite/android/demo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..d8ae03154975f397f8ed1b84f2d4bf9783ecfa26
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/deploy/lite/android/demo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..2c18de9e66108411737e910f5c1972476f03ddbf
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/deploy/lite/android/demo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..beed3cdd2c32af5114a7dc70b9ef5b698eb8797e
Binary files /dev/null and b/deploy/lite/android/demo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/deploy/lite/android/demo/app/src/main/res/values/arrays.xml b/deploy/lite/android/demo/app/src/main/res/values/arrays.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8e08ad57ddaca4bb0cff1a3d61ec84b0442b1b0e
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/values/arrays.xml
@@ -0,0 +1,39 @@
+
+
+
+ - 1 threads
+ - 2 threads
+ - 4 threads
+ - 8 threads
+
+
+ - 1
+ - 2
+ - 4
+ - 8
+
+
+ - HIGH(only big cores)
+ - LOW(only LITTLE cores)
+ - FULL(all cores)
+ - NO_BIND(depends on system)
+ - RAND_HIGH
+ - RAND_LOW
+
+
+ - LITE_POWER_HIGH
+ - LITE_POWER_LOW
+ - LITE_POWER_FULL
+ - LITE_POWER_NO_BIND
+ - LITE_POWER_RAND_HIGH
+ - LITE_POWER_RAND_LOW
+
+
+ - BGR color format
+ - RGB color format
+
+
+ - BGR
+ - RGB
+
+
\ No newline at end of file
diff --git a/deploy/lite/android/demo/app/src/main/res/values/colors.xml b/deploy/lite/android/demo/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000000000000000000000000000000000000..69b22338c6510250df3b43672635120dbce2fa49
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/deploy/lite/android/demo/app/src/main/res/values/strings.xml b/deploy/lite/android/demo/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1bd60b4a28cf4d54f5544a9ed9027d32faa574d0
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/values/strings.xml
@@ -0,0 +1,16 @@
+
+PaddleX Demo
+
+CHOOSE_PRE_INSTALLED_MODEL_KEY
+ENABLE_CUSTOM_SETTINGS_KEY
+MODEL_PATH_KEY
+YAML_PATH_KEY
+IMAGE_PATH_KEY
+CPU_POWER_MODE_KEY
+CPU_THREAD_NUM_KEY
+model/model.nb
+config/model.yml
+images/test.jpg
+1
+LITE_POWER_HIGH
+
\ No newline at end of file
diff --git a/deploy/lite/android/demo/app/src/main/res/values/styles.xml b/deploy/lite/android/demo/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5203f74f64d35d46d4451a4baa9350cf4f7770e8
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/values/styles.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/deploy/lite/android/demo/app/src/main/res/xml/settings.xml b/deploy/lite/android/demo/app/src/main/res/xml/settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b26fdc1f8c2014485dad515f3604a48b79bbf6d1
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/main/res/xml/settings.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/deploy/lite/android/demo/app/src/test/java/com/baidu/paddlex/lite/demo/ExampleUnitTest.java b/deploy/lite/android/demo/app/src/test/java/com/baidu/paddlex/lite/demo/ExampleUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..433c52cc67c4bceca7821441944e71e2bdd08503
--- /dev/null
+++ b/deploy/lite/android/demo/app/src/test/java/com/baidu/paddlex/lite/demo/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.baidu.paddlex.lite.demo;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/deploy/lite/android/demo/build.gradle b/deploy/lite/android/demo/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..fafc1b970be053f8a9ec61f55b94cb2e85b26a33
--- /dev/null
+++ b/deploy/lite/android/demo/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.0'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/deploy/lite/android/demo/gradle.properties b/deploy/lite/android/demo/gradle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..82618cecb4d1cf137df18eca8dbe88e1b3b2c2b8
--- /dev/null
+++ b/deploy/lite/android/demo/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+
diff --git a/deploy/lite/android/demo/gradle/wrapper/gradle-wrapper.jar b/deploy/lite/android/demo/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..f6b961fd5a86aa5fbfe90f707c3138408be7c718
Binary files /dev/null and b/deploy/lite/android/demo/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/deploy/lite/android/demo/gradle/wrapper/gradle-wrapper.properties b/deploy/lite/android/demo/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..578b5482ad45045124272fa3e54d065a77c2eea2
--- /dev/null
+++ b/deploy/lite/android/demo/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Aug 22 15:05:37 CST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/deploy/lite/android/demo/gradlew b/deploy/lite/android/demo/gradlew
new file mode 100644
index 0000000000000000000000000000000000000000..e69ae6eca7aa6d7565cb7f9621ee12a224e47081
--- /dev/null
+++ b/deploy/lite/android/demo/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/deploy/lite/android/demo/gradlew.bat b/deploy/lite/android/demo/gradlew.bat
new file mode 100644
index 0000000000000000000000000000000000000000..f9553162f122c71b34635112e717c3e733b5b212
--- /dev/null
+++ b/deploy/lite/android/demo/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/deploy/lite/android/demo/import-summary.txt b/deploy/lite/android/demo/import-summary.txt
new file mode 100644
index 0000000000000000000000000000000000000000..840e9d2aa7ddc8f33df8d513de711f48d199b51a
--- /dev/null
+++ b/deploy/lite/android/demo/import-summary.txt
@@ -0,0 +1,245 @@
+ECLIPSE ANDROID PROJECT IMPORT SUMMARY
+======================================
+
+Ignored Files:
+--------------
+The following files were *not* copied into the new Gradle project; you
+should evaluate whether these are still needed in your project and if
+so manually move them:
+
+* javadoc/
+* javadoc/allclasses-frame.html
+* javadoc/allclasses-noframe.html
+* javadoc/constant-values.html
+* javadoc/help-doc.html
+* javadoc/index-all.html
+* javadoc/index.html
+* javadoc/org/
+* javadoc/org/opencv/
+* javadoc/org/opencv/android/
+* javadoc/org/opencv/android/BaseLoaderCallback.html
+* javadoc/org/opencv/android/Camera2Renderer.html
+* javadoc/org/opencv/android/CameraBridgeViewBase.CvCameraViewFrame.html
+* javadoc/org/opencv/android/CameraBridgeViewBase.CvCameraViewListener.html
+* javadoc/org/opencv/android/CameraBridgeViewBase.CvCameraViewListener2.html
+* javadoc/org/opencv/android/CameraBridgeViewBase.ListItemAccessor.html
+* javadoc/org/opencv/android/CameraBridgeViewBase.html
+* javadoc/org/opencv/android/CameraGLRendererBase.html
+* javadoc/org/opencv/android/CameraGLSurfaceView.CameraTextureListener.html
+* javadoc/org/opencv/android/CameraGLSurfaceView.html
+* javadoc/org/opencv/android/CameraRenderer.html
+* javadoc/org/opencv/android/FpsMeter.html
+* javadoc/org/opencv/android/InstallCallbackInterface.html
+* javadoc/org/opencv/android/JavaCamera2View.html
+* javadoc/org/opencv/android/JavaCameraView.JavaCameraSizeAccessor.html
+* javadoc/org/opencv/android/JavaCameraView.html
+* javadoc/org/opencv/android/LoaderCallbackInterface.html
+* javadoc/org/opencv/android/OpenCVLoader.html
+* javadoc/org/opencv/android/Utils.html
+* javadoc/org/opencv/android/package-frame.html
+* javadoc/org/opencv/android/package-summary.html
+* javadoc/org/opencv/android/package-tree.html
+* javadoc/org/opencv/calib3d/
+* javadoc/org/opencv/calib3d/Calib3d.html
+* javadoc/org/opencv/calib3d/StereoBM.html
+* javadoc/org/opencv/calib3d/StereoMatcher.html
+* javadoc/org/opencv/calib3d/StereoSGBM.html
+* javadoc/org/opencv/calib3d/package-frame.html
+* javadoc/org/opencv/calib3d/package-summary.html
+* javadoc/org/opencv/calib3d/package-tree.html
+* javadoc/org/opencv/core/
+* javadoc/org/opencv/core/Algorithm.html
+* javadoc/org/opencv/core/Core.MinMaxLocResult.html
+* javadoc/org/opencv/core/Core.html
+* javadoc/org/opencv/core/CvException.html
+* javadoc/org/opencv/core/CvType.html
+* javadoc/org/opencv/core/DMatch.html
+* javadoc/org/opencv/core/KeyPoint.html
+* javadoc/org/opencv/core/Mat.html
+* javadoc/org/opencv/core/MatOfByte.html
+* javadoc/org/opencv/core/MatOfDMatch.html
+* javadoc/org/opencv/core/MatOfDouble.html
+* javadoc/org/opencv/core/MatOfFloat.html
+* javadoc/org/opencv/core/MatOfFloat4.html
+* javadoc/org/opencv/core/MatOfFloat6.html
+* javadoc/org/opencv/core/MatOfInt.html
+* javadoc/org/opencv/core/MatOfInt4.html
+* javadoc/org/opencv/core/MatOfKeyPoint.html
+* javadoc/org/opencv/core/MatOfPoint.html
+* javadoc/org/opencv/core/MatOfPoint2f.html
+* javadoc/org/opencv/core/MatOfPoint3.html
+* javadoc/org/opencv/core/MatOfPoint3f.html
+* javadoc/org/opencv/core/MatOfRect.html
+* javadoc/org/opencv/core/MatOfRect2d.html
+* javadoc/org/opencv/core/MatOfRotatedRect.html
+* javadoc/org/opencv/core/Point.html
+* javadoc/org/opencv/core/Point3.html
+* javadoc/org/opencv/core/Range.html
+* javadoc/org/opencv/core/Rect.html
+* javadoc/org/opencv/core/Rect2d.html
+* javadoc/org/opencv/core/RotatedRect.html
+* javadoc/org/opencv/core/Scalar.html
+* javadoc/org/opencv/core/Size.html
+* javadoc/org/opencv/core/TermCriteria.html
+* javadoc/org/opencv/core/TickMeter.html
+* javadoc/org/opencv/core/package-frame.html
+* javadoc/org/opencv/core/package-summary.html
+* javadoc/org/opencv/core/package-tree.html
+* javadoc/org/opencv/dnn/
+* javadoc/org/opencv/dnn/DictValue.html
+* javadoc/org/opencv/dnn/Dnn.html
+* javadoc/org/opencv/dnn/Layer.html
+* javadoc/org/opencv/dnn/Net.html
+* javadoc/org/opencv/dnn/package-frame.html
+* javadoc/org/opencv/dnn/package-summary.html
+* javadoc/org/opencv/dnn/package-tree.html
+* javadoc/org/opencv/features2d/
+* javadoc/org/opencv/features2d/AKAZE.html
+* javadoc/org/opencv/features2d/AgastFeatureDetector.html
+* javadoc/org/opencv/features2d/BFMatcher.html
+* javadoc/org/opencv/features2d/BOWImgDescriptorExtractor.html
+* javadoc/org/opencv/features2d/BOWKMeansTrainer.html
+* javadoc/org/opencv/features2d/BOWTrainer.html
+* javadoc/org/opencv/features2d/BRISK.html
+* javadoc/org/opencv/features2d/DescriptorMatcher.html
+* javadoc/org/opencv/features2d/FastFeatureDetector.html
+* javadoc/org/opencv/features2d/Feature2D.html
+* javadoc/org/opencv/features2d/Features2d.html
+* javadoc/org/opencv/features2d/FlannBasedMatcher.html
+* javadoc/org/opencv/features2d/GFTTDetector.html
+* javadoc/org/opencv/features2d/KAZE.html
+* javadoc/org/opencv/features2d/MSER.html
+* javadoc/org/opencv/features2d/ORB.html
+* javadoc/org/opencv/features2d/Params.html
+* javadoc/org/opencv/features2d/package-frame.html
+* javadoc/org/opencv/features2d/package-summary.html
+* javadoc/org/opencv/features2d/package-tree.html
+* javadoc/org/opencv/imgcodecs/
+* javadoc/org/opencv/imgcodecs/Imgcodecs.html
+* javadoc/org/opencv/imgcodecs/package-frame.html
+* javadoc/org/opencv/imgcodecs/package-summary.html
+* javadoc/org/opencv/imgcodecs/package-tree.html
+* javadoc/org/opencv/imgproc/
+* javadoc/org/opencv/imgproc/CLAHE.html
+* javadoc/org/opencv/imgproc/Imgproc.html
+* javadoc/org/opencv/imgproc/LineSegmentDetector.html
+* javadoc/org/opencv/imgproc/Moments.html
+* javadoc/org/opencv/imgproc/Subdiv2D.html
+* javadoc/org/opencv/imgproc/package-frame.html
+* javadoc/org/opencv/imgproc/package-summary.html
+* javadoc/org/opencv/imgproc/package-tree.html
+* javadoc/org/opencv/ml/
+* javadoc/org/opencv/ml/ANN_MLP.html
+* javadoc/org/opencv/ml/ANN_MLP_ANNEAL.html
+* javadoc/org/opencv/ml/Boost.html
+* javadoc/org/opencv/ml/DTrees.html
+* javadoc/org/opencv/ml/EM.html
+* javadoc/org/opencv/ml/KNearest.html
+* javadoc/org/opencv/ml/LogisticRegression.html
+* javadoc/org/opencv/ml/Ml.html
+* javadoc/org/opencv/ml/NormalBayesClassifier.html
+* javadoc/org/opencv/ml/ParamGrid.html
+* javadoc/org/opencv/ml/RTrees.html
+* javadoc/org/opencv/ml/SVM.html
+* javadoc/org/opencv/ml/SVMSGD.html
+* javadoc/org/opencv/ml/StatModel.html
+* javadoc/org/opencv/ml/TrainData.html
+* javadoc/org/opencv/ml/package-frame.html
+* javadoc/org/opencv/ml/package-summary.html
+* javadoc/org/opencv/ml/package-tree.html
+* javadoc/org/opencv/objdetect/
+* javadoc/org/opencv/objdetect/BaseCascadeClassifier.html
+* javadoc/org/opencv/objdetect/CascadeClassifier.html
+* javadoc/org/opencv/objdetect/HOGDescriptor.html
+* javadoc/org/opencv/objdetect/Objdetect.html
+* javadoc/org/opencv/objdetect/QRCodeDetector.html
+* javadoc/org/opencv/objdetect/package-frame.html
+* javadoc/org/opencv/objdetect/package-summary.html
+* javadoc/org/opencv/objdetect/package-tree.html
+* javadoc/org/opencv/osgi/
+* javadoc/org/opencv/osgi/OpenCVInterface.html
+* javadoc/org/opencv/osgi/OpenCVNativeLoader.html
+* javadoc/org/opencv/osgi/package-frame.html
+* javadoc/org/opencv/osgi/package-summary.html
+* javadoc/org/opencv/osgi/package-tree.html
+* javadoc/org/opencv/photo/
+* javadoc/org/opencv/photo/AlignExposures.html
+* javadoc/org/opencv/photo/AlignMTB.html
+* javadoc/org/opencv/photo/CalibrateCRF.html
+* javadoc/org/opencv/photo/CalibrateDebevec.html
+* javadoc/org/opencv/photo/CalibrateRobertson.html
+* javadoc/org/opencv/photo/MergeDebevec.html
+* javadoc/org/opencv/photo/MergeExposures.html
+* javadoc/org/opencv/photo/MergeMertens.html
+* javadoc/org/opencv/photo/MergeRobertson.html
+* javadoc/org/opencv/photo/Photo.html
+* javadoc/org/opencv/photo/Tonemap.html
+* javadoc/org/opencv/photo/TonemapDrago.html
+* javadoc/org/opencv/photo/TonemapMantiuk.html
+* javadoc/org/opencv/photo/TonemapReinhard.html
+* javadoc/org/opencv/photo/package-frame.html
+* javadoc/org/opencv/photo/package-summary.html
+* javadoc/org/opencv/photo/package-tree.html
+* javadoc/org/opencv/utils/
+* javadoc/org/opencv/utils/Converters.html
+* javadoc/org/opencv/utils/package-frame.html
+* javadoc/org/opencv/utils/package-summary.html
+* javadoc/org/opencv/utils/package-tree.html
+* javadoc/org/opencv/video/
+* javadoc/org/opencv/video/BackgroundSubtractor.html
+* javadoc/org/opencv/video/BackgroundSubtractorKNN.html
+* javadoc/org/opencv/video/BackgroundSubtractorMOG2.html
+* javadoc/org/opencv/video/DenseOpticalFlow.html
+* javadoc/org/opencv/video/DualTVL1OpticalFlow.html
+* javadoc/org/opencv/video/FarnebackOpticalFlow.html
+* javadoc/org/opencv/video/KalmanFilter.html
+* javadoc/org/opencv/video/SparseOpticalFlow.html
+* javadoc/org/opencv/video/SparsePyrLKOpticalFlow.html
+* javadoc/org/opencv/video/Video.html
+* javadoc/org/opencv/video/package-frame.html
+* javadoc/org/opencv/video/package-summary.html
+* javadoc/org/opencv/video/package-tree.html
+* javadoc/org/opencv/videoio/
+* javadoc/org/opencv/videoio/VideoCapture.html
+* javadoc/org/opencv/videoio/VideoWriter.html
+* javadoc/org/opencv/videoio/Videoio.html
+* javadoc/org/opencv/videoio/package-frame.html
+* javadoc/org/opencv/videoio/package-summary.html
+* javadoc/org/opencv/videoio/package-tree.html
+* javadoc/overview-frame.html
+* javadoc/overview-summary.html
+* javadoc/overview-tree.html
+* javadoc/package-list
+* javadoc/resources/
+* javadoc/resources/background.gif
+* javadoc/resources/tab.gif
+* javadoc/resources/titlebar.gif
+* javadoc/resources/titlebar_end.gif
+* javadoc/serialized-form.html
+* javadoc/stylesheet.css
+
+Moved Files:
+------------
+Android Gradle projects use a different directory structure than ADT
+Eclipse projects. Here's how the projects were restructured:
+
+* AndroidManifest.xml => openCVLibrary346/src/main/AndroidManifest.xml
+* lint.xml => openCVLibrary346/lint.xml
+* res/ => openCVLibrary346/src/main/res/
+* src/ => openCVLibrary346/src/main/java/
+* src/org/opencv/engine/OpenCVEngineInterface.aidl => openCVLibrary346/src/main/aidl/org/opencv/engine/OpenCVEngineInterface.aidl
+
+Next Steps:
+-----------
+You can now build the project. The Gradle project needs network
+connectivity to download dependencies.
+
+Bugs:
+-----
+If for some reason your project does not build, and you determine that
+it is due to a bug or limitation of the Eclipse to Gradle importer,
+please file a bug at http://b.android.com with category
+Component-Tools.
+
+(This import summary is for your information only, and can be deleted
+after import once you are satisfied with the results.)
diff --git a/deploy/lite/android/demo/settings.gradle b/deploy/lite/android/demo/settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..9d495b34f861c6ed05009b95cf15aaf24f76ebc0
--- /dev/null
+++ b/deploy/lite/android/demo/settings.gradle
@@ -0,0 +1 @@
+include ':app'
\ No newline at end of file
diff --git a/deploy/lite/android/sdk/.gitignore b/deploy/lite/android/sdk/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9
--- /dev/null
+++ b/deploy/lite/android/sdk/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/deploy/lite/android/sdk/build.gradle b/deploy/lite/android/sdk/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..11acc92c4d8c1154901c477128ea5c0f58701de2
--- /dev/null
+++ b/deploy/lite/android/sdk/build.gradle
@@ -0,0 +1,163 @@
+import java.security.MessageDigest
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 28
+ buildToolsVersion "29.0.2"
+ defaultConfig {
+ minSdkVersion 15
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ implementation 'com.android.support:design:28.0.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+}
+
+
+def paddleLiteLibs = 'https://bj.bcebos.com/paddlex/deploy/lite/paddle_lite_version_11cbd50e.tar.gz'
+task downloadAndExtractPaddleLiteLibs(type: DefaultTask) {
+ doFirst {
+ println "Downloading and extracting Paddle Lite libs"
+ }
+ doLast {
+ // Prepare cache folder for libs
+ if (!file("cache").exists()) {
+ mkdir "cache"
+ }
+ // Generate cache name for libs
+ MessageDigest messageDigest = MessageDigest.getInstance('MD5')
+ messageDigest.update(paddleLiteLibs.bytes)
+ String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
+ // Download libs
+ if (!file("cache/${cacheName}.tar.gz").exists()) {
+ ant.get(src: paddleLiteLibs, dest: file("cache/${cacheName}.tar.gz"))
+ }
+ // Unpack libs
+ copy {
+ from tarTree("cache/${cacheName}.tar.gz")
+ into "cache/${cacheName}"
+ }
+ // Copy PaddlePredictor.jar
+ if (!file("libs/PaddlePredictor.jar").exists()) {
+ copy {
+ from "cache/${cacheName}/PaddlePredictor.jar"
+ into "libs"
+ }
+ }
+ // Copy libpaddle_lite_jni.so for armeabi-v7a and arm64-v8a
+ if (!file("src/main/jniLibs/armeabi-v7a/libpaddle_lite_jni.so").exists()) {
+ copy {
+ from "cache/${cacheName}/libs/armeabi-v7a/"
+ into "src/main/jniLibs/armeabi-v7a"
+ }
+ }
+ if (!file("src/main/jniLibs/arm64-v8a/libpaddle_lite_jni.so").exists()) {
+ copy {
+ from "cache/${cacheName}/libs/arm64-v8a/"
+ into "src/main/jniLibs/arm64-v8a"
+ }
+ }
+ }
+}
+preBuild.dependsOn downloadAndExtractPaddleLiteLibs
+
+def snakeYamlLibs = 'https://bj.bcebos.com/paddlex/deploy/lite/snakeyaml-1.18-android.tar.gz'
+task downloadAndExtractSnakeYamlLibs(type: DefaultTask) {
+ doFirst {
+ println "Downloading and extracting snake yaml sdk"
+ }
+ doLast {
+ // Prepare cache folder for sdk
+ if (!file("cache").exists()) {
+ mkdir "cache"
+ }
+ // Generate cache name for sdk
+ MessageDigest messageDigest = MessageDigest.getInstance('MD5')
+ messageDigest.update(snakeYamlLibs.bytes)
+ String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
+ // Download libs
+ if (!file("cache/${cacheName}.tar.gz").exists()) {
+ ant.get(src: snakeYamlLibs, dest: file("cache/${cacheName}.tar.gz"))
+ }
+ // Unpack libs
+ copy {
+ from tarTree("cache/${cacheName}.tar.gz")
+ into "cache/${cacheName}"
+ }
+ // Copy .jar
+ if (!file("libs/snakeyaml-1.18-android.jar").exists()) {
+ copy {
+ from "cache/${cacheName}/snakeyaml-1.18-android.jar"
+ into "libs"
+ }
+ }
+ }
+}
+preBuild.dependsOn downloadAndExtractSnakeYamlLibs
+
+def opencvLibs = 'https://bj.bcebos.com/paddlex/deploy/lite/opencv-3.4.6-android.tar.gz'
+task downloadAndExtractOpencvLibs(type: DefaultTask) {
+ doFirst {
+ println "Downloading and extracting opencv sdk"
+ }
+ doLast {
+ // Prepare cache folder for sdk
+ if (!file("cache").exists()) {
+ mkdir "cache"
+ }
+ // Generate cache name for sdk
+ MessageDigest messageDigest = MessageDigest.getInstance('MD5')
+ messageDigest.update(opencvLibs.bytes)
+ String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
+ // Download libs
+ if (!file("cache/${cacheName}.tar.gz").exists()) {
+ ant.get(src: opencvLibs, dest: file("cache/${cacheName}.tar.gz"))
+ }
+ // Unpack libs
+ copy {
+ from tarTree("cache/${cacheName}.tar.gz")
+ into "cache/${cacheName}"
+ }
+ // Copy .jar
+ if (!file("libs/opencv346.jar").exists()) {
+ copy {
+ from "cache/${cacheName}/opencv346.jar"
+ into "libs"
+ }
+ }
+ // Copy .so for armeabi-v7a and arm64-v8a
+ if (!file("src/main/jniLibs/armeabi-v7a/libopencv_java3.so").exists()) {
+ copy {
+ from "cache/${cacheName}/libs/armeabi-v7a/"
+ into "src/main/jniLibs/armeabi-v7a"
+ }
+ }
+ if (!file("src/main/jniLibs/arm64-v8a/libopencv_java3.so").exists()) {
+ copy {
+ from "cache/${cacheName}/libs/arm64-v8a/"
+ into "src/main/jniLibs/arm64-v8a"
+ }
+ }
+ }
+}
+
+preBuild.dependsOn downloadAndExtractOpencvLibs
diff --git a/deploy/lite/android/sdk/consumer-rules.pro b/deploy/lite/android/sdk/consumer-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/deploy/lite/android/sdk/local.properties b/deploy/lite/android/sdk/local.properties
new file mode 100644
index 0000000000000000000000000000000000000000..5d4255d3a02904590fc7ed6606d4201444a6cc54
--- /dev/null
+++ b/deploy/lite/android/sdk/local.properties
@@ -0,0 +1,7 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Tue Jun 16 10:08:04 CST 2020
diff --git a/deploy/lite/android/sdk/proguard-rules.pro b/deploy/lite/android/sdk/proguard-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f1b424510da51fd82143bc74a0a801ae5a1e2fcd
--- /dev/null
+++ b/deploy/lite/android/sdk/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/deploy/lite/android/sdk/src/androidTest/java/com/example/paddlex/ExampleInstrumentedTest.java b/deploy/lite/android/sdk/src/androidTest/java/com/example/paddlex/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a957581b8923cd297821059a8a265b9db3e9627
--- /dev/null
+++ b/deploy/lite/android/sdk/src/androidTest/java/com/example/paddlex/ExampleInstrumentedTest.java
@@ -0,0 +1,36 @@
+package com.example.paddlex;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+
+import com.baidu.paddlex.config.ConfigParser;
+
+import org.json.JSONException;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws IOException, JSONException {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ AssetManager ass = appContext.getAssets();
+ }
+}
diff --git a/deploy/lite/android/sdk/src/main/AndroidManifest.xml b/deploy/lite/android/sdk/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..252453d686d91aca4dfd05e407da03839615a5be
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/Predictor.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/Predictor.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d154492d26637656cd42aa41f58bb798e0675e6
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/Predictor.java
@@ -0,0 +1,409 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex;
+import android.util.Log;
+import com.baidu.paddle.lite.MobileConfig;
+import com.baidu.paddle.lite.PaddlePredictor;
+import com.baidu.paddle.lite.PowerMode;
+import com.baidu.paddle.lite.Tensor;
+import com.baidu.paddlex.config.ConfigParser;
+import com.baidu.paddlex.postprocess.ClsResult;
+import com.baidu.paddlex.postprocess.DetResult;
+import com.baidu.paddlex.postprocess.Result;
+import com.baidu.paddlex.postprocess.SegResult;
+import com.baidu.paddlex.preprocess.ImageBlob;
+import com.baidu.paddlex.preprocess.Transforms;
+import java.util.Date;
+import org.opencv.core.Mat;
+
+public class Predictor {
+ private static final String TAG = Predictor.class.getSimpleName();
+ protected boolean isLoaded = false;
+ protected int warmupIterNum = 0;
+ protected int inferIterNum = 1;
+ protected int cpuThreadNum = 1;
+ protected String cpuPowerMode = "LITE_POWER_HIGH";
+ protected String modelPath = "";
+ protected String modelName = "";
+ protected float inferenceTime = 0;
+ protected float preprocessTime = 0;
+ protected float postprocessTime = 0;
+ protected PaddlePredictor paddlePredictor = null;
+ protected ImageBlob imageBlob = new ImageBlob();
+ protected Transforms transforms = new Transforms();
+ protected ConfigParser configParser = new ConfigParser();
+ protected Mat inputMat;
+ protected Result result;
+
+ public Predictor() {
+ super();
+ }
+
+ public boolean init(String modelPath, int cpuThreadNum, String cpuPowerMode) {
+ if (configParser.getModelType().equalsIgnoreCase("classifier")) {
+ result = new ClsResult();
+ } else if (configParser.getModelType().equalsIgnoreCase("detector")) {
+ result = new DetResult();
+ } else if (configParser.getModelType().equalsIgnoreCase("segmenter")) {
+ result = new SegResult();
+ } else {
+ Log.i(TAG, "model type: " + configParser.getModelType() + " is not support! Only support: 'classifier' or 'detector' or 'segmenter'");
+ }
+ isLoaded = loadModel(modelPath, cpuThreadNum, cpuPowerMode);
+ return isLoaded;
+ }
+
+ public boolean init(ConfigParser configParser) {
+ this.configParser = configParser;
+ init(configParser.getModelPath(), configParser.getCpuThreadNum(), configParser.getCpuPowerMode());
+ transforms.loadConfig(configParser.getTransformsList(), configParser.getTransformsMode());
+ if (!isLoaded()) {
+ return false;
+ }
+ Log.i(TAG, configParser.toString());
+ return isLoaded;
+ }
+
+ public boolean predict() {
+ this.imageBlob.clear();
+ this.imageBlob = transforms.run(inputMat, imageBlob);
+ if (configParser.getModelType().equalsIgnoreCase("classifier")) {
+ runModel((ClsResult) result);
+ } else if (configParser.getModelType().equalsIgnoreCase("detector")) {
+ runModel((DetResult) result);
+ } else if (configParser.getModelType().equalsIgnoreCase("segmenter")) {
+ runModel((SegResult) result);
+ }
+ return true;
+ }
+
+ private boolean runModel(DetResult detReult) {
+ // set input shape & data
+ Tensor imTensor = getInput(0);
+ imTensor.resize(imageBlob.getNewImageSize());
+ imTensor.setData(imageBlob.getImageData());
+ if (configParser.getModel().equalsIgnoreCase("YOLOv3")) {
+ Tensor imSizeTensor = getInput(1);
+ long[] imSize = {1, 2};
+ imSizeTensor.resize(imSize);
+ imSizeTensor.setData(new int[]{(int) imageBlob.getOriImageSize()[2], (int) imageBlob.getOriImageSize()[3]});
+ } else if (configParser.getModel().equalsIgnoreCase("FasterRCNN")) {
+ Tensor imInfoTensor = getInput(1);
+ long[] imInfo = {1, 3};
+ imInfoTensor.resize(imInfo);
+ imInfoTensor.setData(new float[]{imageBlob.getNewImageSize()[2], imageBlob.getNewImageSize()[3], imageBlob.getScale()});
+
+ Tensor imShapeTensor = getInput(2);
+ long[] imShape = {1, 3};
+ imShapeTensor.resize(imShape);
+ imShapeTensor.setData(new float[]{imageBlob.getOriImageSize()[2], imageBlob.getOriImageSize()[3], 1});
+ }
+ // run model
+ runModel();
+ // Fetch output tensor
+ Tensor outputTensor = getOutput(0);
+ float[] output = outputTensor.getFloatData();
+ long[] outputShape = outputTensor.shape();
+ long outputSize = 1;
+ for (long s : outputShape) {
+ outputSize *= s;
+ }
+ int num_boxes = (int) (outputSize / 6);
+ for (int i = 0; i < num_boxes; i++) {
+ DetResult.Box box = detReult.new Box();
+ box.setCategoryId((int) output[i * 6]);
+ box.setCategory(configParser.getLabeList().get(box.getCategoryId()));
+ box.setScore(output[i * 6 + 1]);
+ float xmin = output[i * 6 + 2];
+ float ymin = output[i * 6 + 3];
+ float xmax = output[i * 6 + 4];
+ float ymax = output[i * 6 + 5];
+ box.setCoordinate(new float[]{xmin, ymin, xmax, ymax});
+ detReult.getBoxes().add(box);
+ }
+ return true;
+ }
+
+ private boolean runModel(SegResult segReult) {
+ // set input shape & data
+ Tensor imTensor = getInput(0);
+ imTensor.resize(imageBlob.getNewImageSize());
+ imTensor.setData(imageBlob.getImageData());
+ // run model
+ runModel();
+ Tensor labelTensor = getOutput(0);
+ // Fetch output tensor
+ long[] labelData = labelTensor.getLongData();
+ segReult.getMask().setLabelShape(labelTensor.shape());
+ long labelSize = 1;
+ for (long s : segReult.getMask().getLabelShape()) {
+ labelSize *= s;
+ }
+ segReult.getMask().setLabelData(labelData);
+
+ Tensor scoreTensor = getOutput(1);
+ float[] scoreData = scoreTensor.getFloatData();
+ segReult.getMask().setScoreShape(scoreTensor.shape());
+ segReult.getMask().setScoreData(scoreData);
+ return true;
+ }
+
+ private boolean runModel(ClsResult clsReult) {
+ // set input shape & data
+ Tensor imTensor = getInput(0);
+ imTensor.resize(imageBlob.getNewImageSize());
+ imTensor.setData(imageBlob.getImageData());
+ // run model
+ runModel();
+ // Fetch output tensor
+ Tensor outputTensor = getOutput(0);
+ long[] outputShape = outputTensor.shape();
+ long outputSize = 1;
+ for (long s : outputShape) {
+ outputSize *= s;
+ }
+ int max_index = 0; // Top3 indices
+ float max_score = 0; // Top3 scores
+ for (int i = 0; i < outputSize; i++) {
+ float tmp = outputTensor.getFloatData()[i];
+ if (tmp > max_score) {
+ max_index = i;
+ max_score = tmp;
+ }
+ }
+ clsReult.setCategoryId(max_index);
+ clsReult.setCategory(configParser.getLabeList().get(max_index));
+ clsReult.setScore(max_score);
+ return true;
+ }
+
+ private boolean loadModel(String modelPath, int cpuThreadNum, String cpuPowerMode) {
+ // release model if exists
+ releaseModel();
+ // load model
+ if (modelPath.isEmpty()) {
+ return false;
+ }
+ MobileConfig config = new MobileConfig();
+ config.setModelFromFile(modelPath);
+ config.setThreads(cpuThreadNum);
+ if (cpuPowerMode.equalsIgnoreCase("LITE_POWER_HIGH")) {
+ config.setPowerMode(PowerMode.LITE_POWER_HIGH);
+ } else if (cpuPowerMode.equalsIgnoreCase("LITE_POWER_LOW")) {
+ config.setPowerMode(PowerMode.LITE_POWER_LOW);
+ } else if (cpuPowerMode.equalsIgnoreCase("LITE_POWER_FULL")) {
+ config.setPowerMode(PowerMode.LITE_POWER_FULL);
+ } else if (cpuPowerMode.equalsIgnoreCase("LITE_POWER_NO_BIND")) {
+ config.setPowerMode(PowerMode.LITE_POWER_NO_BIND);
+ } else if (cpuPowerMode.equalsIgnoreCase("LITE_POWER_RAND_HIGH")) {
+ config.setPowerMode(PowerMode.LITE_POWER_RAND_HIGH);
+ } else if (cpuPowerMode.equalsIgnoreCase("LITE_POWER_RAND_LOW")) {
+ config.setPowerMode(PowerMode.LITE_POWER_RAND_LOW);
+ } else {
+ Log.e(TAG, "unknown cpu power mode!");
+ return false;
+ }
+ paddlePredictor = PaddlePredictor.createPaddlePredictor(config);
+ this.cpuThreadNum = cpuThreadNum;
+ this.cpuPowerMode = cpuPowerMode;
+ this.modelPath = modelPath;
+ this.modelName = configParser.getModel();
+ return true;
+ }
+
+ private boolean runModel() {
+ if (!isLoaded()) {
+ return false;
+ }
+ // warm up
+ for (int i = 0; i < warmupIterNum; i++) {
+ paddlePredictor.run();
+ }
+ Date start = new Date();
+ // inference
+ for (int i = 0; i < inferIterNum; i++) {
+ paddlePredictor.run();
+ }
+ Date end = new Date();
+ inferenceTime = (end.getTime() - start.getTime()) / (float) inferIterNum;
+ return true;
+ }
+
+ public void releaseModel() {
+ paddlePredictor = null;
+ isLoaded = false;
+ cpuThreadNum = 1;
+ cpuPowerMode = "LITE_POWER_HIGH";
+ modelPath = "";
+ modelName = "";
+ }
+
+ public boolean isLoaded() {
+ return paddlePredictor != null && isLoaded;
+ }
+
+ public void setLoaded(boolean loaded) {
+ isLoaded = loaded;
+ }
+
+ public int getWarmupIterNum() {
+ return warmupIterNum;
+ }
+
+ public void setWarmupIterNum(int warmupIterNum) {
+ this.warmupIterNum = warmupIterNum;
+ }
+
+ public int getInferIterNum() {
+ return inferIterNum;
+ }
+
+ public void setInferIterNum(int inferIterNum) {
+ this.inferIterNum = inferIterNum;
+ }
+
+ public float getInferenceTime() {
+ return inferenceTime;
+ }
+
+ public void setInferenceTime(float inferenceTime) {
+ this.inferenceTime = inferenceTime;
+ }
+
+ public int getCpuThreadNum() {
+ return cpuThreadNum;
+ }
+
+ public void setCpuThreadNum(int cpuThreadNum) {
+ this.cpuThreadNum = cpuThreadNum;
+ }
+
+ public String getCpuPowerMode() {
+ return cpuPowerMode;
+ }
+
+ public void setCpuPowerMode(String cpuPowerMode) {
+ this.cpuPowerMode = cpuPowerMode;
+ }
+
+ public String getModelPath() {
+ return modelPath;
+ }
+
+ public void setModelPath(String modelPath) {
+ this.modelPath = modelPath;
+ }
+
+ public String getModelName() {
+ return modelName;
+ }
+
+ public void setModelName(String modelName) {
+ this.modelName = modelName;
+ }
+
+ public Result getResult() {
+ return result;
+ }
+
+ public void setResult(Result result) {
+ this.result = result;
+ }
+
+ public PaddlePredictor getPaddlePredictor() {
+ return paddlePredictor;
+ }
+
+ public void setPaddlePredictor(PaddlePredictor paddlePredictor) {
+ this.paddlePredictor = paddlePredictor;
+ }
+
+ public float getPreprocessTime() {
+ return preprocessTime;
+ }
+
+ public void setPreprocessTime(float preprocessTime) {
+ this.preprocessTime = preprocessTime;
+ }
+
+ public float getPostprocessTime() {
+ return postprocessTime;
+ }
+
+ public void setPostprocessTime(float postprocessTime) {
+ this.postprocessTime = postprocessTime;
+ }
+
+ public void setConfigParser(ConfigParser configParser) {
+ this.configParser = configParser;
+ }
+
+ public Mat getInputMat() {
+ return inputMat;
+ }
+
+ public void setInputMat(Mat inputMat) {
+ Mat copyMat = new Mat();
+ inputMat.copyTo(copyMat);
+ this.inputMat = copyMat;
+ }
+
+ public DetResult getDetResult() {
+ if (result.getType() != "det") {
+ Log.e(TAG, "this model_type is not detector");
+ return null;
+ }
+ return (DetResult) result;
+ }
+
+ public SegResult getSegResult() {
+ if (result.getType() != "seg") {
+ Log.e(TAG, "this model_type is not segmeter");
+ return null;
+ }
+ return (SegResult) result;
+ }
+
+ public ClsResult getClsResult() {
+ if (result.getType() != "cls") {
+ Log.e(TAG, "this model_type is not classifier");
+ return null;
+ }
+ return (ClsResult) result;
+ }
+
+ public ImageBlob getImageBlob() {
+ return imageBlob;
+ }
+
+ public void setImageBlob(ImageBlob imageBlob) {
+ this.imageBlob = imageBlob;
+ }
+
+ public Tensor getInput(int idx) {
+ if (!isLoaded()) {
+ return null;
+ }
+ return paddlePredictor.getInput(idx);
+ }
+
+ public Tensor getOutput(int idx) {
+ if (!isLoaded()) {
+ return null;
+ }
+ return paddlePredictor.getOutput(idx);
+ }
+
+}
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/Utils.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/Utils.java
new file mode 100644
index 0000000000000000000000000000000000000000..48ed6f031861ffaabeaea1265cdeb762a29fba6c
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/Utils.java
@@ -0,0 +1,132 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex;
+
+import android.content.Context;
+import android.os.Environment;
+
+import org.opencv.android.OpenCVLoader;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class Utils {
+ private static final String TAG = Utils.class.getSimpleName();
+
+ public static void copyFileFromAssets(Context appCtx, String srcPath, String dstPath) {
+ if (srcPath.isEmpty() || dstPath.isEmpty()) {
+ return;
+ }
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ is = new BufferedInputStream(appCtx.getAssets().open(srcPath));
+ os = new BufferedOutputStream(new FileOutputStream(new File(dstPath)));
+ byte[] buffer = new byte[1024];
+ int length = 0;
+ while ((length = is.read(buffer)) != -1) {
+ os.write(buffer, 0, length);
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ os.close();
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static void copyDirectoryFromAssets(Context appCtx, String srcDir, String dstDir) {
+ if (srcDir.isEmpty() || dstDir.isEmpty()) {
+ return;
+ }
+ try {
+ if (!new File(dstDir).exists()) {
+ new File(dstDir).mkdirs();
+ }
+ for (String fileName : appCtx.getAssets().list(srcDir)) {
+ String srcSubPath = srcDir + File.separator + fileName;
+ String dstSubPath = dstDir + File.separator + fileName;
+ copyFileFromAssets(appCtx, srcSubPath, dstSubPath);
+ if (new File(srcSubPath).isDirectory()) {
+ copyDirectoryFromAssets(appCtx, srcSubPath, dstSubPath);
+ } else {
+ copyFileFromAssets(appCtx, srcSubPath, dstSubPath);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String getFileNameFromString(String srcDir) {
+ if (srcDir.isEmpty()) {
+ return null;
+ }
+ try {
+ String fileName = srcDir.substring(srcDir.lastIndexOf("/") + 1);
+ return fileName;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static float[] parseFloatsFromString(String string, String delimiter) {
+ String[] pieces = string.trim().toLowerCase().split(delimiter);
+ float[] floats = new float[pieces.length];
+ for (int i = 0; i < pieces.length; i++) {
+ floats[i] = Float.parseFloat(pieces[i].trim());
+ }
+ return floats;
+ }
+
+ public static long[] parseLongsFromString(String string, String delimiter) {
+ String[] pieces = string.trim().toLowerCase().split(delimiter);
+ long[] longs = new long[pieces.length];
+ for (int i = 0; i < pieces.length; i++) {
+ longs[i] = Long.parseLong(pieces[i].trim());
+ }
+ return longs;
+ }
+
+ public static String getSDCardDirectory() {
+ return Environment.getExternalStorageDirectory().getAbsolutePath();
+ }
+
+ public static boolean isSupportedNPU() {
+ String hardware = android.os.Build.HARDWARE;
+ return hardware.equalsIgnoreCase("kirin810") || hardware.equalsIgnoreCase("kirin990");
+ }
+
+ public static boolean initialOpencv() {
+ if (!OpenCVLoader.initDebug()) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/config/ConfigParser.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/config/ConfigParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa20f6a685bb6117fca135a5adf5039d42ad5ca6
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/config/ConfigParser.java
@@ -0,0 +1,162 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.config;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ConfigParser {
+ protected String model = "";
+ protected List labeList = new ArrayList<>();
+ protected int numClasses = 0;
+ protected String modelType = "";
+ protected String transformsMode = "RGB";
+ protected List transformsList = new ArrayList();
+ protected String modelPath = "";
+ protected int cpuThreadNum = 1;
+ protected String cpuPowerMode = "";
+ protected String yamlPath = "";
+
+ public void init(String modelPath, String yamlPath, int cpuThreadNum,
+ String cpuPowerMode) throws IOException {
+
+ this.modelPath = modelPath;
+ this.cpuThreadNum = cpuThreadNum;
+ this.cpuPowerMode = cpuPowerMode;
+ this.yamlPath = yamlPath;
+ InputStream ymlStream = new FileInputStream(new File(yamlPath));
+ Yaml yml = new Yaml();
+ HashMap yml_map = (HashMap) yml.load(ymlStream);
+ model = (String) yml_map.get("Model");
+ if (yml_map.containsKey("TransformsMode")) {
+ transformsMode = (String) yml_map.get("TransformsMode");
+ }
+ HashMap _Attributes = (HashMap) yml_map.get("_Attributes");
+ // parser label_list
+ labeList = (List) _Attributes.get("labels");
+ numClasses = (int) _Attributes.get("num_classes");
+ // parser model_type(classifier, segmenter, detector)
+ modelType = (String) _Attributes.get("model_type");
+ // parser Transforms
+ transformsList = (List) yml_map.get("Transforms");
+
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigParser{" +
+ "model='" + model + '\'' +
+ ", labeList=" + labeList +
+ ", numClasses=" + numClasses +
+ ", modelType='" + modelType + '\'' +
+ ", transformsMode='" + transformsMode + '\'' +
+ ", transformsList=" + transformsList +
+ ", modelPath='" + modelPath + '\'' +
+ ", cpuThreadNum=" + cpuThreadNum +
+ ", cpuPowerMode='" + cpuPowerMode + '\'' +
+ ", yamlPath='" + yamlPath + '\'' +
+ '}';
+ }
+
+ public int getNumClasses() {
+ return numClasses;
+ }
+
+ public void setNumClasses(int numClasses) {
+ this.numClasses = numClasses;
+ }
+
+ public List getLabeList() {
+ return labeList;
+ }
+
+ public void setLabeList(List labeList) {
+ this.labeList = labeList;
+ }
+
+ public String getModelType() {
+ return modelType;
+ }
+
+ public void setModelType(String modelType) {
+ this.modelType = modelType;
+ }
+
+ public List getTransformsList() {
+ return transformsList;
+ }
+
+ public void setTransformsList(List transformsList) {
+ this.transformsList = transformsList;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getTransformsMode() {
+ return transformsMode;
+ }
+
+ public void setTransformsMode(String transformsMode) {
+ this.transformsMode = transformsMode;
+ }
+
+ public String getModelPath() {
+ return modelPath;
+ }
+
+ public void setModelPath(String modelPath) {
+ this.modelPath = modelPath;
+ }
+
+ public int getCpuThreadNum() {
+ return cpuThreadNum;
+ }
+
+ public void setCpuThreadNum(int cpuThreadNum) {
+ this.cpuThreadNum = cpuThreadNum;
+ }
+
+ public String getCpuPowerMode() {
+ return cpuPowerMode;
+ }
+
+ public void setCpuPowerMode(String cpuPowerMode) {
+ this.cpuPowerMode = cpuPowerMode;
+ }
+
+ public String getYamlPath() {
+ return yamlPath;
+ }
+
+ public void setYamlPath(String yamlPath) {
+ this.yamlPath = yamlPath;
+ }
+}
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/ClsResult.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/ClsResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..97ca2d92532bdfd826b2d67cc18a403f6e293cc0
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/ClsResult.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.postprocess;
+
+public class ClsResult extends Result {
+ static String type = "cls";
+ protected int categoryId;
+ protected String category;
+ protected float score;
+
+ public int getCategoryId() {
+ return categoryId;
+ }
+
+ public void setCategoryId(int categoryId) {
+ this.categoryId = categoryId;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public void setCategory(String category) {
+ this.category = category;
+ }
+
+ public double getScore() {
+ return score;
+ }
+
+ public void setScore(float score) {
+ this.score = score;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+}
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/DetResult.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/DetResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..422a275ebe5ab1d545d70bf783ba5684e211b2c6
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/DetResult.java
@@ -0,0 +1,76 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.postprocess;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DetResult extends Result {
+ static String type = "det";
+ protected List boxes = new ArrayList();
+
+ public List getBoxes() {
+ return boxes;
+ }
+
+ public void setBoxes(List boxes) {
+ this.boxes = boxes;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ public class Box {
+ protected int categoryId;
+ protected String category;
+ protected float score;
+ protected float[] coordinate = new float[4];
+
+ public int getCategoryId() {
+ return categoryId;
+ }
+
+ public void setCategoryId(int category_id) {
+ this.categoryId = category_id;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public void setCategory(String category) {
+ this.category = category;
+ }
+
+ public float getScore() {
+ return score;
+ }
+
+ public void setScore(float score) {
+ this.score = score;
+ }
+
+ public float[] getCoordinate() {
+ return coordinate;
+ }
+
+ public void setCoordinate(float[] coordinate) {
+ this.coordinate = coordinate;
+ }
+ }
+
+}
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/Result.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/Result.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba57af086e6d50609bcb9b9ae286bea0761f2c5d
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/Result.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.postprocess;
+
+public class Result {
+ static String type = "base";
+
+ public String getType() {
+ return type;
+ }
+}
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/SegResult.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/SegResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3a15f2dcc582300dd2ccc82509dbdd841dcd989
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/postprocess/SegResult.java
@@ -0,0 +1,72 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.postprocess;
+
+public class SegResult extends Result {
+ static String type = "seg";
+ protected Mask mask = new Mask();
+
+ public Mask getMask() {
+ return mask;
+ }
+
+ public void setMask(Mask mask) {
+ this.mask = mask;
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ public class Mask {
+ protected float[] scoreData;
+ protected long[] labelData;
+ protected long[] labelShape = new long[4];
+ protected long[] scoreShape = new long[4];
+
+ public float[] getScoreData() {
+ return scoreData;
+ }
+
+ public void setScoreData(float[] score_data) {
+ this.scoreData = score_data;
+ }
+
+ public long[] getLabelData() {
+ return labelData;
+ }
+
+ public void setLabelData(long[] label_data) {
+ this.labelData = label_data;
+ }
+
+ public long[] getLabelShape() {
+ return labelShape;
+ }
+
+ public void setLabelShape(long[] labelShape) {
+ this.labelShape = labelShape;
+ }
+
+ public long[] getScoreShape() {
+ return scoreShape;
+ }
+
+ public void setScoreShape(long[] scoreShape) {
+ this.scoreShape = scoreShape;
+ }
+ }
+}
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/preprocess/ImageBlob.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/preprocess/ImageBlob.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9bd9a52e5d87792c5705b621a3fb275c68c1f7e
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/preprocess/ImageBlob.java
@@ -0,0 +1,86 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.preprocess;
+
+import java.util.LinkedHashMap;
+
+public class ImageBlob {
+ // Original image height and width
+ private long[] oriImageSize = new long[]{1, 3, -1, -1};
+ // Newest image height and width after process
+ private long[] newImageSize = new long[]{1, 3, -1, -1};
+ // Reshape order, Image height and width before resize
+ private LinkedHashMap reshapeInfo = new LinkedHashMap();
+ // Resize scale
+ private float scale = 1;
+ // Buffer for image data after preprocessing
+ private float[] imageData;
+
+ public void clear() {
+ oriImageSize = new long[]{1, 3, -1, -1};
+ newImageSize = new long[]{1, 3, -1, -1};
+ reshapeInfo.clear();
+ imageData = null;
+ }
+
+ public long[] getOriImageSize() {
+ return oriImageSize;
+ }
+
+ public void setOriImageSize(long[] oriImageSize) {
+ this.oriImageSize = oriImageSize;
+ }
+
+ public void setOriImageSize(long dim, int idx) {
+ this.oriImageSize[idx] = dim;
+ }
+
+ public long[] getNewImageSize() {
+ return newImageSize;
+ }
+
+ public void setNewImageSize(long[] newImageSize) {
+ this.newImageSize = newImageSize;
+ }
+
+ public void setNewImageSize(long dim, int idx) {
+ this.newImageSize[idx] = dim;
+ }
+
+
+ public LinkedHashMap getReshapeInfo() {
+ return reshapeInfo;
+ }
+
+ public void setReshapeInfo(LinkedHashMap reshapeInfo) {
+ this.reshapeInfo = reshapeInfo;
+ }
+
+ public float getScale() {
+ return scale;
+ }
+
+ public void setScale(float scale) {
+ this.scale = scale;
+ }
+
+ public float[] getImageData() {
+ return imageData;
+ }
+
+ public void setImageData(float[] imageData) {
+ this.imageData = imageData;
+ }
+}
\ No newline at end of file
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/preprocess/Transforms.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/preprocess/Transforms.java
new file mode 100644
index 0000000000000000000000000000000000000000..940ebaa234db2e34faa2daaf74dfacc0e9d131fe
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/preprocess/Transforms.java
@@ -0,0 +1,286 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.preprocess;
+import android.util.Log;
+import org.opencv.android.OpenCVLoader;
+import org.opencv.core.Core;
+import org.opencv.core.CvType;
+import org.opencv.core.Mat;
+import org.opencv.core.Rect;
+import org.opencv.core.Scalar;
+import org.opencv.core.Size;
+import org.opencv.imgproc.Imgproc;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class Transforms {
+ private static final String TAG = Transforms.class.getSimpleName();
+ private List transformOps = new ArrayList();
+ private String transformsMode = "RGB";
+ private HashMap interpMap = new HashMap(){{
+ put("LINEAR", Imgproc.INTER_LINEAR);
+ put("NEAREST", Imgproc.INTER_NEAREST);
+ put("AREA", Imgproc.INTER_AREA);
+ put("CUBIC", Imgproc.INTER_CUBIC);
+ put("LANCZOS4", Imgproc.INTER_LANCZOS4);
+ }
+ };
+
+ public void loadConfig(List transforms_list, String transformsMode) {
+ if (!OpenCVLoader.initDebug()) {
+ Log.e(TAG,"OpenCV Loadding failed.");
+ }
+ this.transformsMode = transformsMode;
+ for (int i = 0; i < transforms_list.size(); i++) {
+ HashMap transform_op = (HashMap) (transforms_list.get(i));
+ if (transform_op.containsKey("ResizeByShort")) {
+ HashMap info = (HashMap) transform_op.get("ResizeByShort");
+ ResizeByShort resizeByShort = new ResizeByShort();
+ resizeByShort.max_size = (int)info.get("max_size");
+ resizeByShort.short_size = (int)info.get("short_size");
+ if (info.containsKey("interp")) {
+ resizeByShort.interp = (String) info.get("interp");
+ }
+ transformOps.add(resizeByShort);
+ } else if (transform_op.containsKey("ResizeByLong")) {
+ HashMap info = (HashMap) transform_op.get("ResizeByLong");
+ ResizeByLong resizeByLong = new ResizeByLong();
+ resizeByLong.long_size = (int)info.get("long_size");
+ if (info.containsKey("interp")) {
+ resizeByLong.interp = (String) info.get("interp");
+ }
+ transformOps.add(resizeByLong);
+
+ } else if (transform_op.containsKey("CenterCrop")) {
+ HashMap info = (HashMap) transform_op.get("CenterCrop");
+ CenterCrop centerCrop = new CenterCrop();
+ if (info.get("crop_size") instanceof Integer) {
+ centerCrop.cropHeight = (int) info.get("crop_size");
+ centerCrop.cropWidth = (int) info.get("crop_size");
+ } else {
+ centerCrop.cropWidth = ((List) info.get("crop_size")).get(0);
+ centerCrop.cropHeight = ((List) info.get("crop_size")).get(1);
+ }
+ transformOps.add(centerCrop);
+ } else if (transform_op.containsKey("Normalize")) {
+ HashMap> info = (HashMap>) transform_op.get("Normalize");
+ Normalize normalize = new Normalize();
+ normalize.mean = info.get("mean").toArray(new Double[info.get("mean").size()]);
+ normalize.std = info.get("std").toArray(new Double[info.get("std").size()]);
+ transformOps.add(normalize);
+ } else if (transform_op.containsKey("Resize")) {
+ HashMap info = (HashMap) transform_op.get("Resize");
+ Resize resize = new Resize();
+ if (info.get("target_size") instanceof Integer) {
+ resize.width = (int) info.get("target_size");
+ resize.height = (int) info.get("target_size");
+ } else {
+ resize.width = ((List) info.get("target_size")).get(0);
+ resize.height = ((List) info.get("target_size")).get(1);
+ }
+ if (info.containsKey("interp")) {
+ resize.interp = (String) info.get("interp");
+ }
+ transformOps.add(resize);
+ } else if (transform_op.containsKey("Padding")) {
+ HashMap info = (HashMap) transform_op.get("Padding");
+ Padding padding = new Padding();
+ if (info.containsKey("coarsest_stride")) {
+ padding.coarsest_stride = (int) info.get("coarsest_stride");
+ }
+ if (info.containsKey("target_size")) {
+ if (info.get("target_size") instanceof Integer) {
+ padding.width = (int) info.get("target_size");
+ padding.height = (int) info.get("target_size");
+ } else {
+ padding.width = ((List) info.get("target_size")).get(0);
+ padding.height = ((List) info.get("target_size")).get(1);
+ }
+ }
+ transformOps.add(padding);
+ }
+ }
+ }
+
+ public ImageBlob run(Mat inputMat, ImageBlob imageBlob) {
+ imageBlob.setOriImageSize(inputMat.height(),2);
+ imageBlob.setOriImageSize(inputMat.width(),3);
+ imageBlob.setNewImageSize(inputMat.height(),2);
+ imageBlob.setNewImageSize(inputMat.width(),3);
+
+ if(transformsMode.equalsIgnoreCase("RGB")){
+ Imgproc.cvtColor(inputMat, inputMat, Imgproc.COLOR_BGR2RGB);
+ }else if(!transformsMode.equalsIgnoreCase("BGR")){
+ Log.e(TAG, "transformsMode only support RGB or BGR");
+ }
+ inputMat.convertTo(inputMat, CvType.CV_32FC(3));
+
+ for (transformOp op : transformOps) {
+ inputMat = op.run(inputMat, imageBlob);
+ }
+
+ int w = inputMat.width();
+ int h = inputMat.height();
+ int c = inputMat.channels();
+ imageBlob.setImageData(new float[w * h * c]);
+ int[] channelStride = new int[]{w * h, w * h * 2};
+ for (int y = 0; y < h; y++) {
+ for (int x = 0;
+ x < w; x++) {
+ double[] color = inputMat.get(y, x);
+ imageBlob.getImageData()[y * w + x] = (float) (color[0]);
+ imageBlob.getImageData()[y * w + x + channelStride[0]] = (float) (color[1]);
+ imageBlob.getImageData()[y * w + x + channelStride[1]] = (float) (color[2]);
+ }
+ }
+ return imageBlob;
+ }
+
+ private class transformOp {
+ public Mat run(Mat inputMat, ImageBlob data) {
+ return inputMat;
+ }
+ }
+
+ private class ResizeByShort extends transformOp {
+ private int max_size;
+ private int short_size;
+ private String interp = "LINEAR";
+
+ public Mat run(Mat inputMat, ImageBlob imageBlob) {
+ int origin_w = inputMat.width();
+ int origin_h = inputMat.height();
+ imageBlob.getReshapeInfo().put("resize", new int[]{origin_w, origin_h});
+ int im_size_max = Math.max(origin_w, origin_h);
+ int im_size_min = Math.min(origin_w, origin_h);
+ float scale = (float) (short_size) / (float) (im_size_min);
+ if (max_size > 0) {
+ if (Math.round(scale * im_size_max) > max_size) {
+ scale = (float) (max_size) / (float) (im_size_max);
+ }
+ }
+ int width = Math.round(scale * origin_w);
+ int height = Math.round(scale * origin_h);
+ Size sz = new Size(width, height);
+ Imgproc.resize(inputMat, inputMat, sz,0,0, interpMap.get(interp));
+ imageBlob.setNewImageSize(inputMat.height(),2);
+ imageBlob.setNewImageSize(inputMat.width(),3);
+ imageBlob.setScale(scale);
+ return inputMat;
+ }
+ }
+
+ private class ResizeByLong extends transformOp {
+ private int long_size;
+ private String interp = "LINEAR";
+
+ public Mat run(Mat inputMat, ImageBlob imageBlob) {
+ int origin_w = inputMat.width();
+ int origin_h = inputMat.height();
+ imageBlob.getReshapeInfo().put("resize", new int[]{origin_w, origin_h});
+ int im_size_max = Math.max(origin_w, origin_h);
+ float scale = (float) (long_size) / (float) (im_size_max);
+ int width = Math.round(scale * origin_w);
+ int height = Math.round(scale * origin_h);
+ Size sz = new Size(width, height);
+ Imgproc.resize(inputMat, inputMat, sz,0,0, interpMap.get(interp));
+ imageBlob.setNewImageSize(inputMat.height(),2);
+ imageBlob.setNewImageSize(inputMat.width(),3);
+ imageBlob.setScale(scale);
+ return inputMat;
+ }
+ }
+
+ private class CenterCrop extends transformOp {
+ private int cropHeight;
+ private int cropWidth;
+
+ public Mat run(Mat inputMat, ImageBlob imageBlob) {
+ int origin_w = inputMat.width();
+ int origin_h = inputMat.height();
+ if (origin_h < cropHeight || origin_w < cropWidth) {
+ Log.e(TAG, "[CenterCrop] Image size less than crop size");
+ }
+ int offset_x, offset_y;
+ offset_x = (origin_w - cropWidth) / 2;
+ offset_y = (origin_h - cropHeight) / 2;
+ offset_x = Math.max(Math.min(offset_x, origin_w - cropWidth), 0);
+ offset_y = Math.max(Math.min(offset_y, origin_h - cropHeight), 0);
+ Rect crop_roi = new Rect(offset_x, offset_y, cropHeight, cropWidth);
+ inputMat = inputMat.submat(crop_roi);
+ imageBlob.setNewImageSize(inputMat.height(),2);
+ imageBlob.setNewImageSize(inputMat.width(),3);
+ return inputMat;
+ }
+ }
+
+ private class Resize extends transformOp {
+ private int height;
+ private int width;
+ private String interp = "LINEAR";
+
+ public Mat run(Mat inputMat, ImageBlob imageBlob) {
+ int origin_w = inputMat.width();
+ int origin_h = inputMat.height();
+ imageBlob.getReshapeInfo().put("resize", new int[]{origin_w, origin_h});
+ Size sz = new Size(width, height);
+ Imgproc.resize(inputMat, inputMat, sz,0,0, interpMap.get(interp));
+ imageBlob.setNewImageSize(inputMat.height(),2);
+ imageBlob.setNewImageSize(inputMat.width(),3);
+ return inputMat;
+ }
+ }
+
+ private class Padding extends transformOp {
+ private double width;
+ private double height;
+ private double coarsest_stride;
+
+ public Mat run(Mat inputMat, ImageBlob imageBlob) {
+ int origin_w = inputMat.width();
+ int origin_h = inputMat.height();
+ imageBlob.getReshapeInfo().put("padding", new int[]{origin_w, origin_h});
+ double padding_w = 0;
+ double padding_h = 0;
+ if (width > 1 & height > 1) {
+ padding_w = width;
+ padding_h = height;
+ } else if (coarsest_stride > 1) {
+ padding_h = Math.ceil(origin_h / coarsest_stride) * coarsest_stride;
+ padding_w = Math.ceil(origin_w / coarsest_stride) * coarsest_stride;
+ }
+ imageBlob.setNewImageSize(inputMat.height(),2);
+ imageBlob.setNewImageSize(inputMat.width(),3);
+ Core.copyMakeBorder(inputMat, inputMat, 0, (int)padding_h, 0, (int)padding_w, Core.BORDER_CONSTANT, new Scalar(0));
+ return inputMat;
+ }
+ }
+
+ private class Normalize extends transformOp {
+ private Double[] mean = new Double[3];
+ private Double[] std = new Double[3];
+
+ public Mat run(Mat inputMat, ImageBlob imageBlob) {
+ inputMat.convertTo(inputMat, CvType.CV_32FC(3), 1/255.0);
+ Scalar meanScalar = new Scalar(mean[0], mean[1], mean[2]);
+ Scalar stdScalar = new Scalar(std[0], std[1], std[2]);
+ Core.subtract(inputMat, meanScalar, inputMat);
+ Core.divide(inputMat, stdScalar, inputMat);
+ return inputMat;
+ }
+ }
+}
+
diff --git a/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/visual/Visualize.java b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/visual/Visualize.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2cc7d280a7c7ed02f515a658840f9ad983478b0
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/java/com/baidu/paddlex/visual/Visualize.java
@@ -0,0 +1,148 @@
+// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+//
+// 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.baidu.paddlex.visual;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.Log;
+
+import com.baidu.paddlex.postprocess.DetResult;
+import com.baidu.paddlex.postprocess.SegResult;
+import com.baidu.paddlex.preprocess.ImageBlob;
+
+import org.opencv.core.Core;
+import org.opencv.core.CvType;
+import org.opencv.core.Mat;
+import org.opencv.core.Point;
+import org.opencv.core.Rect;
+import org.opencv.core.Scalar;
+import org.opencv.core.Size;
+import org.opencv.imgproc.Imgproc;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+public class Visualize {
+ protected static final String TAG = Visualize.class.getSimpleName();
+ protected float detectConfidenceThreshold = (float) 0.5;
+ protected Scalar[] colormap = new Scalar[]{};
+
+ protected void generateColorMap(int num_class) {
+ this.colormap = new Scalar[num_class];
+ this.colormap[0] = new Scalar(0, 0, 0);
+ for (int i = 0; i < num_class; i++) {
+ int j = 0;
+ int lab = i;
+ while (lab > 0) {
+ int r = (((lab >> 0) & 1) << (7 - j));
+ int g = (((lab >> 1) & 1) << (7 - j));
+ int b = (((lab >> 2) & 1) << (7 - j));
+ this.colormap[i] = new Scalar(r, g, b);
+ ++j;
+ lab >>= 3;
+ }
+ }
+ }
+
+ public float getDetectConfidenceThreshold() {
+ return detectConfidenceThreshold;
+ }
+
+ public void setDetectConfidenceThreshold(float detectConfidenceThreshold) {
+ this.detectConfidenceThreshold = detectConfidenceThreshold;
+ }
+
+ public Scalar[] getColormap() {
+ return colormap;
+ }
+
+ public void setColormap(Scalar[] colormap) {
+ this.colormap = colormap;
+ }
+
+ public void init(int num_class) {
+ generateColorMap(num_class);
+ }
+
+ public Mat draw(DetResult result, Mat visualizeMat) {
+ Paint rectPaint = new Paint();
+ rectPaint.setStyle(Paint.Style.STROKE);
+ rectPaint.setStrokeWidth(2);
+ Paint txtPaint = new Paint();
+ txtPaint.setTextSize(15);
+ txtPaint.setAntiAlias(true);
+ for (DetResult.Box box : result.getBoxes()) {
+ if (box.getScore() < detectConfidenceThreshold) {
+ continue;
+ }
+
+ String text = box.getCategory() + ":" + String.valueOf(box.getScore()).substring(0, 4);
+ Scalar roiColor = colormap[box.getCategoryId()];
+ double font_scale = 0.5;
+ int thickness = 1;
+ int font_face = Core.FONT_HERSHEY_SIMPLEX;
+
+ Point roiXyMin = new Point(box.getCoordinate()[0],box.getCoordinate()[1]);
+ Point roiXyMax = new Point(box.getCoordinate()[2],box.getCoordinate()[3]);
+ Size text_size = Imgproc.getTextSize(text, font_face,font_scale, thickness,null);
+ Imgproc.rectangle(visualizeMat, roiXyMin, roiXyMax, roiColor,2);
+
+ Point textXyMin = new Point(box.getCoordinate()[0],box.getCoordinate()[1]-text_size.height);
+ Point textXyMax = new Point(box.getCoordinate()[0]+text_size.width,box.getCoordinate()[1]);
+ Imgproc.rectangle(visualizeMat,textXyMin, textXyMax, roiColor,-1);
+ Imgproc.putText(visualizeMat,
+ text,
+ roiXyMin,
+ font_face,
+ font_scale,
+ new Scalar(255, 255, 255));
+ }
+ return visualizeMat;
+ }
+
+ public Mat draw(SegResult result, Mat visualizeMat, ImageBlob imageBlob, int cutoutClass) {
+ int new_h = (int)imageBlob.getNewImageSize()[2];
+ int new_w = (int)imageBlob.getNewImageSize()[3];
+ Mat mask = new Mat(new_h, new_w, CvType.CV_8UC(1));
+
+ for (int h = 0; h < new_h; h++) {
+ for (int w = 0; w < new_w; w++){
+ mask.put(h , w, (1-result.getMask().getScoreData()[cutoutClass + h * new_h + w]) * 255);
+ }
+ }
+ ListIterator> reverseReshapeInfo = new ArrayList>(imageBlob.getReshapeInfo().entrySet()).listIterator(imageBlob.getReshapeInfo().size());
+ while (reverseReshapeInfo.hasPrevious()) {
+ Map.Entry entry = reverseReshapeInfo.previous();
+ if (entry.getKey().equalsIgnoreCase("padding")) {
+ Rect crop_roi = new Rect(0, 0, entry.getValue()[0], entry.getValue()[1]);
+ mask = mask.submat(crop_roi);
+ } else if (entry.getKey().equalsIgnoreCase("resize")) {
+ Size sz = new Size(entry.getValue()[0], entry.getValue()[1]);
+ Imgproc.resize(mask, mask, sz,0,0,Imgproc.INTER_LINEAR);
+ }
+ Log.i(TAG, "postprocess operator: " + entry.getKey());
+ Log.i(TAG, "shape:: " + String.valueOf(mask.width()) + ","+ String.valueOf(mask.height()));
+ }
+
+ Mat dst = new Mat();
+ List listMat = Arrays.asList(visualizeMat, mask);
+ Core.merge(listMat, dst);
+
+ return dst;
+ }
+}
diff --git a/deploy/lite/android/sdk/src/main/res/values/strings.xml b/deploy/lite/android/sdk/src/main/res/values/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1f207644c2963126a573a7e8e694ef198d7c4976
--- /dev/null
+++ b/deploy/lite/android/sdk/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ PaddleX
+
diff --git a/deploy/lite/android/sdk/src/test/java/com/example/paddlex/ExampleUnitTest.java b/deploy/lite/android/sdk/src/test/java/com/example/paddlex/ExampleUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bff08d0b041cd9f4002debb918a602682d88fcc
--- /dev/null
+++ b/deploy/lite/android/sdk/src/test/java/com/example/paddlex/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.paddlex;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file