Thursday 15 September 2016

HB Blog 119: Android OCR - Optical Character Recognition.

Optical character recognition (optical character reader, OCR) is the mechanical or electronic conversion of images of typed, handwritten or printed text into machine-encoded text, whether from a scanned document, a photo of a document, a scene-photo (for example the text on signs and billboards in a landscape photo) or from subtitle text superimposed on an image (for example from a television broadcast). It is widely used as a form of information entry from printed paper data records, whether passport documents, invoices, bank statements, computerised receipts, business cards, mail, printouts of static-data, or any suitable documentation. It is a common method of digitising printed texts so that they can be electronically edited, searched, stored more compactly, displayed on-line, and used in machine processes such as cognitive computing, machine translation, (extracted) text-to-speech, key data and text mining. OCR is a field of research in pattern recognition, artificial intelligence and computer vision.
Android-OCR :-
An experimental app for Android that performs optical character recognition (OCR) on images captured using the device camera.
Runs the Tesseract OCR engine using tess-two, a fork of Tesseract Tools for Android.
Most of the code making up the core structure of this project has been adapted from the ZXing Barcode Scanner. Along with Tesseract-OCR and Tesseract Tools for Android (tesseract-android-tools), several open source projects have been used in this project, including leptonica, google-api-translate-java, microsoft-translator-java-api, and jtar.

Training data for OCR :-
A data file is required for every language you want to recognize. For English, this data file is included in the application assets and is automatically installed when the app is first run.
For other languages (Spanish, French, Chinese, etc.), the app will try to download the training data from an old Google Code repository that is no longer available, and the download fails. So if you want to use training data for other languages, you'll need to package the appropriate training data files in the app or change the code to point to your own download location.

Refer the below link for complete sample code:-

Download Sample Code

Have a look on few code snippets,

//build.gradle
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "com.example.harshalbenake.ocrtessarct"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.rmtheis:tess-two:5.4.1'
}
 
//activity_main.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.harshalbenake.ocrtessarct.MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="Open Image" />

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:layout_below="@+id/button"
        android:textColor="@android:color/black"
        android:textSize="16sp" />

</RelativeLayout>
 
//MainActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.example.harshalbenake.ocrtessarct;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

    private static final int sRC_Document = 1000;
    private final String sdCardPath = Environment.getExternalStorageDirectory() + "/";
    private TessOCR mTessOCR;
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTessOCR = new TessOCR(MainActivity.this);

        mTextView = (TextView) findViewById(R.id.textview);
        Button button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startCustomFileBrowserActivity();


               /* Bitmap bitmap = BitmapFactory.decodeFile(sdCardPath + "3.jpg");
                String strResult = tessOCR.getOCRResult(bitmap);
                System.out.println("strResult: " + strResult);
                textView.setText(strResult);*/
            }
        });
    }

    /**
     * Intent start CustomFileBrowserActivity.
     **/
    public void startCustomFileBrowserActivity() {
        Intent intent = new Intent(MainActivity.this, CustomFileBrowser.class);
        startActivityForResult(intent, sRC_Document);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        switch (requestCode) {
            case sRC_Document:
                if (resultCode == RESULT_OK) {
                    try {
                        final String filePath = intent.getStringExtra("data");
                        if (filePath != null) {
                            Bitmap bitmap = BitmapFactory.decodeFile(filePath);
                            String strResult = mTessOCR.getOCRResult(bitmap);
                            mTextView.setText("Result Data: \n\n" + strResult);
                        } else {
                            //invalid file
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                break;
        }
        super.onActivityResult(requestCode, resultCode, intent);
    }
}

//TessOCR.java
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.example.harshalbenake.ocrtessarct;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.os.Environment;
import android.util.Log;

import com.googlecode.tesseract.android.TessBaseAPI;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;


public class TessOCR {
    private TessBaseAPI mTess;
    Context mContext;

    public TessOCR(Context context) {
        // TODO Auto-generated constructor stub
        this.mContext=context;
        setupOCR();
        mTess = new TessBaseAPI();
        String datapath = Environment.getExternalStorageDirectory() + "/tesseract/";
        File dir = new File(datapath + "tessdata/");
        if (!dir.exists())
            dir.mkdirs();
        mTess.init(datapath, "eng");
    }


    public String getOCRResult(Bitmap bitmap) {
        mTess.setImage(bitmap);
        String result=mTess.getUTF8Text();
      //  mTess.end();
//        if(result!=null) {
            return result.replaceAll("[^A-Za-z0-9 ]", "");
//        }else{
//            return "";
//        }
    }

    public void onDestroy() {
        mTess.end();
    }

    public void setupOCR(){

        File folder = new File(Environment.getExternalStorageDirectory() + "/tesseract/tessdata");
        if (!folder.exists()) {
            folder.mkdirs();
        }

        File saving = new File(folder, "eng.traineddata");
        try {
            saving.createNewFile();
        } catch (Exception e) {
            e.printStackTrace();
        }

        InputStream stream = null;
        try {
            stream = mContext.getAssets().open("eng.traineddata", AssetManager.ACCESS_STREAMING);
        } catch (Exception e) {
            e.printStackTrace();
        }


        if (stream != null){
            copyInputStreamToFile(stream, saving);
        }
    }

    private void copyInputStreamToFile( InputStream in, File file ) {
        try {
            OutputStream out = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int len;
            while((len=in.read(buf))>0){
                out.write(buf,0,len);
            }
            out.close();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void copyAssets() {
        AssetManager assetManager = mContext.getAssets();
        String[] files = null;
        try {
            files = assetManager.list("");
        } catch (Exception e) {
            Log.e("tag", "Failed to get asset file list.", e);
        }
        if (files != null) for (String filename : files) {
            InputStream in = null;
            OutputStream out = null;
            try {
                System.out.println("filename: "+filename);
                in = assetManager.open(filename);

                String datapath = Environment.getExternalStorageDirectory() + "/tesseract/";
                File dir = new File(datapath + "tessdata/");
                if (!dir.exists())
                    dir.mkdirs();

                File outFile = new File(dir+filename);
                out = new FileOutputStream(outFile);
                copyFile(in, out);
            } catch(Exception e) {
                Log.e("tag", "Failed to copy asset file: " + filename, e);
            }
            finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (Exception e) {
                        // NOOP
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    } catch (Exception e) {
                        // NOOP
                    }
                }
            }
        }
    }

    private void copyFile(InputStream in, OutputStream out) throws Exception {
        byte[] buffer = new byte[1024];
        int read;
        while((read = in.read(buffer)) != -1){
            out.write(buffer, 0, read);
        }
    }

}

Friday 2 September 2016

HB Blog 118: Cell Broadcast - The Mobile Technology For Mass Message Broadcast.

Cell Broadcast (CB) is a mobile technology that allows messages (currently of up to 15 pages of up to 93 characters) to be broadcast to all mobile handsets and similar devices within a designated geographical area. The broadcast range can be varied, from a single cell to the entire network.
This technology is used in deploying location-based subscriber services, such as regional auctions, local weather, traffic conditions and 'nearest' services (like requesting the nearest service station or restaurant).
It is designed for simultaneous delivery of messages to multiple users in a specified area. Whereas the Short Message Service (SMS) is a one-to-one and one-to-a-few service, It is one-to-many geographically focused service.
It enables messages to be communicated to multiple mobile phone customers who are located within a given part of its network coverage area at the time the message is broadcast. Cell Broadcast is more akin to other mass distribution media such as teletext or Radio Data System (RDS).
It  is a technology that allows a text or binary message to be defined and distributed to all mobile terminals connected to a set of cells. Whereas SMS messages are sent point-to-point, Cell Broadcast (SMS-CB) messages are sent point-to-area. This means that one SMS-CB message can reach a huge number of terminals at once. In other words, SMS-CB messages are directed to radio cells, rather than to a specific terminal. SMS-CB is an unconfirmed push service, meaning that the originator of the message does not know who has received the message, allowing for services based on anonymity.

A Cell Broadcast Entity (CBE) is a multi-user front-end that allows the definition and control of SMS-CB messages. A CBE can be located at the site of a content provider. At the site of the operator a so-called Cell Broadcast Centre (CBC) is located. The CBC is the heart of the Cell Broadcast System and acts as a server for all CBE clients. It takes care of the administration of all SMS-CB messages it receives from the CBEs and does the communication towards the GSM network. The GSM network itself takes care of delivering the SMS-CB messages to the mobile terminals.
Cell Broadcast can be used for a number of different services and has been de-ployed by several network operators.

Early Warning System (EWS) for citizen alert
Cell Broadcast on mobile telephones can be used for Early Warning Systems (EWS) by Governments. A few countries in the world have already adopted this technique, in addition to older and already existing forms of communication like siren, or radio and TV. The advantage of this system is that it allows sending messages without having to know the phone numbers of the users in the region. Instead of sending a message to a specific known mobile phone you can send a text to all mobile phones in a specific zone. Mass communication, very fast, in case it really matters.

Advertising
Retail outlets in certain areas would be interested in sending customers and potential customers information about special offers and attractions such as sales, special offers, extended opening times and so on. Shopping centers, exhibition halls, airports and sports stadiums are the kinds of location that could be targeted for Cell Broadcast based services.

Information Services
Cell Broadcast is ideal for delivering local or regional information which is suited to all the people in that area, rather than just one or a few people. Examples include hazard warnings, cinema programs, local weather, flight or bus delays, tourist information, parking and traffic information. Cell Broadcast can also be used for managing and communicating with a remote but local team such as emergency services or airport staff. The emergency services could send an encrypted message out to all officers or other staff in a certain area to respond to an incident. This is particularly useful for standby workers who only need to be called in and present in a certain place when certain events occur.

SMS versus Cell Broadcast: -

Short Message Service (SMS)
Characteristic
Cell Broadcast (CELL BROADCAST)
Messages sent point-to-point
Transmission type
Messages sent point-to-area
Required. Requires specific phone numbers to be known
Mobile Number dependency
Independent. Does not require phone numbers to be known
No. Only pre-registered numbers will be notified; message will be received regardless of actual location
Location based targeting
Yes. All phones within a targeted geographical area (cells) will be notified.
Static messages will be sent to pre-registered numbers.
Message type
Location specific. Tailored messages can be sent to different areas.
Direct. Users can receive messages and respond directly to the sender via SMS.
Bi-directionality
Indirect. The message should contain a URL or number to reply.
Subject to network congestion. Delivery is queued. Congestion can occur
Congestion and delay
CELL BROADCAST is always available.
140-160 characters. Longer 'concatenated' messages are supported.
Message length
93 characters. Longer 'multiple page’ messages are supported.
Poor authenticity. The source of the message cannot be verified.
Security
Good security. Only the mobile operator can broadcast messages.
No barring.
Service barring
Yes. Users can turn off CELL BROADCAST reception or a specific channel.
By default. When phone is turned on messages can be received.
Reception
Requires action. CELL BROADCAST needs to be turned on in order to receive messages.
Yes. Senders can request delivery confirmation.
Delivery confirmation
No. Confirmation of delivery to the handset is not available, however actual broadcast in the network is.
No repetition rate.
Repetition rate
Yes. Can be repeated between 2 seconds and 32 minutes.
No. Identical to all receivers.
Language selection
Yes. Messages can be broadcasted in subscriber’s preferred language
Yes.
Message storage
Handset dependant.