我遵循了com.google.codelab.mlkit的教程说明。
而不是使用intent。我使用FileProvider来获取和分析全图。
我根据Android模拟器中相机自定义映像的推荐替换了仿真中的虚拟映像。
所以我启动我的应用程序(主活动),用内部相机(这是替换的虚拟图像)拍照,然后回到主活动。我遇到了代码recognizeTextFromImage(),但我从来没有遇到。addonsuccesslistener()和。addonfailurelistener()。这让我很惊讶,因为我甚至没有得到一个失败。日志中不打印任何内容。
我使用API级别23,因为如果我使用更高的API, resultCode是0(而不是-1)。
我的问题是:为什么我的代码不运行到。addonsuccesslistener()或至少进入。addonfailurelistener () ?
1。更新
我尝试了"intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); ' ' ',这改变了行为。读取文件需要几秒钟。所以我认为@Danish是正确的,该文件不是由相机创建的。但是:addOnFailureListener()也有同样的问题。也许文件太大了?还是我发错格式了?日志上写着"W/e.codelab"。java.lang.String的验证com.google.codelab.mlkit.MainActivity。recognizeTextFromImage(com.google.mlkit.vision.common.InputImage)耗时536.238毫秒
2。更新
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
</paths>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.codelab.mlkit">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera"
android:required="true"/>
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
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>
<meta-data
android:name="com.google.codelab.mlkit.vision.DEPENDENCIES"
android:value="ocr" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
</application>
</manifest>
<?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"
app:layoutDescription="@xml/activity_main_scene"
tools:context=".MainActivity" >
<TableLayout
android:layout_width="360dp"
android:layout_height="539dp"
android:layout_centerInParent="true">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView_ServiceID"
android:layout_width="11dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:gravity="center"
android:text="ServiceID"
android:textAlignment="viewStart" />
<EditText
android:id="@+id/editText_ServiceID"
android:layout_height="match_parent"
android:layout_weight="0.7
"
android:gravity="left"
android:inputType="text"
android:text="4711" />
</TableRow>
</TableLayout>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="359dp"
android:layout_height="match_parent">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView_Site"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:gravity="center"
android:text="Site"
android:textAlignment="viewStart" />
<Spinner
android:id="@+id/spinner_Site"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<ImageButton
android:id="@+id/imageButton_Site"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_photo" />
<EditText
android:id="@+id/editText_Site"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:inputType="text"
android:text="not yet reconized" />
</TableRow>
</TableLayout>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end" >
<TableRow
android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageButton
android:id="@+id/imageButton6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_send" />
<ImageButton
android:id="@+id/imageButton7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_save" />
</TableRow>
</TableLayout>
</TableRow>
</TableLayout>
</RelativeLayout>
package com.google.codelab.mlkit;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private static final String TAG = "MainActivity";
private ImageButton imageButton_Site;
private EditText editText_Site;
private Spinner spinner_Site;
private InputImage createdImage;
String recognizedText = "";
String currentPhotoPath;
static final int REQUEST_IMAGE_CAPTURE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageButton_Site = findViewById(R.id.imageButton_Site);
imageButton_Site.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dispatchTakePictureIntent();
}
});
spinner_Site = findViewById(R.id.spinner_Site);
String[] items = new String[]{"Chicago", "New York"}; // has to be retrieved from server based on GPS (satellite)
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, items);
spinner_Site.setAdapter(adapter);
spinner_Site.setOnItemSelectedListener(this);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(getApplicationContext(), "Error occurred while creating the File!",Toast.LENGTH_LONG).show();
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".fileprovider",
photoFile);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
takePictureIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
takePictureIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // new
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult( requestCode, resultCode, data);
// Log.d("OLR", "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bitmap bitmap=BitmapFactory.decodeFile(currentPhotoPath);
Bitmap imagebitmap=Bitmap.createBitmap(bitmap);//Just add this line and everything will work fine.I tried this code, its working like a charm.
int check = bitmap.getWidth();
InputImage inputImage = InputImage.fromBitmap(imagebitmap, 0);
String text = recognizeTextFromImage(inputImage);
if (text.isEmpty())
{
Toast.makeText(getApplicationContext(), "Nothing recognized. Please try again!",Toast.LENGTH_LONG).show();
editText_Site.setText("Failed !");
}
else {
editText_Site.setText(text);
}
}
else {
Toast.makeText(getApplicationContext(), "An issue occurred. Please inform app owner!",Toast.LENGTH_LONG).show();
}
}
private File createImageFile() throws IOException {
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// create directory if necessary
if (!storageDir.exists()){
storageDir.mkdir();
}
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",Locale.GERMANY).format(new Date());
String imageFileName = "OLR_" + timeStamp + "_";
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// imageFile = image;
currentPhotoPath = image.getAbsolutePath();
return image;
}
private String recognizeTextFromImage(InputImage image) {
TextRecognizer recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);
Task<Text> task = recognizer.process(image);
// recognizer.process(image)
task
.addOnSuccessListener(
new OnSuccessListener<Text>() {
@Override
public void onSuccess(Text texts) {
recognizedText = processTextRecognitionResult(texts);
Log.d(TAG,"Successful");
}
})
/*.addOnSuccessListener(
new OnSuccessListener<Text>() {
@Override
public void onSuccess(Text texts) {
recognizedText = texts.getText();
editText_Site.setText(recognizedText);
Log.d(TAG,"Successful");
}
})*/
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
Log.d(TAG,"Not Successful");
}
});
recognizer.close();
return recognizedText;
}
private String processTextRecognitionResult(Text texts) {
String recognizedText = "";
List<Text.TextBlock> blocks = texts.getTextBlocks();
if (blocks.size() == 0) {
// No text found
}
else {
for (int i = 0; i < blocks.size(); i++) {
List<Text.Line> lines = blocks.get(i).getLines();
for (int j = 0; j < lines.size(); j++) {
List<Text.Element> elements = lines.get(j).getElements();
for (int k = 0; k < elements.size(); k++) {
String elementText = elements.get(k).getText();
recognizedText = recognizedText + elementText;
}
}
}
}
return recognizedText;
}
private void showToast(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
spinner_Site = findViewById(R.id.spinner_Site);
editText_Site = findViewById(R.id.editText_Site);
editText_Site.setText(spinner_Site.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing
}
}
问题解决
(1)我必须加上intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
(2)我检查了返回的字符串"recognizedText"它总是空的,因为线程在变量被填满后才执行。灰烬落在我头上。我要感谢@Danish,他给了我决定性的提示,让我把日志添加到正确的位置。
(3)由于某种原因,我不得不在开始调试之前等待一段时间。
为此工作了几个小时,Alhamdulillah我想出了解决方案。@Micky我在你的代码中发现了bug。所以为了帮助你,我在下面提供了解决方案。基本上,这个bug与旋转有关,如果图像不是在横向模式下捕获的,ocr就不能正确识别文本,所以在扫描之前必须确保图像正确旋转。在这一行也有问题recognizedText = processTextRecognitionResult(文本);它不能正确识别文本,你可以检查下面我已经添加了一个额外的edittext来告诉你如何通过text . gettext()发送文本给你更好的结果的差异。
检查下面的代码:
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.text.Text;
import com.google.mlkit.vision.text.TextRecognition;
import com.google.mlkit.vision.text.TextRecognizer;
import com.google.mlkit.vision.text.latin.TextRecognizerOptions;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private static final String TAG = "MainActivity";
private ImageButton imageButton_Site;
private EditText editText_Site;
EditText editText;
private Spinner spinner_Site;
private InputImage createdImage;
String recognizedText="";
String currentPhotoPath;
static final int REQUEST_IMAGE_CAPTURE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText_Site=findViewById(R.id.editText_Site);
editText=findViewById(R.id.editText);
imageButton_Site = findViewById(R.id.imageButton_Site);
spinner_Site = findViewById(R.id.spinner_Site);
String[] items = new String[]{"Chicago", "Ludwigshafen"}; // has to be retrieved from server based on GPS (satellite)
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, items);
spinner_Site.setAdapter(adapter);
spinner_Site.setOnItemSelectedListener(this);
imageButton_Site.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dispatchTakePictureIntent();
}
});
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(getApplicationContext(), "Error occurred while creating the File!",Toast.LENGTH_LONG).show();
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,BuildConfig.APPLICATION_ID+".fileprovider",
photoFile);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult( requestCode, resultCode, data);
// Log.d("OLR", "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
ParcelFileDescriptor parcelFileDescriptor = null;
try {
parcelFileDescriptor = getContentResolver().openFileDescriptor(Uri.fromFile(new File(currentPhotoPath)), "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
ExifInterface exifInterface = null;
try {
exifInterface = new ExifInterface(fileDescriptor);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
Matrix matrix = new Matrix();
matrix.setRotate(90);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
Matrix matrixe = new Matrix();
matrixe.setRotate(180);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrixe, true);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
Matrix matrixes = new Matrix();
matrixes.setRotate(270);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrixes, true);
break;
case ExifInterface.ORIENTATION_NORMAL:
Matrix matrix12 = new Matrix();
matrix12.setRotate(ExifInterface.ORIENTATION_ROTATE_90);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix12, true);
}
InputImage inputImage=null;
inputImage= InputImage.fromBitmap(bitmap,0);
String text=null;
try {
text = recognizeTextFromImage(inputImage);
} catch (IOException e) {
e.printStackTrace();
}
if (text.isEmpty())
{
Toast.makeText(getApplicationContext(), "Nothing recognized. Please try again!",Toast.LENGTH_LONG).show();
editText_Site.setText("Failed !");
}
else {
editText_Site.setText(text);
}
}
else {
Toast.makeText(getApplicationContext(), "An issue occurred. Please inform app owner!",Toast.LENGTH_LONG).show();
}
}
private File createImageFile() throws IOException {
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// create directory if necessary
if (!storageDir.exists()){
storageDir.mkdir();
}
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.GERMANY).format(new Date());
String imageFileName = "OLR_" + timeStamp + "_";
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// imageFile = image;
currentPhotoPath = image.getAbsolutePath();
return image;
}
private String recognizeTextFromImage(InputImage image) throws IOException {
TextRecognizer recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);
Task<Text> task = recognizer.process(image)
.addOnSuccessListener(
new OnSuccessListener<Text>() {
@Override
public void onSuccess(Text texts) {
recognizedText = processTextRecognitionResult(texts);
editText.setText(texts.getText());
Log.d(TAG,"Successful");
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
Log.d(TAG,"Not Successful");
}
});
return recognizedText;
}
private String processTextRecognitionResult(Text texts) {
String recognizedText = "";
List<Text.TextBlock> blocks = texts.getTextBlocks();
if (blocks.size() == 0) {
// No text found
}
else {
for (int i = 0; i < blocks.size(); i++) {
List<Text.Line> lines = blocks.get(i).getLines();
for (int j = 0; j < lines.size(); j++) {
List<Text.Element> elements = lines.get(j).getElements();
for (int k = 0; k < elements.size(); k++) {
String elementText = elements.get(k).getText();
recognizedText = recognizedText + elementText;
}
}
}
}
return recognizedText;
}
private void showToast(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
spinner_Site = findViewById(R.id.spinner_Site);
editText_Site.setText(spinner_Site.getSelectedItem().toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing
}
}