[Huawei Developers] Freemind R:
More information like this, you can visit HUAWEI Developer Forum

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/844/237/5190090000025844237.20200723073151.64363512892562338807218972528693:50510805055712:2800:C5DF9369DFBAFA552C5C28D1C20914FCF32DC6ADE9F24418C36AF0C20F9F57C5.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/844/237/5190090000025844237.20200723073151.64363512892562338807218972528693:50510805055712:2800:C5DF9369DFBAFA552C5C28D1C20914FCF32DC6ADE9F24418C36AF0C20F9F57C5.png[/IMG]​

Image Kit Vision Service of HMS (Huawei Mobile Services) offers us very stylish filters to build a photo editor app. In this article, we will design a nice filtering screen using Vision Service. Moreover, it will be very easy to develop and it will allow you to make elegant beauty apps.

The Image Vision service provides 24 color filters for image optimization. It renders the images you provide and returns them as filtered bitmap objects.

Requirements :

Huawei Phone (It doesn’t support non-Huawei Phones)

EMUI 8.1 or later (Min Android SDK Version 26)

Restrictions :

When using the filter function of Image Vision, make sure that the size of the image to be parsed is not greater than 15 MB, the image resolution is not greater than 8000 x 8000, and the aspect ratio is between 1:3 and 3:1. If the image resolution is greater than 8000 x 8000 after the image is decompressed by adjusting the compression settings or the aspect ratio is not between 1:3 and 3:1, a result code indicating parameter error will be returned. In addition, a larger image size can lead to longer parsing and response time as well as higher memory and CPU usage and power consumption.

Let’s start to build a nice filtering screen. First of all, please follow these steps to create a regular app on App Gallery.

Then we need to add dependencies to the app level gradle file. (implementation ‘com.huawei.hms:image-vision:1.0.2.301’)

Don’t forget to add agconnect plugin. (apply plugin: ‘com.huawei.agconnect’)

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.huawei.agconnect'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.huawei.hmsimagekitdemo"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.huawei.hms:image-vision:1.0.2.301'
}

Add maven repo url and agconnect dependency to the project level gradle file.

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.3.72"
repositories {
google()
jcenter()
maven { url 'http://developer.huawei.com/repo/' }
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'http://developer.huawei.com/repo/' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

After added dependencies, we need to create an ImageVision instance to perform related operations such as obtaining the filter effect. From now on, you can initialize the service.

private fun initFilter() {
coroutineScope.launch { // CoroutineScope is used for the async calls
// Create an ImageVision instance and initialize the service.
imageVisionAPI = ImageVision.getInstance(baseContext)
imageVisionAPI.setVisionCallBack(object : VisionCallBack {
override fun onSuccess(successCode: Int) {
val initCode = imageVisionAPI.init(baseContext, authJson)
// initCode must be 0 if the initialization is successful.
if (initCode == 0)
Log.d(TAG, "getImageVisionAPI rendered image successfully")
}
override fun onFailure(errorCode: Int) {
Log.e(TAG, "getImageVisionAPI failure, errorCode = $errorCode")
Toast.makeText(this@MainActivity, "initFailed", Toast.LENGTH_SHORT).show()
}
})
}
}

Our app is allowed to use the Image Vision service only after the successful verification. So we should provide an authJson object with app credentials. The value of initCode must be 0, indicating that the initialization is successful.

private fun startFilter(filterType: String, intensity: String, compress: String) {
coroutineScope.launch { // CoroutineScope is used for the async calls
val jsonObject = JSONObject()
val taskJson = JSONObject()
try {
taskJson.put("intensity", intensity) //Filter strength. Generally, set this parameter to 1.
taskJson.put("filterType", filterType) // 24 different filterType code
taskJson.put("compressRate", compress) // Compression ratio.
jsonObject.put("requestId", "1")
jsonObject.put("taskJson", taskJson)
jsonObject.put("authJson", authJson) // App can use the service only after it is successfully authenticated.
coroutineScope.launch {
var deferred: Deferred<ImageVisionResult?> = async(Dispatchers.IO) {
imageVisionAPI?.getColorFilter(jsonObject, bitmapFromGallery)
// Obtain the rendering result from visionResult
}
visionResult = deferred.await() // wait till obtain ImageVisionResult object
val image = visionResult?.image
if (image == null)
Log.e(TAG, "FilterException: Couldn't render the image. Check the restrictions while rendering an image by Image Vision Service")
channel.send(image)
// Sending image bitmap with an async channel to make it receive with another channel
}
} catch (e: JSONException) {
Log.e(TAG, "JSONException: " + e.message)
}
}
}

Select an image from the Gallery. Call Init filter method and then start filtering images one by one which are located in recyclerView.

override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
if (resultCode == RESULT_OK) {
when (requestCode) {
PICK_REQUEST ->
if (intent != null) {
coroutineScope.launch {
var deferred: Deferred<Uri?> =
async(Dispatchers.IO) {
intent.data
}
imageUri = deferred.await()
imgView.setImageURI(imageUri)
bitmapFromGallery = (imgView.getDrawable() as BitmapDrawable).bitmap
initFilter()
startFilterForSubImages()
}
}
}
}
}

