diff --git a/HelloWorldApp/app/build.gradle b/HelloWorldApp/app/build.gradle index d385d700..5d2f7127 100644 --- a/HelloWorldApp/app/build.gradle +++ b/HelloWorldApp/app/build.gradle @@ -6,7 +6,7 @@ repositories { android { compileSdkVersion 28 - buildToolsVersion "29.0.2" + buildToolsVersion buildToolsVersion defaultConfig { applicationId "org.pytorch.helloworld" minSdkVersion 21 @@ -19,10 +19,14 @@ android { minifyEnabled false } } + compileOptions { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } } dependencies { - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'org.pytorch:pytorch_android:1.4.0' - implementation 'org.pytorch:pytorch_android_torchvision:1.4.0' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'org.pytorch:pytorch_android:1.7.0' + implementation 'org.pytorch:pytorch_android_torchvision:1.7.0' } diff --git a/HelloWorldApp/app/src/main/assets/RACHEL1.jpg b/HelloWorldApp/app/src/main/assets/RACHEL1.jpg new file mode 100644 index 00000000..34c50188 Binary files /dev/null and b/HelloWorldApp/app/src/main/assets/RACHEL1.jpg differ diff --git a/HelloWorldApp/app/src/main/assets/mobile_model.pt b/HelloWorldApp/app/src/main/assets/mobile_model.pt new file mode 100644 index 00000000..ff59abec Binary files /dev/null and b/HelloWorldApp/app/src/main/assets/mobile_model.pt differ diff --git a/HelloWorldApp/app/src/main/assets/mobile_model1.pt b/HelloWorldApp/app/src/main/assets/mobile_model1.pt new file mode 100644 index 00000000..05207e30 Binary files /dev/null and b/HelloWorldApp/app/src/main/assets/mobile_model1.pt differ diff --git a/HelloWorldApp/app/src/main/assets/model.pt b/HelloWorldApp/app/src/main/assets/model.pt deleted file mode 100644 index 1cea5f5c..00000000 Binary files a/HelloWorldApp/app/src/main/assets/model.pt and /dev/null differ diff --git a/HelloWorldApp/app/src/main/java/org/pytorch/helloworld/MainActivity.java b/HelloWorldApp/app/src/main/java/org/pytorch/helloworld/MainActivity.java index 6ea7c80c..08ec5a38 100644 --- a/HelloWorldApp/app/src/main/java/org/pytorch/helloworld/MainActivity.java +++ b/HelloWorldApp/app/src/main/java/org/pytorch/helloworld/MainActivity.java @@ -3,6 +3,10 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; import android.os.Bundle; import android.util.Log; import android.widget.ImageView; @@ -11,89 +15,248 @@ import org.pytorch.IValue; import org.pytorch.Module; import org.pytorch.Tensor; -import org.pytorch.torchvision.TensorImageUtils; +import org.pytorch.torchvision.TensorImageUtils; +import java.nio.FloatBuffer; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; import androidx.appcompat.app.AppCompatActivity; +import static java.lang.Math.max; +import static java.lang.Math.min; + public class MainActivity extends AppCompatActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - Bitmap bitmap = null; - Module module = null; - try { - // creating bitmap from packaged into app android asset 'image.jpg', - // app/src/main/assets/image.jpg - bitmap = BitmapFactory.decodeStream(getAssets().open("image.jpg")); - // loading serialized torchscript module from packaged into app android asset model.pt, - // app/src/model/assets/model.pt - module = Module.load(assetFilePath(this, "model.pt")); - } catch (IOException e) { - Log.e("PytorchHelloWorld", "Error reading assets", e); - finish(); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Bitmap bitmap = null; + Module module = null; + try { + // creating bitmap from packaged into app android asset 'image.jpg', + // app/src/main/assets/image.jpg + bitmap = BitmapFactory.decodeStream(getAssets().open("RACHEL4.jpg")); + // loading serialized torchscript module from packaged into app android asset model.pt, + // app/src/model/assets/model.pt + module = Module.load(assetFilePath(this, "mobile_model1.pt")); + } catch (IOException e) { + Log.e("PytorchHelloWorld", "Error reading assets", e); + finish(); + } + + float [] mean = new float[] {0.49804f, 0.49804f, 0.49804f}; + float [] std = new float[] {0.501960f, 0.501960f, 0.501960f}; + float nms_threshold = 0.4f; + + Bitmap bitmap1 = Bitmap.createScaledBitmap(bitmap,480,360,true); +// Bitmap bitmap1; +// if (bitmap.getWidth() > bitmap.getHeight()) +// bitmap1 = Bitmap.createScaledBitmap(bitmap,480,360,true); +// else +// bitmap1 = Bitmap.createScaledBitmap(bitmap,360,480,true); +// Bitmap bitmap1 = getResizedBitmap(bitmap,480,360); + // preparing input tensor +// Tensor inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmap1, +// TensorImageUtils.TORCHVISION_NORM_MEAN_RGB, TensorImageUtils.TORCHVISION_NORM_STD_RGB); + Tensor inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmap1, mean, std); + System.out.println(Arrays.toString(inputTensor.shape())); + //Normalize input +// inputTensor = Normalize_tensor(inputTensor, 127, 128); + // running the model + final IValue[] output = module.forward(IValue.from(inputTensor)).toTuple(); +// for (int i = 0; i < output.length; i++) +// { +// IValue tupleElement = output[i]; +// +// } + Tensor scores = output[0].toTensor(); + Tensor boxes = output[1].toTensor(); + float threshold = (float) 0.99; + + ArrayList possible_indexes = possible_score(scores, boxes, threshold); + System.out.println("in onCreate len possible_indexes " + possible_indexes.size()); + + ArrayList nms_boxes = nms(boxes, scores, possible_indexes, nms_threshold); + + + Bitmap bmp = bitmap.copy(Bitmap.Config.ARGB_8888, true); + Canvas canvas = new Canvas(bmp); + Paint paint = new Paint(); + paint.setColor(Color.BLUE); + paint.setAlpha(100); + for(int i = 0; i < nms_boxes.size(); i++) + { + float[] xyxy = {nms_boxes.get(i)[0]*bmp.getWidth(),nms_boxes.get(i)[1]*bmp.getHeight(),nms_boxes.get(i)[2]*bmp.getWidth(), nms_boxes.get(i)[3]*bmp.getHeight()}; + canvas.drawRect(xyxy[0], xyxy[1], xyxy[2], xyxy[3], paint); + } + + +// canvas.drawLine(0, 0, bmp.getWidth(), bmp.getHeight(), paint); + //canvas.drawBitmap(bmp,0, 0, paint); + // showing image on UI + ImageView imageView = findViewById(R.id.image); + imageView.setImageBitmap(bmp); + // getting tensor content as java array of floats +// final float[] scores = outputTensor.getDataAsFloatArray(); +// +// // searching for the index with maximum score +// float maxScore = -Float.MAX_VALUE; +// int maxScoreIdx = -1; +// for (int i = 0; i < scores.length; i++) { +// if (scores[i] > maxScore) { +// maxScore = scores[i]; +// maxScoreIdx = i; +// } +// } +// +// String className = ImageNetClasses.IMAGENET_CLASSES[maxScoreIdx]; + + // showing className on UI + TextView textView = findViewById(R.id.text); + textView.setText("res"); + } + + /* + * + * box format: xyxy (topleft.x topleft.y bottomright.x bottomright.y) + */ + float IoU(float[] rec1, float[] rec2) + { + + float S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1]); + float S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1]); + +// computing the sum_area + float sum_area = S_rec1 + S_rec2; + +// find the each edge of intersect rectangle + float left_line = max(rec1[1], rec2[1]); + float right_line = min(rec1[3], rec2[3]); + float top_line = max(rec1[0], rec2[0]); + float bottom_line = min(rec1[2], rec2[2]); + +// judge if there is an intersect + float intersect = 0; + if (left_line >= right_line || top_line >= bottom_line) + return 0; + else + intersect = (right_line - left_line) * (bottom_line - top_line); + return (intersect / (sum_area - intersect)); } - // showing image on UI - ImageView imageView = findViewById(R.id.image); - imageView.setImageBitmap(bitmap); + ArrayList nms(Tensor boxes, Tensor scores, ArrayList possible_indexes, float nms_threshold) + { +// float[] sfloatArray = scores.getDataAsFloatArray(); +// int slen = sfloatArray.length; +// long snum = scores.shape()[2]; +// slen = (int)(slen / snum); + + ArrayList nms_boxes = new ArrayList<>(); + float[] bfloatArray = boxes.getDataAsFloatArray(); + int blen = bfloatArray.length; + int bnum = (int) boxes.shape()[2]; + blen = (blen / bnum); - // preparing input tensor - final Tensor inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmap, - TensorImageUtils.TORCHVISION_NORM_MEAN_RGB, TensorImageUtils.TORCHVISION_NORM_STD_RGB); - // running the model - final Tensor outputTensor = module.forward(IValue.from(inputTensor)).toTensor(); + float[] box2 = {1,1,1,1,1}; + for(int i = 0; i < possible_indexes.size() / 2; i++) + { + float[] box1 = {0,0,0,0,0}; + int index = (int) (float) possible_indexes.get(i * 2); + for(int j = 0; j < bnum; j++) + { + box1[j] = bfloatArray[index * bnum + j]; + } + box1[bnum] = possible_indexes.get(i * 2 + 1); + boolean flag = true; + for(int j = 0; j < nms_boxes.size(); j++) + { + box2 = nms_boxes.get(j); + if(IoU(box1, box2) > nms_threshold) { + if (box2[bnum] > box1[bnum]) { //prob of box2 > box1 + nms_boxes.remove(j); + nms_boxes.add(box1); + flag = false; + } else { + flag = false; + break; + } + } + } + if (flag) + nms_boxes.add(box1); - // getting tensor content as java array of floats - final float[] scores = outputTensor.getDataAsFloatArray(); - // searching for the index with maximum score - float maxScore = -Float.MAX_VALUE; - int maxScoreIdx = -1; - for (int i = 0; i < scores.length; i++) { - if (scores[i] > maxScore) { - maxScore = scores[i]; - maxScoreIdx = i; - } + } + + return nms_boxes; } - String className = ImageNetClasses.IMAGENET_CLASSES[maxScoreIdx]; - - // showing className on UI - TextView textView = findViewById(R.id.text); - textView.setText(className); - } - - /** - * Copies specified asset to the file in /files app directory and returns this file absolute path. - * - * @return absolute file path - */ - public static String assetFilePath(Context context, String assetName) throws IOException { - File file = new File(context.getFilesDir(), assetName); - if (file.exists() && file.length() > 0) { - return file.getAbsolutePath(); + + public Tensor Normalize_tensor(Tensor inputTensor, int mean, int std) + { + float[] floatArray = inputTensor.getDataAsFloatArray(); + for (int i = 0; i < floatArray.length; i++) + { + floatArray[i] = (floatArray[i] - mean) / std; + } + return Tensor.fromBlob(floatArray,inputTensor.shape()); } + public ArrayList possible_score(Tensor scores, Tensor boxes, float threshold) + { + ArrayList list_index_prob = new ArrayList<>(); + float[] floatArray = scores.getDataAsFloatArray(); + int len = floatArray.length; + long num = scores.shape()[2]; + len = (int)(len / num); + System.out.println(len); + + + for (int i = 0; i < len; i++) + { + for (int j = 1; j < num; j++) + if (floatArray[(int) (i * num + j)] > threshold) + { + list_index_prob.add((float)i); + list_index_prob.add(floatArray[(int) (i * num + j)]); + System.out.println("porb is " + floatArray[(int) (i * num)] + " and " + floatArray[(int) (i * num + 1)]); + } + + } + + return list_index_prob; + } + + /** + * Copies specified asset to the file in /files app directory and returns this file absolute path. + * + * @return absolute file path + */ + public static String assetFilePath(Context context, String assetName) throws IOException { + File file = new File(context.getFilesDir(), assetName); + if (file.exists() && file.length() > 0) { + return file.getAbsolutePath(); + } - try (InputStream is = context.getAssets().open(assetName)) { - try (OutputStream os = new FileOutputStream(file)) { - byte[] buffer = new byte[4 * 1024]; - int read; - while ((read = is.read(buffer)) != -1) { - os.write(buffer, 0, read); + try (InputStream is = context.getAssets().open(assetName)) { + try (OutputStream os = new FileOutputStream(file)) { + byte[] buffer = new byte[4 * 1024]; + int read; + while ((read = is.read(buffer)) != -1) { + os.write(buffer, 0, read); + } + os.flush(); + } + return file.getAbsolutePath(); } - os.flush(); - } - return file.getAbsolutePath(); } - } } diff --git a/HelloWorldApp/build.gradle b/HelloWorldApp/build.gradle index 462b7120..2b1ebcd3 100644 --- a/HelloWorldApp/build.gradle +++ b/HelloWorldApp/build.gradle @@ -1,3 +1,6 @@ +ext { + buildToolsVersion = '29.0.2' +} buildscript { repositories { google() diff --git a/PyTorchDemoApp/app/build.gradle b/PyTorchDemoApp/app/build.gradle index 06bb95f4..c08e6cd8 100644 --- a/PyTorchDemoApp/app/build.gradle +++ b/PyTorchDemoApp/app/build.gradle @@ -1,10 +1,13 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' repositories { jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } + maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } } android { @@ -15,8 +18,8 @@ android { compileSdkVersion 28 defaultConfig { applicationId "org.pytorch.demo" - minSdkVersion 21 - targetSdkVersion 28 + minSdkVersion 26 + targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -27,17 +30,78 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + + //需要添加下面这段代码 + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + buildToolsVersion '28.0.3' + ndkVersion '21.1.6352462' + kotlinOptions { + jvmTarget = '1.8' + } } dependencies { +// implementation 'com.android.support:appcompat-v7:26.1.0' +// implementation 'com.android.support:appcompat-v7:27.1.1' +// implementation 'com.android.support:design:27.1.1' +// implementation 'com.android.support:v4:27.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'androidx.appcompat:appcompat:1.0.0-beta01' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - - def camerax_version = "1.0.0-alpha05" + implementation 'androidx.wear:wear:1.0.0' + implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2' + implementation 'androidx.navigation:navigation-ui:2.2.2' + implementation 'androidx.viewpager2:viewpager2:1.0.0' + implementation 'androidx.navigation:navigation-fragment:2.2.2' + implementation 'com.android.support.constraint:constraint-layout:1.1.2' + implementation fileTree(dir: 'E:\\hanjiaxiangmu\\android-demo-app\\PyTorchDemoApp\\app\\src\\libs', include: ['*.aar', '*.jar'], exclude: []) + implementation 'androidx.navigation:navigation-ui-ktx:2.2.2' + def camerax_version = "1.0.0-beta07" + // def camerax_version = "1.0.0-alpha05" implementation "androidx.camera:camera-core:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version" - implementation 'com.google.android.material:material:1.0.0-beta01' + implementation "androidx.camera:camera-lifecycle:$camerax_version" + implementation "androidx.camera:camera-view:1.0.0-alpha14" + implementation 'com.google.android.material:material:1.2.0-alpha06' implementation 'org.pytorch:pytorch_android:1.6.0-SNAPSHOT' implementation 'org.pytorch:pytorch_android_torchvision:1.6.0-SNAPSHOT' + implementation "androidx.core:core-ktx:+" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.30" + // 网络通信库 + implementation "com.squareup.okhttp3:okhttp:3.12.2" + implementation "org.java-websocket:Java-WebSocket:1.4.0" + implementation 'com.neovisionaries:nv-websocket-client:2.10' + implementation 'org.conscrypt:conscrypt-android:2.2.1' + + // bitmap to video + implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' + // local library + implementation project(path: ':library') + compileOnly 'com.google.android.wearable:wearable:2.6.0' + + + // for glass activity + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + implementation 'com.valdesekamdem.library:md-toast:0.9.0' +// implementation 'com.github.:rtmp-rtsp-stream-client-java:Tag' +// implementation 'com.github.FaceRecogApp.rtmp-rtsp-stream-client-java:2.0.1' + implementation 'com.github.FaceRecogApp.rtmp-rtsp-stream-client-java:rtplibrary:3.0.0' + implementation 'com.squareup.okio:okio:2.1.0' + + implementation("com.serenegiant:common:1.5.20")//C + implementation project(':libuvccamera') + implementation project(':usbserial-release') + implementation project(':x5s-developmentkit') + + + // layout + implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" + // json parse + implementation 'com.google.code.gson:gson:2.8.4' } diff --git a/PyTorchDemoApp/app/release/output.json b/PyTorchDemoApp/app/release/output.json new file mode 100644 index 00000000..c429e316 --- /dev/null +++ b/PyTorchDemoApp/app/release/output.json @@ -0,0 +1 @@ +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] \ No newline at end of file diff --git a/PyTorchDemoApp/app/src/main/AndroidManifest.xml b/PyTorchDemoApp/app/src/main/AndroidManifest.xml index 5512046a..3a1e3732 100644 --- a/PyTorchDemoApp/app/src/main/AndroidManifest.xml +++ b/PyTorchDemoApp/app/src/main/AndroidManifest.xml @@ -1,33 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - + + android:label="@string/image_classification_title" /> + + - + - - \ No newline at end of file diff --git a/PyTorchDemoApp/app/src/main/assets/mobile_model2.pt b/PyTorchDemoApp/app/src/main/assets/mobile_model2.pt new file mode 100644 index 00000000..9c1350a7 Binary files /dev/null and b/PyTorchDemoApp/app/src/main/assets/mobile_model2.pt differ diff --git a/PyTorchDemoApp/app/src/main/assets/mobilenet_v2.pt b/PyTorchDemoApp/app/src/main/assets/mobilenet_v2.pt deleted file mode 100644 index f2c10543..00000000 Binary files a/PyTorchDemoApp/app/src/main/assets/mobilenet_v2.pt and /dev/null differ diff --git a/PyTorchDemoApp/app/src/main/assets/model-reddit16-f140225004_2.pt1 b/PyTorchDemoApp/app/src/main/assets/model-reddit16-f140225004_2.pt1 deleted file mode 100644 index 728e20d7..00000000 Binary files a/PyTorchDemoApp/app/src/main/assets/model-reddit16-f140225004_2.pt1 and /dev/null differ diff --git a/PyTorchDemoApp/app/src/main/assets/resnet18.pt b/PyTorchDemoApp/app/src/main/assets/resnet18.pt deleted file mode 100644 index 2b94ccf4..00000000 Binary files a/PyTorchDemoApp/app/src/main/assets/resnet18.pt and /dev/null differ diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/AccountLoginActivity.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/AccountLoginActivity.java new file mode 100644 index 00000000..6fd1da93 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/AccountLoginActivity.java @@ -0,0 +1,576 @@ +package org.pytorch.demo; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.StrictMode; +import android.text.InputType; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Toast; + +import com.valdesekamdem.library.mdtoast.MDToast; + +import org.json.JSONException; +import org.json.JSONObject; +import org.pytorch.demo.util.Base64Utils; +import org.pytorch.demo.util.SharedPreferencesUtils; +import org.pytorch.demo.util.Util; +import org.pytorch.demo.widget.LoadingDialog; + +import java.io.IOException; +import java.security.Policy; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +import okhttp3.Call; +import okhttp3.FormBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +/** + * 登录界面 + */ + +public class AccountLoginActivity extends Activity + implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { + //布局内的控件 + private EditText et_name; + private EditText et_password; + private Button mLoginBtn; + private CheckBox checkBox_password; + private CheckBox checkBox_login; + private ImageView iv_see_password; + + private LoadingDialog mLoadingDialog; //显示正在加载的对话框 + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_accountlogin); + initViews(); + setupEvents(); + initData(); + } + + private void initData() { + + + //判断用户第一次登陆 + if (firstLogin()) { + checkBox_password.setChecked(false);//取消记住密码的复选框 + checkBox_login.setChecked(false);//取消自动登录的复选框 + } + //判断是否记住密码 + if (remenberPassword()) { + checkBox_password.setChecked(true);//勾选记住密码 + setTextNameAndPassword();//把密码和账号输入到输入框中 + } else { + setTextName();//把用户账号放到输入账号的输入框中 + } + + //判断是否自动登录 + if (autoLogin()) { + checkBox_login.setChecked(true); + login();//去登录就可以 + + } + } + + /** + * 把本地保存的数据设置数据到输入框中 + */ + public void setTextNameAndPassword() { + et_name.setText("" + getLocalName()); + et_password.setText("" + getLocalPassword()); + } + + /** + * 设置数据到输入框中 + */ + public void setTextName() { + et_name.setText("" + getLocalName()); + } + + + /** + * 获得保存在本地的用户名 + */ + public String getLocalName() { + //获取SharedPreferences对象,使用自定义类的方法来获取对象 + SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting"); + String name = helper.getString("name"); + return name; + } + + + /** + * 获得保存在本地的密码 + */ + public String getLocalPassword() { + //获取SharedPreferences对象,使用自定义类的方法来获取对象 + SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting"); + String password = helper.getString("password"); + return Base64Utils.decryptBASE64(password); //解码一下 +// return password; //解码一下 + + } + + /** + * 判断是否自动登录 + */ + private boolean autoLogin() { + //获取SharedPreferences对象,使用自定义类的方法来获取对象 + SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting"); + boolean autoLogin = helper.getBoolean("autoLogin", false); + return autoLogin; + } + + /** + * 判断是否记住密码 + */ + private boolean remenberPassword() { + //获取SharedPreferences对象,使用自定义类的方法来获取对象 + SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting"); + boolean remenberPassword = helper.getBoolean("remenberPassword", false); + return remenberPassword; + } + + + private void initViews() { + mLoginBtn = (Button) findViewById(R.id.btn_login); + et_name = (EditText) findViewById(R.id.et_account); + et_password = (EditText) findViewById(R.id.et_password); + checkBox_password = (CheckBox) findViewById(R.id.checkBox_password); + checkBox_login = (CheckBox) findViewById(R.id.checkBox_login); + iv_see_password = (ImageView) findViewById(R.id.iv_see_password); + } + + private void setupEvents() { + mLoginBtn.setOnClickListener(this); + checkBox_password.setOnCheckedChangeListener(this); + checkBox_login.setOnCheckedChangeListener(this); + iv_see_password.setOnClickListener(this); + + } + + /** + * 判断是否是第一次登陆 + */ + private boolean firstLogin() { + //获取SharedPreferences对象,使用自定义类的方法来获取对象 + SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting"); + boolean first = helper.getBoolean("first", true); + if (first) { + //创建一个ContentVa对象(自定义的)设置不是第一次登录,,并创建记住密码和自动登录是默认不选,创建账号和密码为空 + helper.putValues(new SharedPreferencesUtils.ContentValue("first", false), + new SharedPreferencesUtils.ContentValue("remenberPassword", false), + new SharedPreferencesUtils.ContentValue("autoLogin", false), + new SharedPreferencesUtils.ContentValue("name", ""), + new SharedPreferencesUtils.ContentValue("password", "")); + return true; + } + return false; + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_login: + loadUserName(); //无论如何保存一下用户名 + login(); //登陆 + break; + case R.id.iv_see_password: + setPasswordVisibility(); //改变图片并设置输入框的文本可见或不可见 + break; + + } + } + + /** + * 模拟登录情况 + * 用户名csdn,密码123456,就能登录成功,否则登录失败 + */ + private void login() { + + //先做一些基本的判断,比如输入的用户命为空,密码为空,网络不可用多大情况,都不需要去链接服务器了,而是直接返回提示错误 + if (getAccount().isEmpty()){ + showToast("你输入的账号为空!"); + return; + } + + if (getPassword().isEmpty()){ + showToast("你输入的密码为空!"); + return; + } + //登录一般都是请求服务器来判断密码是否正确,要请求网络,要子线程 + showLoading();//显示加载框 + Thread loginRunnable = new Thread() { + + @Override + public void run() { + super.run(); + setLoginBtnClickable(false);//点击登录后,设置登录按钮不可点击状态 + + + //睡眠3秒 + try { + Thread.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + //判断账号和密码 +// StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); +// StrictMode.setThreadPolicy(policy); + if (check_password(getAccount(), getPassword())) { + showToast("登录成功"); + loadCheckBoxState();//记录下当前用户记住密码和自动登录的状态; + + startActivity(new Intent(org.pytorch.demo.AccountLoginActivity.this, SideBarActivity.class)); + finish();//关闭页面 + } else { + showToast("输入的登录账号或密码不正确"); + } + + setLoginBtnClickable(true); //这里解放登录按钮,设置为可以点击 + hideLoading();//隐藏加载框 + } + }; + loginRunnable.start(); + + + } + + + /** + * 保存用户账号 + */ + public void loadUserName() { + if (!getAccount().equals("") || !getAccount().equals("请输入登录账号")) { + SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting"); + helper.putValues(new SharedPreferencesUtils.ContentValue("name", getAccount())); + } + + } + + /** + * 设置密码可见和不可见的相互转换 + */ + private void setPasswordVisibility() { + if (iv_see_password.isSelected()) { + iv_see_password.setSelected(false); + //密码不可见 + et_password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); + + } else { + iv_see_password.setSelected(true); + //密码可见 + et_password.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); + } + + } + + public boolean check_password(String u, String p) { + + //获取输入的用户名和密码 + String username = u; + String password = p; + Intent intent = null; + if (username.equals("") || password.equals("")) { + //账户密码不能为空 + showToast("账号或密码不能为空"); + } + String res = null; + + Util util = new Util(); + String server_addr = util.settingContent.getServer_addr(); + String url = "http://"+server_addr+":8080/api/account/login"; + System.out.println("in ala url is " + url); + res = sendByOKHttp(url, username, password); + + System.out.println("in onclick res is " + res); + if (res!=null){ + try { + JSONObject jsonObject = new JSONObject(res); + if(jsonObject.has("detail")){ + JSONObject jo =(JSONObject) jsonObject.getJSONObject("detail"); + String hint = jo.getString("msg"); + showToast(hint); + return false; + } + else{ + String token = jsonObject.getString("access_token"); + new Util().SetToken(token); + Utils.token = token; + return true; + } + } catch (JSONException jsonException) { + jsonException.printStackTrace(); + } + + }else{ +// Toast.makeText(this, "网络或服务器错误", Toast.LENGTH_LONG).show(); + return false; + } + + return false; + } + + + + public String whenSendPostRequest_thenCorrect(String url, String u, String p) + throws IOException { + RequestBody formBody = new FormBody.Builder() + .add("username", u) + .add("password", p) + .build(); + + Request request = new Request.Builder() + .url(url) + .post(formBody) + .build(); + + OkHttpClient client = new OkHttpClient(); + Call call = client.newCall(request); + Response response = call.execute(); + +// assertThat(response.code(), equalTo(200)); + return response.body().string(); + } + + + + public class MyCallBack implements Callable { + private String url; + private String u, p; + public MyCallBack() { + } + public MyCallBack(String url, String u, String p) { + this.url = url; + this.u = u; + this.p = p; + } + + public MyCallBack(String url){ + this.url = url; + } + + public void setUrl(String url) { + this.url = url; + } + + public void setU(String u) { + this.u = u; + } + + public void setP(String p) { + this.p = p; + } + + public String getUrl() { + return url; + } + + public String getU() { + return u; + } + + public String getP() { + return p; + } + + public String call() throws Exception { + return whenSendPostRequest_thenCorrect(url, u, p); +// System.out.println("download file abc"); +// return new Util().DownloadDatagramByName1("abc"); + + } + + } + + private String sendByOKHttp(String url, String u, String p) { + MyCallBack callBack = new MyCallBack(url); + callBack.setP(p); + callBack.setU(u); + FutureTask taskList = new FutureTask(callBack); + Thread t = new Thread(taskList); + t.start(); + try { + String res = taskList.get(); + System.out.println(res); + return res; + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + return null; + } + + + + + + + + + + + /** + * 获取账号 + */ + public String getAccount() { + return et_name.getText().toString().trim();//去掉空格 + } + + /** + * 获取密码 + */ + public String getPassword() { + return et_password.getText().toString().trim();//去掉空格 + } + + + /** + * 保存用户选择“记住密码”和“自动登陆”的状态 + */ + private void loadCheckBoxState() { + loadCheckBoxState(checkBox_password, checkBox_login); + } + + /** + * 保存按钮的状态值 + */ + public void loadCheckBoxState(CheckBox checkBox_password, CheckBox checkBox_login) { + + //获取SharedPreferences对象,使用自定义类的方法来获取对象 + SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting"); + + //如果设置自动登录 + if (checkBox_login.isChecked()) { + //创建记住密码和自动登录是都选择,保存密码数据 + helper.putValues( + new SharedPreferencesUtils.ContentValue("remenberPassword", true), + new SharedPreferencesUtils.ContentValue("autoLogin", true), + new SharedPreferencesUtils.ContentValue("password", Base64Utils.encryptBASE64(getPassword()))); + + } else if (!checkBox_password.isChecked()) { //如果没有保存密码,那么自动登录也是不选的 + //创建记住密码和自动登录是默认不选,密码为空 + helper.putValues( + new SharedPreferencesUtils.ContentValue("remenberPassword", false), + new SharedPreferencesUtils.ContentValue("autoLogin", false), + new SharedPreferencesUtils.ContentValue("password", "")); + } else if (checkBox_password.isChecked()) { //如果保存密码,没有自动登录 + //创建记住密码为选中和自动登录是默认不选,保存密码数据 + helper.putValues( + new SharedPreferencesUtils.ContentValue("remenberPassword", true), + new SharedPreferencesUtils.ContentValue("autoLogin", false), + new SharedPreferencesUtils.ContentValue("password", Base64Utils.encryptBASE64(getPassword()))); + } + } + + /** + * 是否可以点击登录按钮 + * + * @param clickable + */ + public void setLoginBtnClickable(boolean clickable) { + mLoginBtn.setClickable(clickable); + } + + + /** + * 显示加载的进度款 + */ + public void showLoading() { + if (mLoadingDialog == null) { + mLoadingDialog = new LoadingDialog(this, "登录中", false); + } + mLoadingDialog.show(); + } + + + /** + * 隐藏加载的进度框 + */ + public void hideLoading() { + if (mLoadingDialog != null) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mLoadingDialog.hide(); + } + }); + + } + } + + + /** + * CheckBox点击时的回调方法 ,不管是勾选还是取消勾选都会得到回调 + * + * @param buttonView 按钮对象 + * @param isChecked 按钮的状态 + */ + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (buttonView == checkBox_password) { //记住密码选框发生改变时 + if (!isChecked) { //如果取消“记住密码”,那么同样取消自动登陆 + checkBox_login.setChecked(false); + } + } else if (buttonView == checkBox_login) { //自动登陆选框发生改变时 + if (isChecked) { //如果选择“自动登录”,那么同样选中“记住密码” + checkBox_password.setChecked(true); + } + } + } + + + /** + * 监听回退键 + */ + @Override + public void onBackPressed() { + if (mLoadingDialog != null) { + if (mLoadingDialog.isShowing()) { + mLoadingDialog.cancel(); + } else { + finish(); + } + } else { + finish(); + } + + } + + /** + * 页面销毁前回调的方法 + */ + protected void onDestroy() { + if (mLoadingDialog != null) { + mLoadingDialog.cancel(); + mLoadingDialog = null; + } + super.onDestroy(); + } + + + public void showToast(String msg) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MDToast.makeText(org.pytorch.demo.AccountLoginActivity.this, msg, MDToast.LENGTH_SHORT, MDToast.TYPE_INFO).show(); + } + }); + + } + +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/AddNewCrew.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/AddNewCrew.java new file mode 100644 index 00000000..011f408e --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/AddNewCrew.java @@ -0,0 +1,623 @@ +package org.pytorch.demo; + +import android.Manifest; +import android.annotation.TargetApi; +import android.content.ContentUris; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.ExifInterface; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatEditText; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.FileProvider; + +import android.os.Environment; +import android.os.SystemClock; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.material.textfield.TextInputEditText; + +import org.pytorch.IValue; +import org.pytorch.Module; +import org.pytorch.Tensor; +import org.pytorch.demo.util.Util; +import org.pytorch.torchvision.TensorImageUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; + +import static java.lang.Math.max; +import static java.lang.Math.min; +import static org.pytorch.demo.Utils.rotateImage; + +public class AddNewCrew extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_add_new_crew); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + init_button(); + + + } + private String crewID; + private Bitmap crewFace; + + private final String TAG = getClass().getSimpleName(); + private static final String[] PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}; + private static final int REQUEST_PERMISSION_CODE = 267; + private static final int TAKE_PHOTO = 189; + private static final int CHOOSE_PHOTO = 385; + private static final String FILE_PROVIDER_AUTHORITY = Utils.FILE_PROVIDER_AUTHORITY; + private Uri mImageUri, mImageUriFromFile; + private File imageFile; + + private void init_button() + { + findViewById(R.id.btn_set_face).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { +// Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); +// startActivityForResult(intent, CODE_SYSTEM_CAMERA); + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(PERMISSIONS, REQUEST_PERMISSION_CODE); + }else if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(PERMISSIONS, REQUEST_PERMISSION_CODE); + }else + takePhoto(); + } + }); + + findViewById(R.id.btn_select_face).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + openAlbum(); + } + }); + + findViewById(R.id.btn_return).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + findViewById(R.id.btn_submit).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + AppCompatEditText textInputEditText = findViewById(R.id.input_id); + crewID = textInputEditText.getText().toString(); + if(crewFace == null || crewID.equals("")){ + Toast.makeText(AddNewCrew.this,"没有设置人脸或id"+crewID, Toast.LENGTH_SHORT).show(); + } + else{ + //TODO 1. read model 2. calculate encoding of picture 3.add face encoding and id to a new json + + // 1. read model + Module mModule = null; + Module encoder = null; + if (mModule == null) { + try { + final String moduleFileAbsoluteFilePath = new File( + Utils.assetFilePath(AddNewCrew.this, "mobile_model2.pt")).getAbsolutePath(); + mModule = Module.load(moduleFileAbsoluteFilePath); + final String encoderFileAbsoluteFilePath = new File( + Utils.assetFilePath(AddNewCrew.this, "encoder1.pt")).getAbsolutePath(); + encoder = Module.load(encoderFileAbsoluteFilePath); + }catch (Exception e) + {e.printStackTrace();} + } + + // 2. extract face from picture + Bitmap bitmap = crewFace; + float [] mean = new float[] {0.49804f, 0.49804f, 0.49804f}; + float [] std = new float[] {0.501960f, 0.501960f, 0.501960f}; + float nms_threshold = 0.4f; + int w1 = bitmap.getWidth(); + int h1 = bitmap.getHeight(); + + Bitmap bitmap1 = Bitmap.createScaledBitmap(bitmap,480,360,true); + + Tensor inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmap1, mean, std); + System.out.println(Arrays.toString(inputTensor.shape())); + // running the model + final IValue[] output = mModule.forward(IValue.from(inputTensor)).toTuple(); + Tensor scores = output[0].toTensor(); + Tensor boxes = output[1].toTensor(); + float threshold = 0.8f; + + ArrayList possible_indexes = possible_score(scores, boxes, threshold); + System.out.println("in onCreate len possible_indexes " + possible_indexes.size()); + + ArrayList nms_boxes = nms(boxes, scores, possible_indexes, nms_threshold); + float ratio = 0.1f; + nms_boxes = expand_box(nms_boxes, ratio); + + if (nms_boxes.size() > 0){ + + if (nms_boxes.size() > 1){ + Toast.makeText(AddNewCrew.this, "图片中检测到过多的人脸信息", Toast.LENGTH_LONG).show(); + return; + } + + float[] box_c = nms_boxes.get(0); + Bitmap bitmap_c = cropBitmap(bitmap, box_c); + + File bitmap_file = new File(new Util().project_path, "tmp.jpg"); + if (!bitmap_file.exists()) { + try { + bitmap_file.createNewFile(); + FileOutputStream fileOutputStream = new FileOutputStream(bitmap_file); + bitmap_c.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream); + fileOutputStream.flush(); + fileOutputStream.close(); + + + } catch (IOException exception) { + exception.printStackTrace(); + } + } + new Util().UploadNewCrewInfo("hj", "hj", "ls", "111", bitmap_file); + + + + Utils.NamedEmbedding unnamed = encode_face(bitmap_c, encoder); + unnamed.id = crewID; + + // 3. save embedding and id to local file + boolean result = new Util().save_embedding_local_file(unnamed); + if (result){ + Toast.makeText(AddNewCrew.this,"已添加到本地库中:"+crewID, Toast.LENGTH_SHORT).show(); + } + else{ + Toast.makeText(AddNewCrew.this,"添加到本地库失败:"+crewID, Toast.LENGTH_SHORT).show(); + } + } + else{ + Toast.makeText(AddNewCrew.this, "图片中没有检测到人脸信息", Toast.LENGTH_LONG).show(); + return; + } + + + } + + } + }); + } + + + private Bitmap cropBitmap(Bitmap bitmap, float[] rect) { + try{ + int x,y,w,h; + x = (int) (bitmap.getWidth() * rect[0]); + y = (int) (bitmap.getHeight() * rect[1]); + + w = (int) (bitmap.getWidth() * (rect[2]-rect[0])); + h = (int) (bitmap.getHeight() * (rect[3]-rect[1])); + + return Bitmap.createBitmap(bitmap, x, y, w, h,null, false); + }catch (IllegalArgumentException e) + { + e.printStackTrace(); + } + catch (Exception e1) + { + e1.printStackTrace(); + } + return null; + + } + + private Utils.NamedEmbedding encode_face(Bitmap bitmap_c, Module encoder){ + final long startTime = SystemClock.elapsedRealtime(); + + float [] mean = new float[] {0.49804f, 0.49804f, 0.49804f}; + float [] std = new float[] {0.501960f, 0.501960f, 0.501960f}; + + Bitmap bitmap1 = Bitmap.createScaledBitmap(bitmap_c,160,160,true); + Tensor inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmap1, mean, std); + System.out.println(Arrays.toString(inputTensor.shape())); + final long moduleForwardStartTime = SystemClock.elapsedRealtime(); + final Tensor outputTensor = encoder.forward(IValue.from(inputTensor)).toTensor(); +// final IValue[] output = encoder.forward(IValue.from(inputTensor)).toTuple(); + final long moduleForwardDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime; + System.out.println("output tensor shape is "+ Arrays.toString(outputTensor.shape())); + Utils.NamedEmbedding unNamedEmbedding = new Utils.NamedEmbedding(); + + // put encoded face into unNamedEmbedding + float[] tensorDataAsFloatArray = outputTensor.getDataAsFloatArray(); + for (int i = 0; i< 512; i++) + unNamedEmbedding.embedding[i] = tensorDataAsFloatArray[i]; + return unNamedEmbedding; + + } + + public ArrayList possible_score(Tensor scores, Tensor boxes, float threshold) + { + ArrayList list_index_prob = new ArrayList<>(); + float[] floatArray = scores.getDataAsFloatArray(); + int len = floatArray.length; + long num = scores.shape()[2]; + len = (int)(len / num); + System.out.println(len); + + + for (int i = 0; i < len; i++) + { + for (int j = 1; j < num; j++) + if (floatArray[(int) (i * num + j)] > threshold) + { + list_index_prob.add((float)i); + list_index_prob.add(floatArray[(int) (i * num + j)]); + System.out.println("porb is " + floatArray[(int) (i * num)] + " and " + floatArray[(int) (i * num + 1)]); + } + + } + + return list_index_prob; + } + + private ArrayList expand_box(ArrayList boxes, float ratio) + { + for (int i = 0; i < boxes.size(); i++) + { + float w = boxes.get(i)[2] - boxes.get(i)[0]; + float h = boxes.get(i)[3] - boxes.get(i)[1]; + + if (boxes.get(i)[0] - w * ratio > 0) + boxes.get(i)[0] -= w*ratio; + if (boxes.get(i)[1] - h * ratio > 0) + boxes.get(i)[1] -= h*ratio; + if (boxes.get(i)[2] + w * ratio < 1) + boxes.get(i)[2] += w*ratio; + if (boxes.get(i)[3] + w * ratio < 1) + boxes.get(i)[3] += w*ratio; + } + return boxes; + } + + float IoU(float[] rec1, float[] rec2) + { + + float S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1]); + float S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1]); + +// computing the sum_area + float sum_area = S_rec1 + S_rec2; + +// find the each edge of intersect rectangle + float left_line = max(rec1[1], rec2[1]); + float right_line = min(rec1[3], rec2[3]); + float top_line = max(rec1[0], rec2[0]); + float bottom_line = min(rec1[2], rec2[2]); + +// judge if there is an intersect + float intersect = 0; + if (left_line >= right_line || top_line >= bottom_line) + return 0; + else + intersect = (right_line - left_line) * (bottom_line - top_line); + return (intersect / (sum_area - intersect)); + } + + ArrayList nms(Tensor boxes, Tensor scores, ArrayList possible_indexes, float nms_threshold) + { +// float[] sfloatArray = scores.getDataAsFloatArray(); +// int slen = sfloatArray.length; +// long snum = scores.shape()[2]; +// slen = (int)(slen / snum); + + ArrayList nms_boxes = new ArrayList<>(); + float[] bfloatArray = boxes.getDataAsFloatArray(); + int blen = bfloatArray.length; + int bnum = (int) boxes.shape()[2]; + blen = (blen / bnum); + + + float[] box2 = {1,1,1,1,1}; + for(int i = 0; i < possible_indexes.size() / 2; i++) + { + float[] box1 = {0,0,0,0,0}; + int index = (int) (float) possible_indexes.get(i * 2); + for(int j = 0; j < bnum; j++) + { + box1[j] = bfloatArray[index * bnum + j]; + } + box1[bnum] = possible_indexes.get(i * 2 + 1); + boolean flag = true; + for(int j = 0; j < nms_boxes.size(); j++) + { + box2 = nms_boxes.get(j); + if(IoU(box1, box2) > nms_threshold) { + if (box2[bnum] > box1[bnum]) { //prob of box2 > box1 + nms_boxes.remove(j); + nms_boxes.add(box1); + flag = false; + } else { + flag = false; + break; + } + } + } + if (flag) + nms_boxes.add(box1); + + + } + return nms_boxes; + } +// @Override +// protected void onActivityResult(int requestCode, int resultCode, Intent data) { +// super.onActivityResult(requestCode, resultCode, data); +// if (requestCode == CODE_SYSTEM_CAMERA && resultCode == RESULT_OK) { +// /*缩略图信息是储存在返回的intent中的Bundle中的, +// * 对应Bundle中的键为data,因此从Intent中取出 +// * Bundle再根据data取出来Bitmap即可*/ +// Bundle extras = data.getExtras(); +// crewFace = (Bitmap) extras.get("data"); +// ImageView imageView = findViewById(R.id.input_image); +// imageView.setImageBitmap(crewFace); +// } +// } + + /** + * 打开相册 + */ + private void openAlbum() { + Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT); + openAlbumIntent.setType("image/*"); + startActivityForResult(openAlbumIntent, CHOOSE_PHOTO);//打开相册 + } + + /** + * 拍照 + */ + private void takePhoto() { + Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//打开相机的Intent + if (takePhotoIntent.resolveActivity(getPackageManager()) != null) {//这句作用是如果没有相机则该应用不会闪退,要是不加这句则当系统没有相机应用的时候该应用会闪退 + imageFile = createImageFile();//创建用来保存照片的文件 + mImageUriFromFile = Uri.fromFile(imageFile); + Log.i(TAG, "takePhoto: uriFromFile " + mImageUriFromFile); + if (imageFile != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + /*7.0以上要通过FileProvider将File转化为Uri*/ + mImageUri = FileProvider.getUriForFile(this, FILE_PROVIDER_AUTHORITY, imageFile); + } else { + /*7.0以下则直接使用Uri的fromFile方法将File转化为Uri*/ + mImageUri = Uri.fromFile(imageFile); + } + takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);//将用于输出的文件Uri传递给相机 + startActivityForResult(takePhotoIntent, TAKE_PHOTO);//打开相机 + } + } + } + + /** + * 创建用来存储图片的文件,以时间来命名就不会产生命名冲突 + * + * @return 创建的图片文件 + */ + private File createImageFile() { + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); + String imageFileName = "JPEG_" + timeStamp + "_"; + File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + File imageFile = null; + try { + imageFile = File.createTempFile(imageFileName, ".jpg", storageDir); + } catch (IOException e) { + e.printStackTrace(); + } + return imageFile; + } + + /*申请权限的回调*/ + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Log.i(TAG, "onRequestPermissionsResult: permission granted"); + takePhoto(); + } else { + Log.i(TAG, "onRequestPermissionsResult: permission denied"); + Toast.makeText(this, "You Denied Permission", Toast.LENGTH_SHORT).show(); + } + } + + /*相机或者相册返回来的数据*/ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (requestCode) { + case TAKE_PHOTO: + if (resultCode == RESULT_OK) { + try { + /*如果拍照成功,将Uri用BitmapFactory的decodeStream方法转为Bitmap*/ + Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(mImageUri)); + ExifInterface ei = new ExifInterface(imageFile.getAbsolutePath()); + int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_UNDEFINED); + + Bitmap rotatedBitmap = null; + switch(orientation) { + + case ExifInterface.ORIENTATION_ROTATE_90: + rotatedBitmap = rotateImage(bitmap, 90); + break; + + case ExifInterface.ORIENTATION_ROTATE_180: + rotatedBitmap = rotateImage(bitmap, 180); + break; + + case ExifInterface.ORIENTATION_ROTATE_270: + rotatedBitmap = rotateImage(bitmap, 270); + break; + + case ExifInterface.ORIENTATION_NORMAL: + default: + rotatedBitmap = bitmap; + } + Log.i(TAG, "onActivityResult: imageUri " + mImageUri); + galleryAddPic(mImageUriFromFile); + ImageView imageView = findViewById(R.id.input_image); + imageView.setImageBitmap(rotatedBitmap);//显示到ImageView上 + crewFace = rotatedBitmap; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException exception) { + exception.printStackTrace(); + } + } + break; + case CHOOSE_PHOTO: + if (data == null) {//如果没有选取照片,则直接返回 + return; + } + Log.i(TAG, "onActivityResult: ImageUriFromAlbum: " + data.getData()); + if (resultCode == RESULT_OK) { + handleImageOnKitKat(data);//4.4之后图片解析 + } + break; + default: + break; + } + } + + /** + * 4.4版本以下对返回的图片Uri的处理: + * 就是从返回的Intent中取出图片Uri,直接显示就好 + * @param data 调用系统相册之后返回的Uri + */ + private void handleImageBeforeKitKat(Intent data) { + Uri uri = data.getData(); + String imagePath = getImagePath(uri, null); + try { + displayImage(imagePath); + } catch (IOException exception) { + exception.printStackTrace(); + } + } + + /** + * 4.4版本以上对返回的图片Uri的处理: + * 返回的Uri是经过封装的,要进行处理才能得到真实路径 + * @param data 调用系统相册之后返回的Uri + */ + @TargetApi(19) + private void handleImageOnKitKat(Intent data) { + String imagePath = null; + Uri uri = data.getData(); + if (DocumentsContract.isDocumentUri(this, uri)) { + //如果是document类型的Uri,则提供document id处理 + String docId = DocumentsContract.getDocumentId(uri); + if ("com.android.providers.media.documents".equals(uri.getAuthority())) { + String id = docId.split(":")[1];//解析出数字格式的id + String selection = MediaStore.Images.Media._ID + "=" + id; + imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection); + } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { + Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); + imagePath = getImagePath(contentUri, null); + } + } else if ("content".equalsIgnoreCase(uri.getScheme())) { + //如果是content类型的uri,则进行普通处理 + imagePath = getImagePath(uri, null); + } else if ("file".equalsIgnoreCase(uri.getScheme())) { + //如果是file类型的uri,则直接获取路径 + imagePath = uri.getPath(); + } + try { + displayImage(imagePath); + } catch (IOException exception) { + exception.printStackTrace(); + } + } + + /** + * 将imagePath指定的图片显示到ImageView上 + */ + private void displayImage(String imagePath) throws IOException { + if (imagePath != null) { + ExifInterface ei = new ExifInterface(imagePath); + int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_UNDEFINED); + Bitmap bitmap = BitmapFactory.decodeFile(imagePath); + Bitmap rotatedBitmap = null; + switch(orientation) { + + case ExifInterface.ORIENTATION_ROTATE_90: + rotatedBitmap = rotateImage(bitmap, 90); + break; + + case ExifInterface.ORIENTATION_ROTATE_180: + rotatedBitmap = rotateImage(bitmap, 180); + break; + + case ExifInterface.ORIENTATION_ROTATE_270: + rotatedBitmap = rotateImage(bitmap, 270); + break; + + case ExifInterface.ORIENTATION_NORMAL: + default: + rotatedBitmap = bitmap; + } + + ImageView imageView = findViewById(R.id.input_image); + crewFace = rotatedBitmap; + imageView.setImageBitmap(rotatedBitmap); + } else { + Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show(); + } + } + + /** + * 将Uri转化为路径 + * @param uri 要转化的Uri + * @param selection 4.4之后需要解析Uri,因此需要该参数 + * @return 转化之后的路径 + */ + private String getImagePath(Uri uri, String selection) { + String path = null; + Cursor cursor = getContentResolver().query(uri, null, selection, null, null); + if (cursor != null) { + if (cursor.moveToFirst()) { + path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); + } + cursor.close(); + } + return path; + } + + /** + * 将拍的照片添加到相册 + * + * @param uri 拍的照片的Uri + */ + private void galleryAddPic(Uri uri) { + Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + mediaScanIntent.setData(uri); + sendBroadcast(mediaScanIntent); + } + +} \ No newline at end of file diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/BitmapToVideoEncoder.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/BitmapToVideoEncoder.java new file mode 100644 index 00000000..48315bda --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/BitmapToVideoEncoder.java @@ -0,0 +1,347 @@ +package org.pytorch.demo; + +import android.graphics.Bitmap; +import android.media.MediaCodec; +import android.media.MediaCodecInfo; +import android.media.MediaCodecList; +import android.media.MediaFormat; +import android.media.MediaMuxer; +import android.util.Log; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; + +import io.reactivex.Completable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +public class BitmapToVideoEncoder { + private static final String TAG = BitmapToVideoEncoder.class.getSimpleName(); + + private IBitmapToVideoEncoderCallback mCallback; + private File mOutputFile; + private Queue mEncodeQueue = new ConcurrentLinkedQueue(); + private MediaCodec mediaCodec; + private MediaMuxer mediaMuxer; + + private Object mFrameSync = new Object(); + private CountDownLatch mNewFrameLatch; + + private static final String MIME_TYPE = "video/avc"; // H.264 Advanced Video Coding + private static int mWidth; + private static int mHeight; + private static final int BIT_RATE = 16000000; + private static final int FRAME_RATE = 10; // Frames per second + + private static final int I_FRAME_INTERVAL = 1; + + private int mGenerateIndex = 0; + private int mTrackIndex; + private boolean mNoMoreFrames = false; + private boolean mAbort = false; + + public interface IBitmapToVideoEncoderCallback { + void onEncodingComplete(File outputFile); + } + + public BitmapToVideoEncoder(IBitmapToVideoEncoderCallback callback) { + mCallback = callback; + } + + public boolean isEncodingStarted() { + return (mediaCodec != null) && (mediaMuxer != null) && !mNoMoreFrames && !mAbort; + } + + public int getActiveBitmaps() { + return mEncodeQueue.size(); + } + + public void startEncoding(int width, int height, File outputFile) { + mWidth = width; + mHeight = height; + mOutputFile = outputFile; + + String outputFileString; + try { + outputFileString = outputFile.getCanonicalPath(); + } catch (IOException e) { + Log.e(TAG, "Unable to get path for " + outputFile); + return; + } + + MediaCodecInfo codecInfo = selectCodec(MIME_TYPE); + if (codecInfo == null) { + Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); + return; + } + Log.d(TAG, "found codec: " + codecInfo.getName()); + int colorFormat; + try { + colorFormat = selectColorFormat(codecInfo, MIME_TYPE); + } catch (Exception e) { + colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar; + } + + try { + mediaCodec = MediaCodec.createByCodecName(codecInfo.getName()); + } catch (IOException e) { + Log.e(TAG, "Unable to create MediaCodec " + e.getMessage()); + return; + } + + MediaFormat mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight); + mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); + mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); + mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); + mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL); + mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); + mediaCodec.start(); + try { + mediaMuxer = new MediaMuxer(outputFileString, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); + } catch (IOException e) { + Log.e(TAG,"MediaMuxer creation failed. " + e.getMessage()); + return; + } + + Log.d(TAG, "Initialization complete. Starting encoder..."); + + Completable.fromAction(() -> encode()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(); + } + + public void stopEncoding() { + if (mediaCodec == null || mediaMuxer == null) { + Log.d(TAG, "Failed to stop encoding since it never started"); + return; + } + Log.d(TAG, "Stopping encoding"); + + mNoMoreFrames = true; + + synchronized (mFrameSync) { + if ((mNewFrameLatch != null) && (mNewFrameLatch.getCount() > 0)) { + mNewFrameLatch.countDown(); + } + } + } + + public void abortEncoding() { + if (mediaCodec == null || mediaMuxer == null) { + Log.d(TAG, "Failed to abort encoding since it never started"); + return; + } + Log.d(TAG, "Aborting encoding"); + + mNoMoreFrames = true; + mAbort = true; + mEncodeQueue = new ConcurrentLinkedQueue(); // Drop all frames + + synchronized (mFrameSync) { + if ((mNewFrameLatch != null) && (mNewFrameLatch.getCount() > 0)) { + mNewFrameLatch.countDown(); + } + } + } + + public void queueFrame(Bitmap bitmap) { + if (mediaCodec == null || mediaMuxer == null) { + Log.d(TAG, "Failed to queue frame. Encoding not started"); + return; + } + + Log.d(TAG, "Queueing frame"); + mEncodeQueue.add(bitmap); + + synchronized (mFrameSync) { + if ((mNewFrameLatch != null) && (mNewFrameLatch.getCount() > 0)) { + mNewFrameLatch.countDown(); + } + } + } + + private void encode() { + + Log.d(TAG, "Encoder started"); + + while(true) { + if (mNoMoreFrames && (mEncodeQueue.size() == 0)) break; + + Bitmap bitmap = mEncodeQueue.poll(); + if (bitmap == null) { + synchronized (mFrameSync) { + mNewFrameLatch = new CountDownLatch(1); + } + + try { + mNewFrameLatch.await(); + } catch (InterruptedException e) {} + + bitmap = mEncodeQueue.poll(); + } + + if (bitmap == null) continue; + + byte[] byteConvertFrame = getNV21(bitmap.getWidth(), bitmap.getHeight(), bitmap); + + long TIMEOUT_USEC = 500000; + int inputBufIndex = mediaCodec.dequeueInputBuffer(TIMEOUT_USEC); + long ptsUsec = computePresentationTime(mGenerateIndex, FRAME_RATE); + if (inputBufIndex >= 0) { + final ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufIndex); + inputBuffer.clear(); + Log.d(TAG, "inputbuffer capacity " + inputBuffer.capacity()); + inputBuffer.put(byteConvertFrame); + mediaCodec.queueInputBuffer(inputBufIndex, 0, byteConvertFrame.length, ptsUsec, 0); + mGenerateIndex++; + } + MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo(); + int encoderStatus = mediaCodec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC); + if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { + // no output available yet + Log.e(TAG, "No output from encoder available"); + } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { + // not expected for an encoder + MediaFormat newFormat = mediaCodec.getOutputFormat(); + mTrackIndex = mediaMuxer.addTrack(newFormat); + mediaMuxer.start(); + } else if (encoderStatus < 0) { + Log.e(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus); + } else if (mBufferInfo.size != 0) { + ByteBuffer encodedData = mediaCodec.getOutputBuffer(encoderStatus); + if (encodedData == null) { + Log.e(TAG, "encoderOutputBuffer " + encoderStatus + " was null"); + } else { + encodedData.position(mBufferInfo.offset); + encodedData.limit(mBufferInfo.offset + mBufferInfo.size); + mediaMuxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo); + mediaCodec.releaseOutputBuffer(encoderStatus, false); + } + } + } + + release(); + + if (mAbort) { + mOutputFile.delete(); + } else { + mCallback.onEncodingComplete(mOutputFile); + } + } + + private void release() { + if (mediaCodec != null) { + mediaCodec.stop(); + mediaCodec.release(); + mediaCodec = null; + Log.d(TAG,"RELEASE CODEC"); + } + if (mediaMuxer != null) { + mediaMuxer.stop(); + mediaMuxer.release(); + mediaMuxer = null; + Log.d(TAG,"RELEASE MUXER"); + } + } + + private static MediaCodecInfo selectCodec(String mimeType) { + int numCodecs = MediaCodecList.getCodecCount(); + for (int i = 0; i < numCodecs; i++) { + MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); + if (!codecInfo.isEncoder()) { + continue; + } + String[] types = codecInfo.getSupportedTypes(); + for (int j = 0; j < types.length; j++) { + if (types[j].equalsIgnoreCase(mimeType)) { + return codecInfo; + } + } + } + return null; + } + + private static int selectColorFormat(MediaCodecInfo codecInfo, + String mimeType) { + MediaCodecInfo.CodecCapabilities capabilities = codecInfo + .getCapabilitiesForType(mimeType); + for (int i = 0; i < capabilities.colorFormats.length; i++) { + int colorFormat = capabilities.colorFormats[i]; + if (isRecognizedFormat(colorFormat)) { + return colorFormat; + } + } + return 0; // not reached + } + + private static boolean isRecognizedFormat(int colorFormat) { + switch (colorFormat) { + // these are the formats we know how to handle for + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar: + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar: + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar: + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar: + case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar: + return true; + default: + return false; + } + } + + private byte[] getNV21(int inputWidth, int inputHeight, Bitmap scaled) { + + int[] argb = new int[inputWidth * inputHeight]; + + scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight); + + byte[] yuv = new byte[inputWidth * inputHeight * 3 / 2]; + encodeYUV420SP(yuv, argb, inputWidth, inputHeight); + + scaled.recycle(); + + return yuv; + } + + private void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) { + final int frameSize = width * height; + + int yIndex = 0; + int uvIndex = frameSize; + + int a, R, G, B, Y, U, V; + int index = 0; + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + + a = (argb[index] & 0xff000000) >> 24; // a is not used obviously + R = (argb[index] & 0xff0000) >> 16; + G = (argb[index] & 0xff00) >> 8; + B = (argb[index] & 0xff) >> 0; + + + Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; + U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; + V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; + + + yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y)); + if (j % 2 == 0 && index % 2 == 0) { + yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U)); + yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V)); + + } + + index++; + } + } + } + + private long computePresentationTime(long frameIndex, int framerate) { + return 132 + frameIndex * 1000000 / framerate; + } +} \ No newline at end of file diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/ContentfileActivity.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/ContentfileActivity.java new file mode 100644 index 00000000..b2aebfd7 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/ContentfileActivity.java @@ -0,0 +1,58 @@ +package org.pytorch.demo; + + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +//import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.RadioButton; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +//import androidx.fragment.app.Fragment; + +public class ContentfileActivity extends Fragment { + + //创建视图 + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + + + return inflater.inflate( R.layout.content_file, container, false ); //要加载的layout文件 + } + + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Activity activity = getActivity(); + activity.findViewById(R.id.local_data).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(ContentfileActivity.this.getActivity(), SelectFaceDatagram.class)); + } + }); + activity.findViewById(R.id.local_video).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(ContentfileActivity.this.getActivity(), SelectVideos.class)); + } + }); + activity.findViewById(R.id.checkandupdate_person).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(ContentfileActivity.this.getActivity(), SelectCrew.class)); + } + }); + + } + +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/ContentfuncActivity.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/ContentfuncActivity.java new file mode 100644 index 00000000..3c4696c8 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/ContentfuncActivity.java @@ -0,0 +1,106 @@ +package org.pytorch.demo; + + +import android.app.Activity; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import android.widget.RadioButton; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import org.pytorch.demo.util.Util; + + +public class ContentfuncActivity extends Fragment { + + //创建视图 + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + + return inflater.inflate( R.layout.content_func, container, false ); //要加载的layout文件 + } + + + /** + * 在这里才能操作fragment使用当前父Activity的控件。 + */ + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + RadioButton local_recog = getActivity().findViewById(R.id.local_recog); + RadioButton remote_recog = getActivity().findViewById(R.id.remote_recog); + setBounds(R.mipmap.phonemode,local_recog); + setBounds(R.mipmap.phonemode,remote_recog); + RadioButton glass_remote_recog = getActivity().findViewById(R.id.glass_remote_recog); + RadioButton glass_local_recog = getActivity().findViewById(R.id.glass_local_recog); + setBounds(R.mipmap.glassmode,glass_remote_recog); + setBounds(R.mipmap.glassmode,glass_local_recog); + RadioButton shipname_detect = getActivity().findViewById(R.id.shipname_detect); + RadioButton shipclass_detect = getActivity().findViewById(R.id.shipclass_detect); + setBounds(R.mipmap.ship,shipname_detect); + setBounds(R.mipmap.ship,shipclass_detect); + RadioButton add_crew = getActivity().findViewById(R.id.btn_add_crew); + RadioButton other_func = getActivity().findViewById(R.id.btn_other); + setBounds(R.mipmap.account,add_crew); + setBounds(R.mipmap.account,other_func); + Activity baseActivity = getActivity(); + Button local_button = baseActivity.findViewById(R.id.local_recog); + Button remote_button = baseActivity.findViewById(R.id.remote_recog); + local_button.setOnClickListener(v -> startActivity(new Intent(ContentfuncActivity.this.getActivity(),FaceDetectionActivity2.class))); + remote_button.setOnClickListener(v -> startActivity(new Intent(ContentfuncActivity.this.getActivity(),RemoteFaceDetectActivity.class))); + baseActivity.findViewById(R.id.glass_local_recog).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(ContentfuncActivity.this.getActivity(), GlassLocalActivity.class)); + } + }); + baseActivity.findViewById(R.id.glass_remote_recog).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(ContentfuncActivity.this.getActivity(), GlassRemoteActivity.class)); + } + }); + add_crew.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(ContentfuncActivity.this.getActivity(), AddNewCrew.class)); + } + }); + shipname_detect.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { +// new Util().resetPassword("001", "00x"); + new Util().deleteCrewByName("name"); + } + }); + + } + + /** + * + * @param drawableId drawableLeft drawableTop drawableBottom 所用的选择器 通过R.drawable.xx 获得 + * @param radioButton 需要限定图片大小的radioButton + */ + private void setBounds(int drawableId, RadioButton radioButton) { + //定义底部标签图片大小和位置 + Drawable drawable_news = getResources().getDrawable(drawableId); + //当这个图片被绘制时,给他绑定一个矩形 ltrb规定这个矩形 (这里的长和宽写死了 自己可以可以修改成 形参传入) + drawable_news.setBounds(0, 0, 95, 95); + //设置图片在文字的哪个方向 + radioButton.setCompoundDrawables(null,drawable_news,null, null); + } + + + +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/CrewSelectAdapter.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/CrewSelectAdapter.java new file mode 100644 index 00000000..0203c7f0 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/CrewSelectAdapter.java @@ -0,0 +1,414 @@ +package org.pytorch.demo; + + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.view.View; +import android.view.ViewGroup; +import android.view.LayoutInflater; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.PopupWindow; +import android.widget.SimpleAdapter; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.core.content.FileProvider; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import androidx.recyclerview.widget.RecyclerView; + +import com.valdesekamdem.library.mdtoast.MDToast; + +import org.pytorch.demo.util.Util; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + + +public class CrewSelectAdapter extends RecyclerView.Adapter { + ViewGroup parent; + ArrayList crewArrayList; + SwipeRefreshLayout swipeRefreshLayout; + @NonNull + + @Override + public ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.content_select_face_datagram, parent, false); + this.parent = parent; + crewArrayList = new Util().get_all_crews(); + System.out.println("in create crew array list len is " + crewArrayList.size()); + + return new ViewPagerViewHolder(view); + } + + ListView listView; + ListView listView1; + + @Override + public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) { + if(position == 0){ + swipeRefreshLayout = holder.itemView.findViewById(R.id.swiperFresh); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + refresh_lv0(); + } + }); + System.out.println("in onbindviewholder position is "+position); + listView = holder.itemView.findViewById(R.id.list); + updateListView0(crewArrayList); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + AlertDialog alertDialog; + + public void delete_by_name(String name, String filename){ + new Util().delete_by_name(name, filename); + MDToast.makeText(parent.getContext(), "成功删除", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + } +// public void upload_dialog(String filename){ +//// alertDialog.hide(); +// alertDialog.dismiss(); +// System.out.println("before create pd"); +// ProgressDialog dialog = new ProgressDialog(parent.getContext()); +// dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); +// dialog.setCancelable(false); +// dialog.setCanceledOnTouchOutside(false); +// dialog.setTitle("上传中"); +// System.out.println("before setting listener"); +// dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { +// @Override +// public void onDismiss(DialogInterface dialog) { +// MDToast.makeText(parent.getContext(), "上传成功", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); +// } +// }); +// dialog.setMessage("正在上传,请稍等"); +// System.out.println("before show"); +// dialog.show(); +//// dialog.setMax(100); +// +// Util util = new Util(); +// new AsyncTask(){ +// @Override +// protected String doInBackground(String... arg0){ +// String res = util.UploadVideoByName(arg0[0]); +// return res; +// } +// +// protected void onPostExecute(String result){ +// if (result != null){ +// MDToast.makeText(parent.getContext(), "上传完成",MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); +// System.out.println(result); +// }else{ +// MDToast.makeText(parent.getContext(), "上传失败,检查网络或服务器",MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show(); +// } +// } +// }.execute(filename); +// +// System.out.println("before while"); +// while(util.upload_progress < 0.99){ +// System.out.println("in while up is "+ util.upload_progress); +// dialog.setProgress((int)(100 * util.upload_progress)); +// try { +// Thread.sleep(400); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } +//// Toast.makeText(parent.getContext(),"上传成功", Toast.LENGTH_SHORT).show(); +// dialog.dismiss(); +// +// } + + @Override + @SuppressLint("StaticFieldLeak") + public void onItemClick(AdapterView parent, View view, int position, long id) { + System.out.println("position "+position); + String name = ((HashMap)(listView.getItemAtPosition(position))).get("name"); + String filename = ((HashMap)(listView.getItemAtPosition(position))).get("file"); + System.out.println(name); +// Environment.getDataDirectory() + + final String[] choices = new String[]{"预览", "删除"}; + + alertDialog = new AlertDialog.Builder(parent.getContext()) + .setTitle("选择操作") + .setIcon(R.drawable.ic_logo_pytorch) + .setItems(choices, new DialogInterface.OnClickListener() {//添加列表 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if(i==0)//预览 + { + //TODO call media here + } + else if (i == 1)// 删除 + { + new AlertDialog.Builder(parent.getContext()) + .setTitle("删除 " + name) + .setMessage("是否确定删除 "+filename+" 下的" + name) + + // Specifying a listener allows you to take an action before dismissing the dialog. + // The dialog is automatically dismissed when a dialog button is clicked. + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // Continue with delete operation + delete_by_name(name, filename); + } + }) + + // A null listener allows the button to dismiss the dialog and take no further action. + .setNegativeButton(android.R.string.no, null) + .setIcon(android.R.drawable.ic_dialog_alert) + .show(); + } +// Toast.makeText(parent.getContext(), "点的是:" + choices[i], Toast.LENGTH_SHORT).show(); + } + + }) + .create(); + + alertDialog.show(); + + } + }); + } + else { + swipeRefreshLayout = holder.itemView.findViewById(R.id.swiperFresh); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + refresh_lv1(); + } + }); + System.out.println("in onbindviewholder position is " + position); + listView1 = holder.itemView.findViewById(R.id.list); + updateListView1(crewArrayList); + + listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + AlertDialog alertDialog; + + public void delete_by_name(String name, String filename){ + new Util().delete_by_name(name, filename); + MDToast.makeText(parent.getContext(), "成功删除", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + } + public void upload_dialog(String filename){ +// alertDialog.hide(); + alertDialog.dismiss(); + System.out.println("before create pd"); + ProgressDialog dialog = new ProgressDialog(parent.getContext()); + dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + dialog.setCancelable(false); + dialog.setCanceledOnTouchOutside(false); + dialog.setTitle("上传中"); + System.out.println("before setting listener"); + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + MDToast.makeText(parent.getContext(), "上传成功", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + } + }); + dialog.setMessage("正在上传,请稍等"); + System.out.println("before show"); + dialog.show(); +// dialog.setMax(100); + + Util util = new Util(); + new AsyncTask(){ + @Override + protected String doInBackground(String... arg0){ + String res = util.UploadVideoByName(arg0[0]); + return res; + } + + protected void onPostExecute(String result){ + if (result != null){ + MDToast.makeText(parent.getContext(), "上传完成",MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + System.out.println(result); + }else{ + MDToast.makeText(parent.getContext(), "上传失败,检查网络或服务器",MDToast.LENGTH_SHORT, MDToast.TYPE_WARNING).show(); + } + } + }.execute(filename); + + System.out.println("before while"); + while(util.upload_progress < 0.99){ + System.out.println("in while up is "+ util.upload_progress); + dialog.setProgress((int)(100 * util.upload_progress)); + try { + Thread.sleep(400); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +// Toast.makeText(parent.getContext(),"上传成功", Toast.LENGTH_SHORT).show(); + dialog.dismiss(); + + } + + @Override + @SuppressLint("StaticFieldLeak") + public void onItemClick(AdapterView parent, View view, int position, long id) { + System.out.println("position "+position); + String name = ((HashMap)(listView1.getItemAtPosition(position))).get("name"); + String filename = ((HashMap)(listView1.getItemAtPosition(position))).get("file"); + System.out.println(name); +// Environment.getDataDirectory() + + final String[] choices = new String[]{"预览", "上传", "删除"}; + + alertDialog = new AlertDialog.Builder(parent.getContext()) + .setTitle("选择操作") + .setIcon(R.drawable.ic_logo_pytorch) + .setItems(choices, new DialogInterface.OnClickListener() {//添加列表 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if(i==0)//预览 + { + //TODO call media here + File file = new File(new Util().datagram_path , filename); + System.out.println("in onclick video path is " + file.getAbsolutePath()); + Intent intent = new Intent(Intent.ACTION_VIEW); + + + if (file.exists()){ + Uri contentUri = FileProvider.getUriForFile(parent.getContext(), "authority", file); +// Uri uri = Uri.fromFile(file); + parent.getContext().grantUriPermission(parent.getContext().getPackageName(), contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + + String type = Utils.getMIMEType(file); + System.out.println("type is " + type); + System.out.println("uri is " + contentUri.getPath()); + intent.setDataAndType(contentUri, type); + parent.getContext().startActivity(intent); + MDToast.makeText(parent.getContext(), "成功打开", Utils.dura_short, Utils.Type_success).show(); + }else{ + MDToast.makeText(parent.getContext(), "文件不存在,文件路径错误", Utils.dura_short, Utils.Type_error).show(); + } + } + else if (i == 1)// 上传 + { + upload_dialog(name); + } + else if (i == 2)// 删除 + { + new AlertDialog.Builder(parent.getContext()) + .setTitle("删除 " + name) + .setMessage("是否确定删除 "+filename+" 下的" + name) + + // Specifying a listener allows you to take an action before dismissing the dialog. + // The dialog is automatically dismissed when a dialog button is clicked. + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // Continue with delete operation + delete_by_name(name, filename); + } + }) + + // A null listener allows the button to dismiss the dialog and take no further action. + .setNegativeButton(android.R.string.no, null) + .setIcon(android.R.drawable.ic_dialog_alert) + .show(); + } +// Toast.makeText(parent.getContext(), "点的是:" + choices[i], Toast.LENGTH_SHORT).show(); + } + + }) + .create(); + + alertDialog.show(); + + } + }); + } + + } + + public void refresh_lv0(){ + crewArrayList = new Util().get_all_crews(); + updateListView0(crewArrayList); + MDToast.makeText(parent.getContext(),"刷新成功", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + swipeRefreshLayout.setRefreshing(false); + } + public void refresh_lv1(){ + crewArrayList = new Util().get_all_crews(); + updateListView1(crewArrayList); + MDToast.makeText(parent.getContext(),"刷新成功", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + swipeRefreshLayout.setRefreshing(false); + } + + + + public void updateListView1(ArrayList crewArrayList){ + ArrayList> list = new ArrayList<>(); + for (int i = 0; i < crewArrayList.size(); i++){ + String filename = crewArrayList.get(i).getCrew_file().getName(); + System.out.println("in updatelistview1 get name " + filename); + if(filename.startsWith("local_temp_datagram")){ + Map map= new HashMap<>(); + map.put("name", crewArrayList.get(i).getCrew_id()); + map.put("file", crewArrayList.get(i).getCrew_file().getName()); +// map.put("site", jsonArrays.getString(i)); + list.add(map); + } + + } + + + SimpleAdapter adapter = new SimpleAdapter(parent.getContext(), + list, + R.layout.datagram_list_item, + new String[]{"name", "file"}, + new int[]{R.id.text1, R.id.text2}); + + listView1.setAdapter(adapter); + listView1.bringToFront(); + } + + public void updateListView0(ArrayList crewArrayList){ + ArrayList> list = new ArrayList<>(); + for (int i = 0; i < crewArrayList.size(); i++){ + String filename = crewArrayList.get(i).getCrew_file().getName(); + System.out.println("in updatelistview0 get name " + filename); + + Map map= new HashMap<>(); + map.put("name", crewArrayList.get(i).getCrew_id()); + map.put("file", crewArrayList.get(i).getCrew_file().getName()); +// map.put("site", jsonArrays.getString(i)); + list.add(map); + System.out.println("in updatelistview0 list size " + list.size()); + } + + + SimpleAdapter adapter = new SimpleAdapter(parent.getContext(), + list, + R.layout.datagram_list_item, + new String[]{"name", "file"}, + new int[]{R.id.text1, R.id.text2}); + + listView.setAdapter(adapter); + listView.bringToFront(); + } + + @Override + public int getItemCount() { + return 2; + } + + public CrewSelectAdapter() { + super(); + } + + public class ViewPagerViewHolder extends RecyclerView.ViewHolder{ + public ViewPagerViewHolder(View itemView){ + super(itemView); + } + } + +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/DatagramSelectAdapter.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/DatagramSelectAdapter.java new file mode 100644 index 00000000..599ed8a5 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/DatagramSelectAdapter.java @@ -0,0 +1,375 @@ +package org.pytorch.demo; + + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.view.View; +import android.view.ViewGroup; +import android.view.LayoutInflater; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.core.content.FileProvider; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.valdesekamdem.library.mdtoast.MDToast; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.pytorch.demo.util.Util; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + + +public class DatagramSelectAdapter extends RecyclerView.Adapter { + ViewGroup parent; + @NonNull + @Override + public ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.content_select_face_datagram, parent, false); + this.parent = parent; + return new ViewPagerViewHolder(view); + } + + ListView listView; + ListView listView1; + SwipeRefreshLayout swipeRefreshLayout; + @Override + public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) { + + if(position == 0){ + swipeRefreshLayout = holder.itemView.findViewById(R.id.swiperFresh); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + refresh_lv0(); +// new Util().DownloadDatagramByName1("abccc"); +// System.out.println("download abccc"); + swipeRefreshLayout.setRefreshing(false); + } + }); + System.out.println("in onbindviewholder position is "+position); + listView = holder.itemView.findViewById(R.id.list); + refresh_lv0(); +// Button button = holder.itemView.findViewById(R.id.button); + +// button.setOnClickListener(new View.OnClickListener() { +// @SuppressLint("StaticFieldLeak") +// @Override +// public void onClick(View v) { +// String login_id = "1"; +// new AsyncTask() { +// +// +// @Override +// protected String doInBackground(String... arg0) { +// String res = new Util().GetAvailableDatagrams("id"); +// return res; +// } +// +// protected void onPostExecute(String result) { +// if (result != null) { +// Toast.makeText(parent.getContext(), "刷新完成", Toast.LENGTH_SHORT).show(); +// updateListView0(result); +// } else { +// Toast.makeText(parent.getContext(), "刷新失败,检查网络", Toast.LENGTH_SHORT).show(); +// } +// } +// }.execute("1"); +// } +// }); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + @SuppressLint("StaticFieldLeak") + public void onItemClick(AdapterView parent, View view, int position, long id) { + System.out.println("position "+position); + String name = ((HashMap)(listView.getItemAtPosition(position))).get("name"); + System.out.println(name); + new AsyncTask(){ + @Override + protected String doInBackground(String... arg0){ + String res = new Util().DownloadDatagramByName1(arg0[0]); + return res; + } + protected void onPostExecute(String result) { + if (result != null) { + MDToast.makeText(parent.getContext(), "下载完成", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + System.out.println(result); + }else{ + MDToast.makeText(parent.getContext(), "下载失败,网络或远程服务器故障", MDToast.LENGTH_SHORT, MDToast.TYPE_ERROR).show(); + } + } + }.execute(name); + } + }); + } + else { + swipeRefreshLayout = holder.itemView.findViewById(R.id.swiperFresh); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + refresh_lv1(); + swipeRefreshLayout.setRefreshing(false); + } + }); + listView1 = holder.itemView.findViewById(R.id.list); + System.out.println("in onbindviewholder position is " + position); + listView1.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + AlertDialog alertDialog; + + public void upload_dialog(String filename){ +// alertDialog.hide(); + alertDialog.dismiss(); + System.out.println("before create pd"); + ProgressDialog dialog = new ProgressDialog(parent.getContext()); + dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + dialog.setCancelable(false); + dialog.setCanceledOnTouchOutside(false); + dialog.setTitle("选择操作"); + System.out.println("before setting listener"); + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + MDToast.makeText(parent.getContext(), "上传成功", Utils.dura_short, Utils.Type_success).show(); +// Toast.makeText(parent.getContext(), "上传成功", Toast.LENGTH_SHORT).show(); + } + }); + dialog.setMessage("正在上传,请稍等"); + System.out.println("before show"); + dialog.show(); +// dialog.setMax(100); + + Util util = new Util(); + new AsyncTask(){ + @Override + protected String doInBackground(String... arg0){ + String res = util.UploadVideoByName(arg0[0]); + return res; + } + + protected void onPostExecute(String result){ + if (result != null){ + MDToast.makeText(parent.getContext(), "上传完成", Utils.dura_short, Utils.Type_success).show(); +// Toast.makeText(parent.getContext(), "上传完成",Toast.LENGTH_SHORT).show(); + System.out.println(result); + }else{ +// Toast.makeText(parent.getContext(), "上传失败,检查网络或服务器",Toast.LENGTH_SHORT).show(); + MDToast.makeText(parent.getContext(), "上传失败,检查网络或服务器", Utils.dura_short, Utils.Type_warning).show(); + + } + } + }.execute(filename); + + System.out.println("before while"); + while(util.upload_progress < 0.99){ + System.out.println("in while up is "+ util.upload_progress); + dialog.setProgress((int)(100 * util.upload_progress)); + try { + Thread.sleep(400); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +// Toast.makeText(parent.getContext(),"上传成功", Toast.LENGTH_SHORT).show(); + dialog.dismiss(); + + } + + @Override + @SuppressLint("StaticFieldLeak") + public void onItemClick(AdapterView parent, View view, int position, long id) { + System.out.println("position "+position); + String name = ((HashMap)(listView1.getItemAtPosition(position))).get("name"); + System.out.println(name); + + final String[] choices = new String[]{"预览", "删除"}; + + alertDialog = new AlertDialog.Builder(parent.getContext()) + .setTitle("操作"+name) + .setIcon(R.drawable.ic_logo_pytorch) + .setItems(choices, new DialogInterface.OnClickListener() {//添加列表 + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if(i==0)//预览 + { + //TODO call media here + File file = new File(new Util().datagram_path , name); + System.out.println("in onclick video path is " + file.getAbsolutePath()); + Intent intent = new Intent(Intent.ACTION_VIEW); + + + if (file.exists()){ + Uri contentUri = FileProvider.getUriForFile(parent.getContext(), "authority", file); +// Uri uri = Uri.fromFile(file); + parent.getContext().grantUriPermission(parent.getContext().getPackageName(), contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + + String type = Utils.getMIMEType(file); + System.out.println("type is " + type); + System.out.println("uri is " + contentUri.getPath()); + intent.setDataAndType(contentUri, type); + parent.getContext().startActivity(intent); + MDToast.makeText(parent.getContext(), "成功打开", Utils.dura_short, Utils.Type_success).show(); + }else{ + MDToast.makeText(parent.getContext(), "文件不存在,文件路径错误", Utils.dura_short, Utils.Type_error).show(); + } + } + else if (i == 1)//删除 + { + new AlertDialog.Builder(parent.getContext()) + .setTitle("删除 " + name) + .setMessage("是否确定删除 "+ name) + + // Specifying a listener allows you to take an action before dismissing the dialog. + // The dialog is automatically dismissed when a dialog button is clicked. + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // Continue with delete operation + new Util().delete_datagram(name); + MDToast.makeText(parent.getContext(), "文件已删除", Utils.dura_short, Utils.Type_success).show(); + } + }) + + // A null listener allows the button to dismiss the dialog and take no further action. + .setNegativeButton(android.R.string.no, null) + .setIcon(android.R.drawable.ic_dialog_alert) + .show(); + + } + } + }) + .create(); + + alertDialog.show(); + } + }); + + refresh_lv1(); + + } + + } + + private void refresh_lv1() { + String[] filenames = new Util().GetLocalDatagrams(); + MDToast.makeText(parent.getContext(), "刷新完成", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + updateListView1(filenames); + } + + @SuppressLint("StaticFieldLeak") + private void refresh_lv0() { + String login_id = "admin"; + new AsyncTask() { + + + @Override + protected String doInBackground(String... arg0) { + String res = new Util().getAvailableDatagrams(arg0[0]); + return res; + } + + protected void onPostExecute(String result) { + if (result != null) { + MDToast.makeText(parent.getContext(), "刷新完成", MDToast.LENGTH_SHORT, MDToast.TYPE_SUCCESS).show(); + updateListView0(result); + } else { + MDToast.makeText(parent.getContext(), "刷新失败,网络或远程服务器故障", MDToast.LENGTH_SHORT, MDToast.TYPE_ERROR).show(); + } + } + }.execute(login_id); + } + + public void updateListView1(String[] filenames){ + if (filenames.length == 0){ + return; + } + System.out.println("in updata listview first filename string is "+filenames[0]); + ArrayList> list = new ArrayList<>(); + + + for (int i = 0; i < filenames.length; i++){ + Map map= new HashMap<>(); + map.put("name", filenames[i]); +// map.put("mission", jsonArraym.getString(i)); +// map.put("site", jsonArrays.getString(i)); + list.add(map); + } + + + SimpleAdapter adapter = new SimpleAdapter( + parent.getContext(), + list, + R.layout.datagram_list_item, + new String[]{"name"}, + new int[]{R.id.text1}); + + + listView1.setAdapter(adapter); + } + + public void updateListView0(String jsonString){ + System.out.println("in updata listview json string is "+jsonString); + ArrayList> list = new ArrayList<>(); + try{ + JSONObject jsonObject = new JSONObject(jsonString); +// int count = jsonObject.getInt("datagram_len"); +// int count = jsonObject.length(); + + JSONArray jsonArrayn = jsonObject.getJSONArray("datagram_name"); + JSONArray jsonArraym = jsonObject.getJSONArray("datagram_describe"); + int count = jsonArrayn.length(); +// JSONArray jsonArrays = jsonObject.getJSONArray("datagram site"); + + for (int i = 0; i < count; i++){ + Map map= new HashMap<>(); + map.put("name", jsonArrayn.getString(i)); + map.put("describe", jsonArraym.getString(i)); +// map.put("site", jsonArrays.getString(i)); + list.add(map); + } + }catch (JSONException jsonException){ + jsonException.printStackTrace(); + } + + SimpleAdapter adapter = new SimpleAdapter(parent.getContext(), + list, + R.layout.datagram_list_item, + new String[]{"name", "describe"}, + new int[]{R.id.text1, R.id.text2}); + + listView.setAdapter(adapter); + + + + + } + @Override + public int getItemCount() { + return 2; + } + + public DatagramSelectAdapter() { + super(); + } + + public class ViewPagerViewHolder extends RecyclerView.ViewHolder{ + public ViewPagerViewHolder(View itemView){ + super(itemView); + } + } + +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/BASE64Decoder.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/BASE64Decoder.java new file mode 100644 index 00000000..dd50a61c --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/BASE64Decoder.java @@ -0,0 +1,100 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package org.pytorch.demo.Decoder; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PushbackInputStream; + +import org.pytorch.demo.Decoder.CEFormatException; +import org.pytorch.demo.Decoder.CEStreamExhausted; +import org.pytorch.demo.Decoder.CharacterDecoder; + +public class BASE64Decoder extends CharacterDecoder { + private static final char[] pem_array = new char[]{'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', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + private static final byte[] pem_convert_array = new byte[256]; + byte[] decode_buffer = new byte[4]; + + static { + int i; + for(i = 0; i < 255; ++i) { + pem_convert_array[i] = -1; + } + + for(i = 0; i < pem_array.length; ++i) { + pem_convert_array[pem_array[i]] = (byte)i; + } + + } + + public BASE64Decoder() { + } + + protected int bytesPerAtom() { + return 4; + } + + protected int bytesPerLine() { + return 72; + } + + protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int rem) throws IOException { + byte a = -1; + byte b = -1; + byte c = -1; + byte d = -1; + if (rem < 2) { + throw new CEFormatException("BASE64Decoder: Not enough bytes for an atom."); + } else { + int i; + do { + i = inStream.read(); + if (i == -1) { + throw new CEStreamExhausted(); + } + } while(i == 10 || i == 13); + + this.decode_buffer[0] = (byte)i; + i = this.readFully(inStream, this.decode_buffer, 1, rem - 1); + if (i == -1) { + throw new CEStreamExhausted(); + } else { + if (rem > 3 && this.decode_buffer[3] == 61) { + rem = 3; + } + + if (rem > 2 && this.decode_buffer[2] == 61) { + rem = 2; + } + + switch(rem) { + case 4: + d = pem_convert_array[this.decode_buffer[3] & 255]; + case 3: + c = pem_convert_array[this.decode_buffer[2] & 255]; + case 2: + b = pem_convert_array[this.decode_buffer[1] & 255]; + a = pem_convert_array[this.decode_buffer[0] & 255]; + default: + switch(rem) { + case 2: + outStream.write((byte)(a << 2 & 252 | b >>> 4 & 3)); + break; + case 3: + outStream.write((byte)(a << 2 & 252 | b >>> 4 & 3)); + outStream.write((byte)(b << 4 & 240 | c >>> 2 & 15)); + break; + case 4: + outStream.write((byte)(a << 2 & 252 | b >>> 4 & 3)); + outStream.write((byte)(b << 4 & 240 | c >>> 2 & 15)); + outStream.write((byte)(c << 6 & 192 | d & 63)); + } + + } + } + } + } +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/BASE64Encoder.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/BASE64Encoder.java new file mode 100644 index 00000000..b91b86ed --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/BASE64Encoder.java @@ -0,0 +1,59 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package org.pytorch.demo.Decoder; + +import java.io.IOException; +import java.io.OutputStream; +import org.pytorch.demo.Decoder.CharacterDecoder; +//import CharacterEncoder; + +public class BASE64Encoder extends CharacterEncoder { + private static final char[] pem_array = new char[]{'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', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + + public BASE64Encoder() { + } + + protected int bytesPerAtom() { + return 3; + } + + protected int bytesPerLine() { + return 57; + } + + protected void encodeAtom(OutputStream outStream, byte[] data, int offset, int len) throws IOException { + byte a; + if (len == 1) { + a = data[offset]; + byte b = 0; +// byte c = (Byte)false; + outStream.write(pem_array[a >>> 2 & 63]); + outStream.write(pem_array[(a << 4 & 48) + (b >>> 4 & 15)]); + outStream.write(61); + outStream.write(61); + } else { + byte b; + if (len == 2) { + a = data[offset]; + b = data[offset + 1]; + byte c = 0; + outStream.write(pem_array[a >>> 2 & 63]); + outStream.write(pem_array[(a << 4 & 48) + (b >>> 4 & 15)]); + outStream.write(pem_array[(b << 2 & 60) + (c >>> 6 & 3)]); + outStream.write(61); + } else { + a = data[offset]; + b = data[offset + 1]; + byte c = data[offset + 2]; + outStream.write(pem_array[a >>> 2 & 63]); + outStream.write(pem_array[(a << 4 & 48) + (b >>> 4 & 15)]); + outStream.write(pem_array[(b << 2 & 60) + (c >>> 6 & 3)]); + outStream.write(pem_array[c & 63]); + } + } + + } +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CEFormatException.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CEFormatException.java new file mode 100644 index 00000000..2e7e8e14 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CEFormatException.java @@ -0,0 +1,14 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package org.pytorch.demo.Decoder; + +import java.io.IOException; + +public class CEFormatException extends IOException { + public CEFormatException(String s) { + super(s); + } +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CEStreamExhausted.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CEStreamExhausted.java new file mode 100644 index 00000000..4ec96075 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CEStreamExhausted.java @@ -0,0 +1,13 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package org.pytorch.demo.Decoder; + +import java.io.IOException; + +public class CEStreamExhausted extends IOException { + public CEStreamExhausted() { + } +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CharacterDecoder.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CharacterDecoder.java new file mode 100644 index 00000000..bb1dd765 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CharacterDecoder.java @@ -0,0 +1,109 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package org.pytorch.demo.Decoder; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PushbackInputStream; +import java.nio.ByteBuffer; + +import org.pytorch.demo.Decoder.CEStreamExhausted; + +public abstract class CharacterDecoder { + public CharacterDecoder() { + } + + protected abstract int bytesPerAtom(); + + protected abstract int bytesPerLine(); + + protected void decodeBufferPrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException { + } + + protected void decodeBufferSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { + } + + protected int decodeLinePrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException { + return this.bytesPerLine(); + } + + protected void decodeLineSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { + } + + protected void decodeAtom(PushbackInputStream aStream, OutputStream bStream, int l) throws IOException { + throw new CEStreamExhausted(); + } + + protected int readFully(InputStream in, byte[] buffer, int offset, int len) throws IOException { + for(int i = 0; i < len; ++i) { + int q = in.read(); + if (q == -1) { + return i == 0 ? -1 : i; + } + + buffer[i + offset] = (byte)q; + } + + return len; + } + + public void decodeBuffer(InputStream aStream, OutputStream bStream) throws IOException { + int totalBytes = 0; + PushbackInputStream ps = new PushbackInputStream(aStream); + this.decodeBufferPrefix(ps, bStream); + + while(true) { + try { + int length = this.decodeLinePrefix(ps, bStream); + + int i; + for(i = 0; i + this.bytesPerAtom() < length; i += this.bytesPerAtom()) { + this.decodeAtom(ps, bStream, this.bytesPerAtom()); + totalBytes += this.bytesPerAtom(); + } + + if (i + this.bytesPerAtom() == length) { + this.decodeAtom(ps, bStream, this.bytesPerAtom()); + totalBytes += this.bytesPerAtom(); + } else { + this.decodeAtom(ps, bStream, length - i); + totalBytes += length - i; + } + + this.decodeLineSuffix(ps, bStream); + } catch (CEStreamExhausted var8) { + this.decodeBufferSuffix(ps, bStream); + return; + } + } + } + + public byte[] decodeBuffer(String inputString) throws IOException { + byte[] inputBuffer = new byte[inputString.length()]; + inputString.getBytes(0, inputString.length(), inputBuffer, 0); + ByteArrayInputStream inStream = new ByteArrayInputStream(inputBuffer); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + this.decodeBuffer(inStream, outStream); + return outStream.toByteArray(); + } + + public byte[] decodeBuffer(InputStream in) throws IOException { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + this.decodeBuffer(in, outStream); + return outStream.toByteArray(); + } + + public ByteBuffer decodeBufferToByteBuffer(String inputString) throws IOException { + return ByteBuffer.wrap(this.decodeBuffer(inputString)); + } + + public ByteBuffer decodeBufferToByteBuffer(InputStream in) throws IOException { + return ByteBuffer.wrap(this.decodeBuffer(in)); + } +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CharacterEncoder.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CharacterEncoder.java new file mode 100644 index 00000000..1f8d1b0f --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/Decoder/CharacterEncoder.java @@ -0,0 +1,186 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package org.pytorch.demo.Decoder; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.ByteBuffer; + +public abstract class CharacterEncoder { + protected PrintStream pStream; + + public CharacterEncoder() { + } + + protected abstract int bytesPerAtom(); + + protected abstract int bytesPerLine(); + + protected void encodeBufferPrefix(OutputStream aStream) throws IOException { + this.pStream = new PrintStream(aStream); + } + + protected void encodeBufferSuffix(OutputStream aStream) throws IOException { + } + + protected void encodeLinePrefix(OutputStream aStream, int aLength) throws IOException { + } + + protected void encodeLineSuffix(OutputStream aStream) throws IOException { + this.pStream.println(); + } + + protected abstract void encodeAtom(OutputStream var1, byte[] var2, int var3, int var4) throws IOException; + + protected int readFully(InputStream in, byte[] buffer) throws IOException { + for(int i = 0; i < buffer.length; ++i) { + int q = in.read(); + if (q == -1) { + return i; + } + + buffer[i] = (byte)q; + } + + return buffer.length; + } + + public void encode(InputStream inStream, OutputStream outStream) throws IOException { + byte[] tmpbuffer = new byte[this.bytesPerLine()]; + this.encodeBufferPrefix(outStream); + + while(true) { + int numBytes = this.readFully(inStream, tmpbuffer); + if (numBytes == 0) { + break; + } + + this.encodeLinePrefix(outStream, numBytes); + + for(int j = 0; j < numBytes; j += this.bytesPerAtom()) { + if (j + this.bytesPerAtom() <= numBytes) { + this.encodeAtom(outStream, tmpbuffer, j, this.bytesPerAtom()); + } else { + this.encodeAtom(outStream, tmpbuffer, j, numBytes - j); + } + } + + if (numBytes < this.bytesPerLine()) { + break; + } + + this.encodeLineSuffix(outStream); + } + + this.encodeBufferSuffix(outStream); + } + + public void encode(byte[] aBuffer, OutputStream aStream) throws IOException { + ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); + this.encode((InputStream)inStream, aStream); + } + + public String encode(byte[] aBuffer) { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); + String retVal = null; + + try { + this.encode((InputStream)inStream, outStream); + retVal = outStream.toString("8859_1"); + return retVal; + } catch (Exception var6) { + throw new Error("CharacterEncoder.encode internal error"); + } + } + + private byte[] getBytes(ByteBuffer bb) { + byte[] buf = (byte[])null; + if (bb.hasArray()) { + byte[] tmp = bb.array(); + if (tmp.length == bb.capacity() && tmp.length == bb.remaining()) { + buf = tmp; + bb.position(bb.limit()); + } + } + + if (buf == null) { + buf = new byte[bb.remaining()]; + bb.get(buf); + } + + return buf; + } + + public void encode(ByteBuffer aBuffer, OutputStream aStream) throws IOException { + byte[] buf = this.getBytes(aBuffer); + this.encode(buf, aStream); + } + + public String encode(ByteBuffer aBuffer) { + byte[] buf = this.getBytes(aBuffer); + return this.encode(buf); + } + + public void encodeBuffer(InputStream inStream, OutputStream outStream) throws IOException { + byte[] tmpbuffer = new byte[this.bytesPerLine()]; + this.encodeBufferPrefix(outStream); + + int numBytes; + do { + numBytes = this.readFully(inStream, tmpbuffer); + if (numBytes == 0) { + break; + } + + this.encodeLinePrefix(outStream, numBytes); + + for(int j = 0; j < numBytes; j += this.bytesPerAtom()) { + if (j + this.bytesPerAtom() <= numBytes) { + this.encodeAtom(outStream, tmpbuffer, j, this.bytesPerAtom()); + } else { + this.encodeAtom(outStream, tmpbuffer, j, numBytes - j); + } + } + + this.encodeLineSuffix(outStream); + } while(numBytes >= this.bytesPerLine()); + + this.encodeBufferSuffix(outStream); + } + + public void encodeBuffer(byte[] aBuffer, OutputStream aStream) throws IOException { + ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); + this.encodeBuffer((InputStream)inStream, aStream); + } + + public String encodeBuffer(byte[] aBuffer) { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); + + try { + this.encodeBuffer((InputStream)inStream, outStream); + } catch (Exception var5) { + throw new Error("CharacterEncoder.encodeBuffer internal error"); + } + + return outStream.toString(); + } + + public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream) throws IOException { + byte[] buf = this.getBytes(aBuffer); + this.encodeBuffer(buf, aStream); + } + + public String encodeBuffer(ByteBuffer aBuffer) { + byte[] buf = this.getBytes(aBuffer); + return this.encodeBuffer(buf); + } +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/FaceDetectionActivity.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/FaceDetectionActivity.java new file mode 100644 index 00000000..33dd9122 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/FaceDetectionActivity.java @@ -0,0 +1,1005 @@ +package org.pytorch.demo; + +//package org.pytorch.demo; +// +//import android.Manifest; +//import android.annotation.SuppressLint; +//import android.content.BroadcastReceiver; +//import android.content.ComponentName; +//import android.content.Context; +//import android.content.Intent; +//import android.content.IntentFilter; +//import android.content.ServiceConnection; +//import android.content.pm.PackageManager; +//import android.graphics.Bitmap; +//import android.graphics.Canvas; +//import android.graphics.Color; +//import android.graphics.Matrix; +//import android.graphics.Paint; +//import android.graphics.Rect; +//import android.net.Uri; +//import android.os.Bundle; +//import android.os.Environment; +//import android.os.IBinder; +//import android.os.StrictMode; +//import android.os.SystemClock; +//import android.text.TextUtils; +//import android.util.Log; +//import android.util.Size; +//import android.view.SurfaceView; +//import android.view.TextureView; +//import android.view.View; +//import android.view.ViewStub; +//import android.widget.Button; +//import android.widget.ImageView; +//import android.widget.TextView; +//import android.widget.Toast; +// +//import org.pytorch.IValue; +//import org.pytorch.Module; +//import org.pytorch.Tensor; +//import org.pytorch.demo.Constants; +//import org.pytorch.demo.R; +//import org.pytorch.demo.Utils; +//import org.pytorch.demo.YuvToRgbConverter; +// +//import org.pytorch.demo.util.Util; +//import org.pytorch.demo.vision.AbstractCameraXActivity; +//import org.pytorch.demo.vision.Helper.GraphicOverlay; +//import org.pytorch.demo.vision.Helper.DrawImageView; +//import org.pytorch.demo.vision.Helper.RectOverlay; +//import org.pytorch.demo.vision.view.ResultRowView; +//import org.pytorch.torchvision.TensorImageUtils; +// +//import java.io.ByteArrayOutputStream; +//import java.io.File; +//import java.io.FileInputStream; +//import java.io.FileNotFoundException; +//import java.io.IOException; +//import java.lang.reflect.Array; +//import java.net.URI; +//import java.nio.ByteBuffer; +//import java.nio.FloatBuffer; +//import java.nio.charset.StandardCharsets; +//import java.sql.SQLOutput; +//import java.util.ArrayList; +//import java.util.Arrays; +//import java.util.Iterator; +//import java.util.LinkedList; +//import java.util.Locale; +//import java.util.Queue; +// +//import androidx.annotation.Nullable; +//import androidx.annotation.WorkerThread; +//import androidx.camera.core.CameraX; +//import androidx.camera.core.ImageAnalysis; +////import androidx.camera.core.ImageAnalysisConfig; +//import androidx.camera.core.ImageProxy; +//import androidx.camera.core.Preview; +////import androidx.camera.core.PreviewConfig; +//import androidx.camera.core.VideoCapture; +//import androidx.core.app.ActivityCompat; +// +// +//import static java.lang.Math.floor; +//import static java.lang.Math.max; +//import static java.lang.Math.min; +//import static org.pytorch.demo.Utils.IoU; +//import static org.pytorch.demo.Utils.expand_box; +//import static org.pytorch.demo.Utils.nms; +//import static org.pytorch.demo.Utils.possible_score; +// +//import com.neovisionaries.ws.client.HostnameUnverifiedException; +//import com.neovisionaries.ws.client.OpeningHandshakeException; +//import com.neovisionaries.ws.client.WebSocketAdapter; +//import com.neovisionaries.ws.client.WebSocketException; +//import com.neovisionaries.ws.client.WebSocketFactory; +//import com.neovisionaries.ws.client.WebSocket; +//import org.json.*; +//import org.pytorch.demo.Utils.NamedEmbedding; +//import org.pytorch.demo.Utils.NamedBox; +// +public class FaceDetectionActivity{ + +} +// +//public class FaceDetectionActivity extends AbstractCameraXActivity { +// +// public static final String INTENT_MODULE_ASSET_NAME = "INTENT_MODULE_ASSET_NAME"; +// public static final String INTENT_INFO_VIEW_TYPE = "INTENT_INFO_VIEW_TYPE"; +// +// private static final int INPUT_TENSOR_WIDTH = 360; +// private static final int INPUT_TENSOR_HEIGHT = 480; +// private static final int TOP_K = Utils.TOP_K; +// private static final int MOVING_AVG_PERIOD = 10; +// private static final String FORMAT_MS = "%dms"; +// private static final String FORMAT_AVG_MS = "avg:%.0fms"; +// private static final String FORMAT_FPS = "%.1fFPS"; +// public static final String SCORES_FORMAT = "%.2f"; +// private GraphicOverlay graphicOverlay; +// private DrawImageView drawImageView; +// private ViewStub viewStub; +// private WebSocketFactory webSocketFactory; +//// private Button local_remote_switcher; +// private Button record; +// +// +// static class AnalysisResult { +// +// private final String[] topNClassNames; +// private final float[] topNScores; +// private final long analysisDuration; +// private final long moduleForwardDuration; +// private final Bitmap bitmap_c; +// +// +// public AnalysisResult(String[] topNClassNames, float[] topNScores, Bitmap bitmap_c, +// long moduleForwardDuration, long analysisDuration) { +// this.topNClassNames = topNClassNames; +// this.topNScores = topNScores; +// this.moduleForwardDuration = moduleForwardDuration; +// this.analysisDuration = analysisDuration; +// this.bitmap_c = bitmap_c; +// } +// } +// +// private boolean mAnalyzeImageErrorState; +// private ResultRowView[] mResultRowViews = new ResultRowView[TOP_K]; +// private TextView mFpsText; +// private TextView mMsText; +// private TextView mMsAvgText; +// private Module mModule; +// private Module encoder; +// private String mModuleAssetName; +// private FloatBuffer mInputTensorBuffer; +// private Tensor mInputTensor; +// private long mMovingAvgSum = 0; +// private Queue mMovingAvgQueue = new LinkedList<>(); +// private Bitmap bitmap_c = null; +// private float[] box_c = null; +// +// private ImageView imageView; +// +// private ArrayList namedboxpool; +// private ArrayList namedEmbeddings; +// private int detect_mode; +// private final int LOCAL = 0; +// private final int REMOTE = 1; +// private BitmapToVideoEncoder bitmapToVideoEncoder = null; +// private int video_height = 1280; +// private int video_width = 960; +// private String record_mode = null; +//// private String deliminator = "\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$"; +// +// +//// private void get_embeddings(){ +//// webSocket.sendText("get embeddings"); +//// } +//// private String get_embeddings_from_files(){ +////// File Directory = getFilesDir(); +//// File[] files = new Util(this).GetLocalDatagramFiles(); +//// String embedding_str = ""; +//// if(files.length == 0) +//// return ""; +//// for (File f: files){ +//// System.out.println("in fda reading file " + f.getName()); +//// try{ +//// FileInputStream fileInputStream = new FileInputStream(f); +//// int length = fileInputStream.available(); +//// byte bytes[] = new byte[length]; +//// fileInputStream.read(bytes); +//// fileInputStream.close(); +//// String str =new String(bytes, StandardCharsets.UTF_8); +//// embedding_str += str; +//// System.out.println("str len is "+str.length()+" and total embedding len is "+ embedding_str.length()); +//// +//// }catch (FileNotFoundException fileNotFoundException){ +//// fileNotFoundException.printStackTrace(); +//// } catch (IOException e) { +//// e.printStackTrace(); +//// } +//// +//// } +//// return embedding_str; +//// } +// private void update_embeddings(String str){ +// String[] strings = str.split(new Util(this).deliminator); +// for (String s : strings){ +// if(s.length() > 100){ +// namedEmbeddings.add(new NamedEmbedding(s)); +// } +// } +// ArrayList namedEmbeddings1 = new ArrayList<>(); +// for (NamedEmbedding namedEmbedding : namedEmbeddings){ +// if (namedEmbedding.id == null) +// continue; +// else +// namedEmbeddings1.add(namedEmbedding); +// } +// namedEmbeddings = namedEmbeddings1; +// System.out.println("namedEmbeddings.size() "+namedEmbeddings.size()); +// +// } +// +// +// +// @Override +// protected int getContentViewLayoutId() { +// return R.layout.activity_face_detection; +// } +// +// @Override +// protected TextureView getCameraPreviewTextureView() { +// return ((ViewStub) findViewById(R.id.image_classification_texture_view_stub)) +// .inflate() +// .findViewById(R.id.image_classification_texture_view); +// } +// +// @SuppressLint("SetTextI18n") +// @Override +// protected void onCreate(Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// final ResultRowView headerResultRowView = +// findViewById(R.id.image_classification_result_header_row); +// headerResultRowView.nameTextView.setText(R.string.face_of_attention); +// headerResultRowView.scoreTextView.setText(R.string.prediction); +// imageView = findViewById(R.id.imageView); +//// detect_mode = LOCAL; +//// local_remote_switcher = findViewById(R.id.local_remote_detect_switcher); +//// local_remote_switcher.setOnClickListener(new View.OnClickListener() { +//// @Override +//// public void onClick(View view){ +//// // Received a text message. +//// System.out.println("in onclick listener"); +//// String mode; +//// +//// if (detect_mode == REMOTE) { +//// detect_mode = LOCAL; +//// mode = "LOCAL"; +//// +//// } +//// else{ +//// detect_mode = REMOTE; +//// mode = "REMOTE"; +//// } +//// local_remote_switcher.setText(mode); +//// +//// Toast.makeText(FaceDetectionActivity.this, "detect mode changed to " + mode, Toast.LENGTH_SHORT).show(); +//// +//// +//// } +//// }); +// record = findViewById(R.id.record); +// record.setOnClickListener(new View.OnClickListener() { +//// @SuppressLint("RestrictedApi") +// @Override +// public void onClick(View view){ +// +// System.out.println("in onclick record listener"); +// +// //VideoCapture NOT SUPPORTED by current cameraX, wait till further implementation +// +//// // alternative +//// if ("recording".equals(record_mode)) { +//// stopRecord(); +//// Toast.makeText(FaceDetectionActivity.this, "stop recording", Toast.LENGTH_SHORT).show(); +//// record_mode = null; +//// } +//// else{ +//// +//// File sdDir = Environment.getExternalStorageDirectory(); +//// File video = new File(sdDir, "testcamerax.mp4"); +//// startRecord(video, FaceDetectionActivity.this); +//// Toast.makeText(FaceDetectionActivity.this, "start recording", Toast.LENGTH_SHORT).show(); +//// record_mode = "recording"; +//// } +//// +// +// +// +// +// if ("recording".equals(record_mode)) { +// bitmapToVideoEncoder.stopEncoding(); +//// bitmapToVideoEncoder = null; +// record_mode = null; +// } +// else{ +// bitmapToVideoEncoder = new BitmapToVideoEncoder(new BitmapToVideoEncoder.IBitmapToVideoEncoderCallback() { +// @Override +// public void onEncodingComplete(File outputFile) { +//// Toast.makeText(FaceDetectionActivity.this, "Encoding complete!", Toast.LENGTH_LONG).show(); +// Log.d("in listener", "stopped recording"); +// } +// }); +// File sdDir = Environment.getExternalStorageDirectory(); +// File video = new File(sdDir, "testpath.mp4"); +// bitmapToVideoEncoder.startEncoding(video_width, video_height, video); +// +// Toast.makeText(FaceDetectionActivity.this, "start recording", Toast.LENGTH_SHORT).show(); +// record_mode = "recording"; +// +// } +// +// } +// }); +// namedboxpool = new ArrayList<>(); +// namedEmbeddings = new ArrayList<>(); +//// webSocketFactory = new WebSocketFactory(); +////// WebSocket webSocket; +//// try{ +//// webSocket=webSocketFactory.createSocket(serverUri); +//// // Android 4.0 之后不能在主线程中请求HTTP请求 +////// new Thread(new Runnable(){ +////// @Override +////// public void run() { +////// try{ +////// webSocket.connect(); +////// }catch (WebSocketException exception) +////// { +////// exception.printStackTrace(); +////// } +////// +////// } +////// }).start(); +//// // force main thread permitting network +//// StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); +//// StrictMode.setThreadPolicy(policy); +//// +//// webSocket.connect(); +//// webSocket.addListener(new WebSocketAdapter() { +//// @Override +//// public void onTextMessage(WebSocket websocket, String message) throws Exception { +//// // Received a text message. +//// System.out.println("in listener, text message received "+ message); +//// +////// System.out.println(message); +//// //TODO info can be retrived here +//// // need further operation +//// // put box and info into boxpool +//// +//// if (message != null) +//// { +////// NamedBox namedBox = new NamedBox(message); +////// namedboxpool.add(namedBox); +//// update_embeddings(message); +//// } +//// else +//// System.out.println("in onTextMessage namedbox is null"); +//// +//// } +//// }); +//// webSocket.addListener(new WebSocketAdapter(){ +//// @Override +//// public void onBinaryMessage(WebSocket webSocket, byte[] bytes) throws Exception{ +//// System.out.println("in binary message listener received bytes of size " + bytes.length); +//// } +//// +//// }); +////// webSocket.sendText("String websocket"); +//// }catch (IOException ioe) +//// { +//// System.out.println(ioe.toString()); +//// } +//// catch (OpeningHandshakeException e) +//// { +//// // A violation against the WebSocket protocol was detected +//// // during the opening handshake. +//// } +//// catch (HostnameUnverifiedException e) +//// { +//// // The certificate of the peer does not match the expected hostname. +//// } +//// catch (WebSocketException e) +//// { +//// // Failed to establish a WebSocket connection. +//// } +// +// //get_embeddings from server +//// get_embeddings(); +// String embds = new Util().get_embeddings_from_files(); +// update_embeddings(embds); +// graphicOverlay = findViewById(R.id.graphic_overlay); +// graphicOverlay.bringToFront(); +// +// viewStub = (ViewStub) findViewById(R.id.image_classification_texture_view_stub); +//// drawImageView = findViewById(R.id.drawImageView); +//// drawImageView.bringToFront(); +// mResultRowViews[0] = findViewById(R.id.image_classification_top1_result_row); +// mResultRowViews[1] = findViewById(R.id.image_classification_top2_result_row); +// mResultRowViews[2] = findViewById(R.id.image_classification_top3_result_row); +// +// mFpsText = findViewById(R.id.image_classification_fps_text); +// mMsText = findViewById(R.id.image_classification_ms_text); +// mMsAvgText = findViewById(R.id.image_classification_ms_avg_text); +// +// } +// +//// public void send_croped_Image(Bitmap bitmap_c, float[] box_c) +//// { +//// System.out.println("in send cropped Image"); +////// webSocket.sendText("{\"message\": \"on create\"}"); +//// if (bitmap_c != null) +//// { +//// try { +//// String box = "["+box_c[0]+","+box_c[1]+","+box_c[2]+","+box_c[3]+ "]"; +//// String string = "{\"message\": \"cropped image\",\"box\": "+ box +"}"; +//// String deliminater = "$$$$$$$$$$"; +//// string = string + deliminater; +//// byte[] bytes1 = string.getBytes("UTF-8"); +//// ByteArrayOutputStream baos = new ByteArrayOutputStream(); +//// bitmap_c.compress(Bitmap.CompressFormat.JPEG, 100, baos); +//// byte[] bytes = baos.toByteArray(); +//// System.out.println("in onclick bytes len is " + bytes.length); +//// webSocket.sendBinary(byteMerger(bytes1, bytes)); +//// }catch (java.io.UnsupportedEncodingException uee) +//// { +//// uee.printStackTrace(); +//// } +//// +//// } +//// } +// +// +// public void update_namedboxpool() +// { +// ArrayList new_namedboxpool = new ArrayList<>(); +// for (NamedBox nb : namedboxpool) { +// if (nb.is_valid) +// new_namedboxpool.add(nb); //注意这个地方 +// } +// namedboxpool = new_namedboxpool; +// } +// +// public byte[] byteMerger(byte[] bt1, byte[] bt2){ +// byte[] bt3 = new byte[bt1.length+bt2.length]; +// System.arraycopy(bt1, 0, bt3, 0, bt1.length); +// System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length); +// return bt3; +// } +//// +//// @Override +//// public void onRequestPermissionsResult( +//// int requestCode, String[] permissions, int[] grantResults) { +//// if (requestCode == 2077) { +//// if (grantResults[0] == PackageManager.PERMISSION_DENIED) { +//// Toast.makeText( +//// this, +//// "You can't use image classification example without granting INTERNET permission", +//// Toast.LENGTH_LONG) +//// .show(); +//// finish(); +//// } +//// else if (grantResults[1] == PackageManager.PERMISSION_DENIED) { +//// Toast.makeText( +//// this, +//// "You can't store video without granting Write external storage permission", +//// Toast.LENGTH_LONG) +//// .show(); +//// finish(); +//// } +//// else if (grantResults[2] == PackageManager.PERMISSION_DENIED) { +//// Toast.makeText( +//// this, +//// "You can't record video without granting camera permission", +//// Toast.LENGTH_LONG) +//// .show(); +//// finish(); +//// } +//// } +//// +//// } +// +// +// private void output(final String txt) { +// runOnUiThread(new Runnable() { +// @Override +// public void run() { +//// output.setText(output.getText().toString() + "\n\n" + txt); +// //TODO change text of boxes here +// } +// }); +// } +// +// +// +// @Override +// protected void applyToUiAnalyzeImageResult(AnalysisResult result) { +// mMovingAvgSum += result.moduleForwardDuration; +// mMovingAvgQueue.add(result.moduleForwardDuration); +// if (mMovingAvgQueue.size() > MOVING_AVG_PERIOD) { +// mMovingAvgSum -= mMovingAvgQueue.remove(); +// } +// if (result.bitmap_c != null){ +// imageView.setImageBitmap(result.bitmap_c); +// +// Utils.convertDis2Prob(result.topNClassNames, result.topNScores); +// +// for (int i = 0; i < TOP_K; i++) { +// final ResultRowView rowView = mResultRowViews[i]; +// rowView.nameTextView.setText(result.topNClassNames[i]); +// rowView.scoreTextView.setText(String.format(Locale.US, SCORES_FORMAT, +// result.topNScores[i])); +// rowView.setProgressState(false); +// } +// } +// +// mMsText.setText(String.format(Locale.US, FORMAT_MS, result.moduleForwardDuration)); +// if (mMsText.getVisibility() != View.VISIBLE) { +// mMsText.setVisibility(View.VISIBLE); +// } +// mFpsText.setText(String.format(Locale.US, FORMAT_FPS, (1000.f / result.analysisDuration))); +// if (mFpsText.getVisibility() != View.VISIBLE) { +// mFpsText.setVisibility(View.VISIBLE); +// } +// +// if (mMovingAvgQueue.size() == MOVING_AVG_PERIOD) { +// float avgMs = (float) mMovingAvgSum / MOVING_AVG_PERIOD; +// mMsAvgText.setText(String.format(Locale.US, FORMAT_AVG_MS, avgMs)); +// if (mMsAvgText.getVisibility() != View.VISIBLE) { +// mMsAvgText.setVisibility(View.VISIBLE); +// } +// } +// } +// +// protected String getModuleAssetName() { +// if (!TextUtils.isEmpty(mModuleAssetName)) { +// return mModuleAssetName; +// } +// final String moduleAssetNameFromIntent = getIntent().getStringExtra(INTENT_MODULE_ASSET_NAME); +// mModuleAssetName = !TextUtils.isEmpty(moduleAssetNameFromIntent) +// ? moduleAssetNameFromIntent +// : "mobile_model2.pt"; +// +// return mModuleAssetName; +// } +// +// @Override +// protected String getInfoViewAdditionalText() { +// return getModuleAssetName(); +// } +// +// private Bitmap rotateBitmap(Bitmap origin, float alpha) { +// if (origin == null) { +// return null; +// } +// int width = origin.getWidth(); +// int height = origin.getHeight(); +// Matrix matrix = new Matrix(); +// matrix.setRotate(alpha); +// // 围绕原地进行旋转 +// Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false); +// if (newBM.equals(origin)) { +// return newBM; +// } +// origin.recycle(); +// return newBM; +// } +// +// /** +// * 裁剪 +// * +// * @param bitmap 原图 +// * @return 裁剪后的图像 +// */ +// private Bitmap cropBitmap(Bitmap bitmap, float[] rect) { +// try{ +// int x,y,w,h; +// x = (int) (bitmap.getWidth() * rect[0]); +// y = (int) (bitmap.getHeight() * rect[1]); +// +// w = (int) (bitmap.getWidth() * (rect[2]-rect[0])); +// h = (int) (bitmap.getHeight() * (rect[3]-rect[1])); +// +// return Bitmap.createBitmap(bitmap, x, y, w, h,null, false); +// }catch (IllegalArgumentException e) +// { +// e.printStackTrace(); +// } +// catch (Exception e1) +// { +// e1.printStackTrace(); +// } +// return null; +// +// } +// +// private Bitmap drawOnBitmap(Bitmap bitmap, ArrayList nms_boxes) { +// Canvas canvas = new Canvas(bitmap); +// int width = bitmap.getWidth(); +// int height = bitmap.getHeight(); +// Paint paint = new Paint(); +// paint.setColor(Color.RED); +// paint.setStyle(Paint.Style.STROKE);//不填充 +// paint.setStrokeWidth(1); //线的宽度 +// int left,top,right,bottom; +// for (int i = 0; i < nms_boxes.size(); i++) { +// left = (int) (nms_boxes.get(i)[0] * width); +// top = (int) (nms_boxes.get(i)[1] * height); +// right = (int) (nms_boxes.get(i)[2] * width); +// bottom = (int) (nms_boxes.get(i)[3] * height); +// +// canvas.drawRect(left, top, right, bottom, paint); +// } +// return bitmap; +// } +// +//// private void sendByOKHttp() { +//// new Thread(new Runnable() { +//// @Override +//// public void run() { +//// OkHttpClient client = new OkHttpClient(); +//// Request request = new Request.Builder().url("https://www.baidu.com").build(); +//// try { +//// Response response = client.newCall(request).execute();//发送请求 +//// String result = response.body().string(); +//// Log.d("tag in send ok http ", "result: " + result); +//// System.out.println("in run result is "); +//// System.out.println(result); +//// } catch (IOException e) { +//// e.printStackTrace(); +//// } +//// } +//// }).start(); +//// } +// @Override +// @WorkerThread +// @Nullable +// protected AnalysisResult analyzeImage(ImageProxy image, int rotationDegrees) { +// if (mAnalyzeImageErrorState) { +// return null; +// } +// +// NamedBox midbox = null; +// Bitmap bitmap2show = null; +// long moduleForwardDuration = 0; +// long moduleAnalysisDuration = 0; +// try { +// Bitmap bitmap; +// System.out.println("in analyze original image size is w "+image.getWidth() + " h "+image.getHeight()); +// bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888); +// YuvToRgbConverter yuvToRgbConverter = new YuvToRgbConverter(this); +// yuvToRgbConverter.yuvToRgb(image.getImage(), bitmap); +// bitmap = rotateBitmap(bitmap, rotationDegrees); +// +// if (detect_mode == LOCAL) +// { +// if (mModule == null || encoder == null) { +// try { +// final String moduleFileAbsoluteFilePath = new File( +// Utils.assetFilePath(this, "mobile_model2.pt")).getAbsolutePath(); +// mModule = Module.load(moduleFileAbsoluteFilePath); +// final String encoderFileAbsoluteFilePath = new File( +// Utils.assetFilePath(this, "encoder1.pt")).getAbsolutePath(); +// encoder = Module.load(encoderFileAbsoluteFilePath); +// }catch (Exception e) +// { +// Toast.makeText(this, "读取模型时出错", Toast.LENGTH_LONG).show(); +// e.printStackTrace(); +// } +// } +// +// bitmap2show = bitmap; +// final long startTime = SystemClock.elapsedRealtime(); +// +// float [] mean = new float[] {0.49804f, 0.49804f, 0.49804f}; +// float [] std = new float[] {0.501960f, 0.501960f, 0.501960f}; +// float nms_threshold = 0.4f; +// int w1 = bitmap.getWidth(); +// int h1 = bitmap.getHeight(); +// +// Bitmap bitmap1 = Bitmap.createScaledBitmap(bitmap,480,360,true); +//// if (bitmap.getWidth() > bitmap.getHeight()) +//// bitmap = Bitmap.createScaledBitmap(bitmap,480,360,true); +//// else +//// bitmap = Bitmap.createScaledBitmap(bitmap,360,480,true); +// Tensor inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmap1, mean, std); +// System.out.println(Arrays.toString(inputTensor.shape())); +// //Normalize input +//// inputTensor = Normalize_tensor(inputTensor, 127, 128); +// // running the model +// final long moduleForwardStartTime = SystemClock.elapsedRealtime(); +// final IValue[] output = mModule.forward(IValue.from(inputTensor)).toTuple(); +// moduleForwardDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime; +// +//// final Tensor outputTensor = mModule.forward(IValue.from(mInputTensor)).toTensor(); +// +// Tensor scores = output[0].toTensor(); +// Tensor boxes = output[1].toTensor(); +// float threshold = 0.8f; +// +// ArrayList possible_indexes = possible_score(scores, boxes, threshold); +// System.out.println("in onCreate len possible_indexes " + possible_indexes.size()); +// +// ArrayList nms_boxes = nms(boxes, scores, possible_indexes, nms_threshold); +// float ratio = 0.1f; +// nms_boxes = expand_box(nms_boxes, ratio); +// +// if (nms_boxes.size() > 0){ +// +//// +//// drawOnBitmap(bitmap, nms_boxes); +// int width = graphicOverlay.getWidth(); +// int height = (int) (width * h1/(1.0f * w1)); +// System.out.println("in if width is "+width+" height is "+height); +// +// //TODO make http request here to get identity of picture +//// send_unrecognized_image(bitmap, nms_boxes); +// Utils.get_unrecognized_face_embedding(bitmap, nms_boxes, encoder, namedEmbeddings, namedboxpool); +// set_namedboxpool_isvalid_false(); +// midbox = Utils.drawFaceResults(nms_boxes, width, height-100, graphicOverlay, namedboxpool); +//// set_prediction(bitmap, midbox); +// update_namedboxpool(); +// +// System.out.println("nms boxes "+nms_boxes.size()); +// +// } +// else +// { +// graphicOverlay.clear(); +// update_namedboxpool(); +// } +// moduleAnalysisDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime; +// +// System.out.println("inference time is "+moduleForwardDuration); +// } +//// else //remote detect: send whole image to server +//// { +//// +//// long moduleForwardStartTime = SystemClock.elapsedRealtime(); +////// send_whole_image(bitmap); +//// set_namedboxpool_isvalid_false(); +//// update_namedboxpool(); +//// moduleForwardDuration = moduleAnalysisDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime; +//// bitmap2show = bitmap; +//// +//// int width = graphicOverlay.getWidth(); +//// int w1 = bitmap.getWidth(); +//// int h1 = bitmap.getHeight(); +//// int height = (int) (width * h1/(1.0f * w1)); +//// midbox = drawFaceResults_nbp(width, height-100); +////// set_prediction(bitmap, midbox); +//// if (bitmapToVideoEncoder != null) { +//// bitmapToVideoEncoder.queueFrame(bitmap); +//// } +//// } +// +// +//// Bitmap bmp = bitmap.copy(Bitmap.Config.ARGB_8888, true); +//// Canvas canvas = new Canvas(bmp); +//// Paint paint = new Paint(); +//// paint.setColor(Color.BLUE); +//// paint.setAlpha(100); +//// for(int i = 0; i < nms_boxes.size(); i++) +//// { +//// float[] xyxy = {nms_boxes.get(i)[0]*bmp.getWidth(),nms_boxes.get(i)[1]*bmp.getHeight(),nms_boxes.get(i)[2]*bmp.getWidth(), nms_boxes.get(i)[3]*bmp.getHeight()}; +//// canvas.drawRect(xyxy[0], xyxy[1], xyxy[2], xyxy[3], paint); +//// } +//// +//// ImageView imageView = findViewById(R.id.image); +//// imageView.setImageBitmap(bmp); +// +//// final float[] scores = outputTensor.getDataAsFloatArray(); +//// final int[] ixs = Utils.topK(scores, TOP_K); +//// +//// final String[] topKClassNames = new String[TOP_K]; +//// final float[] topKScores = new float[TOP_K]; +//// for (int i = 0; i < TOP_K; i++) { +//// final int ix = ixs[i]; +//// topKClassNames[i] = Constants.IMAGENET_CLASSES[ix]; +//// topKScores[i] = scores[ix]; +//// } +//// final long analysisDuration = SystemClock.elapsedRealtime() - startTime; +//// return new AnalysisResult(topKClassNames, topKScores, moduleForwardDuration, analysisDuration); +// } catch (Exception e) { +// Log.e(Constants.TAG, "Error during image analysis", e); +// mAnalyzeImageErrorState = true; +// runOnUiThread(() -> { +// if (!isFinishing()) { +// showErrorDialog(v -> FaceDetectionActivity.this.finish()); +// } +// }); +// return null; +// } +// if (midbox == null) +// { +// return new AnalysisResult(new String[] {"NO INFO", "NO INFO", "NO INFO"}, new float[] {1f,1f,1f}, null, +// moduleForwardDuration, moduleAnalysisDuration) ; +// } +// else +// { +//// String name = "null"; +//// String career = "null"; +//// String message = "null"; +//// float prob = 1f; +// Bitmap bitmap_c = null; +// bitmap_c = cropBitmap(bitmap2show, midbox.rect); +//// try{ +//// JSONObject jsonObject = new JSONObject(midbox.info); +//// name = jsonObject.getString("id"); +//// career = jsonObject.getString("career"); +//// message = jsonObject.getString("message"); +//// prob = (float) jsonObject.getDouble("prob"); +//// bitmap_c = cropBitmap(bitmap2show, midbox.rect); +//// }catch (JSONException jsonException) {jsonException.printStackTrace();} +// +// return new AnalysisResult(new String[] {midbox.id_k[0], midbox.id_k[1], midbox.id_k[2]}, new float[] {midbox.prob_k[0],midbox.prob_k[1],midbox.prob_k[2]}, bitmap_c, +// moduleForwardDuration, moduleAnalysisDuration) ; +// +// } +// } +// +//// private void send_whole_image(Bitmap bitmap){ +//// System.out.println("in send whole Image"); +////// webSocket.sendText("{\"message\": \"on create\"}"); +//// if (bitmap != null) +//// { +//// try { +//// String string = "{\"message\": \"whole image\",\"box\": 0}"; +//// String deliminater = "$$$$$$$$$$"; +//// string = string + deliminater; +//// byte[] bytes1 = string.getBytes("UTF-8"); +//// ByteArrayOutputStream baos = new ByteArrayOutputStream(); +//// bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); +//// byte[] bytes = baos.toByteArray(); +//// System.out.println("in onclick bytes len is " + bytes.length); +//// webSocket.sendBinary(byteMerger(bytes1, bytes)); +//// }catch (java.io.UnsupportedEncodingException uee) +//// { +//// uee.printStackTrace(); +//// } +//// +//// } +//// } +// +// private void set_prediction(Bitmap bitmap, NamedBox nb){ +// if (nb == null) +// return; +// +// String name = "null"; +// float prob = 1f; +// try{ +// JSONObject jsonObject = new JSONObject(nb.info); +// name = jsonObject.getString("id"); +// prob = (float) jsonObject.getDouble("prob"); +// }catch (JSONException jsonException) {jsonException.printStackTrace();} +// mResultRowViews[0].nameTextView.setText(name); +// mResultRowViews[0].scoreTextView.setText(Float.toString(prob)); +// mResultRowViews[0].setProgressState(false); +// +//// +//// for (int i = 0; i < TOP_K; i++) { +//// final ResultRowView rowView = mResultRowViews[i]; +//// rowView.nameTextView.setText(result.topNClassNames[i]); +//// rowView.scoreTextView.setText(String.format(Locale.US, SCORES_FORMAT, +//// result.topNScores[i])); +//// rowView.setProgressState(false); +//// } +// } +// +// private void set_namedboxpool_isvalid_false() +// { +// for (NamedBox namedBox: namedboxpool) +// { +// namedBox.is_valid = false; +// } +// } +// +//// private void send_unrecognized_image(Bitmap bitmap, ArrayList nms_boxes){ +//// for (int i = 0; i < nms_boxes.size(); i++) +//// { +//// float[] box_c = nms_boxes.get(i).clone(); +//// boolean flag = true; +//// for (NamedBox namedBox: namedboxpool) +//// { +//// if (IoU(box_c, namedBox.rect) > 0.5) +//// { +//// flag = false; +//// } +//// } +//// if (flag){ +//// Bitmap bitmap_c = cropBitmap(bitmap, box_c); +//// send_croped_Image(bitmap_c, box_c); +//// } +//// } +//// +//// } +// +// +// +//// ArrayList nms(Tensor boxes, Tensor scores, ArrayList possible_indexes, float nms_threshold) +//// { +////// float[] sfloatArray = scores.getDataAsFloatArray(); +////// int slen = sfloatArray.length; +////// long snum = scores.shape()[2]; +////// slen = (int)(slen / snum); +//// +//// ArrayList nms_boxes = new ArrayList<>(); +//// float[] bfloatArray = boxes.getDataAsFloatArray(); +//// int blen = bfloatArray.length; +//// int bnum = (int) boxes.shape()[2]; +//// blen = (blen / bnum); +//// +//// +//// float[] box2 = {1,1,1,1,1}; +//// for(int i = 0; i < possible_indexes.size() / 2; i++) +//// { +//// float[] box1 = {0,0,0,0,0}; +//// int index = (int) (float) possible_indexes.get(i * 2); +//// for(int j = 0; j < bnum; j++) +//// { +//// box1[j] = bfloatArray[index * bnum + j]; +//// } +//// box1[bnum] = possible_indexes.get(i * 2 + 1); +//// boolean flag = true; +//// for(int j = 0; j < nms_boxes.size(); j++) +//// { +//// box2 = nms_boxes.get(j); +//// if(IoU(box1, box2) > nms_threshold) { +//// if (box2[bnum] > box1[bnum]) { //prob of box2 > box1 +//// nms_boxes.remove(j); +//// nms_boxes.add(box1); +//// flag = false; +//// } else { +//// flag = false; +//// break; +//// } +//// } +//// } +//// if (flag) +//// nms_boxes.add(box1); +//// +//// +//// } +//// +//// return nms_boxes; +//// } +// +// +// public Tensor Normalize_tensor(Tensor inputTensor, int mean, int std) +// { +// float[] floatArray = inputTensor.getDataAsFloatArray(); +// for (int i = 0; i < floatArray.length; i++) +// { +// floatArray[i] = (floatArray[i] - mean) / std; +// } +// return Tensor.fromBlob(floatArray,inputTensor.shape()); +// } +//// public ArrayList possible_score(Tensor scores, Tensor boxes, float threshold) +//// { +//// ArrayList list_index_prob = new ArrayList<>(); +//// float[] floatArray = scores.getDataAsFloatArray(); +//// int len = floatArray.length; +//// long num = scores.shape()[2]; +//// len = (int)(len / num); +//// System.out.println(len); +//// +//// +//// for (int i = 0; i < len; i++) +//// { +//// for (int j = 1; j < num; j++) +//// if (floatArray[(int) (i * num + j)] > threshold) +//// { +//// list_index_prob.add((float)i); +//// list_index_prob.add(floatArray[(int) (i * num + j)]); +//// System.out.println("porb is " + floatArray[(int) (i * num)] + " and " + floatArray[(int) (i * num + 1)]); +//// } +//// +//// } +//// +//// return list_index_prob; +//// } +// +// +// @Override +// protected int getInfoViewCode() { +// return getIntent().getIntExtra(INTENT_INFO_VIEW_TYPE, -1); +// } +// +// @Override +// protected void onDestroy() { +// super.onDestroy(); +// if (mModule != null) { +// mModule.destroy(); +// } +// } +//} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/FaceDetectionActivity2.kt b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/FaceDetectionActivity2.kt new file mode 100644 index 00000000..f0752e3a --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/FaceDetectionActivity2.kt @@ -0,0 +1,505 @@ +package org.pytorch.demo +import android.Manifest +import android.annotation.SuppressLint +import android.content.pm.PackageManager +import android.graphics.Bitmap +import android.graphics.Color +import android.os.Bundle +import android.os.SystemClock +import android.util.Log +import android.util.Size +import android.view.View +import android.widget.* +import androidx.appcompat.app.AppCompatActivity +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.Preview +import androidx.camera.core.VideoCapture +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.lifecycle.LifecycleOwner +import com.valdesekamdem.library.mdtoast.MDToast +import org.pytorch.IValue +import org.pytorch.Module +import org.pytorch.demo.Utils.* +import org.pytorch.demo.util.Util +import org.pytorch.demo.vision.Helper.GraphicOverlay +import org.pytorch.demo.vision.view.ResultRowView +import org.pytorch.torchvision.TensorImageUtils +import java.io.File +import java.util.* +import kotlin.collections.ArrayList + + +private const val REQUEST_CODE_PERMISSIONS = 10 +private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) +private val tag = FaceDetectionActivity2::class.java.simpleName + +@SuppressLint("RestrictedApi, ClickableViewAccessibility") +class FaceDetectionActivity2 : AppCompatActivity(), LifecycleOwner { + + private var lensFacing: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + private lateinit var preview: Preview + private lateinit var cameraSelector: CameraSelector + private lateinit var namedboxpool: ArrayList + private lateinit var viewFinder: PreviewView + private lateinit var captureButton: Button + private lateinit var videoCapture: VideoCapture + private lateinit var imageAnalysis: ImageAnalysis + private lateinit var btn_getImage: Button + private lateinit var imageView: ImageView + private lateinit var graphicOverlay: GraphicOverlay + private lateinit var namedEmbeddings: ArrayList + private lateinit var switch_cam: ImageView + + private var mResultRowViews = arrayOfNulls(Utils.TOP_K) + private lateinit var mFpsText: TextView + private lateinit var mMsText: TextView + private lateinit var mMsAvgText: TextView + + // private String deliminator = "\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$"; + private fun update_embeddings(str: String) { + val strings = str.split(Util(this).deliminator.toRegex()).toTypedArray() + for (s in strings) { + if (s.length > 100) { + namedEmbeddings.add(NamedEmbedding(s)) + } + } + val namedEmbeddings1 = java.util.ArrayList() + for (namedEmbedding in namedEmbeddings) { + if (namedEmbedding.id == null) continue else namedEmbeddings1.add(namedEmbedding) + } + namedEmbeddings = namedEmbeddings1 + println("namedEmbeddings.size() " + namedEmbeddings.size) + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.activity_face_detection2) + + viewFinder = findViewById(R.id.view_finder) + captureButton = findViewById(R.id.capture_button) + btn_getImage = findViewById(R.id.btn_getImage) + imageView = findViewById(R.id.imageView) + graphicOverlay = findViewById(R.id.graphicOverlay) + graphicOverlay.bringToFront() + switch_cam = findViewById(R.id.img_view_switch) + switch_cam.bringToFront() +// setBounds(R.mipmap.switch_camera, switch_cam) + namedEmbeddings = ArrayList() + namedboxpool = ArrayList() + + + mResultRowViews[0] = findViewById(R.id.image_classification_top1_result_row) + mResultRowViews[1] = findViewById(R.id.image_classification_top2_result_row) + mResultRowViews[2] = findViewById(R.id.image_classification_top3_result_row) + + + + val embds = Util()._embeddings_from_files + update_embeddings(embds) + + // Request camera permissions + if (allPermissionsGranted()) { + viewFinder.post { startCamera() } + } else { + ActivityCompat.requestPermissions( + this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS) + } + + + + btn_getImage.setOnClickListener { view : View -> + var bitmap = viewFinder.bitmap + imageView.setImageBitmap(bitmap) + runOnUiThread { + if (bitmap != null) { + analyzeImage(bitmap) + } + } + } + + switch_cam.setOnClickListener{ view : View -> + if(lensFacing == CameraSelector.DEFAULT_BACK_CAMERA) { + lensFacing = CameraSelector.DEFAULT_FRONT_CAMERA + bindCameraUseCases() + } + else{ + lensFacing = CameraSelector.DEFAULT_BACK_CAMERA + bindCameraUseCases() + } + } + + captureButton.setOnClickListener { + if (captureButton.text.equals("录像")) { + captureButton.setBackgroundColor(Color.GREEN) + captureButton.setText("录像中...") + switch_cam.isEnabled = false + val video_dir = File(Util().video_path) + if (!video_dir.exists()) { + video_dir.mkdir() + } + val child = Util().generateFileName() + val file = File(video_dir, "$child.mp4") + videoCapture.startRecording(file, ContextCompat.getMainExecutor(this), object: VideoCapture.OnVideoSavedCallback{ + override fun onVideoSaved(file: File) { + MDToast.makeText(this@FaceDetectionActivity2,"文件保存到$file", MDToast.LENGTH_LONG, MDToast.TYPE_INFO).show() + Log.i(tag, "Video File : $file") + } + + override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) { + Log.i(tag, "Video Error: $message") + } + +// override fun onError(videoCaptureError: VideoCapture.VideoCaptureError, message: String, cause: Throwable?) { +//// TODO("Not yet implemented") +// Log.i(tag, "Video Error: $message") +// } + }) + + } else if (captureButton.text.equals("录像中...")) { + captureButton.setBackgroundColor(Color.WHITE) + captureButton.setText("录像") + videoCapture.stopRecording() + switch_cam.isEnabled = true + Log.i(tag, "Video File stopped") + } + false + } + +// captureButton.setOnTouchListener { _, event -> +// if (event.action == MotionEvent.ACTION_DOWN) { +// captureButton.setBackgroundColor(Color.GREEN) +// videoCapture.startRecording(file, ContextCompat.getMainExecutor(this), object: VideoCapture.OnVideoSavedCallback{ +// override fun onVideoSaved(file: File) { +// MDToast.makeText(this@FaceDetectionActivity2,"文件保存到$file", MDToast.LENGTH_LONG, MDToast.TYPE_INFO) +// Log.i(tag, "Video File : $file") +// } +// +// override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) { +// Log.i(tag, "Video Error: $message") +// } +// +//// override fun onError(videoCaptureError: VideoCapture.VideoCaptureError, message: String, cause: Throwable?) { +////// TODO("Not yet implemented") +//// Log.i(tag, "Video Error: $message") +//// } +// }) +// +// } else if (event.action == MotionEvent.ACTION_UP) { +// captureButton.setBackgroundColor(Color.RED) +// videoCapture.stopRecording() +// Log.i(tag, "Video File stopped") +// } +// false +// } + } + private fun bindCameraUseCases() { + // Make sure that there are no other use cases bound to CameraX + val cameraProviderFuture = ProcessCameraProvider.getInstance(this) + + cameraProviderFuture.addListener(Runnable { + // Used to bind the lifecycle of cameras to the lifecycle owner + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + cameraProvider.unbindAll(); + // Preview + preview = Preview.Builder() + .build() + .also { + it.setSurfaceProvider(viewFinder.createSurfaceProvider()) + } + + // Select back camera as a default + cameraSelector = lensFacing + + + videoCapture = VideoCapture.Builder() + .setVideoFrameRate(35) +// .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY) + .setTargetResolution(Size(960, 1280)) + .build() + + try { + // Unbind use cases before rebinding + cameraProvider.unbindAll() + + // Bind use cases to camera + cameraProvider.bindToLifecycle( + this, cameraSelector, preview, videoCapture) + + } catch(exc: Exception) { + Log.e("tag", "Use case binding failed", exc) + } + + }, ContextCompat.getMainExecutor(this)) + } + /** + * + * @param drawableId drawableLeft drawableTop drawableBottom 所用的选择器 通过R.drawable.xx 获得 + * @param button 需要限定图片大小的ImageButton + */ + private fun setBounds(drawableId: Int, button: ImageButton) { + //定义底部标签图片大小和位置 + val drawable_news = resources.getDrawable(drawableId) + //当这个图片被绘制时,给他绑定一个矩形 ltrb规定这个矩形 (这里的长和宽写死了 自己可以可以修改成 形参传入) + drawable_news.setBounds(0, 0, 50, 50) + button.setImageDrawable(drawable_news); + } + override fun onRequestPermissionsResult( + requestCode: Int, permissions: Array, grantResults: IntArray) { + if (requestCode == REQUEST_CODE_PERMISSIONS) { + if (allPermissionsGranted()) { + viewFinder.post { startCamera() } + } else { + Toast.makeText(this, + "Permissions not granted by the user.", + Toast.LENGTH_SHORT).show() + finish() + } + } + } + + private fun allPermissionsGranted(): Boolean { + for (permission in REQUIRED_PERMISSIONS) { + if (ContextCompat.checkSelfPermission( + this, permission) != PackageManager.PERMISSION_GRANTED) { + return false + } + } + return true + } + +// private fun startCamera() { +// // Create configuration object for the viewfinder use case +//// val previewConfig = PreviewConfig.Builder().build() +// // Build the viewfinder use case +// val preview = Preview.Builder() +// val lensfacing: CameraSelector.LensFacing +// val cameraSelector = CameraSelector.Builder().requireLensFacing().build() +// +//// val videoCaptureConfig = VideoCaptureConfig. +//// // Create a configuration object for the video use case +//// val videoCaptureConfig = VideoCaptureConfig.Builder().apply { +//// setTargetRotation(viewFinder.display.rotation) +////// setTargetAspectRatio(Rational(4,3)) +////// setTargetResolution(Size(1280,960)) +//// .setLensFacing(CameraX.LensFacing.BACK) +//// .setVideoFrameRate(35) +////// .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY) +//// .setTargetResolution(Size(960, 1280)) +//// .setTargetAspectRatio(Rational(3,4)) +//// }.build() +// videoCapture = VideoCapture.Builder() +// .setVideoFrameRate(35) +//// .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY) +// .setTargetResolution(Size(960, 1280)) +// .setTargetAspectRatio(Rational(3,4)) +// .build() +// +// preview.set +//// preview.setOnPreviewOutputUpdateListener { +//// viewFinder.surfaceTexture = it.surfaceTexture +//// } +// +//// val imageAnalysisConfig = ImageAnalysisConfig.Builder().apply { +//// setTargetRotation(viewFinder.display.rotation) +//// }.build() +//// imageAnalysis = ImageAnalysis(imageAnalysisConfig) +//// imageAnalysis.setAnalyzer(ImageAnalysis.Analyzer { image, rotation-> +//// Log.i("image analysis", "analyzing " + image.height + " " + image.width) +//// // insert your code here. +//// }) +// // Bind use cases to lifecycle +// CameraX.bindToLifecycle(this, preview, videoCapture) +// } + private fun startCamera() { +// val cameraProviderFuture = ProcessCameraProvider.getInstance(this) +// +// cameraProviderFuture.addListener(Runnable { +// // Used to bind the lifecycle of cameras to the lifecycle owner +// val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() +// +// // Preview +// preview = Preview.Builder() +// .build() +// .also { +// it.setSurfaceProvider(viewFinder.createSurfaceProvider()) +// } +// +// // Select back camera as a default +// cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA +// +// +// videoCapture = VideoCapture.Builder() +// .setVideoFrameRate(35) +//// .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY) +// .setTargetResolution(Size(960, 1280)) +// .build() +// +// try { +// // Unbind use cases before rebinding +// cameraProvider.unbindAll() +// +// // Bind use cases to camera +// cameraProvider.bindToLifecycle( +// this, cameraSelector, preview, videoCapture) +// +// } catch(exc: Exception) { +// Log.e("tag", "Use case binding failed", exc) +// } +// +// }, ContextCompat.getMainExecutor(this)) + + bindCameraUseCases() + } + + public var mModule: Module? = null + public var encoder: Module? = null + + public fun analyzeImage(bitmap: Bitmap){ + var midbox: NamedBox? = null + var bitmap2show: Bitmap? = null + var moduleForwardDuration: Long = 0 + var moduleAnalysisDuration: Long = 0 + try { + if (mModule == null || encoder == null) { + try { + val moduleFileAbsoluteFilePath = File( + Utils.assetFilePath(this, "mobile_model2.pt")).absolutePath + mModule = Module.load(moduleFileAbsoluteFilePath) + val encoderFileAbsoluteFilePath = File( + Utils.assetFilePath(this, "encoder1.pt")).absolutePath + encoder = Module.load(encoderFileAbsoluteFilePath) + } catch (e: Exception) { + MDToast.makeText(this, "读取模型时出错", MDToast.LENGTH_LONG, MDToast.TYPE_ERROR).show() + e.printStackTrace() + } + } + bitmap2show = bitmap + val startTime = SystemClock.elapsedRealtime() + val mean = floatArrayOf(0.49804f, 0.49804f, 0.49804f) + val std = floatArrayOf(0.501960f, 0.501960f, 0.501960f) + val nms_threshold = 0.4f + val w1 = bitmap.width + val h1 = bitmap.height + val bitmap1 = Bitmap.createScaledBitmap(bitmap, 480, 360, true) + // if (bitmap.getWidth() > bitmap.getHeight()) +// bitmap = Bitmap.createScaledBitmap(bitmap,480,360,true); +// else +// bitmap = Bitmap.createScaledBitmap(bitmap,360,480,true); + val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmap1, mean, std) + println(Arrays.toString(inputTensor.shape())) + //Normalize input +// inputTensor = Normalize_tensor(inputTensor, 127, 128); + // running the model + val moduleForwardStartTime = SystemClock.elapsedRealtime() + val output: Array = mModule?.forward(IValue.from(inputTensor))!!.toTuple() + moduleForwardDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime + +// final Tensor outputTensor = mModule.forward(IValue.from(mInputTensor)).toTensor(); + val scores = output[0].toTensor() + val boxes = output[1].toTensor() + val threshold = 0.8f + val possible_indexes: ArrayList = possible_score(scores, boxes, threshold) + println("in onCreate len possible_indexes " + possible_indexes.size) + var nms_boxes: ArrayList = nms(boxes, scores, possible_indexes, nms_threshold) + val ratio = 0.1f + nms_boxes = expand_box(nms_boxes, ratio) + if (nms_boxes.size > 0) { + +// +// drawOnBitmap(bitmap, nms_boxes); + val width: Int = viewFinder.measuredWidth + val height = viewFinder.measuredHeight + println("in if width is $width height is $height") + + //TODO make http request here to get identity of picture +// send_unrecognized_image(bitmap, nms_boxes); + get_unrecognized_face_embedding(bitmap, nms_boxes, encoder, namedEmbeddings, namedboxpool) +// midbox = drawFaceResults(nms_boxes, width, height, graphicOverlay, namedboxpool) + midbox = drawFaceResults1(width, height, graphicOverlay, namedboxpool) + // set_prediction(bitmap, midbox); +// update_namedboxpool() + println("nms boxes " + nms_boxes.size) + } else { + graphicOverlay.clear() +// update_namedboxpool() + } + moduleAnalysisDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime + println("inference time is $moduleForwardDuration") + + + } catch (e: Exception) { + Log.e(Constants.TAG, "Error during image analysis", e) + finish() + + } + if (midbox == null) { + } else { + var bitmap_c: Bitmap? = null + bitmap_c = cropBitmap(bitmap2show, midbox.rect) + updateUI(arrayOf(midbox.id_k[0], midbox.id_k[1], midbox.id_k[2]), floatArrayOf(midbox.prob_k[0], midbox.prob_k[1], midbox.prob_k[2]), bitmap_c) + } + } + + private fun updateUI(ids: Array, probs: FloatArray, bitmap_c: Bitmap?) { + + if (bitmap_c != null) { + imageView.setImageBitmap(bitmap_c) + convertDis2Prob(ids, probs) + for (i in 0 until Utils.TOP_K) { + val rowView:ResultRowView? = mResultRowViews[i] + rowView?.nameTextView?.setText(ids.get(i)) + rowView?.scoreTextView?.text = String.format(SCORES_FORMAT, probs[i]) + rowView?.setProgressState(false) + } + } + +// mMsText.setText(String.format(Locale.US, Utils.FORMAT_MS, moduleForwardDuration)) +// if (mMsText.getVisibility() != View.VISIBLE) { +// mMsText.setVisibility(View.VISIBLE) +// } +// mFpsText.setText(String.format(Locale.US, Utils.FORMAT_FPS, 1000f / moduleAnalysisDuration)) +// if (mFpsText.getVisibility() != View.VISIBLE) { +// mFpsText.setVisibility(View.VISIBLE) +// } + + } + + + // public void send_croped_Image(Bitmap bitmap_c, float[] box_c) + // { + // System.out.println("in send cropped Image"); + //// webSocket.sendText("{\"message\": \"on create\"}"); + // if (bitmap_c != null) + // { + // try { + // String box = "["+box_c[0]+","+box_c[1]+","+box_c[2]+","+box_c[3]+ "]"; + // String string = "{\"message\": \"cropped image\",\"box\": "+ box +"}"; + // String deliminater = "$$$$$$$$$$"; + // string = string + deliminater; + // byte[] bytes1 = string.getBytes("UTF-8"); + // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // bitmap_c.compress(Bitmap.CompressFormat.JPEG, 100, baos); + // byte[] bytes = baos.toByteArray(); + // System.out.println("in onclick bytes len is " + bytes.length); + // webSocket.sendBinary(byteMerger(bytes1, bytes)); + // }catch (java.io.UnsupportedEncodingException uee) + // { + // uee.printStackTrace(); + // } + // + // } + // } + fun update_namedboxpool() { + val new_namedboxpool = ArrayList() + for (nb in namedboxpool) { + if (nb.is_valid) new_namedboxpool.add(nb) //注意这个地方 + } + namedboxpool = new_namedboxpool + } +} diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First2Fragment.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First2Fragment.java new file mode 100644 index 00000000..f5eb8b43 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First2Fragment.java @@ -0,0 +1,34 @@ +package org.pytorch.demo; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + +public class First2Fragment extends Fragment { + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState + ) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_first2, container, false); + } + + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + NavHostFragment.findNavController(First2Fragment.this) + .navigate(R.id.action_First2Fragment_to_Second2Fragment); + } + }); + } +} \ No newline at end of file diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First4Fragment.java b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First4Fragment.java new file mode 100644 index 00000000..498bce73 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First4Fragment.java @@ -0,0 +1,34 @@ +package org.pytorch.demo; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + +public class First4Fragment extends Fragment { + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState + ) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_first4, container, false); + } + + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + NavHostFragment.findNavController(First4Fragment.this) + .navigate(R.id.action_First4Fragment_to_Second4Fragment); + } + }); + } +} \ No newline at end of file diff --git a/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First5Fragment.kt b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First5Fragment.kt new file mode 100644 index 00000000..bc1e4b74 --- /dev/null +++ b/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/First5Fragment.kt @@ -0,0 +1,31 @@ +package org.pytorch.demo + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import androidx.navigation.fragment.findNavController + +/** + * A simple [Fragment] subclass as the default destination in the navigation. + */ +class First5Fragment : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_first5, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + view.findViewById + + + + + + + + + + + + + +