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);
        }
    }

}

No comments:

Post a Comment