[Android] Add android aar package (#416)
* [Android] Add Android build docs and demo (#26) * [Backend] Add override flag to lite backend * [Docs] Add Android C++ SDK build docs * [Doc] fix android_build_docs typos * Update CMakeLists.txt * Update android.md * [Doc] Add PicoDet Android demo docs * [Doc] Update PicoDet Andorid demo docs * [Doc] Update PaddleClasModel Android demo docs * [Doc] Update fastdeploy android jni docs * [Doc] Update fastdeploy android jni usage docs * [Android] init fastdeploy android jar package * [Backend] support int8 option for lite backend * [Model] add Backend::Lite to paddle model * [Backend] use CopyFromCpu for lite backend. * [Android] package jni srcs and java api into aar * Update infer.cc * Update infer.cc * [Android] Update package build.gradle * [Android] Update android app examples * [Android] update android detection app
20
java/android/.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
.DS_Store
|
||||
.idea
|
||||
.gradle
|
||||
.cxx
|
||||
cache
|
||||
build
|
||||
app/cache
|
||||
app/libs/fastdeploy*
|
||||
app/.cxx
|
||||
app/build
|
||||
app/src/main/assets/models/*
|
||||
app/.gradle
|
||||
app/.idea
|
||||
fastdeploy/cache
|
||||
fastdeploy/libs/fastdeploy*
|
||||
fastdeploy/.cxx
|
||||
fastdeploy/build
|
||||
fastdeploy/src/main/assets/models/*
|
||||
fastdeploy/.gradle
|
||||
fastdeploy/.idea
|
3
java/android/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# FastDeploy Android AAR 包使用文档
|
||||
|
||||
- TODO
|
82
java/android/app/build.gradle
Normal file
@@ -0,0 +1,82 @@
|
||||
import java.security.MessageDigest
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdk 28
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.baidu.paddle.fastdeploy.app.examples'
|
||||
minSdkVersion 15
|
||||
//noinspection ExpiredTargetSdkVersion
|
||||
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: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
implementation 'org.jetbrains:annotations:15.0'
|
||||
implementation project(path: ':fastdeploy')
|
||||
//noinspection GradleDependency
|
||||
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 archives = [
|
||||
[
|
||||
'src': 'https://bj.bcebos.com/paddlehub/fastdeploy/picodet_s_320_coco_lcnet.tgz',
|
||||
'dest' : 'src/main/assets/models'
|
||||
],
|
||||
[
|
||||
'src': 'https://bj.bcebos.com/paddlehub/fastdeploy/picodet_l_320_coco_lcnet.tgz',
|
||||
'dest' : 'src/main/assets/models'
|
||||
]
|
||||
]
|
||||
|
||||
task downloadAndExtractArchives(type: DefaultTask) {
|
||||
doFirst {
|
||||
println "Downloading and extracting archives including models ..."
|
||||
}
|
||||
doLast {
|
||||
// Prepare cache folder for archives
|
||||
String cachePath = "cache"
|
||||
if (!file("${cachePath}").exists()) {
|
||||
mkdir "${cachePath}"
|
||||
}
|
||||
archives.eachWithIndex { archive, index ->
|
||||
MessageDigest messageDigest = MessageDigest.getInstance('MD5')
|
||||
messageDigest.update(archive.src.bytes)
|
||||
String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
|
||||
// Download the target archive if not exists
|
||||
boolean copyFiles = !file("${archive.dest}").exists()
|
||||
if (!file("${cachePath}/${cacheName}.tgz").exists()) {
|
||||
ant.get(src: archive.src, dest: file("${cachePath}/${cacheName}.tgz"))
|
||||
copyFiles = true // force to copy files from the latest archive files
|
||||
}
|
||||
// Extract the target archive if its dest path does not exists
|
||||
if (copyFiles) {
|
||||
copy {
|
||||
from tarTree("${cachePath}/${cacheName}.tgz")
|
||||
into "${archive.dest}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
preBuild.dependsOn downloadAndExtractArchives
|
21
java/android/app/proguard-rules.pro
vendored
Normal file
@@ -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
|
@@ -0,0 +1,26 @@
|
||||
package com.baidu.paddle.fastdeploy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("com.baidu.paddle.fastdeploy", appContext.getPackageName());
|
||||
}
|
||||
}
|
30
java/android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.baidu.paddle.fastdeploy.app.examples.detection">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name="com.baidu.paddle.fastdeploy.app.examples.detection.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.baidu.paddle.fastdeploy.app.examples.detection.SettingsActivity"
|
||||
android:label="Settings">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
80
java/android/app/src/main/assets/labels/coco_label_list.txt
Normal file
@@ -0,0 +1,80 @@
|
||||
person
|
||||
bicycle
|
||||
car
|
||||
motorcycle
|
||||
airplane
|
||||
bus
|
||||
train
|
||||
truck
|
||||
boat
|
||||
traffic light
|
||||
fire hydrant
|
||||
stop sign
|
||||
parking meter
|
||||
bench
|
||||
bird
|
||||
cat
|
||||
dog
|
||||
horse
|
||||
sheep
|
||||
cow
|
||||
elephant
|
||||
bear
|
||||
zebra
|
||||
giraffe
|
||||
backpack
|
||||
umbrella
|
||||
handbag
|
||||
tie
|
||||
suitcase
|
||||
frisbee
|
||||
skis
|
||||
snowboard
|
||||
sports ball
|
||||
kite
|
||||
baseball bat
|
||||
baseball glove
|
||||
skateboard
|
||||
surfboard
|
||||
tennis racket
|
||||
bottle
|
||||
wine glass
|
||||
cup
|
||||
fork
|
||||
knife
|
||||
spoon
|
||||
bowl
|
||||
banana
|
||||
apple
|
||||
sandwich
|
||||
orange
|
||||
broccoli
|
||||
carrot
|
||||
hot dog
|
||||
pizza
|
||||
donut
|
||||
cake
|
||||
chair
|
||||
couch
|
||||
potted plant
|
||||
bed
|
||||
dining table
|
||||
toilet
|
||||
tv
|
||||
laptop
|
||||
mouse
|
||||
remote
|
||||
keyboard
|
||||
cell phone
|
||||
microwave
|
||||
oven
|
||||
toaster
|
||||
sink
|
||||
refrigerator
|
||||
book
|
||||
clock
|
||||
vase
|
||||
scissors
|
||||
teddy bear
|
||||
hair drier
|
||||
toothbrush
|
21
java/android/app/src/main/assets/labels/pascalvoc_label_list
Normal file
@@ -0,0 +1,21 @@
|
||||
background
|
||||
aeroplane
|
||||
bicycle
|
||||
bird
|
||||
boat
|
||||
bottle
|
||||
bus
|
||||
car
|
||||
cat
|
||||
chair
|
||||
cow
|
||||
diningtable
|
||||
dog
|
||||
horse
|
||||
motorbike
|
||||
person
|
||||
pottedplant
|
||||
sheep
|
||||
sofa
|
||||
train
|
||||
tvmonitor
|
@@ -0,0 +1,255 @@
|
||||
package com.baidu.paddle.fastdeploy.app.examples.detection;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.RuntimeOption;
|
||||
import com.baidu.paddle.fastdeploy.app.examples.detection.R;
|
||||
import com.baidu.paddle.fastdeploy.app.ui.CameraSurfaceView;
|
||||
import com.baidu.paddle.fastdeploy.app.ui.Utils;
|
||||
import com.baidu.paddle.fastdeploy.vision.DetectionResult;
|
||||
import com.baidu.paddle.fastdeploy.vision.detection.PicoDet;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class MainActivity extends Activity implements View.OnClickListener, CameraSurfaceView.OnTextureChangedListener {
|
||||
private static final String TAG = MainActivity.class.getSimpleName();
|
||||
|
||||
CameraSurfaceView svPreview;
|
||||
TextView tvStatus;
|
||||
ImageButton btnSwitch;
|
||||
ImageButton btnShutter;
|
||||
ImageButton btnSettings;
|
||||
ImageView realtimeToggleButton;
|
||||
boolean isRealtimeStatusRunning = false;
|
||||
ImageView backInPreview;
|
||||
|
||||
String savedImagePath = "result.jpg";
|
||||
int lastFrameIndex = 0;
|
||||
long lastFrameTime;
|
||||
|
||||
// Call 'init' and 'release' manually later
|
||||
PicoDet predictor = new PicoDet();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Fullscreen
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
// Clear all setting items to avoid app crashing due to the incorrect settings
|
||||
initSettings();
|
||||
|
||||
// Init the camera preview and UI components
|
||||
initView();
|
||||
|
||||
// Check and request CAMERA and WRITE_EXTERNAL_STORAGE permissions
|
||||
if (!checkAllPermissions()) {
|
||||
requestAllPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NonConstantResourceId")
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.btn_switch:
|
||||
svPreview.switchCamera();
|
||||
break;
|
||||
case R.id.btn_shutter:
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
SimpleDateFormat date = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
|
||||
synchronized (this) {
|
||||
savedImagePath = Utils.getDCIMDirectory() + File.separator + date.format(new Date()).toString() + ".png";
|
||||
}
|
||||
Toast.makeText(MainActivity.this, "Save snapshot to " + savedImagePath, Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case R.id.btn_settings:
|
||||
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
|
||||
break;
|
||||
case R.id.realtime_toggle_btn:
|
||||
toggleRealtimeStyle();
|
||||
break;
|
||||
case R.id.back_in_preview:
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleRealtimeStyle() {
|
||||
if (isRealtimeStatusRunning) {
|
||||
isRealtimeStatusRunning = false;
|
||||
realtimeToggleButton.setImageResource(R.drawable.realtime_stop_btn);
|
||||
svPreview.setOnTextureChangedListener(this);
|
||||
tvStatus.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
isRealtimeStatusRunning = true;
|
||||
realtimeToggleButton.setImageResource(R.drawable.realtime_start_btn);
|
||||
tvStatus.setVisibility(View.GONE);
|
||||
svPreview.setOnTextureChangedListener(new CameraSurfaceView.OnTextureChangedListener() {
|
||||
@Override
|
||||
public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) {
|
||||
String savedImagePath = "";
|
||||
synchronized (this) {
|
||||
savedImagePath = MainActivity.this.savedImagePath;
|
||||
}
|
||||
boolean modified = false;
|
||||
DetectionResult result = predictor.predict(
|
||||
ARGB8888ImageBitmap, savedImagePath, SettingsActivity.scoreThreshold);
|
||||
modified = result.initialized();
|
||||
if (!savedImagePath.isEmpty()) {
|
||||
synchronized (this) {
|
||||
MainActivity.this.savedImagePath = "result.jpg";
|
||||
}
|
||||
}
|
||||
lastFrameIndex++;
|
||||
if (lastFrameIndex >= 30) {
|
||||
final int fps = (int) (lastFrameIndex * 1e9 / (System.nanoTime() - lastFrameTime));
|
||||
runOnUiThread(new Runnable() {
|
||||
@SuppressLint("SetTextI18n")
|
||||
public void run() {
|
||||
tvStatus.setText(Integer.toString(fps) + "fps");
|
||||
}
|
||||
});
|
||||
lastFrameIndex = 0;
|
||||
lastFrameTime = System.nanoTime();
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// Reload settings and re-initialize the predictor
|
||||
checkAndUpdateSettings();
|
||||
// Open camera until the permissions have been granted
|
||||
if (!checkAllPermissions()) {
|
||||
svPreview.disableCamera();
|
||||
}
|
||||
svPreview.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
svPreview.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (predictor != null) {
|
||||
predictor.release();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public void initView() {
|
||||
svPreview = (CameraSurfaceView) findViewById(R.id.sv_preview);
|
||||
svPreview.setOnTextureChangedListener(this);
|
||||
tvStatus = (TextView) findViewById(R.id.tv_status);
|
||||
btnSwitch = (ImageButton) findViewById(R.id.btn_switch);
|
||||
btnSwitch.setOnClickListener(this);
|
||||
btnShutter = (ImageButton) findViewById(R.id.btn_shutter);
|
||||
btnShutter.setOnClickListener(this);
|
||||
btnSettings = (ImageButton) findViewById(R.id.btn_settings);
|
||||
btnSettings.setOnClickListener(this);
|
||||
realtimeToggleButton = findViewById(R.id.realtime_toggle_btn);
|
||||
realtimeToggleButton.setOnClickListener(this);
|
||||
backInPreview = findViewById(R.id.back_in_preview);
|
||||
backInPreview.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public void initSettings() {
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.clear();
|
||||
editor.commit();
|
||||
SettingsActivity.resetSettings();
|
||||
}
|
||||
|
||||
public void checkAndUpdateSettings() {
|
||||
if (SettingsActivity.checkAndUpdateSettings(this)) {
|
||||
String realModelDir = getCacheDir() + "/" + SettingsActivity.modelDir;
|
||||
Utils.copyDirectoryFromAssets(this, SettingsActivity.modelDir, realModelDir);
|
||||
String realLabelPath = getCacheDir() + "/" + SettingsActivity.labelPath;
|
||||
Utils.copyFileFromAssets(this, SettingsActivity.labelPath, realLabelPath);
|
||||
|
||||
String modelFile = realModelDir + "/" + "model.pdmodel";
|
||||
String paramsFile = realModelDir + "/" + "model.pdiparams";
|
||||
String configFile = realModelDir + "/" + "infer_cfg.yml";
|
||||
String labelFile = realLabelPath;
|
||||
RuntimeOption option = new RuntimeOption();
|
||||
option.setCpuThreadNum(SettingsActivity.cpuThreadNum);
|
||||
option.setLitePowerMode(SettingsActivity.cpuPowerMode);
|
||||
option.enableRecordTimeOfRuntime();
|
||||
if (Boolean.parseBoolean(SettingsActivity.enableLiteFp16)) {
|
||||
option.enableLiteFp16();
|
||||
}
|
||||
predictor.init(modelFile, paramsFile, configFile, labelFile, option);
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
new AlertDialog.Builder(MainActivity.this)
|
||||
.setTitle("Permission denied")
|
||||
.setMessage("Click to force quit the app, then open Settings->Apps & notifications->Target " +
|
||||
"App->Permissions to grant all of the permissions.")
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("Exit", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
MainActivity.this.finish();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void requestAllPermissions() {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.CAMERA}, 0);
|
||||
}
|
||||
|
||||
private boolean checkAllPermissions() {
|
||||
return ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
|
||||
&& ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
}
|
@@ -0,0 +1,198 @@
|
||||
package com.baidu.paddle.fastdeploy.app.examples.detection;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.app.examples.detection.R;
|
||||
import com.baidu.paddle.fastdeploy.app.ui.AppCompatPreferenceActivity;
|
||||
import com.baidu.paddle.fastdeploy.app.ui.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SettingsActivity extends AppCompatPreferenceActivity implements
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private static final String TAG = SettingsActivity.class.getSimpleName();
|
||||
|
||||
static public int selectedModelIdx = -1;
|
||||
static public String modelDir = "";
|
||||
static public String labelPath = "";
|
||||
static public int cpuThreadNum = 2;
|
||||
static public String cpuPowerMode = "";
|
||||
static public float scoreThreshold = 0.4f;
|
||||
static public String enableLiteFp16 = "true";
|
||||
|
||||
ListPreference lpChoosePreInstalledModel = null;
|
||||
EditTextPreference etModelDir = null;
|
||||
EditTextPreference etLabelPath = null;
|
||||
ListPreference lpCPUThreadNum = null;
|
||||
ListPreference lpCPUPowerMode = null;
|
||||
EditTextPreference etScoreThreshold = null;
|
||||
ListPreference lpEnableLiteFp16 = null;
|
||||
|
||||
List<String> preInstalledModelDirs = null;
|
||||
List<String> preInstalledLabelPaths = null;
|
||||
List<String> preInstalledCPUThreadNums = null;
|
||||
List<String> preInstalledCPUPowerModes = null;
|
||||
List<String> preInstalledScoreThresholds = null;
|
||||
List<String> preInstalledEnableLiteFp16s = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.settings);
|
||||
ActionBar supportActionBar = getSupportActionBar();
|
||||
if (supportActionBar != null) {
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
// Initialize pre-installed models
|
||||
preInstalledModelDirs = new ArrayList<String>();
|
||||
preInstalledLabelPaths = new ArrayList<String>();
|
||||
preInstalledCPUThreadNums = new ArrayList<String>();
|
||||
preInstalledCPUPowerModes = new ArrayList<String>();
|
||||
preInstalledScoreThresholds = new ArrayList<String>();
|
||||
preInstalledEnableLiteFp16s = new ArrayList<String>();
|
||||
preInstalledModelDirs.add(getString(R.string.MODEL_DIR_DEFAULT));
|
||||
preInstalledLabelPaths.add(getString(R.string.LABEL_PATH_DEFAULT));
|
||||
preInstalledCPUThreadNums.add(getString(R.string.CPU_THREAD_NUM_DEFAULT));
|
||||
preInstalledCPUPowerModes.add(getString(R.string.CPU_POWER_MODE_DEFAULT));
|
||||
preInstalledScoreThresholds.add(getString(R.string.SCORE_THRESHOLD_DEFAULT));
|
||||
preInstalledEnableLiteFp16s.add(getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT));
|
||||
|
||||
// Setup UI components
|
||||
lpChoosePreInstalledModel =
|
||||
(ListPreference) findPreference(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY));
|
||||
String[] preInstalledModelNames = new String[preInstalledModelDirs.size()];
|
||||
for (int i = 0; i < preInstalledModelDirs.size(); i++) {
|
||||
preInstalledModelNames[i] = preInstalledModelDirs.get(i).substring(preInstalledModelDirs.get(i).lastIndexOf("/") + 1);
|
||||
}
|
||||
lpChoosePreInstalledModel.setEntries(preInstalledModelNames);
|
||||
lpChoosePreInstalledModel.setEntryValues(preInstalledModelDirs.toArray(new String[preInstalledModelDirs.size()]));
|
||||
lpCPUThreadNum = (ListPreference) findPreference(getString(R.string.CPU_THREAD_NUM_KEY));
|
||||
lpCPUPowerMode = (ListPreference) findPreference(getString(R.string.CPU_POWER_MODE_KEY));
|
||||
etModelDir = (EditTextPreference) findPreference(getString(R.string.MODEL_DIR_KEY));
|
||||
etModelDir.setTitle("Model dir (SDCard: " + Utils.getSDCardDirectory() + ")");
|
||||
etLabelPath = (EditTextPreference) findPreference(getString(R.string.LABEL_PATH_KEY));
|
||||
etLabelPath.setTitle("Label path (SDCard: " + Utils.getSDCardDirectory() + ")");
|
||||
etScoreThreshold = (EditTextPreference) findPreference(getString(R.string.SCORE_THRESHOLD_KEY));
|
||||
lpEnableLiteFp16 = (ListPreference) findPreference(getString(R.string.ENABLE_LITE_FP16_MODE_KEY));
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private void reloadSettingsAndUpdateUI() {
|
||||
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
|
||||
|
||||
String selected_model_dir = sharedPreferences.getString(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY),
|
||||
getString(R.string.MODEL_DIR_DEFAULT));
|
||||
int selected_model_idx = lpChoosePreInstalledModel.findIndexOfValue(selected_model_dir);
|
||||
if (selected_model_idx >= 0 && selected_model_idx < preInstalledModelDirs.size() && selected_model_idx != selectedModelIdx) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(getString(R.string.MODEL_DIR_KEY), preInstalledModelDirs.get(selected_model_idx));
|
||||
editor.putString(getString(R.string.LABEL_PATH_KEY), preInstalledLabelPaths.get(selected_model_idx));
|
||||
editor.putString(getString(R.string.CPU_THREAD_NUM_KEY), preInstalledCPUThreadNums.get(selected_model_idx));
|
||||
editor.putString(getString(R.string.CPU_POWER_MODE_KEY), preInstalledCPUPowerModes.get(selected_model_idx));
|
||||
editor.putString(getString(R.string.SCORE_THRESHOLD_KEY), preInstalledScoreThresholds.get(selected_model_idx));
|
||||
editor.putString(getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT), preInstalledEnableLiteFp16s.get(selected_model_idx));
|
||||
editor.commit();
|
||||
lpChoosePreInstalledModel.setSummary(selected_model_dir);
|
||||
selectedModelIdx = selected_model_idx;
|
||||
}
|
||||
|
||||
String model_dir = sharedPreferences.getString(getString(R.string.MODEL_DIR_KEY),
|
||||
getString(R.string.MODEL_DIR_DEFAULT));
|
||||
String label_path = sharedPreferences.getString(getString(R.string.LABEL_PATH_KEY),
|
||||
getString(R.string.LABEL_PATH_DEFAULT));
|
||||
String cpu_thread_num = sharedPreferences.getString(getString(R.string.CPU_THREAD_NUM_KEY),
|
||||
getString(R.string.CPU_THREAD_NUM_DEFAULT));
|
||||
String cpu_power_mode = sharedPreferences.getString(getString(R.string.CPU_POWER_MODE_KEY),
|
||||
getString(R.string.CPU_POWER_MODE_DEFAULT));
|
||||
String score_threshold = sharedPreferences.getString(getString(R.string.SCORE_THRESHOLD_KEY),
|
||||
getString(R.string.SCORE_THRESHOLD_DEFAULT));
|
||||
String enable_lite_fp16 = sharedPreferences.getString(getString(R.string.ENABLE_LITE_FP16_MODE_KEY),
|
||||
getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT));
|
||||
|
||||
etModelDir.setSummary(model_dir);
|
||||
etLabelPath.setSummary(label_path);
|
||||
lpCPUThreadNum.setValue(cpu_thread_num);
|
||||
lpCPUThreadNum.setSummary(cpu_thread_num);
|
||||
lpCPUPowerMode.setValue(cpu_power_mode);
|
||||
lpCPUPowerMode.setSummary(cpu_power_mode);
|
||||
etScoreThreshold.setSummary(score_threshold);
|
||||
etScoreThreshold.setText(score_threshold);
|
||||
lpEnableLiteFp16.setValue(enable_lite_fp16);
|
||||
lpEnableLiteFp16.setSummary(enable_lite_fp16);
|
||||
|
||||
}
|
||||
|
||||
static boolean checkAndUpdateSettings(Context ctx) {
|
||||
boolean settingsChanged = false;
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
|
||||
String model_dir = sharedPreferences.getString(ctx.getString(R.string.MODEL_DIR_KEY),
|
||||
ctx.getString(R.string.MODEL_DIR_DEFAULT));
|
||||
settingsChanged |= !modelDir.equalsIgnoreCase(model_dir);
|
||||
modelDir = model_dir;
|
||||
|
||||
String label_path = sharedPreferences.getString(ctx.getString(R.string.LABEL_PATH_KEY),
|
||||
ctx.getString(R.string.LABEL_PATH_DEFAULT));
|
||||
settingsChanged |= !labelPath.equalsIgnoreCase(label_path);
|
||||
labelPath = label_path;
|
||||
|
||||
String cpu_thread_num = sharedPreferences.getString(ctx.getString(R.string.CPU_THREAD_NUM_KEY),
|
||||
ctx.getString(R.string.CPU_THREAD_NUM_DEFAULT));
|
||||
settingsChanged |= cpuThreadNum != Integer.parseInt(cpu_thread_num);
|
||||
cpuThreadNum = Integer.parseInt(cpu_thread_num);
|
||||
|
||||
String cpu_power_mode = sharedPreferences.getString(ctx.getString(R.string.CPU_POWER_MODE_KEY),
|
||||
ctx.getString(R.string.CPU_POWER_MODE_DEFAULT));
|
||||
settingsChanged |= !cpuPowerMode.equalsIgnoreCase(cpu_power_mode);
|
||||
cpuPowerMode = cpu_power_mode;
|
||||
|
||||
String score_threshold = sharedPreferences.getString(ctx.getString(R.string.SCORE_THRESHOLD_KEY),
|
||||
ctx.getString(R.string.SCORE_THRESHOLD_DEFAULT));
|
||||
settingsChanged |= scoreThreshold != Float.parseFloat(score_threshold);
|
||||
scoreThreshold = Float.parseFloat(score_threshold);
|
||||
|
||||
String enable_lite_fp16 = sharedPreferences.getString(ctx.getString(R.string.ENABLE_LITE_FP16_MODE_KEY),
|
||||
ctx.getString(R.string.ENABLE_LITE_FP16_MODE_DEFAULT));
|
||||
settingsChanged |= !enableLiteFp16.equalsIgnoreCase(enable_lite_fp16);
|
||||
enableLiteFp16 = enable_lite_fp16;
|
||||
|
||||
return settingsChanged;
|
||||
}
|
||||
|
||||
static void resetSettings() {
|
||||
selectedModelIdx = -1;
|
||||
modelDir = "";
|
||||
labelPath = "";
|
||||
cpuThreadNum = 2;
|
||||
cpuPowerMode = "";
|
||||
scoreThreshold = 0.4f;
|
||||
enableLiteFp16 = "true";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
|
||||
reloadSettingsAndUpdateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
reloadSettingsAndUpdateUI();
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.baidu.paddle.fastdeploy.app.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
|
||||
public class ActionBarLayout extends RelativeLayout {
|
||||
private int layoutHeight = 150;
|
||||
|
||||
public ActionBarLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ActionBarLayout(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ActionBarLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
setMeasuredDimension(width, layoutHeight);
|
||||
setBackgroundColor(Color.BLACK);
|
||||
setAlpha(0.9f);
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
package com.baidu.paddle.fastdeploy.app.ui;
|
||||
|
||||
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 PreferenceActivity} which implements and proxies the necessary calls
|
||||
* to be used with AppCompat.
|
||||
* <p>
|
||||
* This technique can be used with an {@link android.app.Activity} class, not just
|
||||
* {@link 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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,329 @@
|
||||
package com.baidu.paddle.fastdeploy.app.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.CameraInfo;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.opengl.GLES11Ext;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.opengl.GLSurfaceView.Renderer;
|
||||
import android.opengl.GLUtils;
|
||||
import android.opengl.Matrix;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
public class CameraSurfaceView extends GLSurfaceView implements Renderer,
|
||||
SurfaceTexture.OnFrameAvailableListener {
|
||||
private static final String TAG = CameraSurfaceView.class.getSimpleName();
|
||||
|
||||
public static final int EXPECTED_PREVIEW_WIDTH = 1280;
|
||||
public static final int EXPECTED_PREVIEW_HEIGHT = 720;
|
||||
|
||||
|
||||
protected int numberOfCameras;
|
||||
protected int selectedCameraId;
|
||||
protected boolean disableCamera = false;
|
||||
protected Camera camera;
|
||||
|
||||
protected Context context;
|
||||
protected SurfaceTexture surfaceTexture;
|
||||
protected int surfaceWidth = 0;
|
||||
protected int surfaceHeight = 0;
|
||||
protected int textureWidth = 0;
|
||||
protected int textureHeight = 0;
|
||||
|
||||
// In order to manipulate the camera preview data and render the modified one
|
||||
// to the screen, three textures are created and the data flow is shown as following:
|
||||
// previewdata->camTextureId->fboTexureId->drawTexureId->framebuffer
|
||||
protected int[] fbo = {0};
|
||||
protected int[] camTextureId = {0};
|
||||
protected int[] fboTexureId = {0};
|
||||
protected int[] drawTexureId = {0};
|
||||
|
||||
private final String vss = ""
|
||||
+ "attribute vec2 vPosition;\n"
|
||||
+ "attribute vec2 vTexCoord;\n" + "varying vec2 texCoord;\n"
|
||||
+ "void main() {\n" + " texCoord = vTexCoord;\n"
|
||||
+ " gl_Position = vec4 (vPosition.x, vPosition.y, 0.0, 1.0);\n"
|
||||
+ "}";
|
||||
|
||||
private final String fssCam2FBO = ""
|
||||
+ "#extension GL_OES_EGL_image_external : require\n"
|
||||
+ "precision mediump float;\n"
|
||||
+ "uniform samplerExternalOES sTexture;\n"
|
||||
+ "varying vec2 texCoord;\n"
|
||||
+ "void main() {\n"
|
||||
+ " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}";
|
||||
|
||||
private final String fssTex2Screen = ""
|
||||
+ "precision mediump float;\n"
|
||||
+ "uniform sampler2D sTexture;\n"
|
||||
+ "varying vec2 texCoord;\n"
|
||||
+ "void main() {\n"
|
||||
+ " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}";
|
||||
|
||||
private final float[] vertexCoords = {
|
||||
-1, -1,
|
||||
-1, 1,
|
||||
1, -1,
|
||||
1, 1};
|
||||
private float[] textureCoords = {
|
||||
0, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 0};
|
||||
|
||||
private FloatBuffer vertexCoordsBuffer;
|
||||
private FloatBuffer textureCoordsBuffer;
|
||||
|
||||
private int progCam2FBO = -1;
|
||||
private int progTex2Screen = -1;
|
||||
private int vcCam2FBO;
|
||||
private int tcCam2FBO;
|
||||
private int vcTex2Screen;
|
||||
private int tcTex2Screen;
|
||||
|
||||
public interface OnTextureChangedListener {
|
||||
boolean onTextureChanged(Bitmap ARGB8888ImageBitmap);
|
||||
}
|
||||
|
||||
private OnTextureChangedListener onTextureChangedListener = null;
|
||||
|
||||
public void setOnTextureChangedListener(OnTextureChangedListener listener) {
|
||||
onTextureChangedListener = listener;
|
||||
}
|
||||
|
||||
public CameraSurfaceView(Context ctx, AttributeSet attrs) {
|
||||
super(ctx, attrs);
|
||||
context = ctx;
|
||||
setEGLContextClientVersion(2);
|
||||
setRenderer(this);
|
||||
setRenderMode(RENDERMODE_WHEN_DIRTY);
|
||||
|
||||
// Find the total number of available cameras and the ID of the default camera
|
||||
numberOfCameras = Camera.getNumberOfCameras();
|
||||
CameraInfo cameraInfo = new CameraInfo();
|
||||
for (int i = 0; i < numberOfCameras; i++) {
|
||||
Camera.getCameraInfo(i, cameraInfo);
|
||||
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
|
||||
selectedCameraId = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
// Create OES texture for storing camera preview data(YUV format)
|
||||
GLES20.glGenTextures(1, camTextureId, 0);
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, camTextureId[0]);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
|
||||
surfaceTexture = new SurfaceTexture(camTextureId[0]);
|
||||
surfaceTexture.setOnFrameAvailableListener(this);
|
||||
|
||||
// Prepare vertex and texture coordinates
|
||||
int bytes = vertexCoords.length * Float.SIZE / Byte.SIZE;
|
||||
vertexCoordsBuffer = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
textureCoordsBuffer = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
vertexCoordsBuffer.put(vertexCoords).position(0);
|
||||
textureCoordsBuffer.put(textureCoords).position(0);
|
||||
|
||||
// Create vertex and fragment shaders
|
||||
// camTextureId->fboTexureId
|
||||
progCam2FBO = Utils.createShaderProgram(vss, fssCam2FBO);
|
||||
vcCam2FBO = GLES20.glGetAttribLocation(progCam2FBO, "vPosition");
|
||||
tcCam2FBO = GLES20.glGetAttribLocation(progCam2FBO, "vTexCoord");
|
||||
GLES20.glEnableVertexAttribArray(vcCam2FBO);
|
||||
GLES20.glEnableVertexAttribArray(tcCam2FBO);
|
||||
// fboTexureId/drawTexureId -> screen
|
||||
progTex2Screen = Utils.createShaderProgram(vss, fssTex2Screen);
|
||||
vcTex2Screen = GLES20.glGetAttribLocation(progTex2Screen, "vPosition");
|
||||
tcTex2Screen = GLES20.glGetAttribLocation(progTex2Screen, "vTexCoord");
|
||||
GLES20.glEnableVertexAttribArray(vcTex2Screen);
|
||||
GLES20.glEnableVertexAttribArray(tcTex2Screen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
surfaceWidth = width;
|
||||
surfaceHeight = height;
|
||||
openCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
if (surfaceTexture == null) return;
|
||||
|
||||
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
|
||||
surfaceTexture.updateTexImage();
|
||||
float[] matrix = new float[16];
|
||||
surfaceTexture.getTransformMatrix(matrix);
|
||||
|
||||
// camTextureId->fboTexureId
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
|
||||
GLES20.glViewport(0, 0, textureWidth, textureHeight);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
GLES20.glUseProgram(progCam2FBO);
|
||||
GLES20.glVertexAttribPointer(vcCam2FBO, 2, GLES20.GL_FLOAT, false, 4 * 2, vertexCoordsBuffer);
|
||||
textureCoordsBuffer.clear();
|
||||
textureCoordsBuffer.put(transformTextureCoordinates(textureCoords, matrix));
|
||||
textureCoordsBuffer.position(0);
|
||||
GLES20.glVertexAttribPointer(tcCam2FBO, 2, GLES20.GL_FLOAT, false, 4 * 2, textureCoordsBuffer);
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, camTextureId[0]);
|
||||
GLES20.glUniform1i(GLES20.glGetUniformLocation(progCam2FBO, "sTexture"), 0);
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
GLES20.glFlush();
|
||||
|
||||
// Check if the draw texture is set
|
||||
int targetTexureId = fboTexureId[0];
|
||||
if (onTextureChangedListener != null) {
|
||||
// Read pixels of FBO to a bitmap
|
||||
ByteBuffer pixelBuffer = ByteBuffer.allocate(textureWidth * textureHeight * 4);
|
||||
GLES20.glReadPixels(0, 0, textureWidth, textureHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
|
||||
Bitmap ARGB8888ImageBitmap = Bitmap.createBitmap(textureWidth, textureHeight, Bitmap.Config.ARGB_8888);
|
||||
ARGB8888ImageBitmap.copyPixelsFromBuffer(pixelBuffer);
|
||||
boolean modified = onTextureChangedListener.onTextureChanged(ARGB8888ImageBitmap);
|
||||
if (modified) {
|
||||
targetTexureId = drawTexureId[0];
|
||||
// Update a bitmap to the GL texture if modified
|
||||
GLES20.glActiveTexture(targetTexureId);
|
||||
// GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, targetTexureId);
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, targetTexureId);
|
||||
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, ARGB8888ImageBitmap, 0);
|
||||
}
|
||||
ARGB8888ImageBitmap.recycle();
|
||||
}
|
||||
|
||||
// fboTexureId/drawTexureId->Screen
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
||||
GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
GLES20.glUseProgram(progTex2Screen);
|
||||
GLES20.glVertexAttribPointer(vcTex2Screen, 2, GLES20.GL_FLOAT, false, 4 * 2, vertexCoordsBuffer);
|
||||
textureCoordsBuffer.clear();
|
||||
textureCoordsBuffer.put(textureCoords);
|
||||
textureCoordsBuffer.position(0);
|
||||
GLES20.glVertexAttribPointer(tcTex2Screen, 2, GLES20.GL_FLOAT, false, 4 * 2, textureCoordsBuffer);
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, targetTexureId);
|
||||
GLES20.glUniform1i(GLES20.glGetUniformLocation(progTex2Screen, "sTexture"), 0);
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
GLES20.glFlush();
|
||||
}
|
||||
|
||||
private float[] transformTextureCoordinates(float[] coords, float[] matrix) {
|
||||
float[] result = new float[coords.length];
|
||||
float[] vt = new float[4];
|
||||
for (int i = 0; i < coords.length; i += 2) {
|
||||
float[] v = {coords[i], coords[i + 1], 0, 1};
|
||||
Matrix.multiplyMV(vt, 0, matrix, 0, v, 0);
|
||||
result[i] = vt[0];
|
||||
result[i + 1] = vt[1];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
releaseCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
|
||||
requestRender();
|
||||
}
|
||||
|
||||
public void disableCamera() {
|
||||
disableCamera = true;
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
releaseCamera();
|
||||
selectedCameraId = (selectedCameraId + 1) % numberOfCameras;
|
||||
openCamera();
|
||||
}
|
||||
|
||||
public void openCamera() {
|
||||
if (disableCamera) return;
|
||||
camera = Camera.open(selectedCameraId);
|
||||
List<Size> supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes();
|
||||
Size previewSize = Utils.getOptimalPreviewSize(supportedPreviewSizes, EXPECTED_PREVIEW_WIDTH,
|
||||
EXPECTED_PREVIEW_HEIGHT);
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
parameters.setPreviewSize(previewSize.width, previewSize.height);
|
||||
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
|
||||
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
|
||||
}
|
||||
camera.setParameters(parameters);
|
||||
int degree = Utils.getCameraDisplayOrientation(context, selectedCameraId);
|
||||
camera.setDisplayOrientation(degree);
|
||||
boolean rotate = degree == 90 || degree == 270;
|
||||
textureWidth = rotate ? previewSize.height : previewSize.width;
|
||||
textureHeight = rotate ? previewSize.width : previewSize.height;
|
||||
// Destroy FBO and draw textures
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
||||
GLES20.glDeleteFramebuffers(1, fbo, 0);
|
||||
GLES20.glDeleteTextures(1, drawTexureId, 0);
|
||||
GLES20.glDeleteTextures(1, fboTexureId, 0);
|
||||
// Normal texture for storing modified camera preview data(RGBA format)
|
||||
GLES20.glGenTextures(1, drawTexureId, 0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, drawTexureId[0]);
|
||||
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, textureWidth, textureHeight, 0,
|
||||
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
|
||||
// FBO texture for storing camera preview data(RGBA format)
|
||||
GLES20.glGenTextures(1, fboTexureId, 0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTexureId[0]);
|
||||
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, textureWidth, textureHeight, 0,
|
||||
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
|
||||
// Generate FBO and bind to FBO texture
|
||||
GLES20.glGenFramebuffers(1, fbo, 0);
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
|
||||
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
|
||||
fboTexureId[0], 0);
|
||||
try {
|
||||
camera.setPreviewTexture(surfaceTexture);
|
||||
} catch (IOException exception) {
|
||||
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
|
||||
}
|
||||
camera.startPreview();
|
||||
}
|
||||
|
||||
public void releaseCamera() {
|
||||
if (camera != null) {
|
||||
camera.setPreviewCallback(null);
|
||||
camera.stopPreview();
|
||||
camera.release();
|
||||
camera = null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,244 @@
|
||||
package com.baidu.paddle.fastdeploy.app.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.Camera;
|
||||
import android.opengl.GLES20;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
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;
|
||||
import java.util.List;
|
||||
|
||||
public class Utils {
|
||||
private static final String TAG = Utils.class.getSimpleName();
|
||||
|
||||
public static void RecursiveCreateDirectories(String fileDir) {
|
||||
String[] fileDirs = fileDir.split("\\/");
|
||||
String topPath = "";
|
||||
for (int i = 0; i < fileDirs.length; i++) {
|
||||
topPath += "/" + fileDirs[i];
|
||||
File file = new File(topPath);
|
||||
if (file.exists()) {
|
||||
continue;
|
||||
} else {
|
||||
file.mkdir();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyFileFromAssets(Context appCtx, String srcPath, String dstPath) {
|
||||
if (srcPath.isEmpty() || dstPath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String dstDir = dstPath.substring(0, dstPath.lastIndexOf('/'));
|
||||
if (dstDir.length() > 0) {
|
||||
RecursiveCreateDirectories(dstDir);
|
||||
}
|
||||
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;
|
||||
if (new File(srcSubPath).isDirectory()) {
|
||||
copyDirectoryFromAssets(appCtx, srcSubPath, dstSubPath);
|
||||
} else {
|
||||
copyFileFromAssets(appCtx, srcSubPath, dstSubPath);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
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 String getDCIMDirectory() {
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();
|
||||
}
|
||||
|
||||
public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
|
||||
final double ASPECT_TOLERANCE = 0.1;
|
||||
double targetRatio = (double) w / h;
|
||||
if (sizes == null) return null;
|
||||
|
||||
Camera.Size optimalSize = null;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
|
||||
int targetHeight = h;
|
||||
|
||||
// Try to find an size match aspect ratio and size
|
||||
for (Camera.Size size : sizes) {
|
||||
double ratio = (double) size.width / size.height;
|
||||
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
|
||||
if (Math.abs(size.height - targetHeight) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(size.height - targetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot find the one match the aspect ratio, ignore the requirement
|
||||
if (optimalSize == null) {
|
||||
minDiff = Double.MAX_VALUE;
|
||||
for (Camera.Size size : sizes) {
|
||||
if (Math.abs(size.height - targetHeight) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(size.height - targetHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
return optimalSize;
|
||||
}
|
||||
|
||||
public static int getScreenWidth() {
|
||||
return Resources.getSystem().getDisplayMetrics().widthPixels;
|
||||
}
|
||||
|
||||
public static int getScreenHeight() {
|
||||
return Resources.getSystem().getDisplayMetrics().heightPixels;
|
||||
}
|
||||
|
||||
public static int getCameraDisplayOrientation(Context context, int cameraId) {
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraId, info);
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
int rotation = wm.getDefaultDisplay().getRotation();
|
||||
int degrees = 0;
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_0:
|
||||
degrees = 0;
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
degrees = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
degrees = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
degrees = 270;
|
||||
break;
|
||||
}
|
||||
int result;
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
result = (info.orientation + degrees) % 360;
|
||||
result = (360 - result) % 360; // compensate the mirror
|
||||
} else {
|
||||
// back-facing
|
||||
result = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int createShaderProgram(String vss, String fss) {
|
||||
int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
|
||||
GLES20.glShaderSource(vshader, vss);
|
||||
GLES20.glCompileShader(vshader);
|
||||
int[] status = new int[1];
|
||||
GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetShaderInfoLog(vshader));
|
||||
GLES20.glDeleteShader(vshader);
|
||||
vshader = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
|
||||
GLES20.glShaderSource(fshader, fss);
|
||||
GLES20.glCompileShader(fshader);
|
||||
GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetShaderInfoLog(fshader));
|
||||
GLES20.glDeleteShader(vshader);
|
||||
GLES20.glDeleteShader(fshader);
|
||||
fshader = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int program = GLES20.glCreateProgram();
|
||||
GLES20.glAttachShader(program, vshader);
|
||||
GLES20.glAttachShader(program, fshader);
|
||||
GLES20.glLinkProgram(program);
|
||||
GLES20.glDeleteShader(vshader);
|
||||
GLES20.glDeleteShader(fshader);
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
|
||||
program = 0;
|
||||
return 0;
|
||||
}
|
||||
GLES20.glValidateProgram(program);
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_VALIDATE_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
|
||||
GLES20.glDeleteProgram(program);
|
||||
program = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
public static boolean isSupportedNPU() {
|
||||
String hardware = android.os.Build.HARDWARE;
|
||||
return hardware.equalsIgnoreCase("kirin810") || hardware.equalsIgnoreCase("kirin990");
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="@color/textColorHighlight" />
|
||||
</shape>
|
||||
</item>
|
||||
<!--这里的right和bottom表示的是这一层图片的右边距和下边距,当然还有left和top-->
|
||||
<item android:bottom="5px">
|
||||
<shape>
|
||||
<solid android:color="@color/bk_black" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
7
java/android/app/src/main/res/drawable-v24/album_btn.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:drawable="@drawable/album" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/album" />
|
||||
<item android:state_pressed="true" android:drawable="@drawable/album" />
|
||||
<item android:drawable="@drawable/album_pressed" />
|
||||
</selector>
|
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:drawable="@drawable/realtime_start_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/realtime_start_pressed" />
|
||||
<item android:state_pressed="true" android:drawable="@drawable/realtime_start_pressed" />
|
||||
<item android:drawable="@drawable/realtime_start" />
|
||||
</selector>
|
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:drawable="@drawable/realtime_stop_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/realtime_stop_pressed" />
|
||||
<item android:state_pressed="true" android:drawable="@drawable/realtime_stop_pressed" />
|
||||
<item android:drawable="@drawable/realtime_stop" />
|
||||
</selector>
|
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#FFFFFF" />
|
||||
|
||||
<stroke
|
||||
android:width="1px"
|
||||
android:color="#E5E5E5" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners
|
||||
android:bottomLeftRadius="25dp"
|
||||
android:bottomRightRadius="25dp"
|
||||
android:topLeftRadius="25dp"
|
||||
android:topRightRadius="25dp"></corners>
|
||||
<solid android:color="#3B85F5"></solid>
|
||||
</shape>
|
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!--定义seekbar滑动条的底色-->
|
||||
<item android:id="@android:id/background">
|
||||
<bitmap
|
||||
android:src="@drawable/seekbar_progress_dotted"
|
||||
android:tileMode="mirror"></bitmap>
|
||||
</item>
|
||||
<!--定义seekbar滑动条进度颜色-->
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<solid android:color="#F5A623" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!--定义seekbar滑动条的底色-->
|
||||
<item android:id="@android:id/background">
|
||||
<shape>
|
||||
<solid android:color="#E5E5E5" />
|
||||
</shape>
|
||||
</item>
|
||||
<!--定义seekbar滑动条进度颜色-->
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<solid android:color="#3B85F5" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<selector>
|
||||
<item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/seekbar_thumb_shape" />
|
||||
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/seekbar_thumb_shape" />
|
||||
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/seekbar_thumb_shape" />
|
||||
<item android:drawable="@drawable/seekbar_thumb_shape" />
|
||||
</selector>
|
||||
</selector>
|
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 白色前景 -->
|
||||
<item
|
||||
android:gravity="center"
|
||||
android:bottom="20px"
|
||||
android:top="20px"
|
||||
android:right="20px"
|
||||
android:left="20px">
|
||||
<shape android:shape="oval">
|
||||
<size
|
||||
android:width="20px"
|
||||
android:height="20px" />
|
||||
<solid android:color="#ffffffff" />
|
||||
</shape>
|
||||
</item>
|
||||
<!-- 透明阴影 -->
|
||||
<item android:gravity="center">
|
||||
<shape android:shape="oval">
|
||||
<size
|
||||
android:height="30px"
|
||||
android:width="30px" />
|
||||
<solid android:color="#96ffffff" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:drawable="@drawable/switch_side_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/switch_side_pressed" />
|
||||
<item android:state_pressed="true" android:drawable="@drawable/switch_side_pressed" />
|
||||
<item android:drawable="@drawable/switch_side" />
|
||||
</selector>
|
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:drawable="@drawable/take_picture_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/take_picture_pressed" />
|
||||
<item android:state_pressed="true" android:drawable="@drawable/take_picture_pressed" />
|
||||
<item android:drawable="@drawable/take_picture" />
|
||||
</selector>
|
BIN
java/android/app/src/main/res/drawable-xhdpi/album.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
java/android/app/src/main/res/drawable-xhdpi/album_pressed.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
java/android/app/src/main/res/drawable-xhdpi/back_btn.png
Normal file
After Width: | Height: | Size: 455 B |
BIN
java/android/app/src/main/res/drawable-xhdpi/more_menu.png
Normal file
After Width: | Height: | Size: 414 B |
BIN
java/android/app/src/main/res/drawable-xhdpi/realtime_start.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 6.0 KiB |
BIN
java/android/app/src/main/res/drawable-xhdpi/realtime_stop.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 7.8 KiB |
BIN
java/android/app/src/main/res/drawable-xhdpi/scan_icon.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
java/android/app/src/main/res/drawable-xhdpi/seekbar_handle.png
Normal file
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 944 B |
After Width: | Height: | Size: 2.8 KiB |
BIN
java/android/app/src/main/res/drawable-xhdpi/switch_side.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 4.8 KiB |
BIN
java/android/app/src/main/res/drawable-xhdpi/take_picture.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 9.8 KiB |
6
java/android/app/src/main/res/drawable/btn_settings.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/btn_settings_pressed"/>
|
||||
<item android:drawable="@drawable/btn_settings_default"/>
|
||||
</selector>
|
||||
|
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M10.4696,3.5L9.8539,5.2714C9.7605,5.5401 9.5784,5.7688 9.3375,5.9199L8.0854,6.7054C7.8421,6.8581 7.5537,6.9223 7.2686,6.8872L5.3518,6.6517L3.9124,9.0649L4.9862,10.3888C5.1668,10.6114 5.2654,10.8894 5.2654,11.1762L5.2654,12.9051C5.2654,13.2057 5.157,13.4963 4.9602,13.7235L3.9165,14.9283L5.3573,17.4236L7.264,17.1741C7.5472,17.137 7.8344,17.198 8.0781,17.3469L9.401,18.1555C9.655,18.3107 9.8452,18.5515 9.9375,18.8345L10.4806,20.5L13.5194,20.5L14.0625,18.8345C14.1548,18.5515 14.345,18.3107 14.599,18.1555L15.9219,17.3469C16.1656,17.198 16.4528,17.137 16.736,17.1741L18.6427,17.4236L20.0835,14.9283L19.0398,13.7235C18.843,13.4963 18.7346,13.2057 18.7346,12.9051L18.7346,11.1762C18.7346,10.8894 18.8332,10.6114 19.0138,10.3888L20.0876,9.0649L18.6482,6.6517L16.7314,6.8872C16.4463,6.9223 16.1579,6.8581 15.9146,6.7054L14.6629,5.9202C14.4221,5.7691 14.2399,5.5404 14.1466,5.2718L13.5305,3.5L10.4696,3.5ZM8.4659,4.696L9.1111,2.8396C9.2858,2.3369 9.7596,2 10.2918,2L13.7083,2C14.2404,2 14.7142,2.3369 14.8889,2.8395L15.5345,4.6962L16.6366,5.3876L18.6269,5.143C19.1184,5.0826 19.5993,5.318 19.8529,5.7433L21.4653,8.4465C21.7339,8.8968 21.6928,9.4669 21.3625,9.8742L20.2346,11.2648L20.2346,12.8118L21.3338,14.0807C21.6826,14.4833 21.7379,15.0628 21.4715,15.5241L19.8583,18.3182C19.6057,18.7557 19.1145,18.9982 18.6136,18.9326L16.6288,18.6728L15.46,19.3872L14.8893,21.1375C14.7216,21.6519 14.2419,22 13.7009,22L10.2991,22C9.7581,22 9.2784,21.6519 9.1107,21.1375L8.54,19.3872L7.3712,18.6728L5.3864,18.9326C4.8855,18.9982 4.3943,18.7557 4.1417,18.3182L2.5285,15.5241C2.2621,15.0628 2.3174,14.4833 2.6662,14.0807L3.7654,12.8118L3.7654,11.2648L2.6375,9.8742C2.3072,9.4669 2.2661,8.8968 2.5347,8.4465L4.1471,5.7433C4.4007,5.318 4.8816,5.0826 5.3731,5.143L7.3634,5.3876L8.4659,4.696ZM12,15.75C9.9289,15.75 8.25,14.0711 8.25,12C8.25,9.9289 9.9289,8.25 12,8.25C14.0711,8.25 15.75,9.9289 15.75,12C15.75,14.0711 14.0711,15.75 12,15.75ZM12,14.75C13.5188,14.75 14.75,13.5188 14.75,12C14.75,10.4812 13.5188,9.25 12,9.25C10.4812,9.25 9.25,10.4812 9.25,12C9.25,13.5188 10.4812,14.75 12,14.75Z"
|
||||
android:strokeWidth="0"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#bcbcbc"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M10.4696,3.5L9.8539,5.2714C9.7605,5.5401 9.5784,5.7688 9.3375,5.9199L8.0854,6.7054C7.8421,6.8581 7.5537,6.9223 7.2686,6.8872L5.3518,6.6517L3.9124,9.0649L4.9862,10.3888C5.1668,10.6114 5.2654,10.8894 5.2654,11.1762L5.2654,12.9051C5.2654,13.2057 5.157,13.4963 4.9602,13.7235L3.9165,14.9283L5.3573,17.4236L7.264,17.1741C7.5472,17.137 7.8344,17.198 8.0781,17.3469L9.401,18.1555C9.655,18.3107 9.8452,18.5515 9.9375,18.8345L10.4806,20.5L13.5194,20.5L14.0625,18.8345C14.1548,18.5515 14.345,18.3107 14.599,18.1555L15.9219,17.3469C16.1656,17.198 16.4528,17.137 16.736,17.1741L18.6427,17.4236L20.0835,14.9283L19.0398,13.7235C18.843,13.4963 18.7346,13.2057 18.7346,12.9051L18.7346,11.1762C18.7346,10.8894 18.8332,10.6114 19.0138,10.3888L20.0876,9.0649L18.6482,6.6517L16.7314,6.8872C16.4463,6.9223 16.1579,6.8581 15.9146,6.7054L14.6629,5.9202C14.4221,5.7691 14.2399,5.5404 14.1466,5.2718L13.5305,3.5L10.4696,3.5ZM8.4659,4.696L9.1111,2.8396C9.2858,2.3369 9.7596,2 10.2918,2L13.7083,2C14.2404,2 14.7142,2.3369 14.8889,2.8395L15.5345,4.6962L16.6366,5.3876L18.6269,5.143C19.1184,5.0826 19.5993,5.318 19.8529,5.7433L21.4653,8.4465C21.7339,8.8968 21.6928,9.4669 21.3625,9.8742L20.2346,11.2648L20.2346,12.8118L21.3338,14.0807C21.6826,14.4833 21.7379,15.0628 21.4715,15.5241L19.8583,18.3182C19.6057,18.7557 19.1145,18.9982 18.6136,18.9326L16.6288,18.6728L15.46,19.3872L14.8893,21.1375C14.7216,21.6519 14.2419,22 13.7009,22L10.2991,22C9.7581,22 9.2784,21.6519 9.1107,21.1375L8.54,19.3872L7.3712,18.6728L5.3864,18.9326C4.8855,18.9982 4.3943,18.7557 4.1417,18.3182L2.5285,15.5241C2.2621,15.0628 2.3174,14.4833 2.6662,14.0807L3.7654,12.8118L3.7654,11.2648L2.6375,9.8742C2.3072,9.4669 2.2661,8.8968 2.5347,8.4465L4.1471,5.7433C4.4007,5.318 4.8816,5.0826 5.3731,5.143L7.3634,5.3876L8.4659,4.696ZM12,15.75C9.9289,15.75 8.25,14.0711 8.25,12C8.25,9.9289 9.9289,8.25 12,8.25C14.0711,8.25 15.75,9.9289 15.75,12C15.75,14.0711 14.0711,15.75 12,15.75ZM12,14.75C13.5188,14.75 14.75,13.5188 14.75,12C14.75,10.4812 13.5188,9.25 12,9.25C10.4812,9.25 9.25,10.4812 9.25,12C9.25,13.5188 10.4812,14.75 12,14.75Z"
|
||||
android:strokeWidth="0"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
5
java/android/app/src/main/res/drawable/btn_shutter.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/btn_shutter_pressed"/>
|
||||
<item android:drawable="@drawable/btn_shutter_default"/>
|
||||
</selector>
|
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="201dp"
|
||||
android:width="201dp"
|
||||
android:viewportWidth="201"
|
||||
android:viewportHeight="201">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M 100.5 0 C 156.004617358 0 201 44.995382642 201 100.5 C 201 156.004617358 156.004617358 201 100.5 201 C 44.995382642 201 0 156.004617358 0 100.5 C 0 44.995382642 44.995382642 0 100.5 0 Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:fillColor="#dfe7eb"
|
||||
android:pathData="M 100.5 17.2285714 C 146.489540112 17.2285714 183.7714286 54.5104598876 183.7714286 100.5 C 183.7714286 146.489540112 146.489540112 183.7714286 100.5 183.7714286 C 54.5104598876 183.7714286 17.2285714 146.489540112 17.2285714 100.5 C 17.2285714 54.5104598876 54.5104598876 17.2285714 100.5 17.2285714 Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="201dp"
|
||||
android:width="201dp"
|
||||
android:viewportWidth="201"
|
||||
android:viewportHeight="201">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M 100.5 0 C 156.004617358 0 201 44.995382642 201 100.5 C 201 156.004617358 156.004617358 201 100.5 201 C 44.995382642 201 0 156.004617358 0 100.5 C 0 44.995382642 44.995382642 0 100.5 0 Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:fillColor="#cfd7db"
|
||||
android:pathData="M 100.5 17.2285714 C 146.489540112 17.2285714 183.7714286 54.5104598876 183.7714286 100.5 C 183.7714286 146.489540112 146.489540112 183.7714286 100.5 183.7714286 C 54.5104598876 183.7714286 17.2285714 146.489540112 17.2285714 100.5 C 17.2285714 54.5104598876 54.5104598876 17.2285714 100.5 17.2285714 Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
5
java/android/app/src/main/res/drawable/btn_switch.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/btn_switch_pressed"/>
|
||||
<item android:drawable="@drawable/btn_switch_default"/>
|
||||
</selector>
|
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#008577"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
99
java/android/app/src/main/res/layout-land/activity_main.xml
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:keepScreenOn="true"
|
||||
tools:context="com.baidu.paddle.fastdeploy.app.examples.detection.MainActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorWindow">
|
||||
|
||||
<com.baidu.paddle.fastdeploy.app.ui.CameraSurfaceView
|
||||
android:id="@+id/sv_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="@dimen/top_bar_height"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:background="@color/colorTopBar">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginLeft="@dimen/top_bar_left_right_margin"
|
||||
android:layout_marginBottom="@dimen/top_bar_left_right_margin"
|
||||
android:textColor="@color/colorText"
|
||||
android:gravity="center"
|
||||
android:textSize="@dimen/small_font_size" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="@color/colorBottomBar"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="@dimen/bottom_bar_top_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"></LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="@dimen/large_button_height"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_switch"
|
||||
android:layout_width="@dimen/small_button_width"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/bottom_bar_left_right_margin"
|
||||
android:layout_marginBottom="@dimen/bottom_bar_left_right_margin"
|
||||
android:background="#00000000"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/btn_switch" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_shutter"
|
||||
android:layout_width="@dimen/large_button_width"
|
||||
android:layout_height="@dimen/large_button_height"
|
||||
android:layout_centerInParent="true"
|
||||
android:background="@null"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/btn_shutter" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_settings"
|
||||
android:layout_width="@dimen/small_button_width"
|
||||
android:layout_height="@dimen/small_button_width"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/bottom_bar_left_right_margin"
|
||||
android:background="@null"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/btn_settings" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="@dimen/bottom_bar_bottom_margin"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"></LinearLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
163
java/android/app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:keepScreenOn="true"
|
||||
tools:context="com.baidu.paddle.fastdeploy.app.examples.detection.MainActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorWindow">
|
||||
|
||||
<com.baidu.paddle.fastdeploy.app.ui.ActionBarLayout
|
||||
android:id="@+id/action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back_in_preview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:cropToPadding="true"
|
||||
android:paddingLeft="40px"
|
||||
android:paddingTop="60px"
|
||||
android:paddingRight="60px"
|
||||
android:paddingBottom="40px"
|
||||
android:src="@drawable/back_btn" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="50px"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/action_takepicture_btn"
|
||||
style="@style/action_btn_selected"
|
||||
android:layout_width="300px"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_bar_take_photo"
|
||||
android:textAlignment="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/action_realtime_btn"
|
||||
style="@style/action_btn"
|
||||
android:layout_width="300px"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_bar_realtime"
|
||||
android:textAlignment="center" />
|
||||
</LinearLayout>
|
||||
|
||||
</com.baidu.paddle.fastdeploy.app.ui.ActionBarLayout>
|
||||
|
||||
<!-- 时实-->
|
||||
<com.baidu.paddle.fastdeploy.app.ui.CameraSurfaceView
|
||||
android:id="@+id/sv_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/contral"
|
||||
android:layout_below="@+id/action_bar"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/albumSelect"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="145dp"
|
||||
android:background="@drawable/album_btn"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="60dp"
|
||||
android:layout_marginRight="30dp"
|
||||
android:textColor="@color/colorText"
|
||||
android:textSize="@dimen/small_font_size" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@color/colorTopBar">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_settings"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="10dp"
|
||||
android:background="@null"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/btn_settings" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/contral"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@color/colorBottomBar"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_bar_top_margin"
|
||||
android:orientation="vertical"></LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/large_button_height">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_switch"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="60dp"
|
||||
android:background="#00000000"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/switch_side_btn" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_shutter"
|
||||
android:layout_width="@dimen/large_button_width"
|
||||
android:layout_height="@dimen/large_button_height"
|
||||
android:layout_centerInParent="true"
|
||||
android:background="@null"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/take_picture_btn" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/realtime_toggle_btn"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="60dp"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/realtime_stop_btn" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_bar_bottom_margin"
|
||||
android:orientation="vertical"></LinearLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
BIN
java/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
java/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
java/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
java/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
java/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
java/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
java/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 10 KiB |
BIN
java/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 15 KiB |
39
java/android/app/src/main/res/values/arrays.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="cpu_thread_num_entries">
|
||||
<item>1 threads</item>
|
||||
<item>2 threads</item>
|
||||
<item>4 threads</item>
|
||||
<item>8 threads</item>
|
||||
</string-array>
|
||||
<string-array name="cpu_thread_num_values">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>4</item>
|
||||
<item>8</item>
|
||||
</string-array>
|
||||
<string-array name="cpu_power_mode_entries">
|
||||
<item>HIGH(only big cores)</item>
|
||||
<item>LOW(only LITTLE cores)</item>
|
||||
<item>FULL(all cores)</item>
|
||||
<item>NO_BIND(depends on system)</item>
|
||||
<item>RAND_HIGH</item>
|
||||
<item>RAND_LOW</item>
|
||||
</string-array>
|
||||
<string-array name="cpu_power_mode_values">
|
||||
<item>LITE_POWER_HIGH</item>
|
||||
<item>LITE_POWER_LOW</item>
|
||||
<item>LITE_POWER_FULL</item>
|
||||
<item>LITE_POWER_NO_BIND</item>
|
||||
<item>LITE_POWER_RAND_HIGH</item>
|
||||
<item>LITE_POWER_RAND_LOW</item>
|
||||
</string-array>
|
||||
<string-array name="enable_lite_fp16_mode_entries">
|
||||
<item>true</item>
|
||||
<item>false</item>
|
||||
</string-array>
|
||||
<string-array name="enable_lite_fp16_mode_values">
|
||||
<item>true</item>
|
||||
<item>false</item>
|
||||
</string-array>
|
||||
</resources>
|
22
java/android/app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
<color name="colorWindow">#FF000000</color>
|
||||
<color name="colorTopBar">#00000000</color>
|
||||
<color name="colorBottomBar">#00000000</color>
|
||||
<color name="colorText">#FFFFFFFF</color>
|
||||
|
||||
<color name="bk_black">#000000</color>
|
||||
<color name="bk_blue">#3B85F5</color>
|
||||
<color name="textColorHighlight">#F5A623</color>
|
||||
<color name="textColor">#FFFFFF</color>
|
||||
|
||||
<color name="bk_result_image_padding">#EEEEEE</color>
|
||||
|
||||
<color name="table_result_item_text_color">#3B85F5</color>
|
||||
<color name="table_result_tableheader_text_color">#333333</color>
|
||||
<color name="result_section_border_color">#E5E5E5</color>
|
||||
<color name="result_popview_tablebody_bk">#3b85f5</color>
|
||||
</resources>
|
17
java/android/app/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="bottom_bar_top_margin">26dp</dimen>
|
||||
<dimen name="bottom_bar_bottom_margin">36dp</dimen>
|
||||
<dimen name="bottom_bar_left_right_margin">34dp</dimen>
|
||||
<dimen name="top_bar_height">60dp</dimen>
|
||||
<dimen name="top_bar_left_right_margin">16dp</dimen>
|
||||
<dimen name="large_button_width">67dp</dimen>
|
||||
<dimen name="large_button_height">67dp</dimen>
|
||||
<dimen name="medium_button_width">56dp</dimen>
|
||||
<dimen name="medium_button_height">56dp</dimen>
|
||||
<dimen name="small_button_width">46dp</dimen>
|
||||
<dimen name="small_button_height">46dp</dimen>
|
||||
<dimen name="large_font_size">32dp</dimen>
|
||||
<dimen name="medium_font_size">24dp</dimen>
|
||||
<dimen name="small_font_size">16dp</dimen>
|
||||
</resources>
|
28
java/android/app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<resources>
|
||||
<string name="app_name">FastDeploy PicoDet</string>
|
||||
<string name="CHOOSE_PRE_INSTALLED_MODEL_KEY">CHOOSE_INSTALLED_MODEL_KEY</string>
|
||||
<string name="MODEL_DIR_KEY">MODEL_DIR_KEY</string>
|
||||
<string name="LABEL_PATH_KEY">LABEL_PATH_KEY</string>
|
||||
<string name="CPU_THREAD_NUM_KEY">CPU_THREAD_NUM_KEY</string>
|
||||
<string name="CPU_POWER_MODE_KEY">CPU_POWER_MODE_KEY</string>
|
||||
<string name="SCORE_THRESHOLD_KEY">SCORE_THRESHOLD_KEY</string>
|
||||
<string name="ENABLE_LITE_FP16_MODE_KEY">ENABLE_LITE_FP16_MODE_KEY</string>
|
||||
<string name="MODEL_DIR_DEFAULT">models/picodet_s_320_coco_lcnet</string>
|
||||
<string name="LABEL_PATH_DEFAULT">labels/coco_label_list.txt</string>
|
||||
<string name="CPU_THREAD_NUM_DEFAULT">2</string>
|
||||
<string name="CPU_POWER_MODE_DEFAULT">LITE_POWER_HIGH</string>
|
||||
<string name="SCORE_THRESHOLD_DEFAULT">0.4</string>
|
||||
<string name="ENABLE_LITE_FP16_MODE_DEFAULT">true</string>
|
||||
<!--Other values-->
|
||||
<string name="action_bar_take_photo">拍照识别</string>
|
||||
<string name="action_bar_realtime">FD 实时识别</string>
|
||||
<string name="action_bar_back"><</string>
|
||||
<string name="action_bar_model_name">模型名称</string>
|
||||
<string name="result_label">识别结果</string>
|
||||
<string name="result_table_header_index">序号</string>
|
||||
<string name="result_table_header_name">名称</string>
|
||||
<string name="result_table_header_confidence">置信度</string>
|
||||
<string name="operation_confidence_control">阈值控制</string>
|
||||
<string name="operation_retry">重新识别</string>
|
||||
<string name="operation_save">保存结果</string>
|
||||
</resources>
|
70
java/android/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="OverflowMenuStyle" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
|
||||
<item name="overlapAnchor">false</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
|
||||
|
||||
<style name="list_result_view_item_style">
|
||||
<item name="android:textColor">@color/table_result_item_text_color</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">30px</item>
|
||||
</style>
|
||||
|
||||
<style name="list_result_popview_item_style">
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">15px</item>
|
||||
<item name="android:background">@color/result_popview_tablebody_bk</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:alpha">0.5</item>
|
||||
</style>
|
||||
|
||||
<style name="list_result_view_tablehead_style">
|
||||
<item name="android:textColor">@color/table_result_item_text_color</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">15px</item>
|
||||
</style>
|
||||
|
||||
<style name="list_result_popview_tablehead_style">
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">20px</item>
|
||||
</style>
|
||||
|
||||
<style name="action_btn">
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:background">@color/bk_black</item>
|
||||
</style>
|
||||
|
||||
<style name="action_btn_selected">
|
||||
<item name="android:textColor">@color/textColorHighlight</item>
|
||||
<item name="android:background">@color/bk_black</item>
|
||||
</style>
|
||||
|
||||
|
||||
</resources>
|
45
java/android/app/src/main/res/xml/settings.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ListPreference
|
||||
android:defaultValue="@string/MODEL_DIR_DEFAULT"
|
||||
android:key="@string/CHOOSE_PRE_INSTALLED_MODEL_KEY"
|
||||
android:negativeButtonText="@null"
|
||||
android:positiveButtonText="@null"
|
||||
android:title="Choose Pre-Installed Models" />
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/MODEL_DIR_DEFAULT"
|
||||
android:key="@string/MODEL_DIR_KEY"
|
||||
android:title="Model Dir" />
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/LABEL_PATH_DEFAULT"
|
||||
android:key="@string/LABEL_PATH_KEY"
|
||||
android:title="Label Path" />
|
||||
<ListPreference
|
||||
android:defaultValue="@string/CPU_THREAD_NUM_DEFAULT"
|
||||
android:entries="@array/cpu_thread_num_entries"
|
||||
android:entryValues="@array/cpu_thread_num_values"
|
||||
android:key="@string/CPU_THREAD_NUM_KEY"
|
||||
android:negativeButtonText="@null"
|
||||
android:positiveButtonText="@null"
|
||||
android:title="CPU Thread Num" />
|
||||
<ListPreference
|
||||
android:defaultValue="@string/CPU_POWER_MODE_DEFAULT"
|
||||
android:entries="@array/cpu_power_mode_entries"
|
||||
android:entryValues="@array/cpu_power_mode_values"
|
||||
android:key="@string/CPU_POWER_MODE_KEY"
|
||||
android:negativeButtonText="@null"
|
||||
android:positiveButtonText="@null"
|
||||
android:title="CPU Power Mode" />
|
||||
<EditTextPreference
|
||||
android:key="@string/SCORE_THRESHOLD_KEY"
|
||||
android:defaultValue="@string/SCORE_THRESHOLD_DEFAULT"
|
||||
android:title="Score Threshold: (0.0, 1.0)" />
|
||||
<ListPreference
|
||||
android:defaultValue="@string/ENABLE_LITE_FP16_MODE_DEFAULT"
|
||||
android:entries="@array/enable_lite_fp16_mode_entries"
|
||||
android:entryValues="@array/enable_lite_fp16_mode_values"
|
||||
android:key="@string/ENABLE_LITE_FP16_MODE_KEY"
|
||||
android:negativeButtonText="@null"
|
||||
android:positiveButtonText="@null"
|
||||
android:title="Enable Lite FP16" />
|
||||
</PreferenceScreen>
|
37
java/android/build.gradle
Normal file
@@ -0,0 +1,37 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
//plugins {
|
||||
// id 'com.android.application' version '7.2.2' apply false
|
||||
// id 'com.android.library' version '7.2.2' apply false
|
||||
//}
|
||||
//
|
||||
//task clean(type: Delete) {
|
||||
// delete rootProject.buildDir
|
||||
//}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
// mavenCentral()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
// mavenCentral()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
1
java/android/fastdeploy/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
84
java/android/fastdeploy/build.gradle
Normal file
@@ -0,0 +1,84 @@
|
||||
import java.security.MessageDigest
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
|
||||
android {
|
||||
compileSdk 28
|
||||
|
||||
defaultConfig {
|
||||
minSdk 15
|
||||
targetSdk 28
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DANDROID_PLATFORM=android-21', '-DANDROID_STL=c++_shared', "-DANDROID_TOOLCHAIN=clang"
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a'
|
||||
cppFlags "-std=c++11"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "src/main/cpp/CMakeLists.txt"
|
||||
version "3.10.2"
|
||||
}
|
||||
}
|
||||
ndkVersion '20.1.5948944'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
}
|
||||
|
||||
def archives = [
|
||||
[
|
||||
'src' : 'https://bj.bcebos.com/fastdeploy/test/fastdeploy-android-0.5.0-shared-dev.tgz',
|
||||
'dest': 'libs'
|
||||
]
|
||||
]
|
||||
|
||||
task downloadAndExtractLibs(type: DefaultTask) {
|
||||
doFirst {
|
||||
println "Downloading and extracting archives including libs ..."
|
||||
}
|
||||
doLast {
|
||||
// Prepare cache folder for archives
|
||||
String cachePath = "cache"
|
||||
if (!file("${cachePath}").exists()) {
|
||||
mkdir "${cachePath}"
|
||||
}
|
||||
archives.eachWithIndex { archive, index ->
|
||||
MessageDigest messageDigest = MessageDigest.getInstance('MD5')
|
||||
messageDigest.update(archive.src.bytes)
|
||||
String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
|
||||
// Download the target archive if not exists
|
||||
boolean copyFiles = !file("${archive.dest}").exists()
|
||||
if (!file("${cachePath}/${cacheName}.tgz").exists()) {
|
||||
ant.get(src: archive.src, dest: file("${cachePath}/${cacheName}.tgz"))
|
||||
copyFiles = true // force to copy files from the latest archive files
|
||||
}
|
||||
// Extract the target archive if its dest path does not exists
|
||||
if (copyFiles) {
|
||||
copy {
|
||||
from tarTree("${cachePath}/${cacheName}.tgz")
|
||||
into "${archive.dest}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
preBuild.dependsOn downloadAndExtractLibs
|
0
java/android/fastdeploy/consumer-rules.pro
Normal file
1
java/android/fastdeploy/libs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
fastdeploy-*
|
21
java/android/fastdeploy/proguard-rules.pro
vendored
Normal file
@@ -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
|
@@ -0,0 +1,25 @@
|
||||
package com.baidu.paddle.fastdeploy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("com.baidu.paddle.fastdeploy.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
5
java/android/fastdeploy/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.baidu.paddle.fastdeploy">
|
||||
|
||||
</manifest>
|
60
java/android/fastdeploy/src/main/cpp/CMakeLists.txt
Normal file
@@ -0,0 +1,60 @@
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
cmake_minimum_required(VERSION 3.10.2)
|
||||
|
||||
# Declares and names the project.
|
||||
project("fastdeploy_jni")
|
||||
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# You can define multiple libraries, and CMake builds them for you.
|
||||
# Gradle automatically packages shared libraries with your APK.
|
||||
|
||||
set(FastDeploy_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/fastdeploy-android-0.5.0-shared-dev")
|
||||
|
||||
find_package(FastDeploy REQUIRED)
|
||||
|
||||
include_directories(.)
|
||||
include_directories(${FastDeploy_INCLUDE_DIRS})
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -Ofast -Os -DNDEBUG -fomit-frame-pointer -fno-asynchronous-unwind-tables -fno-unwind-tables")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -ffunction-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,-z,nocopyreloc")
|
||||
|
||||
add_library(
|
||||
fastdeploy_jni
|
||||
SHARED
|
||||
utils_jni.cc
|
||||
bitmap_jni.cc
|
||||
vision/results_jni.cc
|
||||
vision/visualize_jni.cc
|
||||
vision/detection/picodet_jni.cc
|
||||
vision/classification/paddleclas_model_jni.cc)
|
||||
|
||||
# Searches for a specified prebuilt library and stores the path as a
|
||||
# variable. Because CMake includes system libraries in the search path by
|
||||
# default, you only need to specify the name of the public NDK library
|
||||
# you want to add. CMake verifies that the library exists before
|
||||
# completing its build.
|
||||
|
||||
find_library( # Sets the name of the path variable.
|
||||
log-lib
|
||||
# Specifies the name of the NDK library that
|
||||
# you want CMake to locate.
|
||||
log)
|
||||
|
||||
# Specifies libraries CMake should link to your target library. You can link
|
||||
# multiple libraries, such as libraries you define in this build script,
|
||||
# prebuilt third-party libraries, or system libraries.
|
||||
|
||||
target_link_libraries(
|
||||
# Specifies the target library.
|
||||
fastdeploy_jni
|
||||
jnigraphics
|
||||
${FASTDEPLOY_LIBS}
|
||||
GLESv2
|
||||
EGL
|
||||
${log-lib}
|
||||
)
|
100
java/android/fastdeploy/src/main/cpp/bitmap_jni.cc
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#include "bitmap_jni.h" // NOLINT
|
||||
|
||||
#include <android/bitmap.h> // NOLINT
|
||||
|
||||
#include "utils_jni.h" // NOLINT
|
||||
|
||||
namespace fastdeploy {
|
||||
namespace jni {
|
||||
|
||||
jboolean ARGB888Bitmap2RGBA(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
cv::Mat *c_rgba) {
|
||||
// Convert the android bitmap(ARGB8888) to the OpenCV RGBA image. Actually,
|
||||
// the data layout of ARGB8888 is R, G, B, A, it's the same as CV RGBA image,
|
||||
// so it is unnecessary to do the conversion of color format, check
|
||||
// https://developer.android.com/reference/android/graphics/Bitmap.Config#ARGB_8888
|
||||
// to get the more details about Bitmap.Config.ARGB8888
|
||||
AndroidBitmapInfo j_bitmap_info;
|
||||
if (AndroidBitmap_getInfo(env, j_argb8888_bitmap, &j_bitmap_info) < 0) {
|
||||
LOGE("Invoke AndroidBitmap_getInfo() failed!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (j_bitmap_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
|
||||
LOGE("Only Bitmap.Config.ARGB8888 color format is supported!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
void *j_bitmap_pixels;
|
||||
if (AndroidBitmap_lockPixels(env, j_argb8888_bitmap, &j_bitmap_pixels) < 0) {
|
||||
LOGE("Invoke AndroidBitmap_lockPixels() failed!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
cv::Mat j_bitmap_im(static_cast<int>(j_bitmap_info.height),
|
||||
static_cast<int>(j_bitmap_info.width), CV_8UC4,
|
||||
j_bitmap_pixels);
|
||||
j_bitmap_im.copyTo(*(c_rgba));
|
||||
if (AndroidBitmap_unlockPixels(env, j_argb8888_bitmap) < 0) {
|
||||
LOGE("Invoke AndroidBitmap_unlockPixels() failed!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean ARGB888Bitmap2BGR(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
cv::Mat *c_bgr) {
|
||||
cv::Mat c_rgba;
|
||||
if (!ARGB888Bitmap2RGBA(env, j_argb8888_bitmap, &c_rgba)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
cv::cvtColor(c_rgba, *(c_bgr), cv::COLOR_RGBA2BGR);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean RGBA2ARGB888Bitmap(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
const cv::Mat &c_rgba) {
|
||||
AndroidBitmapInfo j_bitmap_info;
|
||||
if (AndroidBitmap_getInfo(env, j_argb8888_bitmap, &j_bitmap_info) < 0) {
|
||||
LOGE("Invoke AndroidBitmap_getInfo() failed!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
void *j_bitmap_pixels;
|
||||
if (AndroidBitmap_lockPixels(env, j_argb8888_bitmap, &j_bitmap_pixels) < 0) {
|
||||
LOGE("Invoke AndroidBitmap_lockPixels() failed!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
cv::Mat j_bitmap_im(static_cast<int>(j_bitmap_info.height),
|
||||
static_cast<int>(j_bitmap_info.width), CV_8UC4,
|
||||
j_bitmap_pixels);
|
||||
c_rgba.copyTo(j_bitmap_im);
|
||||
if (AndroidBitmap_unlockPixels(env, j_argb8888_bitmap) < 0) {
|
||||
LOGE("Invoke AndroidBitmap_unlockPixels() failed!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean BGR2ARGB888Bitmap(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
const cv::Mat &c_bgr) {
|
||||
if (c_bgr.empty()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
cv::Mat c_rgba;
|
||||
cv::cvtColor(c_bgr, c_rgba, cv::COLOR_BGR2RGBA);
|
||||
return RGBA2ARGB888Bitmap(env, j_argb8888_bitmap, c_rgba);
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
} // namespace fastdeploy
|
39
java/android/fastdeploy/src/main/cpp/bitmap_jni.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h> // NOLINT
|
||||
|
||||
#include "fastdeploy/vision.h" // NOLINT
|
||||
|
||||
namespace fastdeploy {
|
||||
namespace jni {
|
||||
|
||||
// Convert the android bitmap(ARGB8888) to the OpenCV RGBA image. Actually,
|
||||
// the data layout of ARGB8888 is R, G, B, A, it's the same as CV RGBA image,
|
||||
// so it is unnecessary to do the conversion of color format, check
|
||||
// https://developer.android.com/reference/android/graphics/Bitmap.Config#ARGB_8888
|
||||
// to get the more details about Bitmap.Config.ARGB8888
|
||||
jboolean ARGB888Bitmap2RGBA(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
cv::Mat *c_rgba);
|
||||
jboolean RGBA2ARGB888Bitmap(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
const cv::Mat &c_rgba);
|
||||
jboolean ARGB888Bitmap2BGR(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
cv::Mat *c_bgr);
|
||||
jboolean BGR2ARGB888Bitmap(JNIEnv *env, jobject j_argb8888_bitmap,
|
||||
const cv::Mat &c_bgr);
|
||||
|
||||
} // namespace jni
|
||||
} // namespace fastdeploy
|
140
java/android/fastdeploy/src/main/cpp/convert_jni.h
Normal file
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h> // NOLINT
|
||||
|
||||
#include <string> // NOLINT
|
||||
#include <vector> // NOLINT
|
||||
|
||||
namespace fastdeploy {
|
||||
namespace jni {
|
||||
|
||||
template <typename OutputType, typename InputType>
|
||||
OutputType ConvertTo(JNIEnv *env, InputType input);
|
||||
|
||||
template <typename OutputType, typename InputType>
|
||||
OutputType ConvertTo(JNIEnv *env, const InputType *input, int64_t len);
|
||||
|
||||
/// jstring -> std::string
|
||||
template <>
|
||||
inline std::string ConvertTo(JNIEnv *env, jstring jstr) {
|
||||
// In java, a unicode char will be encoded using 2 bytes (utf16).
|
||||
// so jstring will contain characters utf16. std::string in c++ is
|
||||
// essentially a string of bytes, not characters, so if we want to
|
||||
// pass jstring from JNI to c++, we have convert utf16 to bytes.
|
||||
if (!jstr) {
|
||||
return "";
|
||||
}
|
||||
const jclass jstring_clazz = env->GetObjectClass(jstr);
|
||||
const jmethodID getBytesID =
|
||||
env->GetMethodID(jstring_clazz, "getBytes", "(Ljava/lang/String;)[B");
|
||||
const jbyteArray jstring_bytes = (jbyteArray)env->CallObjectMethod(
|
||||
jstr, getBytesID, env->NewStringUTF("UTF-8"));
|
||||
|
||||
size_t length = static_cast<size_t>(env->GetArrayLength(jstring_bytes));
|
||||
jbyte *jstring_bytes_ptr = env->GetByteArrayElements(jstring_bytes, NULL);
|
||||
|
||||
std::string res =
|
||||
std::string(reinterpret_cast<char *>(jstring_bytes_ptr), length);
|
||||
env->ReleaseByteArrayElements(jstring_bytes, jstring_bytes_ptr, JNI_ABORT);
|
||||
|
||||
env->DeleteLocalRef(jstring_bytes);
|
||||
env->DeleteLocalRef(jstring_clazz);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// std::string -> jstring
|
||||
template <>
|
||||
inline jstring ConvertTo(JNIEnv *env, std::string str) {
|
||||
auto *cstr_data_ptr = str.c_str();
|
||||
jclass jstring_clazz = env->FindClass("java/lang/String");
|
||||
jmethodID initID =
|
||||
env->GetMethodID(jstring_clazz, "<init>", "([BLjava/lang/String;)V");
|
||||
|
||||
jbyteArray jstring_bytes = env->NewByteArray(strlen(cstr_data_ptr));
|
||||
env->SetByteArrayRegion(jstring_bytes, 0, strlen(cstr_data_ptr),
|
||||
reinterpret_cast<const jbyte *>(cstr_data_ptr));
|
||||
|
||||
jstring jstring_encoding = env->NewStringUTF("UTF-8");
|
||||
jstring res = (jstring)(env->NewObject(jstring_clazz, initID, jstring_bytes,
|
||||
jstring_encoding));
|
||||
|
||||
env->DeleteLocalRef(jstring_clazz);
|
||||
env->DeleteLocalRef(jstring_bytes);
|
||||
env->DeleteLocalRef(jstring_encoding);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// jlongArray -> std::vector<int64_t>
|
||||
template <>
|
||||
inline std::vector<int64_t> ConvertTo(JNIEnv *env, jlongArray jdata) {
|
||||
int jdata_size = env->GetArrayLength(jdata);
|
||||
jlong *jdata_ptr = env->GetLongArrayElements(jdata, nullptr);
|
||||
std::vector<int64_t> res(jdata_ptr, jdata_ptr + jdata_size);
|
||||
env->ReleaseLongArrayElements(jdata, jdata_ptr, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// jfloatArray -> std::vector<float>
|
||||
template <>
|
||||
inline std::vector<float> ConvertTo(JNIEnv *env, jfloatArray jdata) {
|
||||
int jdata_size = env->GetArrayLength(jdata);
|
||||
jfloat *jdata_ptr = env->GetFloatArrayElements(jdata, nullptr);
|
||||
std::vector<float> res(jdata_ptr, jdata_ptr + jdata_size);
|
||||
env->ReleaseFloatArrayElements(jdata, jdata_ptr, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// std::vector<int64_t> -> jlongArray
|
||||
template <>
|
||||
inline jlongArray ConvertTo(JNIEnv *env, const std::vector<int64_t> &cvec) {
|
||||
jlongArray res = env->NewLongArray(cvec.size());
|
||||
jlong *jbuf = new jlong[cvec.size()];
|
||||
for (size_t i = 0; i < cvec.size(); ++i) {
|
||||
jbuf[i] = (jlong)cvec[i];
|
||||
}
|
||||
env->SetLongArrayRegion(res, 0, cvec.size(), jbuf);
|
||||
delete[] jbuf;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// cxx float buffer -> jfloatArray
|
||||
template <>
|
||||
inline jfloatArray ConvertTo(JNIEnv *env, const float *cbuf, int64_t len) {
|
||||
jfloatArray res = env->NewFloatArray(len);
|
||||
env->SetFloatArrayRegion(res, 0, len, cbuf);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// cxx int buffer -> jintArray
|
||||
template <>
|
||||
inline jintArray ConvertTo(JNIEnv *env, const int *cbuf, int64_t len) {
|
||||
jintArray res = env->NewIntArray(len);
|
||||
env->SetIntArrayRegion(res, 0, len, cbuf);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// cxx int8_t buffer -> jbyteArray
|
||||
template <>
|
||||
inline jbyteArray ConvertTo(JNIEnv *env, const int8_t *cbuf, int64_t len) {
|
||||
jbyteArray res = env->NewByteArray(len);
|
||||
env->SetByteArrayRegion(res, 0, len, cbuf);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
} // namespace fastdeploy
|
18
java/android/fastdeploy/src/main/cpp/fastdeploy_jni.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#pragma once
|
||||
#include "bitmap_jni.h" // NOLINT
|
||||
#include "convert_jni.h" // NOLINT
|
||||
#include "utils_jni.h" // NOLINT
|
82
java/android/fastdeploy/src/main/cpp/utils_jni.cc
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// Created by qiuyanjun on 2022/10/19.
|
||||
//
|
||||
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#include "utils_jni.h"
|
||||
|
||||
namespace fastdeploy {
|
||||
namespace jni {
|
||||
|
||||
// Assets Loader Utils.
|
||||
bool AssetsLoaderUtils::detection_labels_loaded_ = false;
|
||||
bool AssetsLoaderUtils::classification_labels_loaded_ = false;
|
||||
std::vector<std::string> AssetsLoaderUtils::detection_labels_ = {};
|
||||
std::vector<std::string> AssetsLoaderUtils::classification_labels_ = {};
|
||||
|
||||
bool AssetsLoaderUtils::IsDetectionLabelsLoaded() {
|
||||
return detection_labels_loaded_;
|
||||
}
|
||||
|
||||
bool AssetsLoaderUtils::IsClassificationLabelsLoaded() {
|
||||
return classification_labels_loaded_;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& AssetsLoaderUtils::GetDetectionLabels() {
|
||||
return detection_labels_;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& AssetsLoaderUtils::GetClassificationLabels() {
|
||||
return classification_labels_;
|
||||
}
|
||||
|
||||
void AssetsLoaderUtils::LoadClassificationLabels(const std::string& path,
|
||||
bool force_reload) {
|
||||
if (force_reload || (!classification_labels_loaded_)) {
|
||||
classification_labels_loaded_ =
|
||||
LoadLabelsFromTxt(path, &classification_labels_);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsLoaderUtils::LoadDetectionLabels(const std::string& path,
|
||||
bool force_reload) {
|
||||
if (force_reload || (!detection_labels_loaded_)) {
|
||||
detection_labels_loaded_ = LoadLabelsFromTxt(path, &detection_labels_);
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetsLoaderUtils::LoadLabelsFromTxt(const std::string& txt_path,
|
||||
std::vector<std::string>* labels) {
|
||||
labels->clear();
|
||||
std::ifstream file;
|
||||
file.open(txt_path);
|
||||
if (!file.is_open()) {
|
||||
return false;
|
||||
}
|
||||
while (file) {
|
||||
std::string line;
|
||||
std::getline(file, line);
|
||||
if (!line.empty() && line != "\n") {
|
||||
labels->push_back(line);
|
||||
}
|
||||
}
|
||||
file.clear();
|
||||
file.close();
|
||||
return labels->size() > 0;
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
} // namespace fastdeploy
|
80
java/android/fastdeploy/src/main/cpp/utils_jni.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h> // NOLINT
|
||||
#endif
|
||||
#include <fstream> // NOLINT
|
||||
#include <string> // NOLINT
|
||||
#include <vector> // NOLINT
|
||||
|
||||
#define TAG "[FastDeploy][JNI]"
|
||||
#ifdef __ANDROID__
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
||||
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
|
||||
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define LOGD(...) \
|
||||
{}
|
||||
#define LOGI(...) \
|
||||
{}
|
||||
#define LOGW(...) \
|
||||
{}
|
||||
#define LOGE(...) \
|
||||
{}
|
||||
#define LOGF(...) \
|
||||
{}
|
||||
#endif
|
||||
|
||||
namespace fastdeploy {
|
||||
namespace jni {
|
||||
|
||||
inline int64_t GetCurrentTime() {
|
||||
struct timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
return 1000000LL * (int64_t)time.tv_sec + (int64_t)time.tv_usec;
|
||||
}
|
||||
|
||||
inline double GetElapsedTime(int64_t time) {
|
||||
return (GetCurrentTime() - time) / 1000.0f;
|
||||
}
|
||||
|
||||
class AssetsLoaderUtils {
|
||||
public:
|
||||
static bool detection_labels_loaded_;
|
||||
static bool classification_labels_loaded_;
|
||||
static std::vector<std::string> detection_labels_;
|
||||
static std::vector<std::string> classification_labels_;
|
||||
|
||||
public:
|
||||
static bool IsDetectionLabelsLoaded();
|
||||
static bool IsClassificationLabelsLoaded();
|
||||
static const std::vector<std::string>& GetDetectionLabels();
|
||||
static const std::vector<std::string>& GetClassificationLabels();
|
||||
static void LoadClassificationLabels(const std::string& path,
|
||||
bool force_reload = false);
|
||||
static void LoadDetectionLabels(const std::string& path,
|
||||
bool force_reload = false);
|
||||
|
||||
private:
|
||||
static bool LoadLabelsFromTxt(const std::string& txt_path,
|
||||
std::vector<std::string>* labels);
|
||||
};
|
||||
|
||||
} // namespace jni
|
||||
} // namespace fastdeploy
|
@@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#include <jni.h> // NOLINT
|
||||
|
||||
#include "fastdeploy_jni.h" // NOLINT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_classification_PaddleClasModel_bindNative(
|
||||
JNIEnv *env, jclass clazz, jstring model_file, jstring params_file,
|
||||
jstring config_file, jint cpu_num_thread, jboolean enable_lite_fp16,
|
||||
jint lite_power_mode, jstring lite_optimized_model_dir,
|
||||
jboolean enable_record_time_of_runtime, jstring label_file) {
|
||||
std::string c_model_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, model_file);
|
||||
std::string c_params_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, params_file);
|
||||
std::string c_config_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, config_file);
|
||||
std::string c_label_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, label_file);
|
||||
std::string c_lite_optimized_model_dir =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, lite_optimized_model_dir);
|
||||
auto c_cpu_num_thread = static_cast<int>(cpu_num_thread);
|
||||
auto c_enable_lite_fp16 = static_cast<bool>(enable_lite_fp16);
|
||||
auto c_lite_power_mode =
|
||||
static_cast<fastdeploy::LitePowerMode>(lite_power_mode);
|
||||
fastdeploy::RuntimeOption c_option;
|
||||
c_option.UseCpu();
|
||||
c_option.UseLiteBackend();
|
||||
c_option.SetCpuThreadNum(c_cpu_num_thread);
|
||||
c_option.SetLitePowerMode(c_lite_power_mode);
|
||||
c_option.SetLiteOptimizedModelDir(c_lite_optimized_model_dir);
|
||||
if (c_enable_lite_fp16) {
|
||||
c_option.EnableLiteFP16();
|
||||
}
|
||||
auto c_model_ptr = new fastdeploy::vision::classification::PaddleClasModel(
|
||||
c_model_file, c_params_file, c_config_file, c_option);
|
||||
// Enable record Runtime time costs.
|
||||
if (enable_record_time_of_runtime) {
|
||||
c_model_ptr->EnableRecordTimeOfRuntime();
|
||||
}
|
||||
// Load classification labels if label path is not empty.
|
||||
if ((!fastdeploy::jni::AssetsLoaderUtils::IsClassificationLabelsLoaded()) &&
|
||||
(!c_label_file.empty())) {
|
||||
fastdeploy::jni::AssetsLoaderUtils::LoadClassificationLabels(c_label_file);
|
||||
}
|
||||
// WARN: need to release manually in Java !
|
||||
return reinterpret_cast<jlong>(c_model_ptr); // native model context
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_classification_PaddleClasModel_predictNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_model_context,
|
||||
jobject argb8888_bitmap, jboolean saved, jstring saved_image_path,
|
||||
jfloat score_threshold, jboolean rendering) {
|
||||
if (native_model_context == 0) {
|
||||
return 0;
|
||||
}
|
||||
cv::Mat c_bgr;
|
||||
auto t = fastdeploy::jni::GetCurrentTime();
|
||||
if (!fastdeploy::jni::ARGB888Bitmap2BGR(env, argb8888_bitmap, &c_bgr)) {
|
||||
return 0;
|
||||
}
|
||||
LOGD("Read from bitmap costs %f ms", fastdeploy::jni::GetElapsedTime(t));
|
||||
auto c_model_ptr =
|
||||
reinterpret_cast<fastdeploy::vision::classification::PaddleClasModel *>(
|
||||
native_model_context);
|
||||
auto c_result_ptr = new fastdeploy::vision::ClassifyResult();
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
if (!c_model_ptr->Predict(&c_bgr, c_result_ptr, 100)) {
|
||||
delete c_result_ptr;
|
||||
return 0;
|
||||
}
|
||||
LOGD("Predict from native costs %f ms", fastdeploy::jni::GetElapsedTime(t));
|
||||
if (c_model_ptr->EnabledRecordTimeOfRuntime()) {
|
||||
auto info_of_runtime = c_model_ptr->PrintStatisInfoOfRuntime();
|
||||
LOGD("Avg runtime costs %f ms", info_of_runtime["avg_time"] * 1000.0f);
|
||||
}
|
||||
if (!c_result_ptr->scores.empty() && rendering) {
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
cv::Mat c_vis_im;
|
||||
if (fastdeploy::jni::AssetsLoaderUtils::IsClassificationLabelsLoaded()) {
|
||||
c_vis_im = fastdeploy::vision::VisClassification(
|
||||
c_bgr, *(c_result_ptr),
|
||||
fastdeploy::jni::AssetsLoaderUtils::GetClassificationLabels(), 5,
|
||||
score_threshold, 1.0f);
|
||||
} else {
|
||||
c_vis_im = fastdeploy::vision::VisClassification(
|
||||
c_bgr, *(c_result_ptr), 5, score_threshold, 1.0f);
|
||||
}
|
||||
LOGD("Visualize from native costs %f ms",
|
||||
fastdeploy::jni::GetElapsedTime(t));
|
||||
// Rendering to bitmap
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
if (!fastdeploy::jni::BGR2ARGB888Bitmap(env, argb8888_bitmap, c_vis_im)) {
|
||||
delete c_result_ptr;
|
||||
return 0;
|
||||
}
|
||||
LOGD("Write to bitmap from native costs %f ms",
|
||||
fastdeploy::jni::GetElapsedTime(t));
|
||||
std::string c_saved_image_path =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, saved_image_path);
|
||||
if (!c_saved_image_path.empty() && saved) {
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
cv::imwrite(c_saved_image_path, c_bgr);
|
||||
LOGD("Save image from native costs %f ms, path: %s",
|
||||
fastdeploy::jni::GetElapsedTime(t), c_saved_image_path.c_str());
|
||||
}
|
||||
}
|
||||
// WARN: need to release it manually in Java !
|
||||
return reinterpret_cast<jlong>(c_result_ptr); // native result context
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_classification_PaddleClasModel_releaseNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_model_context) {
|
||||
auto c_model_ptr =
|
||||
reinterpret_cast<fastdeploy::vision::classification::PaddleClasModel *>(
|
||||
native_model_context);
|
||||
if (c_model_ptr->EnabledRecordTimeOfRuntime()) {
|
||||
auto info_of_runtime = c_model_ptr->PrintStatisInfoOfRuntime();
|
||||
LOGD("[End] Avg runtime costs %f ms",
|
||||
info_of_runtime["avg_time"] * 1000.0f);
|
||||
}
|
||||
delete c_model_ptr;
|
||||
LOGD("[End] Release PaddleClasModel in native !");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#include <jni.h> // NOLINT
|
||||
|
||||
#include "fastdeploy_jni.h" // NOLINT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_detection_PicoDet_bindNative(
|
||||
JNIEnv *env, jclass clazz, jstring model_file, jstring params_file,
|
||||
jstring config_file, jint cpu_num_thread, jboolean enable_lite_fp16,
|
||||
jint lite_power_mode, jstring lite_optimized_model_dir,
|
||||
jboolean enable_record_time_of_runtime, jstring label_file) {
|
||||
std::string c_model_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, model_file);
|
||||
std::string c_params_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, params_file);
|
||||
std::string c_config_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, config_file);
|
||||
std::string c_label_file =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, label_file);
|
||||
std::string c_lite_optimized_model_dir =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, lite_optimized_model_dir);
|
||||
auto c_cpu_num_thread = static_cast<int>(cpu_num_thread);
|
||||
auto c_enable_lite_fp16 = static_cast<bool>(enable_lite_fp16);
|
||||
auto c_lite_power_mode =
|
||||
static_cast<fastdeploy::LitePowerMode>(lite_power_mode);
|
||||
fastdeploy::RuntimeOption c_option;
|
||||
c_option.UseCpu();
|
||||
c_option.UseLiteBackend();
|
||||
c_option.SetCpuThreadNum(c_cpu_num_thread);
|
||||
c_option.SetLitePowerMode(c_lite_power_mode);
|
||||
c_option.SetLiteOptimizedModelDir(c_lite_optimized_model_dir);
|
||||
if (c_enable_lite_fp16) {
|
||||
c_option.EnableLiteFP16();
|
||||
}
|
||||
auto c_model_ptr = new fastdeploy::vision::detection::PicoDet(
|
||||
c_model_file, c_params_file, c_config_file, c_option);
|
||||
// Enable record Runtime time costs.
|
||||
if (enable_record_time_of_runtime) {
|
||||
c_model_ptr->EnableRecordTimeOfRuntime();
|
||||
}
|
||||
// Load detection labels if label path is not empty.
|
||||
if ((!fastdeploy::jni::AssetsLoaderUtils::IsDetectionLabelsLoaded()) &&
|
||||
(!c_label_file.empty())) {
|
||||
fastdeploy::jni::AssetsLoaderUtils::LoadDetectionLabels(c_label_file);
|
||||
}
|
||||
// WARN: need to release manually in Java !
|
||||
return reinterpret_cast<jlong>(c_model_ptr); // native model context
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_detection_PicoDet_predictNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_model_context,
|
||||
jobject argb8888_bitmap, jboolean saved, jstring saved_image_path,
|
||||
jfloat score_threshold, jboolean rendering) {
|
||||
if (native_model_context == 0) {
|
||||
return 0;
|
||||
}
|
||||
cv::Mat c_bgr;
|
||||
auto t = fastdeploy::jni::GetCurrentTime();
|
||||
if (!fastdeploy::jni::ARGB888Bitmap2BGR(env, argb8888_bitmap, &c_bgr)) {
|
||||
return 0;
|
||||
}
|
||||
LOGD("Read from bitmap costs %f ms", fastdeploy::jni::GetElapsedTime(t));
|
||||
auto c_model_ptr = reinterpret_cast<fastdeploy::vision::detection::PicoDet *>(
|
||||
native_model_context);
|
||||
auto c_result_ptr = new fastdeploy::vision::DetectionResult();
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
if (!c_model_ptr->Predict(&c_bgr, c_result_ptr)) {
|
||||
delete c_result_ptr;
|
||||
return 0;
|
||||
}
|
||||
LOGD("Predict from native costs %f ms", fastdeploy::jni::GetElapsedTime(t));
|
||||
if (c_model_ptr->EnabledRecordTimeOfRuntime()) {
|
||||
auto info_of_runtime = c_model_ptr->PrintStatisInfoOfRuntime();
|
||||
LOGD("Avg runtime costs %f ms", info_of_runtime["avg_time"] * 1000.0f);
|
||||
}
|
||||
if (!c_result_ptr->boxes.empty() && rendering) {
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
cv::Mat c_vis_im;
|
||||
if (fastdeploy::jni::AssetsLoaderUtils::IsDetectionLabelsLoaded()) {
|
||||
c_vis_im = fastdeploy::vision::VisDetection(
|
||||
c_bgr, *(c_result_ptr),
|
||||
fastdeploy::jni::AssetsLoaderUtils::GetDetectionLabels(),
|
||||
score_threshold, 2, 1.0f);
|
||||
} else {
|
||||
c_vis_im = fastdeploy::vision::VisDetection(c_bgr, *(c_result_ptr),
|
||||
score_threshold, 2, 1.0f);
|
||||
}
|
||||
LOGD("Visualize from native costs %f ms",
|
||||
fastdeploy::jni::GetElapsedTime(t));
|
||||
// Rendering to bitmap
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
if (!fastdeploy::jni::BGR2ARGB888Bitmap(env, argb8888_bitmap, c_vis_im)) {
|
||||
delete c_result_ptr;
|
||||
return 0;
|
||||
}
|
||||
LOGD("Write to bitmap from native costs %f ms",
|
||||
fastdeploy::jni::GetElapsedTime(t));
|
||||
std::string c_saved_image_path =
|
||||
fastdeploy::jni::ConvertTo<std::string>(env, saved_image_path);
|
||||
if (!c_saved_image_path.empty() && saved) {
|
||||
t = fastdeploy::jni::GetCurrentTime();
|
||||
cv::imwrite(c_saved_image_path, c_vis_im);
|
||||
LOGD("Save image from native costs %f ms, path: %s",
|
||||
fastdeploy::jni::GetElapsedTime(t), c_saved_image_path.c_str());
|
||||
}
|
||||
}
|
||||
// WARN: need to release it manually in Java !
|
||||
return reinterpret_cast<jlong>(c_result_ptr); // native result context
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_detection_PicoDet_releaseNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_model_context) {
|
||||
if (native_model_context == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
auto c_model_ptr = reinterpret_cast<fastdeploy::vision::detection::PicoDet *>(
|
||||
native_model_context);
|
||||
if (c_model_ptr->EnabledRecordTimeOfRuntime()) {
|
||||
auto info_of_runtime = c_model_ptr->PrintStatisInfoOfRuntime();
|
||||
LOGD("[End] Avg runtime costs %f ms",
|
||||
info_of_runtime["avg_time"] * 1000.0f);
|
||||
}
|
||||
delete c_model_ptr;
|
||||
LOGD("[End] Release PicoDet in native !");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
132
java/android/fastdeploy/src/main/cpp/vision/results_jni.cc
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#include <android/bitmap.h> // NOLINT
|
||||
#include <jni.h> // NOLINT
|
||||
|
||||
#include "fastdeploy/vision.h" // NOLINT
|
||||
#include "fastdeploy_jni.h" // NOLINT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Native DetectionResult for vision::DetectionResult.
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_DetectionResult_copyBoxesNumFromNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::DetectionResult *>(
|
||||
native_result_context);
|
||||
return static_cast<jint>(c_result_ptr->boxes.size());
|
||||
}
|
||||
|
||||
JNIEXPORT jfloatArray JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_DetectionResult_copyBoxesFromNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::DetectionResult *>(
|
||||
native_result_context);
|
||||
if (c_result_ptr->boxes.empty()) {
|
||||
return {};
|
||||
}
|
||||
const auto len = static_cast<int64_t>(c_result_ptr->boxes.size());
|
||||
float buffer[len * 4];
|
||||
const auto &boxes = c_result_ptr->boxes;
|
||||
for (int64_t i = 0; i < len; ++i) {
|
||||
std::memcpy((buffer + i * 4), (boxes.at(i).data()), 4 * sizeof(float));
|
||||
}
|
||||
return fastdeploy::jni::ConvertTo<jfloatArray>(env, buffer, len * 4);
|
||||
}
|
||||
|
||||
JNIEXPORT jfloatArray JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_DetectionResult_copyScoresFromNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::DetectionResult *>(
|
||||
native_result_context);
|
||||
if (c_result_ptr->scores.empty()) {
|
||||
return {};
|
||||
}
|
||||
const auto len = static_cast<int64_t>(c_result_ptr->scores.size());
|
||||
const float *buffer = static_cast<float *>(c_result_ptr->scores.data());
|
||||
return fastdeploy::jni::ConvertTo<jfloatArray>(env, buffer, len);
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_DetectionResult_copyLabelIdsFromNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::DetectionResult *>(
|
||||
native_result_context);
|
||||
if (c_result_ptr->label_ids.empty()) {
|
||||
return {};
|
||||
}
|
||||
const auto len = static_cast<int64_t>(c_result_ptr->label_ids.size());
|
||||
const int *buffer = static_cast<int *>(c_result_ptr->label_ids.data());
|
||||
return fastdeploy::jni::ConvertTo<jintArray>(env, buffer, len);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_DetectionResult_releaseNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
if (native_result_context == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::DetectionResult *>(
|
||||
native_result_context);
|
||||
delete c_result_ptr;
|
||||
LOGD("Release DetectionResult in native !");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/// Native ClassifyResult for vision::ClassifyResult.
|
||||
JNIEXPORT jfloatArray JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_ClassifyResult_copyScoresFromNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::ClassifyResult *>(
|
||||
native_result_context);
|
||||
if (c_result_ptr->scores.empty()) {
|
||||
return {};
|
||||
}
|
||||
const auto len = static_cast<int64_t>(c_result_ptr->scores.size());
|
||||
const float *buffer = static_cast<float *>(c_result_ptr->scores.data());
|
||||
return fastdeploy::jni::ConvertTo<jfloatArray>(env, buffer, len);
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_ClassifyResult_copyLabelIdsFromNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::ClassifyResult *>(
|
||||
native_result_context);
|
||||
if (c_result_ptr->label_ids.empty()) {
|
||||
return {};
|
||||
}
|
||||
const auto len = static_cast<int64_t>(c_result_ptr->label_ids.size());
|
||||
const int *buffer = static_cast<int *>(c_result_ptr->label_ids.data());
|
||||
return fastdeploy::jni::ConvertTo<jintArray>(env, buffer, len);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_ClassifyResult_releaseNative(
|
||||
JNIEnv *env, jclass clazz, jlong native_result_context) {
|
||||
if (native_result_context == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
auto c_result_ptr = reinterpret_cast<fastdeploy::vision::ClassifyResult *>(
|
||||
native_result_context);
|
||||
delete c_result_ptr;
|
||||
LOGD("Release ClassifyResult in native !");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
92
java/android/fastdeploy/src/main/cpp/vision/visualize_jni.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2022 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.
|
||||
#include <jni.h>
|
||||
|
||||
#include "fastdeploy_jni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_baidu_paddle_fastdeploy_vision_Visualize_visDetectionNative(
|
||||
JNIEnv *env, jclass clazz, jobject argb8888_bitmap, jobjectArray boxes,
|
||||
jfloatArray scores, jintArray label_ids, jfloat score_threshold,
|
||||
jint line_size, jfloat font_size, jobjectArray labels) {
|
||||
// Draw DetectionResult to ARGB8888 Bitmap
|
||||
int len = env->GetArrayLength(boxes);
|
||||
if ((len == 0) || (len != env->GetArrayLength(scores)) ||
|
||||
(len != env->GetArrayLength(label_ids))) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
fastdeploy::vision::DetectionResult c_result;
|
||||
c_result.Resize(len);
|
||||
bool check_validation = true;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
auto j_box =
|
||||
reinterpret_cast<jfloatArray>(env->GetObjectArrayElement(boxes, i));
|
||||
if (env->GetArrayLength(j_box) == 4) {
|
||||
jfloat *j_box_ptr = env->GetFloatArrayElements(j_box, nullptr);
|
||||
std::memcpy(c_result.boxes[i].data(), j_box_ptr, 4 * sizeof(float));
|
||||
env->ReleaseFloatArrayElements(j_box, j_box_ptr, 0);
|
||||
} else {
|
||||
check_validation = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!check_validation) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
jfloat *j_scores_ptr = env->GetFloatArrayElements(scores, nullptr);
|
||||
std::memcpy(c_result.scores.data(), j_scores_ptr, len * sizeof(float));
|
||||
env->ReleaseFloatArrayElements(scores, j_scores_ptr, 0);
|
||||
jint *j_label_ids_ptr = env->GetIntArrayElements(label_ids, nullptr);
|
||||
std::memcpy(c_result.label_ids.data(), j_label_ids_ptr, len * sizeof(int));
|
||||
env->ReleaseIntArrayElements(label_ids, j_label_ids_ptr, 0);
|
||||
|
||||
// Get labels from Java
|
||||
std::vector<std::string> c_labels;
|
||||
int label_len = env->GetArrayLength(labels);
|
||||
if (label_len > 0) {
|
||||
c_labels.reserve(label_len);
|
||||
for (int i = 0; i < label_len; ++i) {
|
||||
auto j_str =
|
||||
reinterpret_cast<jstring>(env->GetObjectArrayElement(labels, i));
|
||||
c_labels.push_back(fastdeploy::jni::ConvertTo<std::string>(env, j_str));
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat c_bgr;
|
||||
// From ARGB Bitmap to BGR
|
||||
if (!fastdeploy::jni::ARGB888Bitmap2BGR(env, argb8888_bitmap, &c_bgr)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
cv::Mat c_vis_im;
|
||||
if (!c_labels.empty()) {
|
||||
c_vis_im = fastdeploy::vision::VisDetection(
|
||||
c_bgr, c_result, c_labels, score_threshold, line_size, font_size);
|
||||
} else {
|
||||
c_vis_im = fastdeploy::vision::VisDetection(
|
||||
c_bgr, c_result, score_threshold, line_size, font_size);
|
||||
}
|
||||
// Rendering to bitmap
|
||||
if (!fastdeploy::jni::BGR2ARGB888Bitmap(env, argb8888_bitmap, c_vis_im)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,8 @@
|
||||
package com.baidu.paddle.fastdeploy;
|
||||
|
||||
public enum FDModelTag {
|
||||
UNKNOWN,
|
||||
VISION_DETECTION_PICODET,
|
||||
VISION_DETECTION_PPYOLOE,
|
||||
VISION_CLASSIFICATION_PPCLS
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.baidu.paddle.fastdeploy;
|
||||
|
||||
/**
|
||||
* Initializer for FastDeploy. The initialization methods are called by package
|
||||
* classes only. Public users don't have to call them. Public users can get
|
||||
* FastDeploy information constants such as JNI lib name in this class.
|
||||
*/
|
||||
public class FastDeployInitializer {
|
||||
/** name of C++ JNI lib */
|
||||
public final static String JNI_LIB_NAME = "fastdeploy_jni";
|
||||
|
||||
/**
|
||||
* loads the C++ JNI lib. We only call it in our package, so it shouldn't be
|
||||
* visible to public users.
|
||||
*
|
||||
* @return true if initialize successfully.
|
||||
*/
|
||||
public static boolean init() {
|
||||
System.loadLibrary(JNI_LIB_NAME);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package com.baidu.paddle.fastdeploy;
|
||||
|
||||
public enum LitePowerMode {
|
||||
LITE_POWER_HIGH,
|
||||
LITE_POWER_LOW,
|
||||
LITE_POWER_FULL,
|
||||
LITE_POWER_NO_BIND,
|
||||
LITE_POWER_RAND_HIGH,
|
||||
LITE_POWER_RAND_LOW
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
package com.baidu.paddle.fastdeploy;
|
||||
|
||||
public class RuntimeOption {
|
||||
public int mCpuThreadNum = 1;
|
||||
public boolean mEnableLiteFp16 = false;
|
||||
public boolean mEnableRecordTimeOfRuntime = false;
|
||||
public LitePowerMode mLitePowerMode = LitePowerMode.LITE_POWER_NO_BIND;
|
||||
public String mLiteOptimizedModelDir = "";
|
||||
|
||||
public RuntimeOption() {
|
||||
mCpuThreadNum = 1;
|
||||
mEnableLiteFp16 = false;
|
||||
mEnableRecordTimeOfRuntime = false;
|
||||
mLitePowerMode = LitePowerMode.LITE_POWER_NO_BIND;
|
||||
mLiteOptimizedModelDir = "";
|
||||
}
|
||||
|
||||
public void enableLiteFp16() {
|
||||
mEnableLiteFp16 = true;
|
||||
}
|
||||
|
||||
public void disableLiteFP16() {
|
||||
mEnableLiteFp16 = false;
|
||||
}
|
||||
|
||||
public void setCpuThreadNum(int threadNum) {
|
||||
mCpuThreadNum = threadNum;
|
||||
}
|
||||
|
||||
public void setLitePowerMode(LitePowerMode mode) {
|
||||
mLitePowerMode = mode;
|
||||
}
|
||||
|
||||
public void setLitePowerMode(String modeStr) {
|
||||
mLitePowerMode = parseLitePowerModeFromString(modeStr);
|
||||
}
|
||||
|
||||
public void setLiteOptimizedModelDir(String modelDir) {
|
||||
mLiteOptimizedModelDir = modelDir;
|
||||
}
|
||||
|
||||
public void enableRecordTimeOfRuntime() {
|
||||
mEnableRecordTimeOfRuntime = true;
|
||||
}
|
||||
|
||||
// Helpers: parse lite power mode from string
|
||||
public static LitePowerMode parseLitePowerModeFromString(String modeStr) {
|
||||
if (modeStr.equalsIgnoreCase("LITE_POWER_HIGH")) {
|
||||
return LitePowerMode.LITE_POWER_HIGH;
|
||||
} else if (modeStr.equalsIgnoreCase("LITE_POWER_LOW")) {
|
||||
return LitePowerMode.LITE_POWER_LOW;
|
||||
} else if (modeStr.equalsIgnoreCase("LITE_POWER_FULL")) {
|
||||
return LitePowerMode.LITE_POWER_FULL;
|
||||
} else if (modeStr.equalsIgnoreCase("LITE_POWER_NO_BIND")) {
|
||||
return LitePowerMode.LITE_POWER_NO_BIND;
|
||||
} else if (modeStr.equalsIgnoreCase("LITE_POWER_RAND_HIGH")) {
|
||||
return LitePowerMode.LITE_POWER_RAND_HIGH;
|
||||
} else if (modeStr.equalsIgnoreCase("LITE_POWER_RAND_LOW")) {
|
||||
return LitePowerMode.LITE_POWER_RAND_LOW;
|
||||
} else {
|
||||
return LitePowerMode.LITE_POWER_NO_BIND;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package com.baidu.paddle.fastdeploy.vision;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public class ClassifyResult {
|
||||
public float[] mScores; // [n]
|
||||
public int[] mLabelIds; // [n]
|
||||
public boolean mInitialized = false;
|
||||
|
||||
public ClassifyResult() {
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
public ClassifyResult(long nativeResultContext) {
|
||||
mInitialized = copyAllFromNativeContext(nativeResultContext);
|
||||
}
|
||||
|
||||
public boolean initialized() {
|
||||
return mInitialized;
|
||||
}
|
||||
|
||||
private void setScores(@NonNull float[] scoresBuffer) {
|
||||
if (scoresBuffer.length > 0) {
|
||||
mScores = scoresBuffer.clone();
|
||||
}
|
||||
}
|
||||
|
||||
private void setLabelIds(@NonNull int[] labelIdsBuffer) {
|
||||
if (labelIdsBuffer.length > 0) {
|
||||
mLabelIds = labelIdsBuffer.clone();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean copyAllFromNativeContext(long nativeResultContext) {
|
||||
if (nativeResultContext == 0) {
|
||||
return false;
|
||||
}
|
||||
setScores(copyScoresFromNative(nativeResultContext));
|
||||
setLabelIds(copyLabelIdsFromNative(nativeResultContext));
|
||||
// WARN: must release ctx.
|
||||
return releaseNative(nativeResultContext);
|
||||
}
|
||||
|
||||
// Fetch native buffers from native context.
|
||||
private static native float[] copyScoresFromNative(long nativeResultContext);
|
||||
|
||||
private static native int[] copyLabelIdsFromNative(long nativeResultContext);
|
||||
|
||||
private static native boolean releaseNative(long nativeResultContext);
|
||||
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
package com.baidu.paddle.fastdeploy.vision;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.FastDeployInitializer;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class DetectionResult {
|
||||
// Not support MaskRCNN now.
|
||||
public float[][] mBoxes; // [n,4]
|
||||
public float[] mScores; // [n]
|
||||
public int[] mLabelIds; // [n]
|
||||
public boolean mInitialized = false;
|
||||
|
||||
public DetectionResult() {
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
public DetectionResult(long nativeResultContext) {
|
||||
mInitialized = copyAllFromNativeContext(nativeResultContext);
|
||||
}
|
||||
|
||||
public boolean initialized() {
|
||||
return mInitialized;
|
||||
}
|
||||
|
||||
// Setup results from native buffers.
|
||||
private boolean copyAllFromNativeContext(long nativeResultContext) {
|
||||
if (nativeResultContext == 0) {
|
||||
return false;
|
||||
}
|
||||
if (copyBoxesNumFromNative(nativeResultContext) > 0) {
|
||||
setBoxes(copyBoxesFromNative(nativeResultContext));
|
||||
setScores(copyScoresFromNative(nativeResultContext));
|
||||
setLabelIds(copyLabelIdsFromNative(nativeResultContext));
|
||||
}
|
||||
// WARN: must release ctx.
|
||||
return releaseNative(nativeResultContext);
|
||||
}
|
||||
|
||||
private void setBoxes(@NonNull float[] boxesBuffer) {
|
||||
int boxesNum = boxesBuffer.length / 4;
|
||||
if (boxesNum > 0) {
|
||||
mBoxes = new float[boxesNum][4];
|
||||
for (int i = 0; i < boxesNum; ++i) {
|
||||
mBoxes[i] = Arrays.copyOfRange(
|
||||
boxesBuffer, i * 4, (i + 1) * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setScores(@NonNull float[] scoresBuffer) {
|
||||
if (scoresBuffer.length > 0) {
|
||||
mScores = scoresBuffer.clone();
|
||||
}
|
||||
}
|
||||
|
||||
private void setLabelIds(@NonNull int[] labelIdsBuffer) {
|
||||
if (labelIdsBuffer.length > 0) {
|
||||
mLabelIds = labelIdsBuffer.clone();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch native buffers from native context.
|
||||
private static native int copyBoxesNumFromNative(long nativeResultContext);
|
||||
|
||||
private static native float[] copyBoxesFromNative(long nativeResultContext);
|
||||
|
||||
private static native float[] copyScoresFromNative(long nativeResultContext);
|
||||
|
||||
private static native int[] copyLabelIdsFromNative(long nativeResultContext);
|
||||
|
||||
private static native boolean releaseNative(long nativeResultContext);
|
||||
|
||||
// Initializes at the beginning.
|
||||
static {
|
||||
FastDeployInitializer.init();
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
package com.baidu.paddle.fastdeploy.vision;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.FastDeployInitializer;
|
||||
|
||||
|
||||
public class Visualize {
|
||||
// TODO(qiuyanjun):
|
||||
// VisClassification, VisSegmentation, VisMatting, VisOcr, ...
|
||||
|
||||
// Visualize DetectionResult without labels
|
||||
public static boolean visDetection(Bitmap ARGB8888Bitmap,
|
||||
DetectionResult result) {
|
||||
return visDetectionNative(
|
||||
ARGB8888Bitmap,
|
||||
result.mBoxes,
|
||||
result.mScores,
|
||||
result.mLabelIds,
|
||||
0.f, 1, 0.5f,
|
||||
new String[]{});
|
||||
}
|
||||
|
||||
public static boolean visDetection(Bitmap ARGB8888Bitmap,
|
||||
DetectionResult result,
|
||||
float score_threshold,
|
||||
int line_size,
|
||||
float font_size) {
|
||||
return visDetectionNative(
|
||||
ARGB8888Bitmap,
|
||||
result.mBoxes,
|
||||
result.mScores,
|
||||
result.mLabelIds,
|
||||
score_threshold,
|
||||
line_size,
|
||||
font_size,
|
||||
new String[]{});
|
||||
}
|
||||
|
||||
// Visualize DetectionResult with labels
|
||||
public static boolean visDetection(Bitmap ARGB8888Bitmap,
|
||||
DetectionResult result,
|
||||
String[] labels) {
|
||||
return visDetectionNative(
|
||||
ARGB8888Bitmap,
|
||||
result.mBoxes,
|
||||
result.mScores,
|
||||
result.mLabelIds,
|
||||
0.f, 1, 0.5f,
|
||||
labels);
|
||||
}
|
||||
|
||||
public static boolean visDetection(Bitmap ARGB8888Bitmap,
|
||||
DetectionResult result,
|
||||
float score_threshold,
|
||||
int line_size,
|
||||
float font_size,
|
||||
String[] labels) {
|
||||
return visDetectionNative(
|
||||
ARGB8888Bitmap,
|
||||
result.mBoxes,
|
||||
result.mScores,
|
||||
result.mLabelIds,
|
||||
score_threshold,
|
||||
line_size,
|
||||
font_size,
|
||||
labels);
|
||||
}
|
||||
|
||||
// VisDetection in native
|
||||
public static native boolean visDetectionNative(Bitmap ARGB8888Bitmap,
|
||||
float[][] boxes,
|
||||
float[] scores,
|
||||
int[] labelIds,
|
||||
float score_threshold,
|
||||
int line_size,
|
||||
float font_size,
|
||||
String[] labels);
|
||||
|
||||
|
||||
/* Initializes at the beginning */
|
||||
static {
|
||||
FastDeployInitializer.init();
|
||||
}
|
||||
}
|
@@ -0,0 +1,172 @@
|
||||
package com.baidu.paddle.fastdeploy.vision.classification;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.FastDeployInitializer;
|
||||
import com.baidu.paddle.fastdeploy.RuntimeOption;
|
||||
import com.baidu.paddle.fastdeploy.vision.ClassifyResult;
|
||||
|
||||
public class PaddleClasModel {
|
||||
protected long mNativeModelContext = 0; // Context from native.
|
||||
protected boolean mInitialized = false;
|
||||
|
||||
public PaddleClasModel() {
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
// Constructor with default runtime option
|
||||
public PaddleClasModel(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile) {
|
||||
init_(modelFile, paramsFile, configFile, "", new RuntimeOption());
|
||||
}
|
||||
|
||||
public PaddleClasModel(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile,
|
||||
String labelFile) {
|
||||
init_(modelFile, paramsFile, configFile, labelFile, new RuntimeOption());
|
||||
}
|
||||
|
||||
// Constructor without label file
|
||||
public PaddleClasModel(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile,
|
||||
RuntimeOption option) {
|
||||
init_(modelFile, paramsFile, configFile, "", option);
|
||||
}
|
||||
|
||||
// Constructor with label file
|
||||
public PaddleClasModel(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile,
|
||||
String labelFile,
|
||||
RuntimeOption option) {
|
||||
init_(modelFile, paramsFile, configFile, labelFile, option);
|
||||
}
|
||||
|
||||
// Call init manually without label file
|
||||
public boolean init(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile,
|
||||
RuntimeOption option) {
|
||||
return init_(modelFile, paramsFile, configFile, "", option);
|
||||
}
|
||||
|
||||
// Call init manually with label file
|
||||
public boolean init(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile,
|
||||
String labelFile,
|
||||
RuntimeOption option) {
|
||||
return init_(modelFile, paramsFile, configFile, labelFile, option);
|
||||
}
|
||||
|
||||
|
||||
public boolean release() {
|
||||
mInitialized = false;
|
||||
if (mNativeModelContext == 0) {
|
||||
return false;
|
||||
}
|
||||
return releaseNative(mNativeModelContext);
|
||||
}
|
||||
|
||||
public boolean initialized() {
|
||||
return mInitialized;
|
||||
}
|
||||
|
||||
// Predict without image saving and bitmap rendering.
|
||||
public ClassifyResult predict(Bitmap ARGB8888Bitmap) {
|
||||
if (mNativeModelContext == 0) {
|
||||
return new ClassifyResult();
|
||||
}
|
||||
// Only support ARGB8888 bitmap in native now.
|
||||
return new ClassifyResult(predictNative(
|
||||
mNativeModelContext, ARGB8888Bitmap, false,
|
||||
"", 0.f, false));
|
||||
}
|
||||
|
||||
// Predict with image saving and bitmap rendering (will cost more times)
|
||||
public ClassifyResult predict(Bitmap ARGB8888Bitmap,
|
||||
String savedImagePath,
|
||||
float scoreThreshold) {
|
||||
// scoreThreshold is for visualizing only.
|
||||
if (mNativeModelContext == 0) {
|
||||
return new ClassifyResult();
|
||||
}
|
||||
// Only support ARGB8888 bitmap in native now.
|
||||
return new ClassifyResult(predictNative(
|
||||
mNativeModelContext, ARGB8888Bitmap, true,
|
||||
savedImagePath, scoreThreshold, true));
|
||||
}
|
||||
|
||||
// Internal init_ method
|
||||
private boolean init_(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile,
|
||||
String labelFile,
|
||||
RuntimeOption option) {
|
||||
if (!mInitialized) {
|
||||
mNativeModelContext = bindNative(
|
||||
modelFile,
|
||||
paramsFile,
|
||||
configFile,
|
||||
option.mCpuThreadNum,
|
||||
option.mEnableLiteFp16,
|
||||
option.mLitePowerMode.ordinal(),
|
||||
option.mLiteOptimizedModelDir,
|
||||
option.mEnableRecordTimeOfRuntime, labelFile);
|
||||
if (mNativeModelContext != 0) {
|
||||
mInitialized = true;
|
||||
}
|
||||
return mInitialized;
|
||||
} else {
|
||||
// release current native context and bind a new one.
|
||||
if (release()) {
|
||||
mNativeModelContext = bindNative(
|
||||
modelFile,
|
||||
paramsFile,
|
||||
configFile,
|
||||
option.mCpuThreadNum,
|
||||
option.mEnableLiteFp16,
|
||||
option.mLitePowerMode.ordinal(),
|
||||
option.mLiteOptimizedModelDir,
|
||||
option.mEnableRecordTimeOfRuntime, labelFile);
|
||||
if (mNativeModelContext != 0) {
|
||||
mInitialized = true;
|
||||
}
|
||||
return mInitialized;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Bind predictor from native context.
|
||||
private static native long bindNative(String modelFile,
|
||||
String paramsFile,
|
||||
String configFile,
|
||||
int cpuNumThread,
|
||||
boolean enableLiteFp16,
|
||||
int litePowerMode,
|
||||
String liteOptimizedModelDir,
|
||||
boolean enableRecordTimeOfRuntime,
|
||||
String labelFile);
|
||||
|
||||
// Call prediction from native context.
|
||||
private static native long predictNative(long nativeModelContext,
|
||||
Bitmap ARGB8888Bitmap,
|
||||
boolean saved,
|
||||
String savedImagePath,
|
||||
float scoreThreshold,
|
||||
boolean rendering);
|
||||
|
||||
// Release buffers allocated in native context.
|
||||
private static native boolean releaseNative(long nativeModelContext);
|
||||
|
||||
// Initializes at the beginning.
|
||||
static {
|
||||
FastDeployInitializer.init();
|
||||
}
|
||||
|
||||
}
|