Editing Image Using HMS (ML Kit, Cloud Storage, Auth Service) Android — Kotlin

Sezer Özaltun
Huawei Developers
Published in
6 min readMay 17, 2023
Huawei Services Used in the Project

Introduction

Hello everyone, I’m here with the new article. In this article, I will explain how to remove the background of your images using ML Kit, Cloud Storage, and Auth Service from Huawei mobile services.

We will remove the background of the images using the ML Kit

We will securely upload the photos we edited using Cloud Storage to the cloud, and we will have the opportunity to access them from anywhere. We will use the upload, download, and delete listing features, which are Cloud Storage processes.

Auth Service, on the other hand, will be needed for authentication in the use of Cloud Storage.

Integration of Services

Before starting the coding part, you need to integrate HMS Core into your application. You can click the link here for this.

There are a few steps we need to take to integrate the services into our project.

1. Sign in to AppGallery Connect and click My Projects

AppGallery Connect My Projects

2. Click your project card and select the app for which you want to enable a service from the app drop-down list on the top.

Selecting Project

3. To use ML Kit and Auth Service, click on Manage APIs tab, and enable ML Kit and Auth Service.

Enable ML Kit
Enable Auth Service

4. To use Cloud Storage, we need to perform the following steps.

Enable Cloud Storage
Set Instance and location
Finish the integration of Cloud Storage

5. Let’s add the necessary permissions to the AndroidManifest.xml file in Android Studio.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="false"
android:requestLegacyExternalStorage="true"
.
.
. <meta-data
android:name="com.huawei.hms.ml.DEPENDENCY"
android:value="imgseg" />
</application>

6. Let’s add the necessary dependencies in the build.gradle.

//Huawei Auth
implementation 'com.huawei.agconnect:agconnect-auth:1.6.5.300'
//Ml Kit
implementation 'com.huawei.hms:ml-computer-vision-segmentation:3.7.0.302'
// Import the multiclass segmentation model package.
implementation 'com.huawei.hms:ml-computer-vision-image-segmentation-multiclass-model:3.7.0.302'
// Import the human body segmentation model package.
implementation 'com.huawei.hms:ml-computer-vision-image-segmentation-body-model:3.7.0.302'
// Import the hair segmentation model package.
implementation 'com.huawei.hms:ml-computer-vision-image-segmentation-hair-model:3.7.0.302'
//Cloud Storage
implementation "com.huawei.agconnect:agconnect-storage:1.5.0.100"

Implementation

Until now, we have enabled the necessary services via AppGallery Connect and added the necessary dependencies to our project. If you have encountered any errors or want to examine them in more detail, you can review the relevant resources in the references section at the end of the article.

ML Kit Implementation

var setting = MLImageSegmentationSetting.Factory()
.setExact(true)
.setAnalyzerType(MLImageSegmentationSetting.BODY_SEG)
.setScene(MLImageSegmentationScene.FOREGROUND_ONLY)
.create()
analyzer = MLAnalyzerFactory.getInstance().getImageSegmentationAnalyzer(setting)
val drawable: BitmapDrawable = binding.imageView.drawable as BitmapDrawable
bitmap = drawable.bitmap
val mlFrame = MLFrame.Creator().setBitmap(bitmap).create()
val task: Task<MLImageSegmentation> = analyzer.asyncAnalyseFrame(mlFrame)
task.addOnSuccessListener {
removeBackGround(it)
}.addOnFailureListener {
Log.e(TAG1, "analyse -> asyncAnalyseFrame: ", it)
}

We create a new segmentation with the above lines of code. Here, we set the internal analyzer type to BOD_SEG and setScene to FOREGROUND_ONLY to keep human analysis and only foreground permissions. Then we select our image with the bitmap and run the removeBackGround method when the task is successful.

private fun removeBackground(mlImageSegmentation: MLImageSegmentation?) {
if (mlImageSegmentation != null) {
if (bitmap == null) {
Log.e(TAG1, "bitmap is null")
return
}
val bitmapFore: Bitmap = mlImageSegmentation.getForeground()
if (bitmapFore != null) {
binding.imageView.setImageBitmap(bitmapFore)
} else {
Log.e(TAG1, "bitmap is null")
}
}
}

In the removeBackGround method, we delete the background of the image we sent with the bitmap with the MLImageSegmentation class.

Auth Service Implementation

The purpose of using Auth Service is that Cloud Storage requests an authentication while using it.

if (AGConnectAuth.getInstance().currentUser != null) {
DriverManager.println("already sign a user")
Log.i(TAG2, "already sign a user")
return
} else {
AGConnectAuth.getInstance().signInAnonymously()
.addOnSuccessListener {
DriverManager.println("AGConnect OnSuccess")
Log.i(TAG2, "AGConnect OnSuccess")
}
.addOnFailureListener { e ->
DriverManager.println("AGConnect OnFail: " + e.message)
Log.i(TAG2, "AGConnect OnFail ${e.message}")
}
}

