OCR扫描不显示扫描输出

时间:2016-06-30 04:50:17

标签: java android ocr

我目前正在开发能够切换活动标签的第一个应用程序(Android'片段)。我有4个选项卡,在其中一个选项卡中,我实现了图像识别以进行字符识别(OCR)。我使用了由Easy OCR Library制作的简化OCR Tesseract库,名为Priyank Verma。我已经测试了该库中的示例,但它确实有效。但是,当我将该库用于我自己的应用程序时,它无法正常工作。

让我解释一下,在我的应用程序标签中,我有一个'扫描'利用我的手机相机拍照的按钮。拍摄照片后,我的应用程序应扫描保存目录中的捕获图像以进行字符识别。接下来,我的应用将返回上一个'扫描'选项卡然后将在“扫描”上方显示字符识别的输出。该选项卡中的按钮。就是这样,我的应用程序似乎无法扫描。真正的问题是拍摄完照片后&保存,我的应用程序返回到选项卡,根本没有输出。我的代码应该可以工作,但遗憾的是它没有。没有错误,没有任何错误,我几天都在想弄清楚什么是错的。

以下是代码: -

----------我的应用程序清单----------

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kaydarinapp.queueappv2">
    <!-- Save file permission -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- Read file permission -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- Camera permission -->
    <uses-feature android:name="android.hardware.camera" />
    <uses-permission android:name="android.permission.CAMERA" />
    <!-- Internet permission -->
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:screenOrientation="portrait"
            android:configChanges="keyboardHidden|orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

----------来自我的应用程序选项卡----------

我的标签页

<LinearLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".Tab2"
    android:gravity="center_horizontal"
    >

    <TextView android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:layout_marginTop="45dp"
        android:layout_gravity="center_horizontal"
        android:textSize="8pt"
        />


    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button"
        android:layout_marginTop="20dp"
        android:text="Scan"
        android:layout_gravity="center_vertical" />

</LinearLayout>

我的标签页

package com.kaydarinapp.queueappv2;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.wordpress.priyankvex.easyocrscannerdemo.Config;
import com.wordpress.priyankvex.easyocrscannerdemo.EasyOcrScanner;
import com.wordpress.priyankvex.easyocrscannerdemo.EasyOcrScannerListener;

/**
 * Created by Kaydarin on 6/1/2016.
 */

//Our class extending fragment
public class Tab2 extends Fragment implements EasyOcrScannerListener {

    private LinearLayout linearLayout;
    private FragmentActivity fragActivity;
    EasyOcrScanner mEasyOcrScanner;
    TextView textView;
    ProgressDialog mProgressDialog;
    Button btnCapture;

    //Overriden method onCreateView
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        fragActivity = super.getActivity();
        linearLayout = (LinearLayout) inflater.inflate(R.layout.tab2, container, false);

        textView = (TextView) fragActivity.findViewById(R.id.textView);

        // initialize EasyOcrScanner instance.
        mEasyOcrScanner = new EasyOcrScanner(getActivity(), "EasyOcrScanner",
                Config.REQUEST_CODE_CAPTURE_IMAGE, "eng");

        // Set ocrScannerListener
        mEasyOcrScanner.setOcrScannerListener(this);

        btnCapture = (Button) linearLayout.findViewById(R.id.button);
        btnCapture.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                mEasyOcrScanner.takePicture();
            }
        });

        return linearLayout;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // Call onImageTaken() in onActivityResult.
        if (resultCode == getActivity().RESULT_OK && requestCode == Config.REQUEST_CODE_CAPTURE_IMAGE){
            mEasyOcrScanner.onImageTaken();
        }
    }

    /**
     * Callback when after taking picture, scanning process starts.
     * Good place to show a progress dialog.
     * @param filePath file path of the image file being processed.
     */
    @Override
    public void onOcrScanStarted(String filePath) {
        mProgressDialog = new ProgressDialog(getActivity());
        mProgressDialog.setMessage("Scanning...");
        mProgressDialog.show();
    }

    /**
     * Callback when scanning is finished.
     * Good place to hide teh progress dialog.
     * @param bitmap Bitmap of image that was scanned.
     * @param recognizedText Scanned text.
     */
    @Override
    public void onOcrScanFinished(Bitmap bitmap, String recognizedText) {
        textView.setText(recognizedText);
        if (mProgressDialog.isShowing()){
            mProgressDialog.dismiss();
        }
    }
}

----------来自Easy OCR Library ----------

简易OCR图书馆的清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wordpress.priyankvex.easyocrscanner">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA"/>

</manifest>

配置Java

package com.wordpress.priyankvex.easyocrscannerdemo;

/**
 * Created by Priyank(@priyankvex) on 27/8/15.
 */
public class Config {

