Comparison Between Huawei ML Kit Text Recognition & Firebase ML Kit Text Recognition - Huawei Developers

Comparison Between Huawei ML Kit Text Recognition & Firebase ML Kit Text Recognition
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
In this article, we will compare Huawei ML Kit Text Recognition and Firebase ML Kit Text Recognition usages and also we will create sample Android applications to understand how they work. Lets get start it.
Huawei ML Kit Text Recognition
About The Service
HUAWEI ML Kit allows your apps to easily leverage Huawei’s long-term proven expertise in machine learning to support diverse artificial intelligence (AI) applications throughout a wide range of industries. Thanks to Huawei’s technology accumulation, ML Kit provides diversified leading machine learning capabilities that are easy to use, helping you develop various AI apps.
Text Recognition
The text recognition service can extracts text from images of receipts, business cards, and documents. This service is widely used in office, education, transit, and other apps. For example, you can use this service in a translation app to extract text in a photo and translate the text, improving user experience.
This service can run on the cloud or device, but the supported languages differ in the two scenarios. On-device APIs can recognize text in Simplified Chinese, Japanese, Korean, and Latin-based languages (refer to Latin Script Supported by On-device Text Recognition). When running on the cloud, the service can recognize text in languages such as Simplified Chinese, English, Spanish, Portuguese, Italian, German, French, Russian, Japanese, Korean, Polish, Finnish, Norwegian, Swedish, Danish, Turkish, Thai, Arabic, Hindi, and Indonesian.
Configure your project on AppGallery Connect
Registering a Huawei ID
You need to register a Huawei ID to use the plugin. If you don’t have one, follow the instructions here.
Preparations for Integrating HUAWEI HMS Core
First of all, you need to integrate Huawei Mobile Services with your application. I will not get into details about how to integrate your application but you can use this tutorial as step by step guide.
1. Integrating the Text Recognition SDK
You need to integrate the base SDK and then one or more required language model packages in your app-level build.gradle.
Code:
//AGC Core
implementation 'com.huawei.agconnect:agconnect-core:1.4.0.300'
//ML OCR Base SDK
implementation 'com.huawei.hms:ml-computer-vision-ocr:2.0.1.300'
//Latin-based Language Model Package
implementation 'com.huawei.hms:ml-computer-vision-ocr-latin-model:2.0.1.300'
2. Automatically Updating the Machine Learning Model
To use the on-device text recognition service, add the following statements to the AndroidManifest.xml file.
Code:
<manifest
...
<meta-data
android:name="com.huawei.hms.ml.DEPENDENCY"
android:value= "ocr"/>
...
</manifest>
3. There will be an ImageView, a TextView and two Button in our RelativeLayout
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/captured_image_view"
android:layout_width="match_parent"
android:layout_height="400dp" />
<TextView
android:id="@+id/detected_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/captured_image_view"
android:textSize="20sp"
android:maxLines="10"
android:layout_margin="10dp"
/>
<Button
android:id="@+id/capture_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/detect_text_from_image"
android:text="@string/button_text"
android:textAllCaps="false"
android:background="@color/colorAccent"
android:textColor="@android:color/white"
android:textSize="28sp"
android:layout_marginBottom="5dp"
/>
<Button
android:id="@+id/detect_text_from_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/button_detect"
android:textAllCaps="false"
android:background="@color/colorPrimary"
android:textColor="@android:color/white"
android:textSize="28sp"
/>
</RelativeLayout>
4. Text Recognition from Images on the Device
Take a photo with a camera app
The Android way of delegating actions to other applications is to invoke an Intent that describes what you want done. This process involves three pieces: The Intent itself, a call to start the external Activity, and some code to handle the image data when focus returns to your activity.We will see the result into onActivityResult.
Code:
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hmf.tasks.OnSuccessListener;
import com.huawei.hmf.tasks.Task;
import com.huawei.hms.mlsdk.MLAnalyzerFactory;
import com.huawei.hms.mlsdk.common.MLFrame;
import com.huawei.hms.mlsdk.text.MLLocalTextSetting;
import com.huawei.hms.mlsdk.text.MLText;
import com.huawei.hms.mlsdk.text.MLTextAnalyzer;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
private MLTextAnalyzer mTextAnalyzer;
private ImageView capturedImageView;
private TextView detectedTextView;
private Button buttonAddImage, detectTextBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
capturedImageView = findViewById(R.id.captured_image_view);
detectedTextView = findViewById(R.id.detected_text_view);
buttonAddImage = findViewById(R.id.capture_image);
detectTextBtn=findViewById(R.id.detect_text_from_image);
buttonAddImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dispatchTakePictureIntent();
detectedTextView.setText("");
}
});
detectTextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
createMLTextAnalyzer();
}
});
}
private void dispatchTakePictureIntent() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK && data != null) {
Bundle extras = data.getExtras();
Bitmap selectedBitmap = (Bitmap) extras.get("data");
capturedImageView.setImageBitmap(selectedBitmap);
asyncAnalyzeText(selectedBitmap);
}
}
5. Create the text analyzer MLTextAnalyzer to recognize text in images. You can set MLLocalTextSetting to specify languages that can be recognized. If you do not set the languages, only Latin-based languages can be recognized by default.
Code:
private void createMLTextAnalyzer() {
MLLocalTextSetting setting = new MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.setLanguage("en")
.create();
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting);
}
6. Pass the MLFrame object to the asyncAnalyseFrame method for text recognition.
Code:
private void asyncAnalyzeText(Bitmap bitmap) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer();
}
MLFrame frame = MLFrame.fromBitmap(bitmap);
Task<MLText> task = mTextAnalyzer.asyncAnalyseFrame(frame);
task.addOnSuccessListener(new OnSuccessListener<MLText>() {
@Override
public void onSuccess(MLText text) {
detectedTextView.setText(text.getStringValue());
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
detectedTextView.setText(e.getMessage());
}
});
}
7. After the recognition is complete, stop the analyzer to release recognition resources.
Code:
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (mTextAnalyzer != null)
mTextAnalyzer.stop();
} catch (IOException e) {
e.printStackTrace();
}
}
8. You can see all the code in Main Activity below.
Code:
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hmf.tasks.OnSuccessListener;
import com.huawei.hmf.tasks.Task;
import com.huawei.hms.mlsdk.MLAnalyzerFactory;
import com.huawei.hms.mlsdk.common.MLFrame;
import com.huawei.hms.mlsdk.text.MLLocalTextSetting;
import com.huawei.hms.mlsdk.text.MLText;
import com.huawei.hms.mlsdk.text.MLTextAnalyzer;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
private MLTextAnalyzer mTextAnalyzer;
private ImageView capturedImageView;
private TextView detectedTextView;
private Button buttonAddImage, detectTextBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
capturedImageView = findViewById(R.id.captured_image_view);
detectedTextView = findViewById(R.id.detected_text_view);
buttonAddImage = findViewById(R.id.capture_image);
detectTextBtn=findViewById(R.id.detect_text_from_image);
buttonAddImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dispatchTakePictureIntent();
detectedTextView.setText("");
}
});
detectTextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
createMLTextAnalyzer();
}
});
}
private void dispatchTakePictureIntent() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK && data != null) {
Bundle extras = data.getExtras();
Bitmap selectedBitmap = (Bitmap) extras.get("data");
capturedImageView.setImageBitmap(selectedBitmap);
asyncAnalyzeText(selectedBitmap);
}
}
private void createMLTextAnalyzer() {
MLLocalTextSetting setting = new MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.setLanguage("en")
.create();
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting);
}
private void asyncAnalyzeText(Bitmap bitmap) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer();
}
MLFrame frame = MLFrame.fromBitmap(bitmap);
Task<MLText> task = mTextAnalyzer.asyncAnalyseFrame(frame);
task.addOnSuccessListener(new OnSuccessListener<MLText>() {
@Override
public void onSuccess(MLText text) {
detectedTextView.setText(text.getStringValue());
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
detectedTextView.setText(e.getMessage());
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (mTextAnalyzer != null)
mTextAnalyzer.stop();
} catch (IOException e) {
e.printStackTrace();
}
}
}
9. Here’s the result.
Firebase ML Kit Text Recognition
You can use ML Kit to recognize text in images. ML Kit has both a general-purpose API suitable for recognizing text in images, such as the text of a street sign, and an API optimized for recognizing the text of documents. The general-purpose API has both on-device and cloud-based models.
Before you begin
1. If you haven’t already, add Firebase to your Android project.
2. In your project-level build.gradle file, make sure to include Google's Maven repository in both your buildscript and allprojects sections.
3. Add the dependencies for the ML Kit Android libraries to your module (app-level) Gradle file (usually app/build.gradle):
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
dependencies {
// ...
implementation 'com.google.firebase:firebase-core:15.0.2'
implementation 'com.google.firebase:firebase-ml-vision:15.0.0'
}
4. add the following declaration to your app’s AndroidManifest.xml file
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<application ...>
...
<meta-data
android:name="com.google.firebase.ml.vision.DEPENDENCIES"
android:value="ocr" />
<!-- To use multiple models: android:value="ocr,model2,model3" -->
</application>
5. There will be an ImageView, a TextView and two Button in our RelativeLayout
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/captured_image_view"
android:layout_width="match_parent"
android:layout_height="400dp" />
<TextView
android:id="@+id/detected_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/captured_image_view"
android:textSize="20sp"
android:maxLines="10"
android:layout_margin="10dp"
/>
<Button
android:id="@+id/capture_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/detect_text_from_image"
android:text="@string/button_text"
android:textAllCaps="false"
android:background="@color/colorAccent"
android:textColor="@android:color/white"
android:textSize="28sp"
android:layout_marginBottom="5dp"
/>
<Button
android:id="@+id/detect_text_from_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/button_detect"
android:textAllCaps="false"
android:background="@color/colorPrimary"
android:textColor="@android:color/white"
android:textSize="28sp"
/>
</RelativeLayout>
6. Take a photo with a camera app
Here’s a function that invokes an intent to capture a photo.
Code:
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.text.FirebaseVisionText;
import com.google.firebase.ml.vision.text.FirebaseVisionTextDetector;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private Button captureImageBtn, detectTextBtn;
private ImageView capturedImageView;
private TextView detectedTextView;
static final int REQUEST_IMAGE_CAPTURE = 1;
Bitmap imageBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
captureImageBtn = findViewById(R.id.capture_image);
detectTextBtn = findViewById(R.id.detect_text_from_image);
capturedImageView = findViewById(R.id.captured_image_view);
detectedTextView = findViewById(R.id.detected_text_view);
captureImageBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dispatchTakePictureIntent();
detectedTextView.setText("");
}
});
detectTextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
detectTextFromImage();
}
});
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
7. The Android Camera application encodes the photo in the return Intent delivered to onActivityResult() as a small Bitmap in the extras, under the key "data". The following code retrieves this image and displays it in an ImageView.
Code:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
imageBitmap = (Bitmap) extras.get("data");
capturedImageView.setImageBitmap(imageBitmap);
}
}
8. To create a FirebaseVisionImage object from a Bitmap object.
Code:
private void detectTextFromImage() {
FirebaseVisionImage firebaseVisionImage = FirebaseVisionImage.fromBitmap(imageBitmap);
FirebaseVisionTextDetector firebaseVisionTextDetector = FirebaseVision.getInstance().getVisionTextDetector();
firebaseVisionTextDetector.detectInImage(firebaseVisionImage).addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
@Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
displayTextFromImage(firebaseVisionText);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
Log.d("Error", e.getMessage());
}
});
}
9. To display text from the image
Code:
private void displayTextFromImage(FirebaseVisionText firebaseVisionText) {
List<FirebaseVisionText.Block>blockList=firebaseVisionText.getBlocks();
if(blockList.size()==0){
Toast.makeText(this, "No Text Found in Image", Toast.LENGTH_SHORT).show();
}else{
for(FirebaseVisionText.Block block: firebaseVisionText.getBlocks()){
String text=block.getText();
detectedTextView.setText(text);
}
}
}
10. You can see all the code in Main Activity below.
Code:
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.text.FirebaseVisionText;
import com.google.firebase.ml.vision.text.FirebaseVisionTextDetector;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private Button captureImageBtn, detectTextBtn;
private ImageView capturedImageView;
private TextView detectedTextView;
static final int REQUEST_IMAGE_CAPTURE = 1;
Bitmap imageBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
captureImageBtn = findViewById(R.id.capture_image);
detectTextBtn = findViewById(R.id.detect_text_from_image);
capturedImageView = findViewById(R.id.captured_image_view);
detectedTextView = findViewById(R.id.detected_text_view);
captureImageBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dispatchTakePictureIntent();
detectedTextView.setText("");
}
});
detectTextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
detectTextFromImage();
}
});
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
imageBitmap = (Bitmap) extras.get("data");
capturedImageView.setImageBitmap(imageBitmap);
}
}
private void detectTextFromImage() {
FirebaseVisionImage firebaseVisionImage = FirebaseVisionImage.fromBitmap(imageBitmap);
FirebaseVisionTextDetector firebaseVisionTextDetector = FirebaseVision.getInstance().getVisionTextDetector();
firebaseVisionTextDetector.detectInImage(firebaseVisionImage).addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
@Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
displayTextFromImage(firebaseVisionText);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
Log.d("Error", e.getMessage());
}
});
}
private void displayTextFromImage(FirebaseVisionText firebaseVisionText) {
List<FirebaseVisionText.Block>blockList=firebaseVisionText.getBlocks();
if(blockList.size()==0){
Toast.makeText(this, "No Text Found in Image", Toast.LENGTH_SHORT).show();
}else{
for(FirebaseVisionText.Block block: firebaseVisionText.getBlocks()){
String text=block.getText();
detectedTextView.setText(text);
}
}
}
}
11. Here’s the result.
For more information about HUAWEI ML Kit, visit:
https://developer.huawei.com/consumer/en/hms/huawei-mlkit
Other Resources:
https://developer.android.com/training/camera/photobasics#java
https://firebase.google.com/docs/ml-kit/android/recognize-text
https://firebase.google.com/support/release-notes/android
Related Links
Original post: https://medium.com/huawei-developers/comparison-between-huawei-ml-kit-text-recognition-and-firebase-ml-kit-text-recognition-98217e3cfa84

