diff --git a/model_zoo/official/lite/image_classification/app/src/main/cpp/MindSporeNetnative.cpp b/model_zoo/official/lite/image_classification/app/src/main/cpp/MindSporeNetnative.cpp
index 9cf9535614..282065ebfb 100644
--- a/model_zoo/official/lite/image_classification/app/src/main/cpp/MindSporeNetnative.cpp
+++ b/model_zoo/official/lite/image_classification/app/src/main/cpp/MindSporeNetnative.cpp
@@ -371,7 +371,7 @@ Java_com_mindspore_himindsporedemo_gallery_classify_TrackingMobile_loadModel(JNI
mindspore::lite::Context *context = new mindspore::lite::Context;
context->thread_num_ = num_thread;
context->device_list_[0].device_info_.cpu_device_info_.cpu_bind_mode_ = mindspore::lite::NO_BIND;
- context->device_list_[0].device_info_.cpu_device_info_.enable_float16_ = true;
+ context->device_list_[0].device_info_.cpu_device_info_.enable_float16_ = false;
context->device_list_[0].device_type_ = mindspore::lite::DT_CPU;
labelNet->CreateSessionMS(modelBuffer, bufferLen, context);
diff --git a/model_zoo/official/lite/object_detection/app/src/main/cpp/MindSporeNetnative.cpp b/model_zoo/official/lite/object_detection/app/src/main/cpp/MindSporeNetnative.cpp
index 87db306291..3a42d89408 100644
--- a/model_zoo/official/lite/object_detection/app/src/main/cpp/MindSporeNetnative.cpp
+++ b/model_zoo/official/lite/object_detection/app/src/main/cpp/MindSporeNetnative.cpp
@@ -166,7 +166,7 @@ Java_com_mindspore_hiobject_help_TrackingMobile_loadModel(JNIEnv *env, jobject t
mindspore::lite::Context *context = new mindspore::lite::Context;
context->thread_num_ = numThread;
context->device_list_[0].device_info_.cpu_device_info_.cpu_bind_mode_ = mindspore::lite::NO_BIND;
- context->device_list_[0].device_info_.cpu_device_info_.enable_float16_ = true;
+ context->device_list_[0].device_info_.cpu_device_info_.enable_float16_ = false;
context->device_list_[0].device_type_ = mindspore::lite::DT_CPU;
labelNet->CreateSessionMS(modelBuffer, bufferLen, context);
diff --git a/model_zoo/official/lite/posenet/.gitignore b/model_zoo/official/lite/posenet/.gitignore
new file mode 100644
index 0000000000..603b140773
--- /dev/null
+++ b/model_zoo/official/lite/posenet/.gitignore
@@ -0,0 +1,14 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
diff --git a/model_zoo/official/lite/posenet/app/.gitignore b/model_zoo/official/lite/posenet/app/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/model_zoo/official/lite/posenet/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/model_zoo/official/lite/posenet/app/build.gradle b/model_zoo/official/lite/posenet/app/build.gradle
new file mode 100644
index 0000000000..9d57898096
--- /dev/null
+++ b/model_zoo/official/lite/posenet/app/build.gradle
@@ -0,0 +1,59 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.1"
+
+ defaultConfig {
+ applicationId "com.mindspore.posnetdemo"
+ minSdkVersion 21
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ aaptOptions {
+ noCompress "ms"
+ }
+
+ lintOptions {
+ checkReleaseBuilds false
+ // Or, if you prefer, you can continue to check for errors in release builds,
+ // but continue the build even when errors are found:
+ abortOnError false
+ }
+
+ repositories {
+ google()
+ jcenter()
+ flatDir {
+ dirs 'libs'
+ }
+ }
+}
+
+// Download default models; if you wish to use your own models then
+// place them in the "assets" directory and comment out this line.
+apply from:'download.gradle'
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+
+ implementation(name: 'mindspore-lite-1.0.1', ext: 'aar')
+
+}
\ No newline at end of file
diff --git a/model_zoo/official/lite/posenet/app/download.gradle b/model_zoo/official/lite/posenet/app/download.gradle
new file mode 100644
index 0000000000..b05f4d0f92
--- /dev/null
+++ b/model_zoo/official/lite/posenet/app/download.gradle
@@ -0,0 +1,73 @@
+/**
+ * To download necessary library from HuaWei server.
+ * Including mindspore-lite .so file, minddata-lite .so file and model file.
+ * The libraries can be downloaded manually.
+ */
+def mindsporeLite_Version = "mindspore-lite-maven-1.0.1"
+def targetModelFile = "src/main/assets/posenet_model.ms"
+def modelDownloadUrl = "https://download.mindspore.cn/model_zoo/official/lite/posenet_lite/posenet_model.ms"
+def mindsporeLiteDownloadUrl = "https://ms-release.obs.cn-north-4.myhuaweicloud.com/1.0.1/lite/java/${mindsporeLite_Version}.zip"
+def mindSporeLibrary = "libs/${mindsporeLite_Version}.zip"
+def cleantargetMindSporeInclude = "libs"
+def targetMindSporeInclude = "libs/"
+
+
+task downloadModelFile(type: DownloadUrlTask) {
+ doFirst {
+ println "Downloading ${modelDownloadUrl}"
+ }
+ sourceUrl = "${modelDownloadUrl}"
+ target = file("${targetModelFile}")
+}
+
+
+task downloadMindSporeLibrary(type: DownloadUrlTask) {
+ doFirst {
+ println "Downloading ${mindsporeLiteDownloadUrl}"
+ }
+ sourceUrl = "${mindsporeLiteDownloadUrl}"
+ target = file("${mindSporeLibrary}")
+}
+
+task unzipMindSporeInclude(type: Copy, dependsOn: ['downloadMindSporeLibrary']) {
+ doFirst {
+ println "Unzipping ${mindSporeLibrary}"
+ }
+ from zipTree("${mindSporeLibrary}")
+ into "${targetMindSporeInclude}"
+}
+
+task cleanUnusedmindsporeFiles(type: Delete, dependsOn: ['unzipMindSporeInclude']) {
+ delete fileTree("${cleantargetMindSporeInclude}").matching {
+ include "*.zip"
+ }
+}
+
+if (file("libs/mindspore-lite-1.0.1.aar").exists()){
+ downloadMindSporeLibrary.enabled = false
+ unzipMindSporeInclude.enabled = false
+ cleanUnusedmindsporeFiles.enabled = false
+}
+
+
+if (file("src/main/assets/posenet_model.ms").exists()){
+ downloadModelFile.enabled = false
+}
+
+preBuild.dependsOn downloadModelFile
+preBuild.dependsOn downloadMindSporeLibrary
+preBuild.dependsOn unzipMindSporeInclude
+preBuild.dependsOn cleanUnusedmindsporeFiles
+
+class DownloadUrlTask extends DefaultTask {
+ @Input
+ String sourceUrl
+
+ @OutputFile
+ File target
+
+ @TaskAction
+ void download() {
+ ant.get(src: sourceUrl, dest: target)
+ }
+}
diff --git a/model_zoo/official/lite/posenet/app/proguard-rules.pro b/model_zoo/official/lite/posenet/app/proguard-rules.pro
new file mode 100644
index 0000000000..481bb43481
--- /dev/null
+++ b/model_zoo/official/lite/posenet/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/model_zoo/official/lite/posenet/app/src/androidTest/java/com/mindspore/posenetdemo/ExampleInstrumentedTest.java b/model_zoo/official/lite/posenet/app/src/androidTest/java/com/mindspore/posenetdemo/ExampleInstrumentedTest.java
new file mode 100644
index 0000000000..081ff1d69f
--- /dev/null
+++ b/model_zoo/official/lite/posenet/app/src/androidTest/java/com/mindspore/posenetdemo/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.mindspore.posenetdemo;
+
+import android.content.Context;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.mindspore.posnetdemo", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/model_zoo/official/lite/posenet/app/src/main/AndroidManifest.xml b/model_zoo/official/lite/posenet/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..16d81da437
--- /dev/null
+++ b/model_zoo/official/lite/posenet/app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
+
+
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mindspore.posenetdemo; + +import android.media.Image; +import android.view.SurfaceView; + +public interface CameraDataDealListener { + void dataDeal(Image image, SurfaceView surfaceView); +} diff --git a/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/ImageUtils.java b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/ImageUtils.java new file mode 100644 index 0000000000..856eef7c28 --- /dev/null +++ b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/ImageUtils.java @@ -0,0 +1,74 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mindspore.posenetdemo; + +public class ImageUtils { + // This value is 2 ^ 18 - 1, and is used to hold the RGB values together before their ranges + // are normalized to eight bits. + private static final int MAX_CHANNEL_VALUE = 262143; + + /** + * Helper function to convert y,u,v integer values to RGB format + */ + private static int convertYUVToRGB(int y, int u, int v) { + // Adjust and check YUV values + int yNew = y - 16 < 0 ? 0 : y - 16; + int uNew = u - 128; + int vNew = v - 128; + int expandY = 1192 * yNew; + int r = checkBoundaries(expandY + 1634 * vNew); + int g = checkBoundaries(expandY - 833 * vNew - 400 * uNew); + int b = checkBoundaries(expandY + 2066 * uNew); + + return -0x1000000 | (r << 6 & 0xff0000) | (g >> 2 & 0xff00) | (b >> 10 & 0xff); + } + + + private static int checkBoundaries(int value) { + if (value > MAX_CHANNEL_VALUE) { + return MAX_CHANNEL_VALUE; + } else if (value < 0) { + return 0; + } else { + return value; + } + } + + /** + * Converts YUV420 format image data (ByteArray) into ARGB8888 format with IntArray as output. + */ + public static void convertYUV420ToARGB8888(byte[] yData, byte[] uData, byte[] vData, + int width, int height, + int yRowStride, int uvRowStride, int uvPixelStride, int[] out) { + + int outputIndex = 0; + for (int j = 0; j < height; j++) { + int positionY = yRowStride * j; + int positionUV = uvRowStride * (j >> 1); + + for (int i = 0; i < width; i++) { + int uvOffset = positionUV + (i >> 1) * uvPixelStride; + + // "0xff and" is used to cut off bits from following value that are higher than + // the low 8 bits + out[outputIndex++] = convertYUVToRGB( + 0xff & yData[positionY + i], 0xff & uData[uvOffset], + 0xff & vData[uvOffset]); + + } + } + } +} diff --git a/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/MainActivity.java b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/MainActivity.java new file mode 100644 index 0000000000..9ea88ee371 --- /dev/null +++ b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/MainActivity.java @@ -0,0 +1,258 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mindspore.posenetdemo; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.hardware.camera2.CameraCharacteristics; +import android.media.Image; +import android.os.Bundle; +import android.view.SurfaceView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.util.Pair; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; + +import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_ANKLE; +import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_ELBOW; +import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_HIP; +import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_KNEE; +import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_SHOULDER; +import static com.mindspore.posenetdemo.Posenet.BodyPart.LEFT_WRIST; +import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_ANKLE; +import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_ELBOW; +import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_HIP; +import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_KNEE; +import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_SHOULDER; +import static com.mindspore.posenetdemo.Posenet.BodyPart.RIGHT_WRIST; + +public class MainActivity extends AppCompatActivity implements CameraDataDealListener { + + private final List bodyJoints = Arrays.asList( + new Pair(LEFT_WRIST, LEFT_ELBOW), new Pair(LEFT_ELBOW, LEFT_SHOULDER), + new Pair(LEFT_SHOULDER, RIGHT_SHOULDER), new Pair(RIGHT_SHOULDER, RIGHT_ELBOW), + new Pair(RIGHT_ELBOW, RIGHT_WRIST), new Pair(LEFT_SHOULDER, LEFT_HIP), + new Pair(LEFT_HIP, RIGHT_HIP), new Pair(RIGHT_HIP, RIGHT_SHOULDER), + new Pair(LEFT_HIP, LEFT_KNEE), new Pair(LEFT_KNEE, LEFT_ANKLE), + new Pair(RIGHT_HIP, RIGHT_KNEE), new Pair(RIGHT_KNEE, RIGHT_ANKLE)); + + + /** + * Model input shape for images. + */ + private final static int MODEL_WIDTH = 257; + private final static int MODEL_HEIGHT = 257; + + private final double minConfidence = 0.5; + private final float circleRadius = 8.0f; + private Paint paint = new Paint(); + private final int PREVIEW_WIDTH = 640; + private final int PREVIEW_HEIGHT = 480; + private Posenet posenet; + private int[] rgbBytes = new int[PREVIEW_WIDTH * PREVIEW_HEIGHT]; + private byte[][] yuvBytes = new byte[3][]; + private SurfaceView surfaceView; + + private int lensFacing = CameraCharacteristics.LENS_FACING_BACK; + private PoseNetFragment poseNetFragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + addCameraFragment(); + } + + private void addCameraFragment() { + posenet = new Posenet(this); + + poseNetFragment = PoseNetFragment.newInstance(); + poseNetFragment.setCameraDataDealListener(this); + // poseNetFragment.setFacingCamera(lensFacing); + getSupportFragmentManager().popBackStack(); + getSupportFragmentManager().beginTransaction() + .replace(R.id.container, poseNetFragment) + .commitAllowingStateLoss(); + } + + @Override + public void dataDeal(Image image, SurfaceView surfaceView) { + if (image == null || image.getPlanes() == null) { + return; + } + this.surfaceView = surfaceView; + fillBytes(image.getPlanes(), yuvBytes); + ImageUtils.convertYUV420ToARGB8888(yuvBytes[0], yuvBytes[1], yuvBytes[2], + PREVIEW_WIDTH, PREVIEW_HEIGHT, + image.getPlanes()[0].getRowStride(), + image.getPlanes()[1].getRowStride(), + image.getPlanes()[1].getPixelStride(), + rgbBytes); + + Bitmap imageBitmap = Bitmap.createBitmap( + rgbBytes, PREVIEW_WIDTH, PREVIEW_HEIGHT, + Bitmap.Config.ARGB_8888); + Matrix rotateMatrix = new Matrix(); + rotateMatrix.postRotate(90.0f); + + Bitmap rotatedBitmap = Bitmap.createBitmap( + imageBitmap, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT, + rotateMatrix, true + ); + image.close(); + processImage(rotatedBitmap); + } + + + /** + * Fill the yuvBytes with data from image planes. + */ + private void fillBytes(Image.Plane[] planes, byte[][] yuvBytes) { + // Row stride is the total number of bytes occupied in memory by a row of an image. + // Because of the variable row stride it's not possible to know in + // advance the actual necessary dimensions of the yuv planes + for (int i = 0; i < planes.length; ++i) { + ByteBuffer buffer = planes[i].getBuffer(); + if (yuvBytes[i] == null) { + yuvBytes[i] = new byte[buffer.capacity()]; + } + buffer.get(yuvBytes[i]); + } + } + + /** + * Crop Bitmap to maintain aspect ratio of model input. + */ + private Bitmap cropBitmap(Bitmap bitmap) { + float bitmapRatio = bitmap.getHeight() / bitmap.getWidth(); + float modelInputRatio = MODEL_HEIGHT / MODEL_WIDTH; + double maxDifference = 1.0E-5D; + float cropHeight = modelInputRatio - bitmapRatio; + + if (Math.abs(cropHeight) < maxDifference) { + return bitmap; + } else { + Bitmap croppedBitmap; + if (modelInputRatio < bitmapRatio) { + cropHeight = (float) bitmap.getHeight() - (float) bitmap.getWidth() / modelInputRatio; + croppedBitmap = Bitmap.createBitmap(bitmap, + 0, (int) (cropHeight / 2), bitmap.getWidth(), (int) (bitmap.getHeight() - cropHeight)); + } else { + cropHeight = (float) bitmap.getWidth() - (float) bitmap.getHeight() * modelInputRatio; + croppedBitmap = Bitmap.createBitmap(bitmap, + (int) (cropHeight / 2), 0, (int) (bitmap.getWidth() - cropHeight), bitmap.getHeight()); + } + return croppedBitmap; + } + } + + /** + * Set the paint color and size. + */ + private void setPaint() { + paint.setColor(getResources().getColor(R.color.text_blue)); + paint.setTextSize(80.0f); + paint.setStrokeWidth(8.0f); + } + + /** + * Draw bitmap on Canvas. + */ + private void draw(Canvas canvas, Posenet.Person person, Bitmap bitmap) { + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + // Draw `bitmap` and `person` in square canvas. + int screenWidth, screenHeight; + int left, right, top, bottom; + if (canvas.getHeight() > canvas.getWidth()) { + screenWidth = canvas.getWidth(); + screenHeight = canvas.getWidth(); + left = 0; + top = (canvas.getHeight() - canvas.getWidth()) / 2; + } else { + screenWidth = canvas.getHeight(); + screenHeight = canvas.getHeight(); + left = (canvas.getWidth() - canvas.getHeight()) / 2; + top = 0; + } + right = left + screenWidth; + bottom = top + screenHeight; + + setPaint(); + canvas.drawBitmap( + bitmap, + new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()), + new Rect(left, top, right, bottom), paint); + + float widthRatio = screenWidth / MODEL_WIDTH; + float heightRatio = screenHeight / MODEL_HEIGHT; + + for (Posenet.KeyPoint keyPoint : person.keyPoints) { + if (keyPoint.score > minConfidence) { + Posenet.Position position = keyPoint.position; + float adjustedX = position.x * widthRatio + left; + float adjustedY = position.y * heightRatio + top; + canvas.drawCircle(adjustedX, adjustedY, circleRadius, paint); + } + } + + for (int i = 0; i < bodyJoints.size(); i++) { + Pair line = (Pair) bodyJoints.get(i); + Posenet.BodyPart first = (Posenet.BodyPart) line.first; + Posenet.BodyPart second = (Posenet.BodyPart) line.second; + + if (person.keyPoints.get(first.ordinal()).score > minConfidence & + person.keyPoints.get(second.ordinal()).score > minConfidence) { + canvas.drawLine( + person.keyPoints.get(first.ordinal()).position.x * widthRatio + left, + person.keyPoints.get(first.ordinal()).position.y * heightRatio + top, + person.keyPoints.get(second.ordinal()).position.x * widthRatio + left, + person.keyPoints.get(second.ordinal()).position.y * heightRatio + top, paint); + } + } + + canvas.drawText(String.format("Score: %.2f", person.score), + (15.0f * widthRatio), (30.0f * heightRatio + bottom), paint); + canvas.drawText(String.format("Time: %.2f ms", posenet.lastInferenceTimeNanos * 1.0f / 1_000_000), + (15.0f * widthRatio), (50.0f * heightRatio + bottom), paint + ); + + // Draw! + surfaceView.getHolder().unlockCanvasAndPost(canvas); + } + + /** + * Process image using Posenet library. + */ + private void processImage(Bitmap bitmap) { + // Crop bitmap. + Bitmap croppedBitmap = cropBitmap(bitmap); + // Created scaled version of bitmap for model input. + Bitmap scaledBitmap = Bitmap.createScaledBitmap(croppedBitmap, MODEL_WIDTH, MODEL_HEIGHT, true); + // Perform inference. + Posenet.Person person = posenet.estimateSinglePose(scaledBitmap); + Canvas canvas = surfaceView.getHolder().lockCanvas(); + draw(canvas, person, scaledBitmap); + } + +} \ No newline at end of file diff --git a/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/PoseNetFragment.java b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/PoseNetFragment.java new file mode 100644 index 0000000000..ad991322c1 --- /dev/null +++ b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/PoseNetFragment.java @@ -0,0 +1,388 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mindspore.posenetdemo; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.media.Image; +import android.media.ImageReader; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; +import android.util.Size; +import android.view.LayoutInflater; +import android.view.Surface; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.fragment.app.Fragment; + +import java.util.Arrays; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +/** + * A simple {@link Fragment} subclass. + * create an instance of this fragment. + */ +public class PoseNetFragment extends Fragment { + + private final static int REQUEST_CAMERA_PERMISSION = 1; + private String cameraId = "1"; + private SurfaceView surfaceView; + private CameraCaptureSession captureSession; + private CameraDevice cameraDevice; + private Size previewSize; + private int previewWidth; + private int previewHeight; + private final int PREVIEW_WIDTH = 640; + private final int PREVIEW_HEIGHT = 480; + private HandlerThread backgroundThread; + private Handler backgroundHandler; + private ImageReader imageReader; + private CaptureRequest.Builder previewRequestBuilder; + private CaptureRequest previewRequest; + private Semaphore cameraOpenCloseLock = new Semaphore(1);//使用信号量 Semaphore 进行多线程任务调度 + private boolean flashSupported; + + + private static final String TAG = "PoseNetFragment"; + + private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { + + @Override + public void onOpened(@NonNull CameraDevice mCameraDevice) { + cameraOpenCloseLock.release(); + Log.d(TAG, "camera has open"); + PoseNetFragment.this.cameraDevice = mCameraDevice; + createCameraPreviewSession(); + } + + @Override + public void onDisconnected(@NonNull CameraDevice cameraDevice) { + cameraOpenCloseLock.release(); + cameraDevice.close(); + PoseNetFragment.this.cameraDevice = null; + } + + @Override + public void onError(@NonNull CameraDevice cameraDevice, int error) { + onDisconnected(cameraDevice); + Activity activity = getActivity(); + if (activity != null) { + activity.finish(); + } + } + }; + + + private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { + @Override + public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { + super.onCaptureProgressed(session, request, partialResult); + } + + @Override + public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { + super.onCaptureCompleted(session, request, result); + } + }; + + private CameraDataDealListener cameraDataDealListener; + + public void setCameraDataDealListener(CameraDataDealListener cameraDataDealListener) { + this.cameraDataDealListener = cameraDataDealListener; + } + + public static PoseNetFragment newInstance() { + PoseNetFragment fragment = new PoseNetFragment(); + return fragment; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_pose_net, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + this.surfaceView = view.findViewById(R.id.surfaceView); + } + + @Override + public void onResume() { + super.onResume(); + startBackgroundThread(); + } + + public void onStart() { + super.onStart(); + openCamera(); + } + + public void onPause() { + this.closeCamera(); + this.stopBackgroundThread(); + super.onPause(); + } + + public void onDestroy() { + super.onDestroy(); + } + + private void requestCameraPermission() { + if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { + Toast.makeText(getContext(), "This app needs camera permission.", Toast.LENGTH_LONG).show(); + } else { + requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_CAMERA_PERMISSION) { + if (allPermissionsGranted(grantResults)) { + Toast.makeText(getContext(), "This app needs camera permission.", Toast.LENGTH_LONG).show(); + } + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } + + private boolean allPermissionsGranted(int[] grantResults) { + for (int grantResult : grantResults) { + if (grantResult == PackageManager.PERMISSION_DENIED) { + return false; + } + } + return true; + } + + /** + * Sets up member variables related to camera. + */ + private void setUpCameraOutputs() { + CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE); + try { + for (String cameraId : manager.getCameraIdList()) { + CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); + // We don't use a front facing camera in this sample. + Integer cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING); + if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) { + continue; + } + + previewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT); + + imageReader = ImageReader.newInstance( + PREVIEW_WIDTH, PREVIEW_HEIGHT, + ImageFormat.YUV_420_888, /*maxImages*/ 2 + ); + + previewHeight = previewSize.getHeight(); + previewWidth = previewSize.getWidth(); + // Initialize the storage bitmaps once when the resolution is known. + + // Check if the flash is supported. + flashSupported = + characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true; + + this.cameraId = cameraId; + + // We've found a viable camera and finished setting up member variables, + // so we don't need to iterate through other available cameras. + return; + } + } catch (CameraAccessException e) { + e.printStackTrace(); + } catch (NullPointerException e) { + e.printStackTrace(); + } + } + + /** + * Opens the camera specified by [PosenetActivity.cameraId]. + */ + private void openCamera() { + if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + this.requestCameraPermission(); + } + setUpCameraOutputs(); + CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE); + try { + // Wait for camera to open - 2.5 seconds is sufficient + if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("Time out waiting to lock camera opening."); + } + manager.openCamera(cameraId, mStateCallback, backgroundHandler); + } catch (CameraAccessException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void closeCamera() { + try { + cameraOpenCloseLock.acquire(); + if (captureSession != null) { + captureSession.close(); + captureSession = null; + } + if (null != cameraDevice) { + cameraDevice.close(); + cameraDevice = null; + } + if (null != imageReader) { + imageReader.close(); + imageReader = null; + } + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted while trying to lock camera closing.", e); + } finally { + cameraOpenCloseLock.release(); + } + } + + /** + * Starts a background thread and its [Handler]. + */ + private void startBackgroundThread() { + backgroundThread = new HandlerThread("imageAvailableListener"); + backgroundThread.start(); + backgroundHandler = new Handler(backgroundThread.getLooper()); + } + + /** + * Stops the background thread and its [Handler]. + */ + private void stopBackgroundThread() { + backgroundThread.quitSafely(); + try { + backgroundThread.join(); + backgroundThread = null; + backgroundHandler = null; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + + private final ImageReader.OnImageAvailableListener imageAvailableListener = new ImageReader.OnImageAvailableListener() { + @Override + public void onImageAvailable(ImageReader imageReader) { + if (previewWidth != 0 && previewHeight != 0 && imageReader != null) { + Image image = imageReader.acquireLatestImage(); + + if (cameraDataDealListener != null) { + cameraDataDealListener.dataDeal(image, surfaceView); + } + } + } + }; + + + /** + * Creates a new [CameraCaptureSession] for camera preview. + */ + private void createCameraPreviewSession() { + try { + // We capture images from preview in YUV format. + imageReader = ImageReader.newInstance( + previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2); + imageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler); + + // This is the surface we need to record images for processing. + Surface recordingSurface = imageReader.getSurface(); + + // We set up a CaptureRequest.Builder with the output Surface. + previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + previewRequestBuilder.addTarget(recordingSurface); + + // Here, we create a CameraCaptureSession for camera preview. + cameraDevice.createCaptureSession( + Arrays.asList(recordingSurface), + new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { + // The camera is already closed + if (cameraDevice == null) { + return; + } + + // When the session is ready, we start displaying the preview. + captureSession = cameraCaptureSession; + try { + // Auto focus should be continuous for camera preview. + previewRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, + CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE + ); + // Flash is automatically enabled when necessary. + setAutoFlash(previewRequestBuilder); + + // Finally, we start displaying the camera preview. + previewRequest = previewRequestBuilder.build(); + captureSession.setRepeatingRequest( + previewRequest, + captureCallback, backgroundHandler); + } catch (CameraAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { + } + }, + null); + } catch (CameraAccessException e) { + Log.e(TAG, e.toString()); + } + } + + private void setAutoFlash(CaptureRequest.Builder requestBuilder) { + if (flashSupported) { + requestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, + CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); + } + } + +} \ No newline at end of file diff --git a/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/Posenet.java b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/Posenet.java new file mode 100644 index 0000000000..6c30e1fc34 --- /dev/null +++ b/model_zoo/official/lite/posenet/app/src/main/java/com/mindspore/posenetdemo/Posenet.java @@ -0,0 +1,315 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.mindspore.posenetdemo;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.core.util.Pair;
+
+import com.mindspore.lite.LiteSession;
+import com.mindspore.lite.MSTensor;
+import com.mindspore.lite.Model;
+import com.mindspore.lite.config.CpuBindMode;
+import com.mindspore.lite.config.DeviceType;
+import com.mindspore.lite.config.MSConfig;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import static java.lang.Math.exp;
+
+public class Posenet {
+
+ public enum BodyPart {
+ NOSE,
+ LEFT_EYE,
+ RIGHT_EYE,
+ LEFT_EAR,
+ RIGHT_EAR,
+ LEFT_SHOULDER,
+ RIGHT_SHOULDER,
+ LEFT_ELBOW,
+ RIGHT_ELBOW,
+ LEFT_WRIST,
+ RIGHT_WRIST,
+ LEFT_HIP,
+ RIGHT_HIP,
+ LEFT_KNEE,
+ RIGHT_KNEE,
+ LEFT_ANKLE,
+ RIGHT_ANKLE
+ }
+
+ public class Position {
+ int x;
+ int y;
+ }
+
+ public class KeyPoint {
+ BodyPart bodyPart = BodyPart.NOSE;
+ Position position = new Position();
+ float score = 0.0f;
+ }
+
+ public class Person {
+ List
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.mindspore.posenetdemo;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.widget.ImageView;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+public class TestActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_test);
+
+ ImageView sampleImageView = findViewById(R.id.image);
+ Drawable drawedImage = getResources().getDrawable(R.drawable.image);
+ Bitmap imageBitmap = drawableToBitmap(drawedImage);
+ sampleImageView.setImageBitmap(imageBitmap);
+ Posenet posenet = new Posenet(this);
+ Posenet.Person person = posenet.estimateSinglePose(imageBitmap);
+
+ // Draw the keypoints over the image.
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+
+ Bitmap mutableBitmap = imageBitmap.copy(Bitmap.Config.ARGB_8888, true);
+ Canvas canvas = new Canvas(mutableBitmap);
+ for (Posenet.KeyPoint keypoint : person.keyPoints) {
+ canvas.drawCircle(
+ keypoint.position.x,
+ keypoint.position.y, 2.0f, paint);
+ }
+
+
+ sampleImageView.setAdjustViewBounds(true);
+ sampleImageView.setImageBitmap(mutableBitmap);
+ }
+
+
+ private Bitmap drawableToBitmap(Drawable drawable) {
+ Bitmap bitmap = Bitmap.createBitmap(257, 257, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+}
\ No newline at end of file
diff --git a/model_zoo/official/lite/posenet/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/model_zoo/official/lite/posenet/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000000..2b068d1146
--- /dev/null
+++ b/model_zoo/official/lite/posenet/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+