diff --git a/model_zoo/official/lite/image_segmentation/.gitignore b/model_zoo/official/lite/image_segmentation/.gitignore new file mode 100644 index 0000000000..aa724b7707 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/.gitignore @@ -0,0 +1,15 @@ +*.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 +local.properties diff --git a/model_zoo/official/lite/image_segmentation/app/.gitignore b/model_zoo/official/lite/image_segmentation/app/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/build.gradle b/model_zoo/official/lite/image_segmentation/app/build.gradle new file mode 100644 index 0000000000..28e4d480c2 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/build.gradle @@ -0,0 +1,59 @@ +plugins { + id 'com.android.application' +} + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.1" + + defaultConfig { + applicationId "com.mindspore.imagesegmentation" + minSdkVersion 21 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + aaptOptions { + noCompress "ms" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + repositories { + google() + jcenter() + flatDir { + dirs 'libs' + } + } + + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +apply from: 'download.gradle' + +dependencies { + implementation fileTree(dir: "libs", include: ['*.aar', '*.jar']) + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' + implementation 'com.google.android.material:material:1.2.1' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + testImplementation 'junit:junit:4.13' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation 'com.github.bumptech.glide:glide:4.11.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' +} \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/download.gradle b/model_zoo/official/lite/image_segmentation/app/download.gradle new file mode 100644 index 0000000000..fb2b09b787 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/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/mobile_segment.ms" +def modelDownloadUrl = "https://download.mindspore.cn/model_zoo/official/lite/mobile_segment_lite/mobile_segment.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/mobile_segment.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/image_segmentation/app/libs/mindspore-lite-1.0.1.aar b/model_zoo/official/lite/image_segmentation/app/libs/mindspore-lite-1.0.1.aar new file mode 100644 index 0000000000..c50f5ef24a Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/libs/mindspore-lite-1.0.1.aar differ diff --git a/model_zoo/official/lite/image_segmentation/app/proguard-rules.pro b/model_zoo/official/lite/image_segmentation/app/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/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/image_segmentation/app/src/androidTest/java/com/mindspore/imagesegmentation/ExampleInstrumentedTest.java b/model_zoo/official/lite/image_segmentation/app/src/androidTest/java/com/mindspore/imagesegmentation/ExampleInstrumentedTest.java new file mode 100644 index 0000000000..5601cbf2c0 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/androidTest/java/com/mindspore/imagesegmentation/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.mindspore.imagesegmentation; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see 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.imagesegmentation", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/AndroidManifest.xml b/model_zoo/official/lite/image_segmentation/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..52d2d33605 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/assets/mobile_segment.ms b/model_zoo/official/lite/image_segmentation/app/src/main/assets/mobile_segment.ms new file mode 100644 index 0000000000..bd9d72e299 Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/assets/mobile_segment.ms differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/BitmapUtils.java b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/BitmapUtils.java new file mode 100644 index 0000000000..807e656d47 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/BitmapUtils.java @@ -0,0 +1,151 @@ +/** + * 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.imagesegmentation; + +import android.app.Activity; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.media.ExifInterface; +import android.net.Uri; +import android.provider.MediaStore; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; + +public class BitmapUtils { + private static final String TAG = "BitmapUtils"; + + public static void recycleBitmap(Bitmap... bitmaps) { + for (Bitmap bitmap : bitmaps) { + if (bitmap != null && !bitmap.isRecycled()) { + bitmap.recycle(); + bitmap = null; + } + } + } + + private static String getImagePath(Activity activity, Uri uri) { + String[] projection = {MediaStore.Images.Media.DATA}; + Cursor cursor = activity.managedQuery(uri, projection, null, null, null); + int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + return cursor.getString(columnIndex); + } + + public static Bitmap loadFromPath(Activity activity, int id, int width, int height) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + InputStream is = activity.getResources().openRawResource(id); + int sampleSize = calculateInSampleSize(options, width, height); + options.inSampleSize = sampleSize; + options.inJustDecodeBounds = false; + return zoomImage(BitmapFactory.decodeStream(is), width, height); + } + + public static Bitmap loadFromPath(Activity activity, Uri uri, int width, int height) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + + String path = getImagePath(activity, uri); + BitmapFactory.decodeFile(path, options); + int sampleSize = calculateInSampleSize(options, width, height); + options.inSampleSize = sampleSize; + options.inJustDecodeBounds = false; + + Bitmap bitmap = zoomImage(BitmapFactory.decodeFile(path, options), width, height); + return rotateBitmap(bitmap, getRotationAngle(path)); + } + + private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + final int width = options.outWidth; + final int height = options.outHeight; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + // Calculate height and required height scale. + final int heightRatio = Math.round((float) height / (float) reqHeight); + // Calculate width and required width scale. + final int widthRatio = Math.round((float) width / (float) reqWidth); + // Take the larger of the values. + inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio; + } + return inSampleSize; + } + + // Scale pictures to screen width. + private static Bitmap zoomImage(Bitmap imageBitmap, int targetWidth, int maxHeight) { + float scaleFactor = + Math.max( + (float) imageBitmap.getWidth() / (float) targetWidth, + (float) imageBitmap.getHeight() / (float) maxHeight); + Bitmap resizedBitmap = + Bitmap.createScaledBitmap( + imageBitmap, + (int) (imageBitmap.getWidth() / scaleFactor), + (int) (imageBitmap.getHeight() / scaleFactor), + true); + + return resizedBitmap; + } + + /** + * Get the rotation angle of the photo. + * + * @param path photo path. + * @return angle. + */ + public static int getRotationAngle(String path) { + int rotation = 0; + try { + ExifInterface exifInterface = new ExifInterface(path); + int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + rotation = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + rotation = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + rotation = 270; + break; + default: + break; + } + } catch (IOException e) { + Log.e(TAG, "Failed to get rotation: " + e.getMessage()); + } + return rotation; + } + + public static Bitmap rotateBitmap(Bitmap bitmap, int angle) { + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + Bitmap result = null; + try { + result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } catch (OutOfMemoryError e) { + Log.e(TAG, "Failed to rotate bitmap: " + e.getMessage()); + } + if (result == null) { + return bitmap; + } + return result; + } +} diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/MainActivity.java b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/MainActivity.java new file mode 100644 index 0000000000..b0e537fcc7 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/MainActivity.java @@ -0,0 +1,386 @@ +/** + * 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.imagesegmentation; + +import android.Manifest; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.MediaStore; +import android.util.Log; +import android.util.Pair; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.FileProvider; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.mindspore.imagesegmentation.help.ImageUtils; +import com.mindspore.imagesegmentation.help.ModelTrackingResult; +import com.mindspore.imagesegmentation.help.TrackingMobile; + +import java.io.File; +import java.io.FileNotFoundException; +import java.lang.ref.WeakReference; + +public class MainActivity extends AppCompatActivity implements OnBackgroundImageListener { + private static final String TAG = "MainActivity"; + + private static final int[] IMAGES = {R.drawable.img_001, R.drawable.img_002, R.drawable.img_003, R.drawable.img_004, R.drawable.img_005, + R.drawable.img_006, R.drawable.img_007, R.drawable.img_008, R.drawable.add}; + + private static final int REQUEST_PERMISSION = 0; + private static final int RC_CHOOSE_PHOTO = 1; + private static final int RC_CHOOSE_PHOTO_FOR_BACKGROUND = 11; + private static final int RC_CHOOSE_CAMERA = 2; + + private boolean isHasPermssion; + + private ImageView imgPreview; + private TextView textOriginImage; + public ProgressBar progressBar; + private Uri imageUri; + + private Bitmap originBitmap, lastOriginBitmap; + private Integer maxWidthOfImage; + private Integer maxHeightOfImage; + private boolean isLandScape; + + private TrackingMobile trackingMobile; + private int selectedPosition; + public boolean isRunningModel; + private Handler mHandler; + public ModelTrackingResult modelTrackingResult; + private Bitmap processedImage; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.isLandScape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + setContentView(R.layout.activity_main); + + init(); + trackingMobile = new TrackingMobile(this); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + isHasPermssion = true; + } else { + requestPermissions(); + } + } + + private void init() { + imgPreview = findViewById(R.id.img_origin); + textOriginImage = findViewById(R.id.tv_image); + progressBar = findViewById(R.id.progress); + RecyclerView recyclerView = findViewById(R.id.recyclerview); + + GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3); + recyclerView.setLayoutManager(gridLayoutManager); + recyclerView.setAdapter(new StyleRecyclerViewAdapter(this, IMAGES, this)); + } + + + private void requestPermissions() { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA}, REQUEST_PERMISSION); + } + + /** + * Authority application result callback + */ + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (REQUEST_PERMISSION == requestCode) { + isHasPermssion = true; + } + } + + public void onClickPhoto(View view) { + if (isHasPermssion) { + openGallay(RC_CHOOSE_PHOTO); + textOriginImage.setVisibility(View.GONE); + } else { + requestPermissions(); + } + } + + public void onClickCamera(View view) { + if (isHasPermssion) { + openCamera(); + textOriginImage.setVisibility(View.GONE); + } else { + requestPermissions(); + } + } + + public void onClickRecovery(View view) { + if (originBitmap != null) { + Glide.with(this).load(originBitmap).into(imgPreview); + } else { + Toast.makeText(this, "Please select an original picture first", Toast.LENGTH_SHORT).show(); + } + } + + public void onClickSave(View view) { + if (this.processedImage == null) { + Log.e(TAG, "null processed image"); + Toast.makeText(this.getApplicationContext(), R.string.no_pic_neededSave, Toast.LENGTH_SHORT).show(); + } else { + ImageUtils.saveToAlbum(getApplicationContext(), this.processedImage); + Toast.makeText(this.getApplicationContext(), R.string.save_success, Toast.LENGTH_SHORT).show(); + } + } + + private void openGallay(int request) { + Intent intent = new Intent(Intent.ACTION_PICK, null); + intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); + startActivityForResult(intent, request); + } + + private void openCamera() { + Intent intentToTakePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + String mTempPhotoPath = Environment.getExternalStorageDirectory() + File.separator + "photo.jpeg"; + imageUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".fileprovider", new File(mTempPhotoPath)); + intentToTakePhoto.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); + startActivityForResult(intentToTakePhoto, RC_CHOOSE_CAMERA); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + if (RC_CHOOSE_PHOTO == requestCode) { + if (null != data && null != data.getData()) { + this.imageUri = data.getData(); + showOriginImage(); + } else { + finish(); + } + } else if (RC_CHOOSE_PHOTO_FOR_BACKGROUND == requestCode) { + if (null != data && null != data.getData()) { + showCustomBack(data.getData()); + } else { + finish(); + } + } else if (RC_CHOOSE_CAMERA == requestCode) { + if (null != data && null != data.getData()) { + this.imageUri = data.getData(); + showOriginImage(); + } + showOriginCamera(); + } + } + } + + private void showOriginImage() { + Pair targetedSize = this.getTargetSize(); + int targetWidth = targetedSize.first; + int maxHeight = targetedSize.second; + originBitmap = BitmapUtils.loadFromPath(this, imageUri, targetWidth, maxHeight); + // Determine how much to scale down the image. + Log.i(TAG, "resized image size width:" + originBitmap.getWidth() + ",height: " + originBitmap.getHeight()); + if (originBitmap != null) { + Glide.with(this).load(originBitmap).into(imgPreview); + } + } + + private void showOriginCamera() { + try { + originBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + // Determine how much to scale down the image. + if (originBitmap != null) { + Glide.with(this).load(originBitmap).into(imgPreview); + } + } + + private BitmapDrawable customBack; + + private void showCustomBack(Uri imageUri) { + Pair targetedSize = this.getTargetSize(); + int targetWidth = targetedSize.first; + int maxHeight = targetedSize.second; + Bitmap bitmap = BitmapUtils.loadFromPath(this, imageUri, targetWidth, maxHeight); + customBack = new BitmapDrawable(getResources(), bitmap); + changeBackground(false); + } + + // Returns max width of image. + private Integer getMaxWidthOfImage() { + if (this.maxWidthOfImage == null) { + if (this.isLandScape) { + this.maxWidthOfImage = ((View) this.imgPreview.getParent()).getHeight(); + } else { + this.maxWidthOfImage = ((View) this.imgPreview.getParent()).getWidth(); + } + } + return this.maxWidthOfImage; + } + + // Returns max height of image. + private Integer getMaxHeightOfImage() { + if (this.maxHeightOfImage == null) { + if (this.isLandScape) { + this.maxHeightOfImage = ((View) this.imgPreview.getParent()).getWidth(); + } else { + this.maxHeightOfImage = ((View) this.imgPreview.getParent()).getHeight(); + } + } + return this.maxHeightOfImage; + } + + // Gets the targeted size(width / height). + private Pair getTargetSize() { + Integer targetWidth; + Integer targetHeight; + Integer maxWidth = this.getMaxWidthOfImage(); + Integer maxHeight = this.getMaxHeightOfImage(); + targetWidth = this.isLandScape ? maxHeight : maxWidth; + targetHeight = this.isLandScape ? maxWidth : maxHeight; + Log.i(TAG, "height:" + targetHeight + ",width:" + targetWidth); + return new Pair<>(targetWidth, targetHeight); + } + + private void startRunningModel(boolean isDemo) { + if (!isRunningModel) { + if (originBitmap == null) { + Toast.makeText(this, "Please select an original picture first", Toast.LENGTH_SHORT).show(); + return; + } + progressBar.setVisibility(View.VISIBLE); + new Thread(() -> { + isRunningModel = true; + modelTrackingResult = trackingMobile.execut(originBitmap); + if (modelTrackingResult != null) { + isRunningModel = false; + lastOriginBitmap = originBitmap; + } + Looper.prepare(); + mHandler = new MyHandler(MainActivity.this, isDemo); + mHandler.sendEmptyMessage(1); + Looper.loop(); + }).start(); + } else { + Toast.makeText(this, "Previous Model still running", Toast.LENGTH_SHORT).show(); + } + } + + + private static class MyHandler extends Handler { + private final WeakReference weakReference; + private boolean isDemo; + + public MyHandler(MainActivity activity, boolean demo) { + weakReference = new WeakReference<>(activity); + this.isDemo = demo; + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + Log.i(TAG, "handleMessage: load"); + MainActivity activity = weakReference.get(); + if (msg.what == 1) { + if (null != activity && null != activity.modelTrackingResult) { + activity.changeBackground(isDemo); + } + } + } + } + + public void changeBackground(boolean isDemo) { + runOnUiThread(() -> { + if(null != modelTrackingResult && null !=modelTrackingResult.getBitmapMaskOnly()){ + if (progressBar.getVisibility() == View.VISIBLE) { + progressBar.setVisibility(View.INVISIBLE); + } + Bitmap foreground = modelTrackingResult.getBitmapMaskOnly(); + Matrix matrix = new Matrix(); + matrix.setScale(0.7f, 0.7f); + foreground = Bitmap.createBitmap(foreground, 0, 0, foreground.getWidth(), foreground.getHeight(), matrix, false); + + MainActivity.this.imgPreview.setImageBitmap(foreground); + MainActivity.this.imgPreview.setDrawingCacheEnabled(true); + MainActivity.this.imgPreview.setBackground(isDemo ? getDrawable(IMAGES[selectedPosition]) : customBack); + MainActivity.this.imgPreview.setImageBitmap(foreground); + MainActivity. this.processedImage = Bitmap.createBitmap( MainActivity.this.imgPreview.getDrawingCache()); + MainActivity.this.imgPreview.setDrawingCacheEnabled(false); + }else{ + Toast.makeText(this, "Please select an original picture first", Toast.LENGTH_SHORT).show(); + } + + }); + + } + + @Override + public void onBackImageSelected(int position) { + selectedPosition = position; + if (lastOriginBitmap == originBitmap) { + changeBackground(true); + } else { + startRunningModel(true); + } + } + + @Override + public void onImageAdd(View view) { + if (originBitmap == null) { + Toast.makeText(this, "Please select an original picture first", Toast.LENGTH_SHORT).show(); + return; + } + if (lastOriginBitmap == originBitmap) { + openGallay(RC_CHOOSE_PHOTO_FOR_BACKGROUND); + } else { + startRunningModel(false); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + trackingMobile.free(); + if (mHandler != null) { + mHandler.removeCallbacksAndMessages(null); + } + BitmapUtils.recycleBitmap(this.originBitmap, this.lastOriginBitmap, this.processedImage); + + } + +} \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/OnBackgroundImageListener.java b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/OnBackgroundImageListener.java new file mode 100644 index 0000000000..c50f900aba --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/OnBackgroundImageListener.java @@ -0,0 +1,25 @@ +/** + * 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.imagesegmentation; + +import android.view.View; + +public interface OnBackgroundImageListener { + void onBackImageSelected(int position); + + void onImageAdd(View view); + +} diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/StyleRecyclerViewAdapter.java b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/StyleRecyclerViewAdapter.java new file mode 100644 index 0000000000..1c1da01626 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/StyleRecyclerViewAdapter.java @@ -0,0 +1,97 @@ +/** + * 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.imagesegmentation; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; + +public class StyleRecyclerViewAdapter extends RecyclerView.Adapter { + + private final int[] IMAGES; + private final Context context; + private final OnBackgroundImageListener mListener; + + public StyleRecyclerViewAdapter(Context context, int[] IMAGES, OnBackgroundImageListener mListener) { + this.IMAGES = IMAGES; + this.context = context; + this.mListener = mListener; + } + + @NonNull + @Override + public StyleItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(context) + .inflate(R.layout.image_item, parent, false); + return new StyleItemViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull StyleItemViewHolder holder, int position) { + Glide.with(context). + load(IMAGES[position]). + into(holder.getImageView()); + + View view = holder.getMView(); + view.setTag(IMAGES[position]); + view.setOnClickListener(view1 -> { + if (mListener != null) { + if (IMAGES.length - 1 == position) { + mListener.onImageAdd(holder.getImageView()); + } else { + mListener.onBackImageSelected(position); + } + } + }); + } + + + @Override + public int getItemCount() { + return IMAGES == null ? 0 : IMAGES.length; + } + + + public class StyleItemViewHolder extends RecyclerView.ViewHolder { + private ImageView imageView; + private final View mView; + + public final ImageView getImageView() { + return this.imageView; + } + + public final void setImageView(ImageView imageView) { + this.imageView = imageView; + } + + public final View getMView() { + return this.mView; + } + + public StyleItemViewHolder(View mView) { + super(mView); + this.mView = mView; + this.imageView = mView.findViewById(R.id.image_view); + } + } +} diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/ImageUtils.java b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/ImageUtils.java new file mode 100644 index 0000000000..04e4038b0d --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/ImageUtils.java @@ -0,0 +1,266 @@ +/** + * 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.imagesegmentation.help; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.media.MediaScannerConnection; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.exifinterface.media.ExifInterface; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class ImageUtils { + + private static final String TAG = "ImageUtils"; + + private static Matrix decodeExifOrientation(int orientation) { + Matrix matrix = new Matrix(); + + switch (orientation) { + case ExifInterface.ORIENTATION_NORMAL: + case ExifInterface.ORIENTATION_UNDEFINED: + break; + case ExifInterface.ORIENTATION_ROTATE_90: + matrix.postRotate(90F); + break; + case ExifInterface.ORIENTATION_ROTATE_180: + matrix.postRotate(180F); + break; + case ExifInterface.ORIENTATION_ROTATE_270: + matrix.postRotate(270F); + break; + case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: + matrix.postScale(-1F, 1F); + break; + case ExifInterface.ORIENTATION_FLIP_VERTICAL: + matrix.postScale(1F, -1F); + break; + case ExifInterface.ORIENTATION_TRANSPOSE: + matrix.postScale(-1F, 1F); + matrix.postRotate(270F); + break; + case ExifInterface.ORIENTATION_TRANSVERSE: + matrix.postScale(-1F, 1F); + matrix.postRotate(90F); + break; + + default: + try { + new IllegalArgumentException("Invalid orientation: " + orientation); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + return matrix; + } + + public void setExifOrientation(@NonNull String filePath, @NonNull String value) { + try { + ExifInterface exif = new ExifInterface(filePath); + exif.setAttribute(ExifInterface.TAG_ORIENTATION, value); + exif.saveAttributes(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public int computeExifOrientation(int rotationDegrees, boolean mirrored) { + if (rotationDegrees == 0 && !mirrored) { + return ExifInterface.ORIENTATION_NORMAL; + } else if (rotationDegrees == 0 && mirrored) { + return ExifInterface.ORIENTATION_FLIP_HORIZONTAL; + } else if (rotationDegrees == 180 && !mirrored) { + return ExifInterface.ORIENTATION_ROTATE_180; + } else if (rotationDegrees == 180 && mirrored) { + return ExifInterface.ORIENTATION_FLIP_VERTICAL; + } else if (rotationDegrees == 90 && !mirrored) { + return ExifInterface.ORIENTATION_ROTATE_90; + } else if (rotationDegrees == 90 && mirrored) { + return ExifInterface.ORIENTATION_TRANSPOSE; + } else if (rotationDegrees == 270 && !mirrored) { + return ExifInterface.ORIENTATION_ROTATE_270; + } else if (rotationDegrees == 270 && mirrored) { + return ExifInterface.ORIENTATION_TRANSVERSE; + } else { + return ExifInterface.ORIENTATION_UNDEFINED; + } + } + + public static Bitmap decodeBitmap(@NonNull File file) { + Bitmap finalBitmap = null; + try { + ExifInterface exif = new ExifInterface(file.getAbsolutePath()); + + Matrix transformation = decodeExifOrientation(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_ROTATE_90)); + + BitmapFactory.Options options = new BitmapFactory.Options(); + Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options); + finalBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), transformation, true); + } catch (IOException e) { + e.printStackTrace(); + } + return finalBitmap; + } + + + public static Bitmap scaleBitmapAndKeepRatio(Bitmap targetBmp, int reqHeightInPixels, int reqWidthInPixels) { + if (targetBmp.getHeight() == reqHeightInPixels && targetBmp.getWidth() == reqWidthInPixels) { + return targetBmp; + } + + Matrix matrix = new Matrix(); + matrix.setRectToRect(new RectF(0f, 0f, + targetBmp.getWidth(), + targetBmp.getHeight() + ), new RectF(0f, 0f, + reqWidthInPixels, + reqHeightInPixels + ), Matrix.ScaleToFit.FILL); + + return Bitmap.createBitmap( + targetBmp, 0, 0, + targetBmp.getWidth(), + targetBmp.getHeight(), matrix, true + ); + } + + public static Bitmap loadBitmapFromResources(Context context, String path) { + try { + InputStream inputStream = context.getAssets().open(path); + return BitmapFactory.decodeStream(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static ByteBuffer bitmapToByteBuffer(Bitmap bitmapIn, int width, int height, float mean, float std) { + Bitmap bitmap = scaleBitmapAndKeepRatio(bitmapIn, width, height); + ByteBuffer inputImage = ByteBuffer.allocateDirect(1 * width * height * 3 * 4); + inputImage.order(ByteOrder.nativeOrder()); + inputImage.rewind(); + int[] intValues = new int[width * height]; + bitmap.getPixels(intValues, 0, width, 0, 0, width, height); + int pixel = 0; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int value = intValues[pixel++]; + inputImage.putFloat(((float) (value >> 16 & 255) - mean) / std); + inputImage.putFloat(((float) (value >> 8 & 255) - mean) / std); + inputImage.putFloat(((float) (value & 255) - mean) / std); + } + } + inputImage.rewind(); + return inputImage; + } + + + public static Bitmap convertArrayToBitmap(float[][][][] imageArray, int imageWidth, int imageHeight) { + Bitmap styledImage = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888); + + for (int x = 0; x < imageArray[0].length; x++) { + for (int y = 0; y < imageArray[0][0].length; y++) { + + int color = Color.rgb((int) (imageArray[0][x][y][0] * (float) 255), + (int) (imageArray[0][x][y][1] * (float) 255), + (int) (imageArray[0][x][y][2] * (float) 255)); + // this y, x is in the correct order!!! + styledImage.setPixel(y, x, color); + } + } + return styledImage; + } + + public Bitmap createEmptyBitmap(int imageWidth, int imageHeigth, int color) { + Bitmap ret = Bitmap.createBitmap(imageWidth, imageHeigth, Bitmap.Config.RGB_565); + if (color != 0) { + ret.eraseColor(color); + } + return ret; + } + + // Save the picture to the system album and refresh it. + public static void saveToAlbum(final Context context, Bitmap bitmap) { + File file = null; + String fileName = System.currentTimeMillis() + ".jpg"; + File root = new File(Environment.getExternalStorageDirectory().getAbsoluteFile(), context.getPackageName()); + File dir = new File(root, "image"); + if (dir.mkdirs() || dir.isDirectory()) { + file = new File(dir, fileName); + } + FileOutputStream os = null; + try { + os = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); + os.flush(); + + } catch (FileNotFoundException e) { + Log.e(TAG, e.getMessage()); + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + } + } + if (file == null) { + return; + } + // Gallery refresh. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + String path = null; + try { + path = file.getCanonicalPath(); + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + } + MediaScannerConnection.scanFile(context, new String[]{path}, null, + new MediaScannerConnection.OnScanCompletedListener() { + @Override + public void onScanCompleted(String path, Uri uri) { + Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + mediaScanIntent.setData(uri); + context.sendBroadcast(mediaScanIntent); + } + }); + } else { + String relationDir = file.getParent(); + File file1 = new File(relationDir); + context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.fromFile(file1.getAbsoluteFile()))); + } + } +} \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/ModelTrackingResult.java b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/ModelTrackingResult.java new file mode 100644 index 0000000000..8a3301d6b8 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/ModelTrackingResult.java @@ -0,0 +1,81 @@ +/** + * 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.imagesegmentation.help; + +import android.graphics.Bitmap; + +import java.util.Set; + +public class ModelTrackingResult { + private Bitmap bitmapResult; + private Bitmap bitmapOriginal; + private Bitmap bitmapMaskOnly; + private String executionLog; + private Set itemsFound; + + public ModelTrackingResult(Bitmap bitmapResult, Bitmap bitmapOriginal, Bitmap bitmapMaskOnly, String executionLog, Set itemsFound) { + this.bitmapResult = bitmapResult; + this.bitmapOriginal = bitmapOriginal; + this.bitmapMaskOnly = bitmapMaskOnly; + this.executionLog = executionLog; + this.itemsFound = itemsFound; + } + + public Bitmap getBitmapResult() { + return bitmapResult; + } + + public ModelTrackingResult setBitmapResult(Bitmap bitmapResult) { + this.bitmapResult = bitmapResult; + return this; + } + + public Bitmap getBitmapOriginal() { + return bitmapOriginal; + } + + public ModelTrackingResult setBitmapOriginal(Bitmap bitmapOriginal) { + this.bitmapOriginal = bitmapOriginal; + return this; + } + + public Bitmap getBitmapMaskOnly() { + return bitmapMaskOnly; + } + + public ModelTrackingResult setBitmapMaskOnly(Bitmap bitmapMaskOnly) { + this.bitmapMaskOnly = bitmapMaskOnly; + return this; + } + + public String getExecutionLog() { + return executionLog; + } + + public ModelTrackingResult setExecutionLog(String executionLog) { + this.executionLog = executionLog; + return this; + } + + public Set getItemsFound() { + return itemsFound; + } + + public ModelTrackingResult setItemsFound(Set itemsFound) { + this.itemsFound = itemsFound; + return this; + } +} diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/TrackingMobile.java b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/TrackingMobile.java new file mode 100644 index 0000000000..7634b0a32f --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/java/com/mindspore/imagesegmentation/help/TrackingMobile.java @@ -0,0 +1,204 @@ +/** + * 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.imagesegmentation.help; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.Log; + +import androidx.core.graphics.ColorUtils; + +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.FloatBuffer; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +public class TrackingMobile { + private static final String TAG = "TrackingMobile"; + + private static final String IMAGESEGMENTATIONMODEL = "mobile_segment.ms"; + private static final int imageSize = 257; + public static final int NUM_CLASSES = 21; + private static final float IMAGE_MEAN = 127.5F; + private static final float IMAGE_STD = 127.5F; + + public static final int[] segmentColors = new int[2]; + + private Bitmap maskBitmap; + private Bitmap resultBitmap; + private HashSet itemsFound = new HashSet(); + + private final Context mContext; + + private MSConfig msConfig; + private LiteSession session; + private Model model; + + public TrackingMobile(Context context) { + mContext = context; + init(); + } + + public void init() { + // Load the .ms model. + model = new Model(); + if (!model.loadModel(mContext, IMAGESEGMENTATIONMODEL)) { + Log.e(TAG, "Load Model failed"); + return; + } + + // Create and init config. + msConfig = new MSConfig(); + if (!msConfig.init(DeviceType.DT_CPU, 2, CpuBindMode.MID_CPU)) { + Log.e(TAG, "Init context failed"); + return; + } + + // Create the MindSpore lite session. + session = new LiteSession(); + if (!session.init(msConfig)) { + Log.e(TAG, "Create session failed"); + msConfig.free(); + return; + } + msConfig.free(); + + // Complile graph. + if (!session.compileGraph(model)) { + Log.e(TAG, "Compile graph failed"); + model.freeBuffer(); + return; + } + + // Note: when use model.freeBuffer(), the model can not be complile graph again. + model.freeBuffer(); + + } + + public ModelTrackingResult execut(Bitmap bitmap) { + // Set input tensor values. + List inputs = session.getInputs(); + if (inputs.size() != 1) { + Log.e(TAG, "inputs.size() != 1"); + return null; + } + + float resource_height = bitmap.getHeight(); + float resource_weight = bitmap.getWidth(); + + Bitmap scaledBitmap = ImageUtils.scaleBitmapAndKeepRatio(bitmap, imageSize, imageSize); + ByteBuffer contentArray = ImageUtils.bitmapToByteBuffer(scaledBitmap, imageSize, imageSize, IMAGE_MEAN, IMAGE_STD); + + MSTensor inTensor = inputs.get(0); + // int byteLen = (int) inTensor.size(); + inTensor.setData(contentArray); + + // Run graph to infer results. + if (!session.runGraph()) { + Log.e(TAG, "Run graph failed"); + return null; + } + + // Get output tensor values. + List tensorNames = session.getOutputTensorNames(); + Map outputs = session.getOutputMapByTensor(); + for (String tensorName : tensorNames) { + MSTensor output = outputs.get(tensorName); + if (output == null) { + Log.e(TAG, "Can not find output " + tensorName); + return null; + } + float[] results = output.getFloatData(); + + ByteBuffer bytebuffer_results = floatArrayToByteArray(results); + + convertBytebufferMaskToBitmap( + bytebuffer_results, imageSize, imageSize, scaledBitmap, + segmentColors + ); + //scaledBitmap resize成resource_height,resource_weight + scaledBitmap = ImageUtils.scaleBitmapAndKeepRatio(scaledBitmap, (int) resource_height, (int) resource_weight); + resultBitmap = ImageUtils.scaleBitmapAndKeepRatio(resultBitmap, (int) resource_height, (int) resource_weight); + maskBitmap = ImageUtils.scaleBitmapAndKeepRatio(maskBitmap, (int) resource_height, (int) resource_weight); + } + return new ModelTrackingResult(resultBitmap, scaledBitmap, maskBitmap, this.formatExecutionLog(), itemsFound); + } + + private static ByteBuffer floatArrayToByteArray(float[] floats) { + ByteBuffer buffer = ByteBuffer.allocate(4 * floats.length); + FloatBuffer floatBuffer = buffer.asFloatBuffer(); + floatBuffer.put(floats); + return buffer; + } + + private void convertBytebufferMaskToBitmap(ByteBuffer inputBuffer, int imageWidth, + int imageHeight, Bitmap backgroundImage, int[] colors) { + Bitmap.Config conf = Bitmap.Config.ARGB_8888; + maskBitmap = Bitmap.createBitmap(imageWidth, imageHeight, conf); + resultBitmap = Bitmap.createBitmap(imageWidth, imageHeight, conf); + Bitmap scaledBackgroundImage = + ImageUtils.scaleBitmapAndKeepRatio(backgroundImage, imageWidth, imageHeight); + int[][] mSegmentBits = new int[imageWidth][imageHeight]; + inputBuffer.rewind(); + for (int y = 0; y < imageHeight; y++) { + for (int x = 0; x < imageWidth; x++) { + float maxVal = 0f; + mSegmentBits[x][y] = 0; + for (int i = 0; i < NUM_CLASSES; i++) { + float value = inputBuffer.getFloat((y * imageWidth * NUM_CLASSES + x * NUM_CLASSES + i) * 4); + if (i == 0 || value > maxVal) { + maxVal = value; + if (i == 15) { + mSegmentBits[x][y] = i; + } else { + mSegmentBits[x][y] = 0; + } + } + } + itemsFound.add(mSegmentBits[x][y]); + + int newPixelColor = ColorUtils.compositeColors( + colors[mSegmentBits[x][y] == 0 ? 0 : 1], + scaledBackgroundImage.getPixel(x, y) + ); + resultBitmap.setPixel(x, y, newPixelColor); + maskBitmap.setPixel(x, y, mSegmentBits[x][y] == 0 ? colors[0] : scaledBackgroundImage.getPixel(x, y)); + } + } + } + + // Note: we must release the memory at the end, otherwise it will cause the memory leak. + public void free() { + session.free(); + model.free(); + } + + + private final String formatExecutionLog() { + StringBuilder sb = new StringBuilder(); + sb.append("Input Image Size: " + imageSize * imageSize + '\n'); + return sb.toString(); + } + +} diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000000..2b068d1146 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/add.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/add.jpg new file mode 100644 index 0000000000..bdfe6d7518 Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/add.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_001.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_001.jpg new file mode 100644 index 0000000000..4b69593e25 Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_001.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_002.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_002.jpg new file mode 100644 index 0000000000..1a3d5cc100 Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_002.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_003.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_003.jpg new file mode 100644 index 0000000000..1d958a0d1f Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_003.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_004.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_004.jpg new file mode 100644 index 0000000000..8d0cab6a99 Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_004.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_005.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_005.jpg new file mode 100644 index 0000000000..5337b50dad Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_005.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_006.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_006.jpg new file mode 100644 index 0000000000..e28061a2ba Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_006.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_007.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_007.jpg new file mode 100644 index 0000000000..74b046d50b Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_007.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_008.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_008.jpg new file mode 100644 index 0000000000..3a5c7fdcc8 Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_008.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_009.jpg b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_009.jpg new file mode 100644 index 0000000000..d84b9fe27a Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/img_009.jpg differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/logo.png b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/logo.png new file mode 100644 index 0000000000..c90f1dda43 Binary files /dev/null and b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable-xxhdpi/logo.png differ diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable/ic_launcher_background.xml b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000000..07d5da9cbf --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable/progressbar.xml b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable/progressbar.xml new file mode 100644 index 0000000000..d48a929d88 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/res/drawable/progressbar.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/model_zoo/official/lite/image_segmentation/app/src/main/res/layout/activity_main.xml b/model_zoo/official/lite/image_segmentation/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000..b9cb3d8884 --- /dev/null +++ b/model_zoo/official/lite/image_segmentation/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + +