[Android] Add SCRFD android app example (#682)

* [Android] Add CxxBuffer to native PaddleSegModel

* [Android] Add PaddleSeg android app example

* [Android] Add SCRFD android app example

* [Doc] fix typos

* [Android] revert camera setting changes
This commit is contained in:
DefTruth
2022-11-23 21:08:27 +08:00
committed by GitHub
parent 1af54c41cd
commit c2714000b5
93 changed files with 11203 additions and 53 deletions

View File

@@ -23,9 +23,10 @@
4. 点击 Run 按钮,自动编译 APP 并安装到手机。(该过程会自动下载预编译的 FastDeploy Android 库 以及 模型文件,需要联网)
成功后效果如下图一APP 安装到手机;图二: APP 打开后的效果会自动识别图片中的物体并标记图三APP设置选项点击右上角的设置图片可以设置不同选项进行体验。
| APP 图标 | APP 效果 | APP设置项
| APP 图标 | APP 效果 | APP设置项
| --- | --- | --- |
| ![app_pic](https://user-images.githubusercontent.com/31974251/203268599-c94018d8-3683-490a-a5c7-a8136a4fa284.jpg) | ![app_res](https://user-images.githubusercontent.com/31974251/197169609-bb214af3-d6e7-4433-bb96-1225cddd441c.jpg) | ![app_setup](https://user-images.githubusercontent.com/31974251/197332983-afbfa6d5-4a3b-4c54-a528-4a3e58441be1.jpg) |
| <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/203268599-c94018d8-3683-490a-a5c7-a8136a4fa284.jpg"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/203261763-a7513df7-e0ab-42e5-ad50-79ed7e8c8cd2.gif"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/197332983-afbfa6d5-4a3b-4c54-a528-4a3e58441be1.jpg"> |
### PicoDet Java API 说明
- 模型初始化 API: 模型初始化API包含两种方式方式一是通过构造函数直接初始化方式二是通过调用init函数在合适的程序节点进行初始化。PicoDet初始化参数说明如下

View File

@@ -287,27 +287,20 @@ public class CameraSurfaceView extends GLSurfaceView implements Renderer,
public void openCamera() {
if (disableCamera) return;
camera = Camera.open(selectedCameraId);
Camera.Parameters parameters = camera.getParameters();
int degree = Utils.getCameraDisplayOrientation(context, selectedCameraId);
camera.setDisplayOrientation(degree);
boolean rotate = degree == 90 || degree == 270;
int adjusted_width = rotate ? EXPECTED_PREVIEW_HEIGHT : EXPECTED_PREVIEW_WIDTH;
int adjusted_height = rotate ? EXPECTED_PREVIEW_WIDTH : EXPECTED_PREVIEW_HEIGHT;
List<Size> supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes();
Size previewSize = Utils.getOptimalPreviewSize(
supportedPreviewSizes, adjusted_width, adjusted_height);
textureWidth = previewSize.width;
textureHeight = previewSize.height;
Size previewSize = Utils.getOptimalPreviewSize(supportedPreviewSizes, EXPECTED_PREVIEW_WIDTH,
EXPECTED_PREVIEW_HEIGHT);
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(previewSize.width, previewSize.height);
camera.setParameters(parameters);
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);

View 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

View File

@@ -0,0 +1,148 @@
# 目标检测 SCRFD Android Demo 使用文档
在 Android 上实现实时的人脸检测功能,此 Demo 有很好的的易用性和开放性,如在 Demo 中跑自己训练好的模型等。
## 环境准备
1. 在本地环境安装好 Android Studio 工具,详细安装方法请见[Android Stuido 官网](https://developer.android.com/studio)。
2. 准备一部 Android 手机,并开启 USB 调试模式。开启方法: `手机设置 -> 查找开发者选项 -> 打开开发者选项和 USB 调试模式`
## 部署步骤
1. 目标检测 SCRFD Demo 位于 `fastdeploy/examples/vision/facedet/scrfd/android` 目录
2. 用 Android Studio 打开 scrfd/android 工程
3. 手机连接电脑,打开 USB 调试和文件传输模式,并在 Android Studio 上连接自己的手机设备(手机需要开启允许从 USB 安装软件权限)
<p align="center">
<img width="1440" alt="image" src="https://user-images.githubusercontent.com/31974251/203257262-71b908ab-bb2b-47d3-9efb-67631687b774.png">
</p>
> **注意:**
>> 如果您在导入项目、编译或者运行过程中遇到 NDK 配置错误的提示,请打开 ` File > Project Structure > SDK Location`,修改 `Andriod SDK location` 为您本机配置的 SDK 所在路径。
4. 点击 Run 按钮,自动编译 APP 并安装到手机。(该过程会自动下载预编译的 FastDeploy Android 库 以及 模型文件,需要联网)
成功后效果如下图一APP 安装到手机;图二: APP 打开后的效果会自动识别图片中的人脸并绘制框图三APP设置选项点击右上角的设置图片可以设置不同选项进行体验。
| APP 图标 | APP 效果 | APP设置项
| --- | --- | --- |
| <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/203268599-c94018d8-3683-490a-a5c7-a8136a4fa284.jpg"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/203261714-c74631dd-ec5b-4738-81a3-8dfc496f7547.gif"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/197332983-afbfa6d5-4a3b-4c54-a528-4a3e58441be1.jpg"> |
## SCRFD Java API 说明
- 模型初始化 API: 模型初始化API包含两种方式方式一是通过构造函数直接初始化方式二是通过调用init函数在合适的程序节点进行初始化。PaddleSegModel初始化参数说明如下
- modelFile: String, paddle格式的模型文件路径如 model.pdmodel
- paramFile: String, paddle格式的参数文件路径如 model.pdiparams
- option: RuntimeOption可选参数模型初始化option。如果不传入该参数则会使用默认的运行时选项。
```java
// 构造函数: constructor w/o label file
public SCRFD(); // 空构造函数之后可以调用init初始化
public SCRFD(String modelFile, String paramsFile);
public SCRFD(String modelFile, String paramsFile, RuntimeOption option);
// 手动调用init初始化: call init manually w/o label file
public boolean init(String modelFile, String paramsFile, RuntimeOption option);
```
- 模型预测 API模型预测API包含直接预测的API以及带可视化功能的API直接预测是指不保存图片以及不渲染结果到Bitmap上仅预测推理结果预测并且可视化是指预测结果以及可视化并将可视化后的图片保存到指定的途径以及将可视化结果渲染在Bitmap(目前支持ARGB8888格式的Bitmap), 后续可将该Bitmap在camera中进行显示
```java
// 直接预测不保存图片以及不渲染结果到Bitmap上
public FaceDetectionResult predict(Bitmap ARGB8888Bitmap)
public FaceDetectionResult predict(Bitmap ARGB8888Bitmap, float confThreshold, float nmsIouThreshold) // 设置置信度阈值和NMS阈值
// 预测并且可视化预测结果以及可视化并将可视化后的图片保存到指定的途径以及将可视化结果渲染在Bitmap上
public FaceDetectionResult predict(Bitmap ARGB8888Bitmap, String savedImagePath, float confThreshold, float nmsIouThreshold);
public FaceDetectionResult predict(Bitmap ARGB8888Bitmap, boolean rendering, float confThreshold, float nmsIouThreshold); // 只渲染 不保存图片
```
- 模型资源释放 API调用 release() API 可以释放模型资源返回true表示释放成功false表示失败调用 initialized() 可以判断模型是否初始化成功true表示初始化成功false表示失败。
```java
public boolean release(); // 释放native资源
public boolean initialized(); // 检查是否初始化成功
```
- RuntimeOption设置说明
```java
public void enableLiteFp16(); // 开启fp16精度推理
public void disableLiteFP16(); // 关闭fp16精度推理
public void setCpuThreadNum(int threadNum); // 设置线程数
public void setLitePowerMode(LitePowerMode mode); // 设置能耗模式
public void setLitePowerMode(String modeStr); // 通过字符串形式设置能耗模式
```
- 模型结果SegmentationResult说明
```java
public class FaceDetectionResult {
public float[][] mBoxes; // [n,4] 检测框 (x1,y1,x2,y2)
public float[] mScores; // [n] 每个检测框得分(置信度,概率值)
public float[][] mLandmarks; // [nx?,2] 每个检测到的人脸对应关键点
int mLandmarksPerFace = 0; // 每个人脸对应的关键点个数
public boolean initialized(); // 检测结果是否有效
}
```
其他参考C++/Python对应的FaceDetectionResult说明: [api/vision_results/face_detection_result.md](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/api/vision_results/face_detection_result.md)
- 模型调用示例1使用构造函数以及默认的RuntimeOption
```java
import java.nio.ByteBuffer;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import com.baidu.paddle.fastdeploy.vision.FaceDetectionResult;
import com.baidu.paddle.fastdeploy.vision.facedet.SCRFD;
// 初始化模型
SCRFD model = new SCRFD(
"scrfd_500m_bnkps_shape320x320_pd/model.pdmodel",
"scrfd_500m_bnkps_shape320x320_pd/model.pdiparams");
// 读取图片: 以下仅为读取Bitmap的伪代码
ByteBuffer pixelBuffer = ByteBuffer.allocate(width * height * 4);
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
Bitmap ARGB8888ImageBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
ARGB8888ImageBitmap.copyPixelsFromBuffer(pixelBuffer);
// 直接预测返回 FaceDetectionResult
FaceDetectionResult result = model.predict(ARGB8888ImageBitmap);
// 释放模型资源
model.release();
```
- 模型调用示例2: 在合适的程序节点手动调用init并自定义RuntimeOption
```java
// import 同上 ...
import com.baidu.paddle.fastdeploy.RuntimeOption;
import com.baidu.paddle.fastdeploy.LitePowerMode;
import com.baidu.paddle.fastdeploy.vision.FaceDetectionResult;
import com.baidu.paddle.fastdeploy.vision.facedet.SCRFD;
// 新建空模型
SCRFD model = new SCRFD();
// 模型路径
String modelFile = "scrfd_500m_bnkps_shape320x320_pd/model.pdmodel";
String paramFile = "scrfd_500m_bnkps_shape320x320_pd/model.pdiparams";
// 指定RuntimeOption
RuntimeOption option = new RuntimeOption();
option.setCpuThreadNum(2);
option.setLitePowerMode(LitePowerMode.LITE_POWER_HIGH);
option.enableLiteFp16();
// 使用init函数初始化
model.init(modelFile, paramFile, option);
// Bitmap读取、模型预测、资源释放 同上 ...
```
更详细的用法请参考 [FaceDetMainActivity](./app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/facedet/FaceDetMainActivity.java) 中的用法
## 替换 FastDeploy SDK和模型
替换FastDeploy预测库和模型的步骤非常简单。预测库所在的位置为 `app/libs/fastdeploy-android-sdk-xxx.aar`,其中 `xxx` 表示当前您使用的预测库版本号。模型所在的位置为,`app/src/main/assets/models/scrfd_500m_bnkps_shape320x320_pd`。
- 替换FastDeploy Android SDK: 下载或编译最新的FastDeploy Android SDK解压缩后放在 `app/libs` 目录下;详细配置文档可参考:
- [在 Android 中使用 FastDeploy Java SDK](../../../../../java/android/)
- 替换SCRFD模型的步骤
- 通过X2Paddle导出其他版本的SCRFD模型请参考 [SCRFD文档](../README.md) 以及 [X2Paddle](https://github.com/PaddlePaddle/X2Paddle)
- 将您的SCRFD模型放在 `app/src/main/assets/models` 目录下;
- 修改 `app/src/main/res/values/strings.xml` 中模型路径的默认值,如:
```xml
<!-- 将这个路径指修改成您的模型,如 models/scrfd_500m_bnkps_shape320x320_pd -->
<string name="FACEDET_MODEL_DIR_DEFAULT">models/scrfd_500m_bnkps_shape320x320_pd</string>
```
## 更多参考文档
如果您想知道更多的FastDeploy Java API文档以及如何通过JNI来接入FastDeploy C++ API感兴趣可以参考以下内容:
- [在 Android 中使用 FastDeploy Java SDK](../../../../../java/android/)
- [在 Android 中使用 FastDeploy C++ SDK](../../../../../docs/cn/faq/use_cpp_sdk_on_android.md)

View File

@@ -0,0 +1,113 @@
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: ['*.aar'], 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'
//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 FD_MODEL = [
[
'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/scrfd_500m_bnkps_shape320x320_pd.tgz',
'dest': 'src/main/assets/models'
]
]
def FD_JAVA_SDK = [
[
'src' : 'https://bj.bcebos.com/fastdeploy/test/fastdeploy-android-sdk-latest-dev.aar',
'dest': 'libs'
]
]
task downloadAndExtractModels(type: DefaultTask) {
doFirst {
println "Downloading and extracting fastdeploy models ..."
}
doLast {
String cachePath = "cache"
if (!file("${cachePath}").exists()) {
mkdir "${cachePath}"
}
FD_MODEL.eachWithIndex { model, index ->
String[] modelPaths = model.src.split("/")
String modelName = modelPaths[modelPaths.length - 1]
// Download the target model if not exists
boolean copyFiles = !file("${model.dest}").exists()
if (!file("${cachePath}/${modelName}").exists()) {
println "Downloading ${model.src} -> ${cachePath}/${modelName}"
ant.get(src: model.src, dest: file("${cachePath}/${modelName}"))
copyFiles = true
}
if (copyFiles) {
println "Coping ${cachePath}/${modelName} -> ${model.dest}"
copy {
from tarTree("${cachePath}/${modelName}")
into "${model.dest}"
}
}
}
}
}
task downloadAndExtractSDKs(type: DefaultTask) {
doFirst {
println "Downloading and extracting fastdeploy android java sdk ..."
}
doLast {
String cachePath = "cache"
if (!file("${cachePath}").exists()) {
mkdir "${cachePath}"
}
FD_JAVA_SDK.eachWithIndex { sdk, index ->
String[] sdkPaths = sdk.src.split("/")
String sdkName = sdkPaths[sdkPaths.length - 1]
// Download the target SDK if not exists
boolean copyFiles = !file("${sdk.dest}/${sdkName}").exists()
if (!file("${cachePath}/${sdkName}").exists()) {
println "Downloading ${sdk.src} -> ${cachePath}/${sdkName}"
ant.get(src: sdk.src, dest: file("${cachePath}/${sdkName}"))
copyFiles = true
}
if (copyFiles) {
println "Coping ${cachePath}/${sdkName} -> ${sdk.dest}/${sdkName}"
copy {
from "${cachePath}/${sdkName}"
into "${sdk.dest}"
}
}
}
}
}
preBuild.dependsOn downloadAndExtractSDKs
preBuild.dependsOn downloadAndExtractModels

View 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

View File

@@ -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());
}
}