Using the above line of code, we log in anonymously and can use Cloud Storage. You can also log in as a real user if you want.

Cloud Storage Implementation

First of all, we need to get write and read permissions with the following code.

1. private val permissions = arrayOf<String>(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
2. ActivityCompat.requestPermissions(this, permissions, 1)

After that, we need to get an instance with storage management in order to use Cloud Storage. This instance will provide our connection to the Cloud.

private var mAGCStorageManagement: AGCStorageManagement? = null
val storageManagement = AGCStorageManagement.getInstance()
private fun initAGCStorageManagement() {
mAGCStorageManagement = AGCStorageManagement.getInstance()
Log.i(TAG2, "Init AGC Storage Management success! ")
}

Cloud Storage Upload

With the following line of code, we can upload our images to the Cloud side. The path here is the name of the file to be created on the cloud side.

val progressDialog = ProgressDialog(this)
progressDialog.setMessage("Uploading File....")
progressDialog.setCancelable(false)
progressDialog.show()
val systemCurrentTime: Long = System.currentTimeMillis()
val path = "/images/${systemCurrentTime}.png"
val agcSdkDirPath = agcSdkDirPath
val file = File(agcSdkDirPath)
if (!file.exists()) {
Log.i(TAG2, "file is not exist!")
return
} else {
Log.i(TAG2, "file is exist")
val storageReference =
mAGCStorageManagement!!.getStorageReference(path)
val uploadTask = storageReference.putFile(file)

uploadTask.addOnSuccessListener {
Log.i(TAG2, "upload success!")
progressDialog.dismiss()
}
.addOnFailureListener { e: Exception ->
progressDialog.dismiss()
Log.i(
TAG2,
"Upload Failed $e"
)
}
}
private val agcSdkDirPath: String
get() {
DriverManager.println("path=$path")
val dir = File(path)
if (!dir.exists()) {
dir.mkdirs()
}
return path!!
}

Cloud Storage Listing Files

With the following lines of code, we can view the files we have uploaded to “images/ “ folders and list them on the list.

val path = "images/"
val storageReference = mAGCStorageManagement?.getStorageReference(path)
var listResultTask: Task<ListResult>? = null
listResultTask = storageReference?.list(100)
listResultTask?.addOnSuccessListener {
fileList = ArrayList(it.fileList)
mAdapter = DownloadListAdapter(
this@DownloadListActivity,
fileList = fileList,
mAGCStorageManagement,
this@DownloadListActivity
)
binding.recyclerView.adapter = mAdapter
mAdapter.notifyDataSetChanged()

Log.i("MYSTORAGE", "SUCCEDD: ${fileList.size}")
}?.addOnFailureListener {
Log.e("MYSTORAGE", "FAIL: ${it.printStackTrace()}")
}
}

Cloud Storage Download

When we want to download any of our files from the Cloud, we need to define the path and name of that file correctly. For this, I defined the agcSdkDirPath and fileName parameters to the File method and I send a file download request with storageReference.getFile(file).

val progressDialog = ProgressDialog(context)
progressDialog.setMessage("Downloading File....")
progressDialog.setCancelable(false)
progressDialog.show()
val fileName = fileName
val path = path
val agcSdkDirPath = agcSdkDirPath2
val file = File(agcSdkDirPath, fileName)
val storageReference = mAGCStorageManagement!!.getStorageReference(path)
val downloadTask = storageReference.getFile(file)
downloadTask.addOnSuccessListener {
Toast.makeText(context, "Download Succeed", Toast.LENGTH_SHORT).show()
progressDialog.dismiss()
}.addOnFailureListener { e: Exception ->
Toast.makeText(context, "Download Error", Toast.LENGTH_SHORT).show()
progressDialog.dismiss()
Log.i("MYSTORAGE", "DOWNLOAD ERROR: $e")
}
private val agcSdkDirPath2: String
get() {
val path =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absoluteFile.toString()
DriverManager.println("path=$path")
val dir = File(path)
if (!dir.exists()) {
dir.mkdirs()
}
return path
}

Cloud Storage Delete

As in downloading a file, the path must be given correctly and the storageReference.delete() method must be called.

val path = path
DriverManager.println("path=%s$path")
val storageReference = mAGCStorageManagement!!.getStorageReference(path)
val deleteTask = storageReference.delete()
deleteTask.addOnSuccessListener {
Toast.makeText(context, "Delete Succeed", Toast.LENGTH_SHORT).show()
activity.getAllList()
notifyDataSetChanged()

}
.addOnFailureListener { e: Exception ->
Toast.makeText(context, "Delete Error:", Toast.LENGTH_SHORT).show()
Log.i("MYSTORAGE", "DELETE ERROR: $e")
}
Screenshots

--

--