    public static String TAG = "OcrScanner";
    public static int REQUEST_CODE_CAPTURE_IMAGE = 1995;

}

EasyOCRScannerListener Java

package com.wordpress.priyankvex.easyocrscannerdemo;

import android.graphics.Bitmap;

/**
 * Created by Priyank(@priyankvex) on 27/8/15.
 *
 * Interface for the callbacks for {@link EasyOcrScanner}.
 */
public interface EasyOcrScannerListener {

    public void onOcrScanStarted(String filePath);

    public void onOcrScanFinished(Bitmap bitmap, String recognizedText);
}

EasyOCRScanner Java

package com.wordpress.priyankvex.easyocrscannerdemo;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;

import java.io.File;
import java.util.Calendar;

/**
 * Created by Priyank(@priyankvex) on 27/8/15.
 *
 * Class to handle scanning of image.
 */
public class EasyOcrScanner {

    protected Activity mActivity;
    private String directoryPathOriginal;
    private String filePathOriginal;
    private int requestCode;
    private EasyOcrScannerListener mOcrScannerListener;
    private String trainedDataCode;

    public EasyOcrScanner(Activity activity, String directoryPath, int requestCode, String trainedDataCode){
        this.mActivity = activity;
        this.directoryPathOriginal = directoryPath;
        this.requestCode = requestCode;
        this.trainedDataCode = trainedDataCode;
    }

    public void takePicture(){
        Intent e = new Intent("android.media.action.IMAGE_CAPTURE");
        this.filePathOriginal = FileUtils.getDirectory(this.directoryPathOriginal) + File.separator + Calendar.getInstance().getTimeInMillis() + ".jpg";
        e.putExtra("output", Uri.fromFile(new File(this.filePathOriginal)));

        startActivity(e);
    }

    public void onImageTaken(){
        Log.d(Config.TAG, "onImageTaken with path " + this.filePathOriginal);
        ImageProcessingThread thread = new ImageProcessingThread(this.mOcrScannerListener,
                this.filePathOriginal, this.directoryPathOriginal, this.mActivity, this.trainedDataCode);
        thread.execute();
    }

    private void startActivity(Intent intent){
        if(this.mActivity != null) {
            this.mActivity.startActivityForResult(intent, this.requestCode);
        }
    }

    public void setOcrScannerListener(EasyOcrScannerListener mOcrScannerListener) {
        this.mOcrScannerListener = mOcrScannerListener;
    }


}

FileUtils Java

package com.wordpress.priyankvex.easyocrscannerdemo;

import android.os.Environment;
import android.util.Log;

import java.io.File;

/**
 * Created by Priyank(@priyankvex) on 27/8/15.
 */
public class FileUtils {

    public static String getDirectory(String folderName) {
        File directory = null;
        directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + folderName);
        if(!directory.exists()) {
            directory.mkdirs();
        }

        return directory.getAbsolutePath();
    }

    public static String getTessdataDirectory(String directoryPath){
        File tessdataDirectory = new File(directoryPath + "/tessdata");
        if (tessdataDirectory.mkdirs()){
            Log.d(Config.TAG, "tessdata directory created");
        }
        return tessdataDirectory.getAbsolutePath();
    }
}

ImageProcessingThread Java

package com.wordpress.priyankvex.easyocrscannerdemo;

import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.os.AsyncTask;
import android.util.Log;

import com.googlecode.tesseract.android.TessBaseAPI;

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

/**
 * Created by Priyank(@priyankvex) on 27/8/15.
 *
 * Async Task to process the image and scan the image using tesseract library.
 * Equipped with proper callbacks.
 */
public class ImageProcessingThread extends AsyncTask<Void, Void, Void> {

    private EasyOcrScannerListener mOcrScannerListener;
    private String filePath;
    private Bitmap mBitmap;
    private String scannedText;
    // trained data file used by Tesseract will be copied in directoryPath/tessdata
    private String directoryPath;
    private String absoluteDirectoryPath;
    private Activity mActivity;
    String trainedDataCode;

    public ImageProcessingThread(EasyOcrScannerListener ocrScannerListener, String filePath,
                                 String directoryPath, Activity activity, String trainedDataCode) {
        this.mOcrScannerListener = ocrScannerListener;
        this.filePath = filePath;
        this.directoryPath = directoryPath;
        this.absoluteDirectoryPath = FileUtils.getDirectory(this.directoryPath);
        this.mActivity = activity;
        this.trainedDataCode = trainedDataCode;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mOcrScannerListener.onOcrScanStarted(this.filePath);
    }

    @Override
    protected Void doInBackground(Void... params) {
        processImage();
        makeTessdataReady();
        scannedText = scanImage();
        Log.d(Config.TAG, "Scanned test : " + scannedText);
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        mOcrScannerListener.onOcrScanFinished(mBitmap, scannedText);
    }

