我目前正在开发能够切换活动标签的第一个应用程序(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");
}
}
}
我希望你们能帮助我。几天来弄清楚这段代码有什么问题.......
答案 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");
}
}