View 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">
<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=".facedet.FaceDetMainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".facedet.FaceDetSettingsActivity"
android:label="Settings">
</activity>
</application>
</manifest>

View 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

View File

@@ -0,0 +1,94 @@
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
`
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
!
"
#
$
%
&
'
(
)
*
+
,
-
.
/

View 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

View File

@@ -0,0 +1,497 @@
package com.baidu.paddle.fastdeploy.app.examples.facedet;
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.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import com.baidu.paddle.fastdeploy.RuntimeOption;
import com.baidu.paddle.fastdeploy.app.examples.R;
import com.baidu.paddle.fastdeploy.app.ui.view.CameraSurfaceView;
import com.baidu.paddle.fastdeploy.app.ui.view.ResultListView;
import com.baidu.paddle.fastdeploy.app.ui.Utils;
import com.baidu.paddle.fastdeploy.app.ui.view.adapter.BaseResultAdapter;
import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel;
import com.baidu.paddle.fastdeploy.vision.FaceDetectionResult;
import com.baidu.paddle.fastdeploy.vision.Visualize;
import com.baidu.paddle.fastdeploy.vision.facedet.SCRFD;
import static com.baidu.paddle.fastdeploy.app.ui.Utils.decodeBitmap;
import static com.baidu.paddle.fastdeploy.app.ui.Utils.getRealPathFromURI;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class FaceDetMainActivity extends Activity implements View.OnClickListener, CameraSurfaceView.OnTextureChangedListener {
private static final String TAG = FaceDetMainActivity.class.getSimpleName();
CameraSurfaceView svPreview;
TextView tvStatus;
ImageButton btnSwitch;
ImageButton btnShutter;
ImageButton btnSettings;
ImageView realtimeToggleButton;
boolean isRealtimeStatusRunning = false;
ImageView backInPreview;
private ImageView albumSelectButton;
private View cameraPageView;
private ViewGroup resultPageView;
private ImageView resultImage;
private ImageView backInResult;
private SeekBar confidenceSeekbar;
private TextView seekbarText;
private float resultNum = 1.0f;
private ResultListView resultView;
private Bitmap picBitmap;
private Bitmap shutterBitmap;
private Bitmap originPicBitmap;
private Bitmap originShutterBitmap;
private boolean isShutterBitmapCopied = false;
public static final int TYPE_UNKNOWN = -1;
public static final int BTN_SHUTTER = 0;
public static final int ALBUM_SELECT = 1;
public static final int REALTIME_DETECT = 2;
private static int TYPE = REALTIME_DETECT;
private static final int REQUEST_PERMISSION_CODE_STORAGE = 101;
private static final int INTENT_CODE_PICK_IMAGE = 100;
private static final int TIME_SLEEP_INTERVAL = 50; // ms
long timeElapsed = 0;
long frameCounter = 0;
// Call 'init' and 'release' manually later
SCRFD predictor = new SCRFD();
public float[] scores; // [n]
public boolean initialized = false;
private List<BaseResultModel> results = new ArrayList<>();
@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.facedet_activity_main);
// Clear all setting items to avoid app crashing due to the incorrect settings
initSettings();
// Check and request CAMERA and WRITE_EXTERNAL_STORAGE permissions
if (!checkAllPermissions()) {
requestAllPermissions();
}
// Init the camera preview and UI components
initView();
}
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_switch:
svPreview.switchCamera();
break;
case R.id.btn_shutter:
TYPE = BTN_SHUTTER;
shutterAndPauseCamera();
resultView.setAdapter(null);
break;
case R.id.btn_settings:
startActivity(new Intent(FaceDetMainActivity.this, FaceDetSettingsActivity.class));
break;
case R.id.realtime_toggle_btn:
toggleRealtimeStyle();
break;
case R.id.back_in_preview:
finish();
break;
case R.id.album_select:
TYPE = ALBUM_SELECT;
// Judge whether authority has been granted.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// If this permission was requested before the application but the user refused the request, this method will return true.
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE_STORAGE);
} else {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, INTENT_CODE_PICK_IMAGE);
}
resultView.setAdapter(null);
break;
case R.id.back_in_result:
back();
break;
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
back();
}
private void back() {
resultPageView.setVisibility(View.GONE);
cameraPageView.setVisibility(View.VISIBLE);
TYPE = REALTIME_DETECT;
isShutterBitmapCopied = false;
svPreview.onResume();
results.clear();
if (scores != null) {
scores = null;
}
}
private void shutterAndPauseCamera() {
new Thread(new Runnable() {
@Override
public void run() {
try {
// Sleep some times to ensure picture has been correctly shut.
Thread.sleep(TIME_SLEEP_INTERVAL * 10); // 500ms
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@SuppressLint("SetTextI18n")
public void run() {
// These codes will run in main thread.
svPreview.onPause();
cameraPageView.setVisibility(View.GONE);
resultPageView.setVisibility(View.VISIBLE);
seekbarText.setText(resultNum + "");
confidenceSeekbar.setProgress((int) (resultNum * 100));
if (shutterBitmap != null && !shutterBitmap.isRecycled()) {
resultImage.setImageBitmap(shutterBitmap);
} else {
new AlertDialog.Builder(FaceDetMainActivity.this)
.setTitle("Empty Result!")
.setMessage("Current picture is empty, please shutting it again!")
.setCancelable(true)
.show();
}
}
});
}
}).start();
}
private void copyBitmapFromCamera(Bitmap ARGB8888ImageBitmap) {
if (isShutterBitmapCopied || ARGB8888ImageBitmap == null) {
return;
}
if (!ARGB8888ImageBitmap.isRecycled()) {
synchronized (this) {
shutterBitmap = ARGB8888ImageBitmap.copy(Bitmap.Config.ARGB_8888, true);
originShutterBitmap = ARGB8888ImageBitmap.copy(Bitmap.Config.ARGB_8888, true);
}
SystemClock.sleep(TIME_SLEEP_INTERVAL);
isShutterBitmapCopied = true;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == INTENT_CODE_PICK_IMAGE) {
if (resultCode == Activity.RESULT_OK) {
cameraPageView.setVisibility(View.GONE);
resultPageView.setVisibility(View.VISIBLE);
seekbarText.setText(resultNum + "");
confidenceSeekbar.setProgress((int) (resultNum * 100));
Uri uri = data.getData();
String path = getRealPathFromURI(this, uri);
picBitmap = decodeBitmap(path, 720, 1280);
originPicBitmap = picBitmap.copy(Bitmap.Config.ARGB_8888, true);
resultImage.setImageBitmap(picBitmap);
}
}
}
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);
isShutterBitmapCopied = false;
// Camera is still working but detecting loop is on pause.
svPreview.setOnTextureChangedListener(new CameraSurfaceView.OnTextureChangedListener() {
@Override
public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) {
if (TYPE == BTN_SHUTTER) {
copyBitmapFromCamera(ARGB8888ImageBitmap);
}
return false;
}
});
}
}
@Override
public boolean onTextureChanged(Bitmap ARGB8888ImageBitmap) {
if (TYPE == BTN_SHUTTER) {
copyBitmapFromCamera(ARGB8888ImageBitmap);
return false;
}
boolean modified = false;
long tc = System.currentTimeMillis();
FaceDetectionResult result = predictor.predict(
ARGB8888ImageBitmap, FaceDetSettingsActivity.scoreThreshold, 0.4f);
timeElapsed += (System.currentTimeMillis() - tc);
Visualize.visFaceDetection(ARGB8888ImageBitmap, result);
modified = result.initialized();
frameCounter++;
if (frameCounter >= 30) {
final int fps = (int) (1000 / (timeElapsed / 30));
runOnUiThread(new Runnable() {
@SuppressLint("SetTextI18n")
public void run() {
tvStatus.setText(Integer.toString(fps) + "fps");
}
});
frameCounter = 0;
timeElapsed = 0;
}
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() {
TYPE = REALTIME_DETECT;
// (1) EXPECTED_PREVIEW_WIDTH should mean 'height' and EXPECTED_PREVIEW_HEIGHT
// should mean 'width' if the camera display orientation is 90 | 270 degree
// (Hold the phone upright to record video)
// (2) Smaller resolution is more suitable for lite face detection
// on mobile phone. So, we set this preview size (480,480) here.
// CameraSurfaceView.EXPECTED_PREVIEW_WIDTH = 480;
// CameraSurfaceView.EXPECTED_PREVIEW_HEIGHT = 480;
svPreview = (CameraSurfaceView) findViewById(R.id.sv_preview);
svPreview.setOnTextureChangedListener(this);
svPreview.switchCamera(); // Front camera for HumanSeg
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);
albumSelectButton = findViewById(R.id.album_select);
albumSelectButton.setOnClickListener(this);
cameraPageView = findViewById(R.id.camera_page);
resultPageView = findViewById(R.id.result_page);
resultImage = findViewById(R.id.result_image);
backInResult = findViewById(R.id.back_in_result);
backInResult.setOnClickListener(this);
confidenceSeekbar = findViewById(R.id.confidence_seekbar);
seekbarText = findViewById(R.id.seekbar_text);
resultView = findViewById(R.id.result_list_view);
confidenceSeekbar.setMax(100);
confidenceSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
float resultConfidence = seekBar.getProgress() / 100f;
BigDecimal bd = new BigDecimal(resultConfidence);
resultNum = bd.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue();
seekbarText.setText(resultNum + "");
confidenceSeekbar.setProgress((int) (resultNum * 100));
results.clear();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (TYPE == ALBUM_SELECT) {
SystemClock.sleep(TIME_SLEEP_INTERVAL * 10); // 500ms
detail(picBitmap);
picBitmap = originPicBitmap.copy(Bitmap.Config.ARGB_8888, true);
} else {
SystemClock.sleep(TIME_SLEEP_INTERVAL * 10); // 500ms
detail(shutterBitmap);
shutterBitmap = originShutterBitmap.copy(Bitmap.Config.ARGB_8888, true);
}
}
});
}
});
}
private void detail(Bitmap bitmap) {
FaceDetectionResult result = predictor.predict(bitmap, true, resultNum, 0.4f);
scores = result.mScores;
initialized = result.initialized();
if (initialized) {
for (int i = 0; i < scores.length; i++) {
if (scores[i] > resultNum) {
results.add(new BaseResultModel(i + 1, "face", scores[i]));
}
}
}
BaseResultAdapter adapter = new BaseResultAdapter(getBaseContext(), R.layout.facedet_result_page_item, results);
resultView.setAdapter(adapter);
resultView.invalidate();
resultImage.setImageBitmap(bitmap);
resultNum = 1.0f;
}
@SuppressLint("ApplySharedPref")
public void initSettings() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.commit();
FaceDetSettingsActivity.resetSettings();
}
public void checkAndUpdateSettings() {
if (FaceDetSettingsActivity.checkAndUpdateSettings(this)) {
String realModelDir = getCacheDir() + "/" + FaceDetSettingsActivity.modelDir;
Utils.copyDirectoryFromAssets(this, FaceDetSettingsActivity.modelDir, realModelDir);
String modelFile = realModelDir + "/" + "model.pdmodel";
String paramsFile = realModelDir + "/" + "model.pdiparams";
RuntimeOption option = new RuntimeOption();
option.setCpuThreadNum(FaceDetSettingsActivity.cpuThreadNum);
option.setLitePowerMode(FaceDetSettingsActivity.cpuPowerMode);
if (Boolean.parseBoolean(FaceDetSettingsActivity.enableLiteFp16)) {
option.enableLiteFp16();
}
predictor.init(modelFile, paramsFile, 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(FaceDetMainActivity.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) {
FaceDetMainActivity.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;
}
}

View File

@@ -0,0 +1,181 @@
package com.baidu.paddle.fastdeploy.app.examples.facedet;
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.R;
import com.baidu.paddle.fastdeploy.app.ui.Utils;
import com.baidu.paddle.fastdeploy.app.ui.view.AppCompatPreferenceActivity;
import java.util.ArrayList;
import java.util.List;
public class FaceDetSettingsActivity extends AppCompatPreferenceActivity implements
SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = FaceDetSettingsActivity.class.getSimpleName();
static public int selectedModelIdx = -1;
static public String modelDir = "";
static public int cpuThreadNum = 2;
static public String cpuPowerMode = "";
static public float scoreThreshold = 0.25f;
static public String enableLiteFp16 = "true";
ListPreference lpChoosePreInstalledModel = null;
EditTextPreference etModelDir = null;
ListPreference lpCPUThreadNum = null;
ListPreference lpCPUPowerMode = null;
EditTextPreference etScoreThreshold = null;
ListPreference lpEnableLiteFp16 = null;
List<String> preInstalledModelDirs = 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.facedet_setting);
ActionBar supportActionBar = getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setDisplayHomeAsUpEnabled(true);
}
// Initialize pre-installed models
preInstalledModelDirs = new ArrayList<String>();
preInstalledCPUThreadNums = new ArrayList<String>();
preInstalledCPUPowerModes = new ArrayList<String>();
preInstalledScoreThresholds = new ArrayList<String>();
preInstalledEnableLiteFp16s = new ArrayList<String>();
preInstalledModelDirs.add(getString(R.string.FACEDET_MODEL_DIR_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_FACEDET));
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() + ")");
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.FACEDET_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.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.FACEDET_MODEL_DIR_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_FACEDET));
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);
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.FACEDET_MODEL_DIR_DEFAULT));
settingsChanged |= !modelDir.equalsIgnoreCase(model_dir);
modelDir = model_dir;
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_FACEDET));
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 = "";
cpuThreadNum = 2;
cpuPowerMode = "";
scoreThreshold = 0.25f; // confThreshold
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();
}
}

View File

@@ -0,0 +1,313 @@
package com.baidu.paddle.fastdeploy.app.ui;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.net.Uri;
import android.opengl.GLES20;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Surface;
import android.view.WindowManager;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
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.3;
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");
}
public static Bitmap decodeBitmap(String path, int displayWidth, int displayHeight) {
BitmapFactory.Options op = new BitmapFactory.Options();
op.inJustDecodeBounds = true;// Only the width and height information of Bitmap is read, not the pixels.
Bitmap bmp = BitmapFactory.decodeFile(path, op); // Get size information.
int wRatio = (int) Math.ceil(op.outWidth / (float) displayWidth);// Get Scale Size.
int hRatio = (int) Math.ceil(op.outHeight / (float) displayHeight);
// If the specified size is exceeded, reduce the corresponding scale.
if (wRatio > 1 && hRatio > 1) {
if (wRatio > hRatio) {
// If it is too wide, we will reduce the width to the required size. Note that the height will become smaller.
op.inSampleSize = wRatio;
} else {
op.inSampleSize = hRatio;
}
}
op.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeFile(path, op);
// Create a Bitmap with a given width and height from the original Bitmap.
return Bitmap.createScaledBitmap(bmp, displayWidth, displayHeight, true);
}
public static String getRealPathFromURI(Context context, Uri contentURI) {
String result;
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(contentURI, null, null, null, null);
} catch (Throwable e) {
e.printStackTrace();
}
if (cursor == null) {
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
public static List<String> readTxt(String txtPath) {
File file = new File(txtPath);
if (file.isFile() && file.exists()) {
try {
FileInputStream fileInputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String text;
List<String> labels = new ArrayList<>();
while ((text = bufferedReader.readLine()) != null) {
labels.add(text);
}
return labels;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}

View File

@@ -0,0 +1,33 @@
package com.baidu.paddle.fastdeploy.app.ui.layout;
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);
}
}

View File

@@ -0,0 +1,111 @@
package com.baidu.paddle.fastdeploy.app.ui.view;
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;
}
}

View File

@@ -0,0 +1,349 @@
package com.baidu.paddle.fastdeploy.app.ui.view;
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 com.baidu.paddle.fastdeploy.app.ui.Utils;
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 int EXPECTED_PREVIEW_WIDTH = 1280; // 1920
public static int EXPECTED_PREVIEW_HEIGHT = 720; // 960
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;
protected Bitmap ARGB8888ImageBitmap;
protected boolean bitmapReleaseMode = true;
// 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 void setBitmapReleaseMode(boolean mode) {
synchronized (this) {
bitmapReleaseMode = mode;
}
}
public Bitmap getBitmap() {
return ARGB8888ImageBitmap; // may null or recycled.
}
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);
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);
}
if (bitmapReleaseMode) {
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;
}
}
}

View File

@@ -0,0 +1,43 @@
package com.baidu.paddle.fastdeploy.app.ui.view;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.widget.ListView;
public class ResultListView extends ListView {
public ResultListView(Context context) {
super(context);
}
public ResultListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ResultListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private Handler handler;
public void setHandler(Handler mHandler) {
handler = mHandler;
}
public void clear() {
handler.post(new Runnable() {
@Override
public void run() {
removeAllViewsInLayout();
invalidate();
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}

View File

@@ -0,0 +1,48 @@
package com.baidu.paddle.fastdeploy.app.ui.view.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.baidu.paddle.fastdeploy.app.examples.R;
import com.baidu.paddle.fastdeploy.app.ui.view.model.BaseResultModel;
import java.text.DecimalFormat;
import java.util.List;
public class BaseResultAdapter extends ArrayAdapter<BaseResultModel> {
private int resourceId;
public BaseResultAdapter(@NonNull Context context, int resource) {
super(context, resource);
}
public BaseResultAdapter(@NonNull Context context, int resource, @NonNull List<BaseResultModel> objects) {
super(context, resource, objects);
resourceId = resource;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
BaseResultModel model = getItem(position);
View view = LayoutInflater.from(getContext()).inflate(resourceId, null);
TextView indexText = (TextView) view.findViewById(R.id.index);
TextView nameText = (TextView) view.findViewById(R.id.name);
TextView confidenceText = (TextView) view.findViewById(R.id.confidence);
indexText.setText(String.valueOf(model.getIndex()));
nameText.setText(String.valueOf(model.getName()));
confidenceText.setText(formatFloatString(model.getConfidence()));
return view;
}
public static String formatFloatString(float number) {
DecimalFormat df = new DecimalFormat("0.00");
return df.format(number);
}
}

View File

@@ -0,0 +1,41 @@
package com.baidu.paddle.fastdeploy.app.ui.view.model;
public class BaseResultModel {
private int index;
private String name;
private float confidence;
public BaseResultModel() {
}
public BaseResultModel(int index, String name, float confidence) {
this.index = index;
this.name = name;
this.confidence = confidence;
}
public float getConfidence() {
return confidence;
}
public void setConfidence(float confidence) {
this.confidence = confidence;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -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>

View 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>

View File

@@ -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>

View 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/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>

View 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/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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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/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>

View 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/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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View 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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/facedet_camera_page"
android:id="@+id/camera_page"></include>
<include
layout="@layout/facedet_result_page"
android:id="@+id/result_page"
android:visibility="gone"></include>
</FrameLayout>

View File

@@ -0,0 +1,159 @@
<?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=".facedet.FaceDetMainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorWindow">
<com.baidu.paddle.fastdeploy.app.ui.layout.ActionBarLayout
android:id="@+id/action_bar_main"
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="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_bar_realtime"
android:textAlignment="center" />
</LinearLayout>
<com.baidu.paddle.fastdeploy.app.ui.view.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_main"
android:layout_centerInParent="true" />
<ImageView
android:id="@+id/album_select"
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" />
<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>

View File

@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical">
<com.baidu.paddle.fastdeploy.app.ui.layout.ActionBarLayout
android:id="@+id/action_bar_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/back_in_result"
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" />
<TextView
android:id="@+id/model_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="50px"
android:textColor="@color/textColor"
android:textSize="@dimen/action_btn_text_size" />
</com.baidu.paddle.fastdeploy.app.ui.layout.ActionBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="700px">
<ImageView
android:id="@+id/result_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bk_result_image_padding" />
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40px"
android:layout_marginTop="26px"
android:layout_marginBottom="20px"
android:text="@string/result_label"
android:textColor="@color/bk_black"
android:textSize="56px"
android:visibility="visible" />
<LinearLayout
android:id="@+id/result_seekbar_section"
android:layout_width="match_parent"
android:layout_height="130px"
android:layout_marginLeft="@dimen/result_list_padding_lr"
android:layout_marginRight="@dimen/result_list_padding_lr"
android:layout_marginBottom="@dimen/result_list_gap_width"
android:background="@drawable/result_page_border_section_bk"
android:visibility="visible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:paddingLeft="30px"
android:text="@string/result_table_header_confidence"
android:textColor="@color/table_result_tableheader_text_color"
android:textSize="@dimen/result_list_view_text_size" />
<SeekBar
android:id="@+id/confidence_seekbar"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="6"
android:focusable="false"
android:maxHeight="8px"
android:progressDrawable="@drawable/seekbar_progress_result"
android:splitTrack="false"
android:thumb="@drawable/seekbar_handle" />
<TextView
android:id="@+id/seekbar_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:paddingRight="30px"
android:textSize="@dimen/result_list_view_text_size"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/result_list_padding_lr"
android:layout_marginRight="@dimen/result_list_padding_lr"
android:layout_marginBottom="@dimen/result_list_gap_width"
android:background="@drawable/result_page_border_section_bk"
android:visibility="visible">
<TextView
style="@style/list_result_view_tablehead_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/result_table_header_index"
android:textColor="@color/table_result_tableheader_text_color" />
<TextView
style="@style/list_result_view_tablehead_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/result_table_header_name"
android:textColor="@color/table_result_tableheader_text_color" />
<TextView
style="@style/list_result_view_tablehead_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.4"
android:gravity="right"
android:text="@string/result_table_header_confidence"
android:textColor="@color/table_result_tableheader_text_color" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15px"
android:paddingLeft="@dimen/result_list_padding_lr"
android:paddingRight="@dimen/result_list_padding_lr">
<com.baidu.paddle.fastdeploy.app.ui.view.ResultListView
android:id="@+id/result_list_view"
android:layout_width="match_parent"
android:layout_height="700px"
android:divider="#FFFFFF"
android:dividerHeight="@dimen/result_list_gap_width"></com.baidu.paddle.fastdeploy.app.ui.view.ResultListView>
</ScrollView>
</FrameLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/result_page_border_section_bk">
<TextView
android:id="@+id/index"
style="@style/list_result_view_item_style"
android:layout_width="wrap_content"
android:layout_weight="0.2" />
<TextView
android:id="@+id/name"
style="@style/list_result_view_item_style"
android:layout_width="wrap_content"
android:layout_weight="0.6"
android:maxWidth="300px" />
<TextView
android:id="@+id/confidence"
style="@style/list_result_view_item_style"
android:layout_weight="0.2"
android:layout_width="wrap_content" />
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View 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>

View 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>

View 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>

View File

@@ -0,0 +1,51 @@
<resources>
<!-- Default App name -->
<string name="app_name">EasyEdge</string>
<!-- Other App name -->
<string name="detection_app_name">EasyEdge</string>
<string name="ocr_app_name">EasyEdge</string>
<string name="classification_app_name">EasyEdge</string>
<string name="facedet_app_name">EasyEdge</string>
<string name="segmentation_app_name">EasyEdge</string>
<!-- Keys for PreferenceScreen -->
<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>
<!-- Common default values ... -->
<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="SCORE_THRESHOLD_CLASSIFICATION">0.1</string>
<string name="SCORE_THRESHOLD_FACEDET">0.25</string>
<string name="ENABLE_LITE_FP16_MODE_DEFAULT">true</string>
<!--Other values-->
<!-- Detection model & Label paths & other values ... -->
<string name="DETECTION_MODEL_DIR_DEFAULT">models/picodet_s_320_coco_lcnet</string>
<string name="DETECTION_LABEL_PATH_DEFAULT">labels/coco_label_list.txt</string>
<!-- PP-OCRv2 & PP-OCRv3 values ... -->
<string name="OCR_MODEL_DIR_DEFAULT">models</string>
<string name="OCR_REC_LABEL_DEFAULT">labels/ppocr_keys_v1.txt</string>
<!-- classification values ... -->
<string name="CLASSIFICATION_MODEL_DIR_DEFAULT">models/MobileNetV1_x0_25_infer</string>
<string name="CLASSIFICATION_LABEL_PATH_DEFAULT">labels/imagenet1k_label_list.txt</string>
<!-- facedet values ... -->
<string name="FACEDET_MODEL_DIR_DEFAULT">models/scrfd_500m_bnkps_shape320x320_pd</string>
<!-- segmentation values ... -->
<string name="SEGMENTATION_MODEL_DIR_DEFAULT">models/portrait_pp_humansegv2_lite_256x144_inference_model</string>
<!-- Other resources values-->
<string name="action_bar_take_photo">拍照识别</string>
<string name="action_bar_realtime">实时识别</string>
<string name="action_bar_back">&lt;</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>

View 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>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="action_btn_size">120dp</dimen>
<dimen name="action_btn_text_size">46px</dimen>
<dimen name="operation_btn_margin_top_take_picture">126px</dimen>
<dimen name="operation_btn_margin_top">136px</dimen>
<dimen name="result_list_view_text_size">46px</dimen>
<dimen name="result_list_popview_text_size">36px</dimen>
<dimen name="result_list_padding_lr">15dp</dimen>
<dimen name="result_list_gap_width">15dp</dimen>
</resources>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:defaultValue="@string/FACEDET_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/FACEDET_MODEL_DIR_DEFAULT"
android:key="@string/MODEL_DIR_KEY"
android:title="Model Dir" />
<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>

View 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
}

View File

@@ -0,0 +1,13 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx3096m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

View File

@@ -0,0 +1,6 @@
#Sat Oct 08 17:24:34 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

@@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

View File

@@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,8 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Thu Oct 20 16:50:08 CST 2022
sdk.dir=/Users/qiuyanjun/Library/Android/sdk

View File

@@ -0,0 +1 @@
include ':app'

View File

@@ -1,6 +1,6 @@
# 目标检测 PaddleSeg Android Demo 使用文档
在 Android 上实现实时的目标检测功能,此 Demo 有很好的的易用性和开放性,如在 Demo 中跑自己训练好的模型等。
在 Android 上实现实时的人像分割功能,此 Demo 有很好的的易用性和开放性,如在 Demo 中跑自己训练好的模型等。
## 环境准备
@@ -23,9 +23,10 @@
4. 点击 Run 按钮,自动编译 APP 并安装到手机。(该过程会自动下载预编译的 FastDeploy Android 库 以及 模型文件,需要联网)
成功后效果如下图一APP 安装到手机;图二: APP 打开后的效果会自动识别图片中的人物并绘制mask图三APP设置选项点击右上角的设置图片可以设置不同选项进行体验。
| APP 图标 | APP 效果 | APP设置项
| APP 图标 | APP 效果 | APP设置项
| --- | --- | --- |
| ![app_pic](https://user-images.githubusercontent.com/31974251/203268599-c94018d8-3683-490a-a5c7-a8136a4fa284.jpg) | <img width="1200" height="600" alt="image" src="https://user-images.githubusercontent.com/31974251/203507683-bc990cf5-393e-4e0d-bd6b-0f114235d320.png"> | ![app_setup](https://user-images.githubusercontent.com/31974251/197332983-afbfa6d5-4a3b-4c54-a528-4a3e58441be1.jpg) |
| <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/203268599-c94018d8-3683-490a-a5c7-a8136a4fa284.jpg"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/203267867-7c51b695-65e6-402e-9826-5d6d5864da87.gif"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/197332983-afbfa6d5-4a3b-4c54-a528-4a3e58441be1.jpg"> |
## PaddleSegModel Java API 说明
- 模型初始化 API: 模型初始化API包含两种方式方式一是通过构造函数直接初始化方式二是通过调用init函数在合适的程序节点进行初始化。PaddleSegModel初始化参数说明如下

View File

@@ -287,27 +287,20 @@ public class CameraSurfaceView extends GLSurfaceView implements Renderer,
public void openCamera() {
if (disableCamera) return;
camera = Camera.open(selectedCameraId);
Camera.Parameters parameters = camera.getParameters();
int degree = Utils.getCameraDisplayOrientation(context, selectedCameraId);
camera.setDisplayOrientation(degree);
boolean rotate = degree == 90 || degree == 270;
int adjusted_width = rotate ? EXPECTED_PREVIEW_HEIGHT : EXPECTED_PREVIEW_WIDTH;
int adjusted_height = rotate ? EXPECTED_PREVIEW_WIDTH : EXPECTED_PREVIEW_HEIGHT;
List<Size> supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes();
Size previewSize = Utils.getOptimalPreviewSize(
supportedPreviewSizes, adjusted_width, adjusted_height);
textureWidth = previewSize.width;
textureHeight = previewSize.height;
Size previewSize = Utils.getOptimalPreviewSize(supportedPreviewSizes, EXPECTED_PREVIEW_WIDTH,
EXPECTED_PREVIEW_HEIGHT);
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(previewSize.width, previewSize.height);
camera.setParameters(parameters);
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);

View File

@@ -287,27 +287,20 @@ public class CameraSurfaceView extends GLSurfaceView implements Renderer,
public void openCamera() {
if (disableCamera) return;
camera = Camera.open(selectedCameraId);
Camera.Parameters parameters = camera.getParameters();
int degree = Utils.getCameraDisplayOrientation(context, selectedCameraId);
camera.setDisplayOrientation(degree);
boolean rotate = degree == 90 || degree == 270;
int adjusted_width = rotate ? EXPECTED_PREVIEW_HEIGHT : EXPECTED_PREVIEW_WIDTH;
int adjusted_height = rotate ? EXPECTED_PREVIEW_WIDTH : EXPECTED_PREVIEW_HEIGHT;
List<Size> supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes();
Size previewSize = Utils.getOptimalPreviewSize(
supportedPreviewSizes, adjusted_width, adjusted_height);
textureWidth = previewSize.width;
textureHeight = previewSize.height;
Size previewSize = Utils.getOptimalPreviewSize(supportedPreviewSizes, EXPECTED_PREVIEW_WIDTH,
EXPECTED_PREVIEW_HEIGHT);
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(previewSize.width, previewSize.height);
camera.setParameters(parameters);
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);