In our scenario, a user clicks a filter to render the selected image we provide and the Image Vision Result object returns the filtered bitmap. So we need to implement onSelected method of the interface to our activity which gets the FilterItem object of the clicked item from the adapter.

// Initialize and start a filter operation when a filter item is selected
override fun onSelected(item: BaseInterface) {
if (!channelIsFetching)
{
if (bitmapFromGallery == null)
Toast.makeText(baseContext, getString(R.string.select_photo_from_gallery), Toast.LENGTH_SHORT).show()
else
{
var filterItem = item as FilterItem
initFilter() // initialize the vision service
startFilter(filterItem.filterId, "1", "1") // intensity and compress are 1
coroutineScope.launch {
withContext(Dispatchers.Main)
{
imgView.setImageBitmap(channel.receive()) // receive the filtered bitmap result from another channel
stopFilter() // stop the vision service
}
}
}
}
else
Toast.makeText(baseContext, getString(R.string.wait_to_complete_filtering), Toast.LENGTH_SHORT).show()
}

FilterType codes of 24 different filters as follows:

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/844/237/5190090000025844237.20200723073758.17569451828247973236370873800164:50510805055712:2800:5FDF0A6E3396A4D483EB106D3D54F0079E29758EC537DE56C1379CCC0BD7DEF3.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/844/237/5190090000025844237.20200723073758.17569451828247973236370873800164:50510805055712:2800:5FDF0A6E3396A4D483EB106D3D54F0079E29758EC537DE56C1379CCC0BD7DEF3.png[/IMG]​

When the user opens the gallery and selects an image from a directory, we will produce 24 different filtered versions of the image. I used async coroutine channels to render images with first in first out manner. So we can obtain the filter images one by one. Using Image Vision Service with Kotlin Coroutines is so fast and performance-friendly.

To turn off hardware acceleration, configure the AndroidManifest.xml file as follows:

<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

If you do not need to use filters any longer, call the imageVisionAPI.stop() API to stop the Image Vision service. If the returned stopCode is 0, the service is successfully stopped.

private fun stopFilter() {
if(imageVisionAPI != null)
imageVisionAPI.stop() // Stop the service if you don't need anymore
}

We have designed an elegant filtering screen quite easily. Preparing a filter page will no longer take your time. You will be able to develop quickly without having to know OpenGL. You should try Image Kit Vision Service as soon as possible.

And the result :

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/844/237/5190090000025844237.20200723074034.73605371408380682217617015445427:50510805055712:2800:C7FA7ECB1A68D207D261F9FB97BD7975A1779597C2D17015C6832E86579D87B3.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/844/237/5190090000025844237.20200723074034.73605371408380682217617015445427:50510805055712:2800:C7FA7ECB1A68D207D261F9FB97BD7975A1779597C2D17015C6832E86579D87B3.png[/IMG]​

For more information about HMS Image Kit Vision Service please refer to :

HMS Image Kit Vision Service Documentation