Nice article
Is huawei ML kit is better than firebase ML kit?

riteshchanchal said:
Is huawei ML kit is better than firebase ML kit?
Click to expand...
Click to collapse
I'm not sure which one is better here I just used text recognition. But in this example the Huawei Ml kit worked better. Also, payment is required to use the latest version of the Firebase ML kit but Huawei ML kit is free.

Related

Validate your news: Feat. Huawei ML Kit (Text Image Super-Resolution)

Introduction
Quality improvement has become crucial in this era of digitalization where all our documents are kept in the folders, shared over the network and read on the digital device.
Imaging the grapple of an elderly person who has no way to read and understand an old prescribed medical document which has gone blurred and deteriorated.
Can we evade such issues??
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Let’s unbind what Huawei ML Kit offers to overcome such challenges of our day to day life.
Huawei ML Kit provides Text Image Super-Resolution API to improvise the quality and visibility of old and blurred text on an image.
Text Image Super-Resolution can zoom in an image that contains the text and significantly improve the definition of the text.
Limitations
The text image super-resolution service requires images with the maximum resolution 800 x 800 px and the length greater than or equal to 64 px.
Development Overview
Prerequisite
Must have a Huawei Developer Account
Must have Android Studio 3.0 or later
Must have a Huawei phone with HMS Core 4.0.2.300 or later
EMUI 3.0 or later
Software Requirements
Java SDK 1.7 or later
Android 5.0 or later
Preparation
Create an app or project in the Huawei app gallery connect.
Provide the SHA Key and App Package name of the project in App Information Section and enable the ML Kit API.
Download the agconnect-services.json file.
Create an Android project.
Integration
Add below to build.gradle (project)file, under buildscript/repositories and allprojects/repositories.
Code:
Maven {url 'http://developer.huawei.com/repo/'}
Add below to build.gradle (app) file, under dependencies.
To use the Base SDK of ML Kit-Text Image Super Resolution, add the following dependencies:
Code:
dependencies{
// Import the base SDK.
implementation 'com.huawei.hms:ml-computer-vision-textimagesuperresolution:2.0.3.300'
}
Adding permissions
Code:
<uses-permission android:name="android.permission.CAMERA " />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Automatically Updating the Machine Learning Model
Add the following statements to the AndroidManifest.xml file to automatically install the machine learning model on the user’s device.
Code:
<meta-data
android:name="com.huawei.hms.ml.DEPENDENCY"
android:value= "tisr"/>
Development Process
This article focuses on demonstrating the capabilities of Huawei’s ML Kit: Text Image Super- Resolution API’s.
Here is the example which explains how can we integrate this powerful API to leverage the benefits of improvising the Text-Image quality and provide full accessibility to the reader to read the old and blur newspapers from an online news directory.
TextImageView Activity : Launcher Activity
This is main activity of “The News Express “application.
Code:
package com.mlkitimagetext.example;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.mlkitimagetext.example.textimagesuperresolution.TextImageSuperResolutionActivity;
public class TextImageView extends AppCompatActivity {
Button NewsExpress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_image_view);
NewsExpress = findViewById(R.id.bt1);
NewsExpress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(TextImageView.this, TextImageSuperResolutionActivity.class));
}
});
}
}
Activity_text_image_view.xml
This is the view class for the above activity class.
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/im3">
<LinearLayout
android:id="@+id/ll_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:orientation="vertical">
<Button
android:id="@+id/bt1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:layout_gravity="center"
android:text="The News Express"
android:textAllCaps="false"
android:textStyle="bold"
android:textSize="34dp"
android:textColor="@color/mlkit_bcr_text_color_white"></Button>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textStyle="bold"
android:text="Validate Your News"
android:textSize="20sp"
android:layout_gravity="center"
android:textColor="#9fbfdf"/>
</LinearLayout>
</RelativeLayout>
TextImageSuperResolutionActivity
This activity class performs following actions:
Image picker implementation to pick the image from the gallery
Convert selected image to Bitmap
Create a text image super-resolution analyser.
Create an MLFrame object by using android.graphics.Bitmap.
Perform super-resolution processing on the image with text.
Stop the analyser to release detection resources.
Code:
package com.mlkitimagetext.example;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hmf.tasks.OnSuccessListener;
import com.huawei.hmf.tasks.Task;
import com.huawei.hms.mlsdk.common.MLException;
import com.huawei.hms.mlsdk.common.MLFrame;
import com.huawei.hms.mlsdk.textimagesuperresolution.MLTextImageSuperResolution;
import com.huawei.hms.mlsdk.textimagesuperresolution.MLTextImageSuperResolutionAnalyzer;
import com.huawei.hms.mlsdk.textimagesuperresolution.MLTextImageSuperResolutionAnalyzerFactory;
import com.mlkitimagetext.example.R;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
public class TextImageSuperResolutionActivity<button> extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "TextSuperResolutionActivity";
private MLTextImageSuperResolutionAnalyzer analyzer;
private static final int INDEX_3X = 1;
private static final int INDEX_ORIGINAL = 2;
private ImageView imageView;
private Bitmap srcBitmap;
Uri imageUri;
Boolean ImageSetupFlag = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_super_resolution);
imageView = findViewById(R.id.image);
imageView.setOnClickListener(this);
findViewById(R.id.btn_load).setOnClickListener(this);
createAnalyzer();
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.btn_load) {
openGallery();
}else if (view.getId() == R.id.image)
{
if(ImageSetupFlag != true)
{
detectImage(INDEX_3X);
}else {
detectImage(INDEX_ORIGINAL);
ImageSetupFlag = false;
}
}
}
private void openGallery() {
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(gallery, 1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 1){
imageUri = data.getData();
try {
srcBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
} catch (IOException e) {
e.printStackTrace();
}
//BitmapFactory.decodeResource(getResources(), R.drawable.new1);
imageView.setImageURI(imageUri);
}
}
private void release() {
if (analyzer == null) {
return;
}
analyzer.stop();
}
private void detectImage(int type) {
if (type == INDEX_ORIGINAL) {
setImage(srcBitmap);
return;
}
if (analyzer == null) {
return;
}
// Create an MLFrame by using the bitmap.
MLFrame frame = new MLFrame.Creator().setBitmap(srcBitmap).create();
Task<MLTextImageSuperResolution> task = analyzer.asyncAnalyseFrame(frame);
task.addOnSuccessListener(new OnSuccessListener<MLTextImageSuperResolution>() {
public void onSuccess(MLTextImageSuperResolution result) {
// success.
Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT).show();
setImage(result.getBitmap());
ImageSetupFlag = true;
}
})
.addOnFailureListener(new OnFailureListener() {
public void onFailure(Exception e) {
// failure.
if (e instanceof MLException) {
MLException mlException = (MLException) e;
// Get the error code, developers can give different page prompts according to the error code.
int errorCode = mlException.getErrCode();
// Get the error message, developers can combine the error code to quickly locate the problem.
String errorMessage = mlException.getMessage();
Toast.makeText(getApplicationContext(), "Error:" + errorCode + " Message:" + errorMessage, Toast.LENGTH_SHORT).show();
} else {
// Other exception。
Toast.makeText(getApplicationContext(), "Failed:" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
}
private void setImage(final Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
}
private void createAnalyzer() {
analyzer = MLTextImageSuperResolutionAnalyzerFactory.getInstance().getTextImageSuperResolutionAnalyzer();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (srcBitmap != null) {
srcBitmap.recycle();
}
release();
}
}
More details, you can check https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202388336667910498&fid=0101187876626530001
Which all image format is supported?

Demystifying Document Skew Correction feat. HUAWEI ML KIT

Prolusion
This era is revolutionary for the science and research as most of the innovation is for the consumer needs.
We all know that document scanning is routine errand for most of us and a dire need for today’s digital world.
In such needs, we often require a powerful mechanism which can correct the informalities and skew for our documents.
Document Skew Correction is a technique which helps in correcting the tilted images to the right facing angle which further improvise the visibility of the image.
Huawei ML Kit offers a robust API for skew correction which enables automatic position identification of a document in an image and corrects the shooting angle. It also allows users to customize the edge points.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Suggestions
It is recommended the shooting angle of the image should be within 30 degrees.
It is recommended that the image size be within the range of 320 x 320 px to 1920 x 1920 px.
Skew detection API supports JPG, JPEG, and PNG image formats.
Development Overview
Prerequisite
Must have a Huawei Developer Account
Must have Android Studio 3.0 or later
Must have a Huawei phone with HMS Core 4.0.2.300 or later
EMUI 3.0 or later
Software Requirements
Java SDK 1.7 or later
Android 5.0 or later
Preparation
Create an app or project in the Huawei app gallery connect.
Provide the SHA Key and App Package name of the project in App Information Section and enable the ML Kit API.
Download the agconnect-services.json file.
Create an Android project.
Integration
Add below to build.gradle (project)file, under buildscript/repositories and allprojects/repositories.
Maven {url 'http://developer.huawei.com/repo/'}
Add below to build.gradle (app) file, under dependencies.
To use the Base SDK of ML Kit-Document Skew Correction, add the following dependencies:
dependencies{
// Import the base SDK.
implementation 'com.huawei.hms:ml-computer-vision-documentskew:2.0.4.300'
}
To use the Full SDK of ML Kit- Document Skew Correction, add the following dependencies:
dependencies{
// Import the Model Package.
implementation 'com.huawei.hms:ml-computer-vision-documentskew-model:2.0.4.300'
}
Adding permissions
<uses-permission android:name="android.permission.CAMERA " />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Automatically Updating the Machine Learning Model
Add the following statements to the AndroidManifest.xml file to automatically install the machine learning model on the user’s device.
<meta-data
android:name="com.huawei.hms.ml.DEPENDENCY"
android:value= "dsc"/>
Development Process
This article focuses on demonstrating the capabilities of Huawei’s ML Kit: Document Skew Correction API’s.
Here is the example of “SUPER DOC” application which allows user to capture and fetch the images from local memory of the device and let them correct using the document which explains how we can integrate this powerful API to leverage the benefits of correcting a skewed document image to provider the right angle to the document which eventually improves the readability of the document.
Skewdetect Activity
This activity is responsible to click and fetch the images and detect them for the skew correction and further align them and provide the output as aligned document image.
Code:
package com.mlkit.documentSkewCorrection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hmf.tasks.OnSuccessListener;
import com.huawei.hmf.tasks.Task;
import com.huawei.hms.mlsdk.common.MLFrame;
import com.huawei.hms.mlsdk.dsc.MLDocumentSkewCorrectionConstant;
import com.huawei.hms.mlsdk.dsc.MLDocumentSkewCorrectionCoordinateInput;
import com.huawei.hms.mlsdk.dsc.MLDocumentSkewCorrectionResult;
import com.huawei.hms.mlsdk.dsc.MLDocumentSkewCorrectionAnalyzer;
import com.huawei.hms.mlsdk.dsc.MLDocumentSkewCorrectionAnalyzerFactory;
import com.huawei.hms.mlsdk.dsc.MLDocumentSkewCorrectionAnalyzerSetting;
import ccom.huawei.hms.mlsdk.dsc.MLDocumentSkewDetectResult;
import com.mlkit.documentSkewCorrection.R;
public class SkewDetect extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "SkewDetectActivity";
private MLDocumentSkewCorrectionAnalyzer analyzer;
private ImageView mImageView;
private Bitmap bitmap;
Uri imageUri;
private MLDocumentSkewCorrectionCoordinateInput input;
private MLFrame mlFrame;
Boolean FlagCameraClickDone = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_document_skew_correction);
this.findViewById(R.id.image_refine).setOnClickListener(this);
this.mImageView = this.findViewById(R.id.image_refine_result);
if(FlagCameraClickDone)
{
this.findViewById(R.id.image_refine).setVisibility(View.VISIBLE);
}
else
{
this.findViewById(R.id.image_refine).setVisibility(View.GONE);
}
// Create the setting.
MLDocumentSkewCorrectionAnalyzerSetting setting = new MLDocumentSkewCorrectionAnalyzerSetting
.Factory()
.create();
// Get the analyzer.
this.analyzer = MLDocumentSkewCorrectionAnalyzerFactory.getInstance().getDocumentSkewCorrectionAnalyzer(setting);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FlagCameraClickDone = false;
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(gallery, 1);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 1){
imageUri = data.getData();
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
// Create a MLFrame by using the bitmap.
this.mlFrame = new MLFrame.Creator().setBitmap(this.bitmap).create();
} catch (IOException e) {
e.printStackTrace();
}
//BitmapFactory.decodeResource(getResources(), R.drawable.new1);
FlagCameraClickDone = true;
this.findViewById(R.id.image_refine).setVisibility(View.VISIBLE);
mImageView.setImageURI(imageUri);
}
}
@Override
public void onClick(View v) {
this.analyzer();
}
private void analyzer() {
// Call document skew detect interface to get coordinate data
Task<MLDocumentSkewDetectResult> detectTask = this.analyzer.asyncDocumentSkewDetect(this.mlFrame);
detectTask.addOnSuccessListener(new OnSuccessListener<MLDocumentSkewDetectResult>() {
@Override
public void onSuccess(MLDocumentSkewDetectResult detectResult) {
Log.e(TAG, detectResult.getResultCode() + ":");
if (detectResult != null) {
int resultCode = detectResult.getResultCode();
// Detect success.
if (resultCode == MLDocumentSkewCorrectionConstant.SUCCESS) {
Point leftTop = detectResult.getLeftTopPosition();
Point rightTop = detectResult.getRightTopPosition();
Point leftBottom = detectResult.getLeftBottomPosition();
Point rightBottom = detectResult.getRightBottomPosition();
List<Point> coordinates = new ArrayList<>();
coordinates.add(leftTop);
coordinates.add(rightTop);
coordinates.add(rightBottom);
coordinates.add(leftBottom);
SkewDetect .this.setDetectData(new MLDocumentSkewCorrectionCoordinateInput(coordinates));
SkewDetect .this.refineImg();
} else if (resultCode == MLDocumentSkewCorrectionConstant.IMAGE_DATA_ERROR) {
// Parameters error.
Log.e(TAG, "Parameters error!");
SkewDetect.this.displayFailure();
} else if (resultCode == MLDocumentSkewCorrectionConstant.DETECT_FAILD) {
// Detect failure.
Log.e(TAG, "Detect failed!");
SkewDetect .this.displayFailure();
}
} else {
// Detect exception.
Log.e(TAG, "Detect exception!");
SkewDetect .this.displayFailure();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
// Processing logic for detect failure.
Log.e(TAG, e.getMessage() + "");
SkewDetect .this.displayFailure();
}
});
}
// Show result
private void displaySuccess(MLDocumentSkewCorrectionResult refineResult) {
if (this.bitmap == null) {
this.displayFailure();
return;
}
// Draw the portrait with a transparent background.
Bitmap corrected = refineResult.getCorrected();
if (corrected != null) {
this.mImageView.setImageBitmap(corrected);
} else {
this.displayFailure();
}
}
private void displayFailure() {
Toast.makeText(this.getApplicationContext(), "Fail", Toast.LENGTH_SHORT).show();
}
private void setDetectData(MLDocumentSkewCorrectionCoordinateInput input) {
this.input = input;
}
// Refine image
private void refineImg() {
// Call refine image interface
Task<MLDocumentSkewCorrectionResult> correctionTask = this.analyzer.asyncDocumentSkewCorrect(this.mlFrame, this.input);
correctionTask.addOnSuccessListener(new OnSuccessListener<MLDocumentSkewCorrectionResult>() {
@Override
public void onSuccess(MLDocumentSkewCorrectionResult refineResult) {
if (refineResult != null) {
int resultCode = refineResult.getResultCode();
if (resultCode == MLDocumentSkewCorrectionConstant.SUCCESS) {
SkewDetect .this.displaySuccess(refineResult);
} else if (resultCode == MLDocumentSkewCorrectionConstant.IMAGE_DATA_ERROR) {
// Parameters error.
Log.e(TAG, "Parameters error!");
SkewDetect .this.displayFailure();
} else if (resultCode == MLDocumentSkewCorrectionConstant.CORRECTION_FAILD) {
// Correct failure.
Log.e(TAG, "Correct failed!");
SkewDetect .this.displayFailure();
}
} else {
// Correct exception.
Log.e(TAG, "Correct exception!");
SkewDetect .this.displayFailure();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
// Processing logic for refine failure.
SkewDetect .this.displayFailure();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (this.analyzer != null) {
try {
this.analyzer.stop();
} catch (IOException e) {
Log.e(SkewDetect .TAG, "Stop failed: " + e.getMessage());
}
}
}
}
Skewdetect Activity View Class
This class is responsible for creating the UI definition of the application.
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shape"
tools:context="com.huawei.mlkit.example.face.StillFaceAnalyseActivity">
/**Create an image view to hold the bitmap**/
<ImageView
android:id="@+id/image_refine_result"
android:layout_width="500dp"
android:layout_height="300dp"
android:layout_below="@+id/image_foreground"
android:layout_marginTop="20dp"></ImageView>
<RelativeLayout
android:id="@+id/relativeLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp">
/**Create a button to fetch the ML kit API for skew correction**/
<Button
android:id="@+id/imagecorrection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_gravity="start|bottom"
android:background="@color/emui_color_gray_1"
android:text=" Skew Correction "
android:textAllCaps="false"
android:textColor="@color/emui_color_gray_7"></Button>
/**Create a button to capture the image for skew correction**/
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_gravity="end|bottom"
android:contentDescription="@string/camera"
android:outlineProvider="none"
android:src="@drawable/gall"
app:backgroundTint="@color/emui_color_gray_1"
app:borderWidth="0dp"
app:elevation="2dp" />
/**Create a button to fetch the image for skew correction**/
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/cam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:layout_alignParentLeft="true"
android:contentDescription="@string/camera"
android:outlineProvider="none"
android:src="@drawable/icon_cam"
app:backgroundTint="@color/emui_color_gray_1"
app:borderWidth="0dp"
app:elevation="2dp" />
</RelativeLayout>
</RelativeLayout>
Results
Conclusion
In this article we took a small step to create and demonstrate the integration of Document Skew Correction API’s from Huawei ML Kit for better document image readability.
Upcoming article will have the integration of multiple ML API’s under one powerful application.
Stay tuned!!
References
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/documentskewcorrection-0000001051703156

Huawei's ML Kit's MLTextAnalyzer API and Firebase FirebaseVisionTextRecognizer API, A comparison and quick look at pricing.

Introduction
In today's world, it has become vital for mobile applications to have intelligent capabilities. Machine learning enables us to bring such capabilities to light, one such capability is to recognise the text in a picture.
In this article we will explore Huawei ML Kit MLTextAnalyzer and Google's ML Kit FirebaseVisionTextRecognizer side by side. We will see the integration of text recognition APIs and compare the pricing as well.
Steps to begin with:
1. Register your app in AGC and add the agconnect-service.json to your project.
2. Include Huawei developers Maven repository in both your buildscript and allprojects sections of your project-level build.gradle file. Preparations to integrate HMS core is mentioned here
3. Add the below dependencies for the ML Kit Android libraries at app-level Gradle file.
Code:
//AGC Core
implementation 'com.huawei.agconnect:agconnect-core:1.4.0.300'
//ML OCR Base SDK
implementation 'com.huawei.hms:ml-computer-vision-ocr:2.0.5.300'
4. After the user installs the app from HUAWEI AppGallery, the machine learning model is automatically updated to the user's device. To do that add the following in AndroidManifest.xml
Code:
<manifest>
...
<meta-data
android:name="com.huawei.hms.ml.DEPENDENCY"
android:value= "ocr"/>
...
</manifest>
5. We include an ImageView, a TextView to display the extracted text from the image and relative buttons for respective operations.
Code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/captured_image_view"
android:layout_width="match_parent"
android:layout_height="400dp"
android:contentDescription="@string/content_description" />
<TextView
android:id="@+id/detected_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/captured_image_view"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:maxLines="10"
android:textAlignment="center"
android:textSize="20sp" />
<Button
android:id="@+id/capture_image"
android:layout_width="350dp"
android:layout_height="wrap_content"
android:layout_above="@+id/detect_text_from_image"
android:layout_centerHorizontal="true"
android:layout_marginBottom="11dp"
android:background="@drawable/button_background"
android:text="@string/capture_image"
android:textAllCaps="false"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="@android:color/widget_edittext_dark"
android:textSize="26sp" />
<Button
android:id="@+id/detect_text_from_image"
android:layout_width="350dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="15dp"
android:background="@drawable/button_background"
android:text="@string/detect_text"
android:textAllCaps="false"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="@android:color/widget_edittext_dark"
android:textSize="26sp" />
</RelativeLayout>
6. Before we delve into the MainActivity, let us apply required permissions in our AndroidManifest.xml.
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
7. MainActivity will be as follows.
* Here dispatchTakePictureIntent() method is invoked to take a picture.
* onActivityResult() retrieves the image captured and displays it in an ImageView.
* runTextRecognition() will convert the image in bitmap format to text using an object of MLTextAnalyser.
* asyncAnalyzeText() will display the extracted text from the image.
Code:
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.huawei.hmf.tasks.OnFailureListener;
import com.huawei.hmf.tasks.OnSuccessListener;
import com.huawei.hmf.tasks.Task;
import com.huawei.hms.mlsdk.MLAnalyzerFactory;
import com.huawei.hms.mlsdk.common.MLFrame;
import com.huawei.hms.mlsdk.text.MLLocalTextSetting;
import com.huawei.hms.mlsdk.text.MLText;
import com.huawei.hms.mlsdk.text.MLTextAnalyzer;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
Bitmap myBitmapImage;
private MLTextAnalyzer mTextAnalyzer;
private Button captureImageBtn, detectBtn;
private ImageView capturedImageView;
private TextView detectedTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
captureImageBtn = findViewById(R.id.capture_image);
detectBtn = findViewById(R.id.detect_text_from_image);
capturedImageView = findViewById(R.id.captured_image_view);
detectedTextView = findViewById(R.id.detected_text_view);
captureImageBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dispatchTakePictureIntent();
detectedTextView.setText("");
}
});
detectBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
createMLTextAnalyzer();
}
});
}
private void dispatchTakePictureIntent() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK && data != null) {
Bundle extras = data.getExtras();
Bitmap selectedBitmap = (Bitmap) extras.get("data");
capturedImageView.setImageBitmap(selectedBitmap);
asyncAnalyzeText(selectedBitmap);
}
}
private void createMLTextAnalyzer() {
MLLocalTextSetting setting = new MLLocalTextSetting.Factory()
.setOCRMode(MLLocalTextSetting.OCR_DETECT_MODE)
.setLanguage("en")
.create();
mTextAnalyzer = MLAnalyzerFactory.getInstance().getLocalTextAnalyzer(setting);
}
private void asyncAnalyzeText(Bitmap bitmap) {
if (mTextAnalyzer == null) {
createMLTextAnalyzer();
}
MLFrame frame = MLFrame.fromBitmap(bitmap);
Task<MLText> task = mTextAnalyzer.asyncAnalyseFrame(frame);
task.addOnSuccessListener(new OnSuccessListener<MLText>() {
@Override
public void onSuccess(MLText text) {
detectedTextView.setText(text.getStringValue());
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
detectedTextView.setText(e.getMessage());
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (mTextAnalyzer != null)
mTextAnalyzer.stop();
} catch (IOException e) {
e.printStackTrace();
}
}
}
8. The result is as follows:
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
More details, you can check https://forums.developer.huawei.com/forumPortal/en/topic/0203446016529250080

Beginner: Page Ability features in Huawei Harmony OS

Introduction
In this article, we can create an application showing below features:
1. Page Ability and Ability Slice
2. Page Ability life cycle and Ability Slice life cycle
3. Switching between Ability slices
4. Switching between abilities.
5. Transfer data between abilities.
Requirements
1. DevEco IDE
2. Wearable watch (Can use simulator also)
Harmony OS Supports various 2 types of abilities
1. Feature Ability
2. Particle Ability
In this article, we will test Feature Ability template called Page template.
UI Design
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Ability Slice:
An Ability Slice represents a single screen and its control logic.
Page Template (Page Abilities):
Page template is used by Feature ability to interact with users, one page template can contain one or more Ability Slices. Like shown below.
When a Page ability appears in the foreground, it presents one of its ability slices by default.
config.json
I have declared 2 abilities with type page.
JSON:
{
"app": {
"bundleName": "com.example.threadingsample",
"vendor": "example",
"version": {
"code": 1,
"name": "1.0"
},
"apiVersion": {
"compatible": 3,
"target": 3
}
},
"deviceConfig": {},
"module": {
"package": "com.example.threadingsample",
"name": ".MyApplication",
"deviceType": [
"wearable"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "entry",
"moduleType": "entry"
},
"abilities": [
{
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
],
"orientation": "landscape",
"name": "com.example.threadingsample.MainAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "ThreadingSample",
"type": "page",
"launchType": "standard"
},
{
"orientation": "landscape",
"name": "com.example.threadingsample.second.SecondAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "SecondAbility",
"type": "page",
"launchType": "standard"
}
]
}
}
Page Ability life cycle
For more information: https://developer.harmonyos.com/en/...uides/ability-page-lifecycle-0000000000029840
Ability Slice life cycle:
An ability slice's lifecycle is bound to the Page ability that hosts it. You must override the onStart() callback of ability slices and use setUIContent() to set the UI content to display in this callback.
Switching between slices
Add the below code in MainAbilitySlice.java
Java:
package com.example.threadingsample.slice;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
Text text;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
HiLog.info(LABEL_LOG, "MainAbilitySlice->"+Thread.currentThread().getName());
text = (Text) findComponentById(ResourceTable.Id_text);
Button launchNewSlice = (Button) findComponentById(ResourceTable.Id_button_launch_new_slice);
launchNewSlice.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
present(new ChildAbilitySlice(), new Intent());
}
});
Button launchNewAbility = (Button) findComponentById(ResourceTable.Id_button_launch_new_ability);
launchNewAbility.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
HiLog.info(LABEL_LOG, "MainAbilitySlice launch new [email protected]@->"+Thread.currentThread().getName());
Intent intent = new Intent();
// Use the OperationBuilder class of Intent to construct an Operation object and set the deviceId (left empty if a local ability is required), bundleName, and abilityName attributes for the object.
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.threadingsample")
.withAbilityName("com.example.threadingsample.second.SecondAbility")
.build();
intent.setParam("TEST_KEY", "apple");
// Set the created Operation object to the Intent as its operation attribute.
intent.setOperation(operation);
startAbility(intent);
}
});
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Page Ability life cycle
For more information: https://developer.harmonyos.com/en/...uides/ability-page-lifecycle-0000000000029840
Ability Slice life cycle:
An ability slice's lifecycle is bound to the Page ability that hosts it. You must override the onStart() callback of ability slices and use setUIContent() to set the UI content to display in this callback.
Switching between slices
Add the below code in MainAbilitySlice.java
Java:
package com.example.threadingsample.slice;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
Text text;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
HiLog.info(LABEL_LOG, "MainAbilitySlice->"+Thread.currentThread().getName());
text = (Text) findComponentById(ResourceTable.Id_text);
Button launchNewSlice = (Button) findComponentById(ResourceTable.Id_button_launch_new_slice);
launchNewSlice.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
present(new ChildAbilitySlice(), new Intent());
}
});
Button launchNewAbility = (Button) findComponentById(ResourceTable.Id_button_launch_new_ability);
launchNewAbility.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
HiLog.info(LABEL_LOG, "MainAbilitySlice launch new [email protected]@->"+Thread.currentThread().getName());
Intent intent = new Intent();
// Use the OperationBuilder class of Intent to construct an Operation object and set the deviceId (left empty if a local ability is required), bundleName, and abilityName attributes for the object.
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.threadingsample")
.withAbilityName("com.example.threadingsample.second.SecondAbility")
.build();
intent.setParam("TEST_KEY", "apple");
// Set the created Operation object to the Intent as its operation attribute.
intent.setOperation(operation);
startAbility(intent);
}
});
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Add below code in ability_main.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:background_element="#8c7373"
ohos:padding="32">
<Text
ohos:multiple_lines="true"
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="200"
ohos:layout_alignment="horizontal_center"
ohos:text="Text"
ohos:text_size="10fp"/>
<Button
ohos:id="$+id:button_launch_new_slice"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_button"
ohos:layout_alignment="horizontal_center"
ohos:padding="5"
ohos:text="Launch new Slice"
ohos:text_size="30"
ohos:top_margin="5"/>
<Button
ohos:id="$+id:button_launch_new_ability"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_button"
ohos:layout_alignment="horizontal_center"
ohos:padding="5"
ohos:text="Launch new Ability"
ohos:text_size="30"
ohos:top_margin="5"/>
</DirectionalLayout>
Add the below code in ChildAbilitySlice.java
Java:
package com.example.threadingsample.slice;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class ChildAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
Text text;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_child_slice_two);
HiLog.info(LABEL_LOG, "ChildAbilitySlice->"+Thread.currentThread().getName());
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Add the below code in child_slice_two.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:background_element="#8c7373"
ohos:padding="32">
<Text
ohos:multiple_lines="true"
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="200"
ohos:layout_alignment="horizontal_center"
ohos:text="Child Slice"
ohos:text_size="10fp"/>
</DirectionalLayout>
Switch from MainAbilitySlice to ChildAbilitySlice using present method.
Java:
Button launchNewSlice = (Button) findComponentById(ResourceTable.Id_button_launch_new_slice);
launchNewSlice.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
present(new ChildAbilitySlice(), new Intent());
}
});
Switching from MainAbility to SecondAbility.
Java:
Button launchNewAbility = (Button) findComponentById(ResourceTable.Id_button_launch_new_ability);
launchNewAbility.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
HiLog.info(LABEL_LOG, "MainAbilitySlice launch new [email protected]@->"+Thread.currentThread().getName());
Intent intent = new Intent();
// Use the OperationBuilder class of Intent to construct an Operation object and set the deviceId (left empty if a local ability is required), bundleName, and abilityName attributes for the object.
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.threadingsample")
.withAbilityName("com.example.threadingsample.second.SecondAbility")
.build();
intent.setParam("TEST_KEY", "apple");
// Set the created Operation object to the Intent as its operation attribute.
intent.setOperation(operation);
startAbility(intent);
}
});
Add the below code to SecondAbility.java
Java:
package com.example.threadingsample.second;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class SecondAbility extends Ability {
private static final int MY_PERMISSIONS_REQUEST_LOCATION = 1001;
static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(SecondAbilitySlice.class.getName());
}
}
Add the below code in SecondAbilitySlice.java
Java:
package com.example.threadingsample.second;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Text;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class SecondAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_two);
HiLog.info(LABEL_LOG, "inside SecondAbilitySlice!!");
if(getAbility() != null) {
if (getAbility().getIntent() != null) {
if (getAbility().getIntent().hasParameter("TEST_KEY")) {
String valueFromFirstAbility = getAbility().getIntent().getStringParam("TEST_KEY");
HiLog.info(LABEL_LOG, "inside [email protected]@-->"+valueFromFirstAbility);
Text text = (Text) findComponentById(ResourceTable.Id_text);
text.setText(valueFromFirstAbility);
} else {
HiLog.info(LABEL_LOG, "TEST_KEY parameter is not present");
}
} else {
HiLog.info(LABEL_LOG, "intent is null");
}
}else{
HiLog.info(LABEL_LOG, "ability is null");
}
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Add the below code in ability_two.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:background_element="#8c7373"
ohos:padding="32">
<Text
ohos:multiple_lines="true"
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="200"
ohos:layout_alignment="horizontal_center"
ohos:text="Ability2"
ohos:text_size="10fp"/>
</DirectionalLayout>
Transfer data from one ability to another
Java:
Intent intent = new Intent();
intent.setParam("TEST_KEY", "apple");
Retrieve data on other ability
Java:
if(getAbility() != null) {
if (getAbility().getIntent() != null) {
if (getAbility().getIntent().hasParameter("TEST_KEY")) {
String valueFromFirstAbility = getAbility().getIntent().getStringParam("TEST_KEY");
HiLog.info(LABEL_LOG, "inside [email protected]@-->"+valueFromFirstAbility);
Text text = (Text) findComponentById(ResourceTable.Id_text);
text.setText(valueFromFirstAbility);
} else {
HiLog.info(LABEL_LOG, "TEST_KEY parameter is not present");
}
} else {
HiLog.info(LABEL_LOG, "intent is null");
}
}else{
HiLog.info(LABEL_LOG, "ability is null");
}
Tips and Tricks
All Abilities must be registered into config.json
Conclusion
In this article, we have UI components, there life cycle and navigation between them, transfer data between two pages.
Reference
Harmony Official document
DevEco Studio User guide
JS API Reference
Read In Forum
Does this Page ability is like Fragment in Android ?
Does
ask011 said:
Introduction
In this article, we can create an application showing below features:
1. Page Ability and Ability Slice
2. Page Ability life cycle and Ability Slice life cycle
3. Switching between Ability slices
4. Switching between abilities.
5. Transfer data between abilities.
Requirements
1. DevEco IDE
2. Wearable watch (Can use simulator also)
Harmony OS Supports various 2 types of abilities
1. Feature Ability
2. Particle Ability
In this article, we will test Feature Ability template called Page template.
UI Design
Ability Slice:
An Ability Slice represents a single screen and its control logic.
Page Template (Page Abilities):
Page template is used by Feature ability to interact with users, one page template can contain one or more Ability Slices. Like shown below.
When a Page ability appears in the foreground, it presents one of its ability slices by default.
config.json
I have declared 2 abilities with type page.
JSON:
{
"app": {
"bundleName": "com.example.threadingsample",
"vendor": "example",
"version": {
"code": 1,
"name": "1.0"
},
"apiVersion": {
"compatible": 3,
"target": 3
}
},
"deviceConfig": {},
"module": {
"package": "com.example.threadingsample",
"name": ".MyApplication",
"deviceType": [
"wearable"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "entry",
"moduleType": "entry"
},
"abilities": [
{
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
],
"orientation": "landscape",
"name": "com.example.threadingsample.MainAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "ThreadingSample",
"type": "page",
"launchType": "standard"
},
{
"orientation": "landscape",
"name": "com.example.threadingsample.second.SecondAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "SecondAbility",
"type": "page",
"launchType": "standard"
}
]
}
}
Page Ability life cycle
For more information: https://developer.harmonyos.com/en/...uides/ability-page-lifecycle-0000000000029840
Ability Slice life cycle:
An ability slice's lifecycle is bound to the Page ability that hosts it. You must override the onStart() callback of ability slices and use setUIContent() to set the UI content to display in this callback.
Switching between slices
Add the below code in MainAbilitySlice.java
Java:
package com.example.threadingsample.slice;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
Text text;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
HiLog.info(LABEL_LOG, "MainAbilitySlice->"+Thread.currentThread().getName());
text = (Text) findComponentById(ResourceTable.Id_text);
Button launchNewSlice = (Button) findComponentById(ResourceTable.Id_button_launch_new_slice);
launchNewSlice.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
present(new ChildAbilitySlice(), new Intent());
}
});
Button launchNewAbility = (Button) findComponentById(ResourceTable.Id_button_launch_new_ability);
launchNewAbility.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
HiLog.info(LABEL_LOG, "MainAbilitySlice launch new [email protected]@->"+Thread.currentThread().getName());
Intent intent = new Intent();
// Use the OperationBuilder class of Intent to construct an Operation object and set the deviceId (left empty if a local ability is required), bundleName, and abilityName attributes for the object.
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.threadingsample")
.withAbilityName("com.example.threadingsample.second.SecondAbility")
.build();
intent.setParam("TEST_KEY", "apple");
// Set the created Operation object to the Intent as its operation attribute.
intent.setOperation(operation);
startAbility(intent);
}
});
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Page Ability life cycle
For more information: https://developer.harmonyos.com/en/...uides/ability-page-lifecycle-0000000000029840
Ability Slice life cycle:
An ability slice's lifecycle is bound to the Page ability that hosts it. You must override the onStart() callback of ability slices and use setUIContent() to set the UI content to display in this callback.
Switching between slices
Add the below code in MainAbilitySlice.java
Java:
package com.example.threadingsample.slice;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
Text text;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
HiLog.info(LABEL_LOG, "MainAbilitySlice->"+Thread.currentThread().getName());
text = (Text) findComponentById(ResourceTable.Id_text);
Button launchNewSlice = (Button) findComponentById(ResourceTable.Id_button_launch_new_slice);
launchNewSlice.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
present(new ChildAbilitySlice(), new Intent());
}
});
Button launchNewAbility = (Button) findComponentById(ResourceTable.Id_button_launch_new_ability);
launchNewAbility.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
HiLog.info(LABEL_LOG, "MainAbilitySlice launch new [email protected]@->"+Thread.currentThread().getName());
Intent intent = new Intent();
// Use the OperationBuilder class of Intent to construct an Operation object and set the deviceId (left empty if a local ability is required), bundleName, and abilityName attributes for the object.
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.threadingsample")
.withAbilityName("com.example.threadingsample.second.SecondAbility")
.build();
intent.setParam("TEST_KEY", "apple");
// Set the created Operation object to the Intent as its operation attribute.
intent.setOperation(operation);
startAbility(intent);
}
});
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Add below code in ability_main.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:background_element="#8c7373"
ohos:padding="32">
<Text
ohos:multiple_lines="true"
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="200"
ohos:layout_alignment="horizontal_center"
ohos:text="Text"
ohos:text_size="10fp"/>
<Button
ohos:id="$+id:button_launch_new_slice"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_button"
ohos:layout_alignment="horizontal_center"
ohos:padding="5"
ohos:text="Launch new Slice"
ohos:text_size="30"
ohos:top_margin="5"/>
<Button
ohos:id="$+id:button_launch_new_ability"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_button"
ohos:layout_alignment="horizontal_center"
ohos:padding="5"
ohos:text="Launch new Ability"
ohos:text_size="30"
ohos:top_margin="5"/>
</DirectionalLayout>
Add the below code in ChildAbilitySlice.java
Java:
package com.example.threadingsample.slice;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class ChildAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
Text text;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_child_slice_two);
HiLog.info(LABEL_LOG, "ChildAbilitySlice->"+Thread.currentThread().getName());
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Add the below code in child_slice_two.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:background_element="#8c7373"
ohos:padding="32">
<Text
ohos:multiple_lines="true"
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="200"
ohos:layout_alignment="horizontal_center"
ohos:text="Child Slice"
ohos:text_size="10fp"/>
</DirectionalLayout>
Switch from MainAbilitySlice to ChildAbilitySlice using present method.
Java:
Button launchNewSlice = (Button) findComponentById(ResourceTable.Id_button_launch_new_slice);
launchNewSlice.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
present(new ChildAbilitySlice(), new Intent());
}
});
Switching from MainAbility to SecondAbility.
Java:
Button launchNewAbility = (Button) findComponentById(ResourceTable.Id_button_launch_new_ability);
launchNewAbility.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
HiLog.info(LABEL_LOG, "MainAbilitySlice launch new [email protected]@->"+Thread.currentThread().getName());
Intent intent = new Intent();
// Use the OperationBuilder class of Intent to construct an Operation object and set the deviceId (left empty if a local ability is required), bundleName, and abilityName attributes for the object.
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.example.threadingsample")
.withAbilityName("com.example.threadingsample.second.SecondAbility")
.build();
intent.setParam("TEST_KEY", "apple");
// Set the created Operation object to the Intent as its operation attribute.
intent.setOperation(operation);
startAbility(intent);
}
});
Add the below code to SecondAbility.java
Java:
package com.example.threadingsample.second;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class SecondAbility extends Ability {
private static final int MY_PERMISSIONS_REQUEST_LOCATION = 1001;
static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(SecondAbilitySlice.class.getName());
}
}
Add the below code in SecondAbilitySlice.java
Java:
package com.example.threadingsample.second;
import com.example.threadingsample.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Text;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class SecondAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_two);
HiLog.info(LABEL_LOG, "inside SecondAbilitySlice!!");
if(getAbility() != null) {
if (getAbility().getIntent() != null) {
if (getAbility().getIntent().hasParameter("TEST_KEY")) {
String valueFromFirstAbility = getAbility().getIntent().getStringParam("TEST_KEY");
HiLog.info(LABEL_LOG, "inside [email protected]@-->"+valueFromFirstAbility);
Text text = (Text) findComponentById(ResourceTable.Id_text);
text.setText(valueFromFirstAbility);
} else {
HiLog.info(LABEL_LOG, "TEST_KEY parameter is not present");
}
} else {
HiLog.info(LABEL_LOG, "intent is null");
}
}else{
HiLog.info(LABEL_LOG, "ability is null");
}
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
Add the below code in ability_two.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:background_element="#8c7373"
ohos:padding="32">
<Text
ohos:multiple_lines="true"
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="200"
ohos:layout_alignment="horizontal_center"
ohos:text="Ability2"
ohos:text_size="10fp"/>
</DirectionalLayout>
Transfer data from one ability to another
Java:
Intent intent = new Intent();
intent.setParam("TEST_KEY", "apple");
Retrieve data on other ability
Java:
if(getAbility() != null) {
if (getAbility().getIntent() != null) {
if (getAbility().getIntent().hasParameter("TEST_KEY")) {
String valueFromFirstAbility = getAbility().getIntent().getStringParam("TEST_KEY");
HiLog.info(LABEL_LOG, "inside [email protected]@-->"+valueFromFirstAbility);
Text text = (Text) findComponentById(ResourceTable.Id_text);
text.setText(valueFromFirstAbility);
} else {
HiLog.info(LABEL_LOG, "TEST_KEY parameter is not present");
}
} else {
HiLog.info(LABEL_LOG, "intent is null");
}
}else{
HiLog.info(LABEL_LOG, "ability is null");
}
Tips and Tricks
All Abilities must be registered into config.json
Conclusion
In this article, we have UI components, there life cycle and navigation between them, transfer data between two pages.
Reference
Harmony Official document
DevEco Studio User guide
JS API Reference
Read In Forum
Click to expand...
Click to collapse
Is there any life cycle for Page ability