    private void processImage() {
        int imageOrientationCode = getImageOrientation();
        Bitmap rawBitmap = getBitmapFromPath();
        // Getting the bitmap in right orientation.
        this.mBitmap = rotateBitmap(rawBitmap, imageOrientationCode);
    }

    private Bitmap getBitmapFromPath() {
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inSampleSize = 4;
        Bitmap bitmap = BitmapFactory.decodeFile(this.filePath, bmOptions);
        return bitmap;
    }

    private int getImageOrientation() {
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(this.filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }

        assert exif != null;
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED);
        return orientation;
    }

    private Bitmap rotateBitmap(Bitmap bitmap, int orientation){

        Matrix matrix = new Matrix();
        switch (orientation) {
            case ExifInterface.ORIENTATION_NORMAL:
                return bitmap;
            case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                matrix.setScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                matrix.setRotate(180);
                break;
            case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                matrix.setRotate(180);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_TRANSPOSE:
                matrix.setRotate(90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                matrix.setRotate(90);
                break;
            case ExifInterface.ORIENTATION_TRANSVERSE:
                matrix.setRotate(-90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                matrix.setRotate(-90);
                break;
            default:
                return bitmap;
        }
        try {
            Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            bitmap.recycle();
            return bmRotated;
        }
        catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        }
    }

    private String scanImage(){
        TessBaseAPI baseApi = new TessBaseAPI();
        Log.d(Config.TAG, "Data path : " + FileUtils.getDirectory(this.directoryPath));
        baseApi.init(FileUtils.getDirectory(this.directoryPath) + "/", this.trainedDataCode);
        baseApi.setImage(this.mBitmap);
        String recognizedText = baseApi.getUTF8Text();
        baseApi.end();

        return recognizedText;
    }

    private void makeTessdataReady(){

        // created test data directory if necessary under absoluteDirectoryPath and returns its absolute path.
        String tessdirectoryPath = FileUtils.getTessdataDirectory(this.absoluteDirectoryPath);

        if (!(new File(tessdirectoryPath+ "/" + this.trainedDataCode + ".traineddata")).exists()) {
            try {

                AssetManager assetManager = mActivity.getAssets();
                InputStream in = assetManager.open("tessdata/" + this.trainedDataCode + ".traineddata");
                //GZIPInputStream gin = new GZIPInputStream(in);
                // Output stream with the location where we have to write the eng.traineddata file.
                OutputStream out = new FileOutputStream(tessdirectoryPath + "/"  + this.trainedDataCode
                        + ".traineddata");

                // Transfer bytes from in to out
                byte[] buf = new byte[1024];
                int len;
                //while ((lenf = gin.read(buff)) > 0) {
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                in.close();
                //gin.close();
                out.close();

                Log.v(Config.TAG, "Copied " + " traineddata");
            } catch (IOException e) {
                Log.e(Config.TAG, "Was unable to copy " + " traineddata " + e.toString());
            }
        }
        else{
            Log.d(Config.TAG, "tessdata already present");
        }
    }

}

我希望你们能帮助我。几天来弄清楚这段代码有什么问题.......

1 个答案:

答案 0 :(得分:0)

我想问题是相机活动没有返回RESULT_OK,而是RESULT_CANCELED - 因此从不调用tesseract。你可以验证这个e。 G。通过在方法“onActivityResult”的开头添加“Tab2.java”:

Log.d("PictureEdit", "onActivityResult w/ resultCode=" + resultCode + " (is ok: " + (resultCode == RESULT_OK) + " is canceled: " + (resultCode == RESULT_CANCELED) + ")" + " requestCode=" + requestCode);

为什么会这样?因为从Android 6(Marshmallow)开始,仅仅在清单中声明必要的权限是不够的。此外,权限必须在运行时从用户处获得。

见这里:https://developer.android.com/training/permissions/requesting.html

以下是我用于获取相机权限和r / w外部存储空间的代码:

private void checkPermissions(){
    if (Build.VERSION.SDK_INT >= 23) {
        boolean needWriteExtStorage = checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED;
        boolean needCamera = checkSelfPermission(android.Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED;
        if (needWriteExtStorage || needCamera){
            String[] permissions = new String[((needWriteExtStorage)?(1):(0)) + ((needCamera)?(1):(0))];
            int idx = 0;
            if (needWriteExtStorage){
                permissions[idx] = android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
                idx++;
            }
            if (needCamera){
                permissions[idx] = android.Manifest.permission.CAMERA;
                idx++;
            }
            ActivityCompat.requestPermissions(
                    this, permissions, 1);
        }
    } else { 
        //permission is automatically granted on sdk<23 upon installation
        //Log.e("testing", "Permission is already granted");
    }
}