Book Reader Application Using General Text Recognition by Huawei HiAI in Android

Introduction
In this article, we will learn how to integrate Huawei General Text Recognition using Huawei HiAI. We will build the Book reader application.
About application:
Usually user get bored to read book. This application helps them to listen book reading instead of manual book reading. So all they need to do is just capture photo of book and whenever user is travelling or whenever user want to read the book on their free time. Just user need to select image from galley and listen like music.
Huawei general text recognition works on OCR technology.
First let us understand about OCR.
What is optical character recognition (OCR)?
Optical Character Recognition (OCR) technology is a business solution for automating data extraction from printed or written text from a scanned document or image file and then converting the text into a machine-readable form to be used for data processing like editing or searching.
Now let us understand about General Text Recognition (GTR).
At the core of the GTR is Optical Character Recognition (OCR) technology, which extracts text in screenshots and photos taken by the phone camera. For photos taken by the camera, this API can correct for tilts, camera angles, reflections, and messy backgrounds up to a certain degree. It can also be used for document and streetscape photography, as well as a wide range of usage scenarios, and it features strong anti-interference capability. This API works on device side processing and service connection.
Features
For photos: Provides text area detection and text recognition for Chinese, English, Japanese, Korean, Russian, Italian, Spanish, Portuguese, German, and French texts in multiple printing fonts. A wide range of scenarios are supported, and a high recognition accuracy can be achieved even under the influence of complex lighting condition, background, or more.
For screenshots: Optimizes text extraction algorithms based on the characteristics of screenshots captured on mobile phones. Currently, this function is available in the Chinese mainland supporting Chinese and English texts.
OCR features
Lightweight: This API greatly reduces the computing time and ROM space the algorithm model takes up, making your app more lightweight.
Customized hierarchical result return: You can choose to return the coordinates of text blocks, text lines, and text characters in the screenshot based on app requirements.
How to integrate General Text Recognition
1. Configure the application on the AGC.
2. Apply for HiAI Engine Library
3. Client application development process.
Configure application on the AGC
Follow the steps
Step 1: We need to register as a developer account in AppGallery Connect. If you are already a developer ignore this step.
Step 2: Create an app by referring to Creating a Project and Creating an App in the Project
Step 3: Set the data storage location based on the current location.
Step 4: Generating a Signing Certificate Fingerprint.
Step 5: Configuring the Signing Certificate Fingerprint.
Step 6: Download your agconnect-services.json file, paste it into the app root directory.
Apply for HiAI Engine Library
What is Huawei HiAI?
HiAI is Huawei’s AI computing platform. HUAWEI HiAI is a mobile terminal–oriented artificial intelligence (AI) computing platform that constructs three layers of ecology: service capability openness, application capability openness, and chip capability openness. The three-layer open platform that integrates terminals, chips, and the cloud brings more extraordinary experience for users and developers.
How to apply for HiAI Engine?
Follow the steps
Step 1: Navigate to this URL, choose App Service > Development and click HUAWEI HiAI.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Step 2: Click Apply for HUAWEI HiAI kit.
Step 3: Enter required information like Product name and Package name, click Next button.
Step 4: Verify the application details and click Submit button.
Step 5: Click the Download SDK button to open the SDK list.
Step 6: Unzip downloaded SDK and add into your android project under libs folder.
Step 7: Add jar files dependences into app build.gradle file.
Code:
implementation fileTree(include: ['*.aar', '*.jar'], dir: 'libs')
implementation 'com.google.code.gson:gson:2.8.6'
repositories {
flatDir {
dirs 'libs'
}
}
Client application development process
Follow the steps
Step 1: Create an Android application in the Android studio (Any IDE which is your favorite).
Step 2: Add the App level Gradle dependencies. Choose inside project Android > app > build.gradle.
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
Root level gradle dependencies.
Code:
maven { url 'https://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Step 3: Add permission in AndroidManifest.xml
XML:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
Step 4: Build application.
Initialize all view.
Java:
private void initializeView() {
mPlayAudio = findViewById(R.id.playAudio);
mTxtViewResult = findViewById(R.id.result);
mImageView = findViewById(R.id.imgViewPicture);
}
Request the runtime permission
Java:
private void requestPermissions() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permission1 = ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permission2 = ActivityCompat.checkSelfPermission(this,
Manifest.permission.CAMERA);
if (permission1 != PackageManager.PERMISSION_GRANTED || permission2 != PackageManager
.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 0x0010);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length <= 0
|| grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
}
}
Initialize vision base
Java:
private void initVision() {
VisionBase.init(this, new ConnectionCallback() {
@override
public void onServiceConnect() {
Log.e(TAG, " onServiceConnect");
}
@override
public void onServiceDisconnect() {
Log.e(TAG, " onServiceDisconnect");
}
});
}
Initialize text to speech
Java:
private void initializeTextToSpeech() {
textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
@override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.UK);
}
}
});
}
Copy code
Create TextDetector instance.
Java:
mTextDetector = new TextDetector(this);
Define Vision image.
Java:
VisionImage image = VisionImage.fromBitmap(mBitmap);
Create instance of Text class.
Java:
final Text result = new Text();
Create and set VisionTextConfiguration
Java:
VisionTextConfiguration config = new VisionTextConfiguration.Builder()
.setAppType(VisionTextConfiguration.APP_NORMAL)
.setProcessMode(VisionTextConfiguration.MODE_IN)
.setDetectType(TextDetectType.TYPE_TEXT_DETECT_FOCUS_SHOOT)
.setLanguage(TextConfiguration.AUTO).build();
//Set vision configuration
mTextDetector.setVisionConfiguration(config);
Call detect method to get the result
Java:
int result_code = mTextDetector.detect(image, result, new VisionCallback<Text>() {
@override
public void onResult(Text text) {
dismissDialog();
Message message = Message.obtain();
message.what = TYPE_SHOW_RESULT;
message.obj = text;
mHandler.sendMessage(message);
}
@override
public void onError(int i) {
Log.d(TAG, "Callback: onError " + i);
mHandler.sendEmptyMessage(TYPE_TEXT_ERROR);
}
@override
public void onProcessing(float v) {
Log.d(TAG, "Callback: onProcessing:" + v);
}
});
Copy code
Create Handler
Java:
private final Handler mHandler = new Handler() {
[USER=439709]@override[/USER]
public void handleMessage(Message msg) {
super.handleMessage(msg);
int status = msg.what;
Log.d(TAG, "handleMessage status = " + status);
switch (status) {
case TYPE_CHOOSE_PHOTO: {
if (mBitmap == null) {
Log.e(TAG, "bitmap is null");
return;
}
mImageView.setImageBitmap(mBitmap);
mTxtViewResult.setText("");
showDialog();
detectTex();
break;
}
case TYPE_SHOW_RESULT: {
Text result = (Text) msg.obj;
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
if (result == null) {
mTxtViewResult.setText("Failed to detect text lines, result is null.");
break;
}
String textValue = result.getValue();
Log.d(TAG, "text value: " + textValue);
StringBuffer textResult = new StringBuffer();
List<TextLine> textLines = result.getBlocks().get(0).getTextLines();
for (TextLine line : textLines) {
textResult.append(line.getValue() + " ");
}
Log.d(TAG, "OCR Detection succeeded.");
mTxtViewResult.setText(textResult.toString());
textToSpeechString = textResult.toString();
break;
}
case TYPE_TEXT_ERROR: {
mTxtViewResult.setText("Failed to detect text lines, result is null.");
}
default:
break;
}
}
};
Complete code as follows
Java:
import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.speech.tts.TextToSpeech;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.huawei.hiai.vision.common.ConnectionCallback;
import com.huawei.hiai.vision.common.VisionBase;
import com.huawei.hiai.vision.common.VisionCallback;
import com.huawei.hiai.vision.common.VisionImage;
import com.huawei.hiai.vision.text.TextDetector;
import com.huawei.hiai.vision.visionkit.text.Text;
import com.huawei.hiai.vision.visionkit.text.TextDetectType;
import com.huawei.hiai.vision.visionkit.text.TextLine;
import com.huawei.hiai.vision.visionkit.text.config.TextConfiguration;
import com.huawei.hiai.vision.visionkit.text.config.VisionTextConfiguration;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int REQUEST_CHOOSE_PHOTO_CODE = 2;
private Bitmap mBitmap;
private ImageView mPlayAudio;
private ImageView mImageView;
private TextView mTxtViewResult;
protected ProgressDialog dialog;
private TextDetector mTextDetector;
Text imageText = null;
TextToSpeech textToSpeech;
String textToSpeechString = "";
private static final int TYPE_CHOOSE_PHOTO = 1;
private static final int TYPE_SHOW_RESULT = 2;
private static final int TYPE_TEXT_ERROR = 3;
[USER=439709]@override[/USER]
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeView();
requestPermissions();
initVision();
initializeTextToSpeech();
}
private void initializeView() {
mPlayAudio = findViewById(R.id.playAudio);
mTxtViewResult = findViewById(R.id.result);
mImageView = findViewById(R.id.imgViewPicture);
}
private void initVision() {
VisionBase.init(this, new ConnectionCallback() {
[USER=439709]@override[/USER]
public void onServiceConnect() {
Log.e(TAG, " onServiceConnect");
}
[USER=439709]@override[/USER]
public void onServiceDisconnect() {
Log.e(TAG, " onServiceDisconnect");
}
});
}
private void initializeTextToSpeech() {
textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
[USER=439709]@override[/USER]
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.UK);
}
}
});
}
public void onChildClick(View view) {
switch (view.getId()) {
case R.id.btnSelect: {
Log.d(TAG, "Select an image");
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_CHOOSE_PHOTO_CODE);
break;
}
case R.id.playAudio: {
if (textToSpeechString != null && !textToSpeechString.isEmpty())
textToSpeech.speak(textToSpeechString, TextToSpeech.QUEUE_FLUSH, null);
break;
}
}
}
private void detectTex() {
/* create a TextDetector instance firstly */
mTextDetector = new TextDetector(this);
/*Define VisionImage and transfer the Bitmap image to be detected*/
VisionImage image = VisionImage.fromBitmap(mBitmap);
/*Define the Text class.*/
final Text result = new Text();
/*Use VisionTextConfiguration to select the type of the image to be called. */
VisionTextConfiguration config = new VisionTextConfiguration.Builder()
.setAppType(VisionTextConfiguration.APP_NORMAL)
.setProcessMode(VisionTextConfiguration.MODE_IN)
.setDetectType(TextDetectType.TYPE_TEXT_DETECT_FOCUS_SHOOT)
.setLanguage(TextConfiguration.AUTO).build();
//Set vision configuration
mTextDetector.setVisionConfiguration(config);
/*Call the detect method of TextDetector to obtain the result*/
int result_code = mTextDetector.detect(image, result, new VisionCallback<Text>() {
[USER=439709]@override[/USER]
public void onResult(Text text) {
dismissDialog();
Message message = Message.obtain();
message.what = TYPE_SHOW_RESULT;
message.obj = text;
mHandler.sendMessage(message);
}
[USER=439709]@override[/USER]
public void onError(int i) {
Log.d(TAG, "Callback: onError " + i);
mHandler.sendEmptyMessage(TYPE_TEXT_ERROR);
}
[USER=439709]@override[/USER]
public void onProcessing(float v) {
Log.d(TAG, "Callback: onProcessing:" + v);
}
});
}
private void showDialog() {
if (dialog == null) {
dialog = new ProgressDialog(MainActivity.this);
dialog.setTitle("Detecting text...");
dialog.setMessage("Please wait...");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
}
dialog.show();
}
private final Handler mHandler = new Handler() {
[USER=439709]@override[/USER]
public void handleMessage(Message msg) {
super.handleMessage(msg);
int status = msg.what;
Log.d(TAG, "handleMessage status = " + status);
switch (status) {
case TYPE_CHOOSE_PHOTO: {
if (mBitmap == null) {
Log.e(TAG, "bitmap is null");
return;
}
mImageView.setImageBitmap(mBitmap);
mTxtViewResult.setText("");
showDialog();
detectTex();
break;
}
case TYPE_SHOW_RESULT: {
Text result = (Text) msg.obj;
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
if (result == null) {
mTxtViewResult.setText("Failed to detect text lines, result is null.");
break;
}
String textValue = result.getValue();
Log.d(TAG, "text value: " + textValue);
StringBuffer textResult = new StringBuffer();
List<TextLine> textLines = result.getBlocks().get(0).getTextLines();
for (TextLine line : textLines) {
textResult.append(line.getValue() + " ");
}
Log.d(TAG, "OCR Detection succeeded.");
mTxtViewResult.setText(textResult.toString());
textToSpeechString = textResult.toString();
break;
}
case TYPE_TEXT_ERROR: {
mTxtViewResult.setText("Failed to detect text lines, result is null.");
}
default:
break;
}
}
};
[USER=439709]@override[/USER]
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CHOOSE_PHOTO_CODE && resultCode == Activity.RESULT_OK) {
if (data == null) {
return;
}
Uri selectedImage = data.getData();
getBitmap(selectedImage);
}
}
private void requestPermissions() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int permission1 = ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permission2 = ActivityCompat.checkSelfPermission(this,
Manifest.permission.CAMERA);
if (permission1 != PackageManager.PERMISSION_GRANTED || permission2 != PackageManager
.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 0x0010);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getBitmap(Uri imageUri) {
String[] pathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(imageUri, pathColumn, null, null, null);
if (cursor == null) return;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(pathColumn[0]);
/* get image path */
String picturePath = cursor.getString(columnIndex);
cursor.close();
mBitmap = BitmapFactory.decodeFile(picturePath);
if (mBitmap == null) {
return;
}
//You can set image here
//mImageView.setImageBitmap(mBitmap);
// You can pass it handler as well
mHandler.sendEmptyMessage(TYPE_CHOOSE_PHOTO);
mTxtViewResult.setText("");
mPlayAudio.setEnabled(true);
}
private void dismissDialog() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
[USER=439709]@override[/USER]
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length <= 0
|| grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
}
}
[USER=439709]@override[/USER]
protected void onDestroy() {
super.onDestroy();
/* release ocr instance and free the npu resources*/
if (mTextDetector != null) {
mTextDetector.release();
}
dismissDialog();
if (mBitmap != null) {
mBitmap.recycle();
}
}
}
activity_main.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
androidrientation="vertical"
android:background="@android:color/darker_gray">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#ff0000"
android:elevation="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
androidrientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Book Reader"
android:layout_gravity="center"
android:gravity="center|start"
android:layout_weight="1"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="20sp"/>
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_baseline_play_circle_outline_24"
android:layout_gravity="center|end"
android:layout_marginEnd="10dp"
android:id="@+id/playAudio"
androidadding="5dp"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
androidrientation="vertical"
android:background="@android:color/darker_gray"
>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
app:cardElevation="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="20dp"
android:layout_gravity="center">
<ImageView
android:id="@+id/imgViewPicture"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_margin="8dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitXY" />
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="5dp"
app:cardElevation="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="10dp"
android:layout_gravity="center"
android:layout_marginBottom="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
androidrientation="vertical"
>
<TextView
android:layout_margin="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:text="Text on the image"
android:textStyle="normal"
/>
<TextView
android:id="@+id/result"
android:layout_margin="5dp"
android:layout_marginBottom="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#ff0000"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<Button
android:id="@+id/btnSelect"
android:layout_width="match_parent"
android:layout_height="wrap_content"
androidnClick="onChildClick"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:text="[USER=936943]@string[/USER]/select_picture"
android:background="@drawable/round_button_bg"
android:textColor="@android:color/white"
android:textAllCaps="false"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
Result
Tips and Tricks
Maximum width and height: 1440 px and 15210 px (If the image is larger than this, you will receive error code 200).
Photos recommended size for optimal recognition accuracy.
Resolution > 720P
Aspect ratio < 2:1
If you are taking Video from a camera or gallery make sure your app has camera and storage permission.
Add the downloaded huawei-hiai-vision-ove-10.0.4.307.aar, huawei-hiai-pdk-1.0.0.aar file to libs folder.
Check dependencies added properly
Latest HMS Core APK is required.
Min SDK is 21. Otherwise you will get Manifest merge issue.
Conclusion
In this article, we have learnt the following concepts.
What is OCR?
Learnt about general text recognition.
Feature of GTR
Features of OCR
How to integrate General Text Recognition using Huawei HiAI
How to Apply Huawei HiAI
How to build the application
Reference
General Text Recognition
Apply for Huawei HiAI
Happy coding
how many languages can it be detected?

Categories

Resources