Android中拍照后用TextRecognizer识别文本无结果的问题求助
解决相机拍摄图片无法被TextRecognizer识别的问题
我帮你排查了下问题所在,核心原因是你目前通过data.getExtras().get("data")获取的是相机返回的缩略图,分辨率极低,TextRecognizer需要足够清晰的原图才能准确识别文字。而你从drawable加载的是完整分辨率的图片,所以能正常工作。
下面是具体的解决方案,分步骤帮你修改代码:
1. 核心思路调整
放弃获取缩略图,改为让相机直接将拍摄的原图保存到指定文件,然后从该文件加载完整分辨率的Bitmap用于识别。同时要处理图片的旋转问题(部分手机拍摄的图片会带有旋转角度,直接识别会失败)。
2. 步骤一:准备文件存储与权限
首先,我们需要创建一个用于保存拍照图片的文件,同时处理Android的权限问题(相机权限、存储权限,Android 6.0+需要动态申请)。
添加权限到AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 适配Android 7.0+的FileProvider --> <application> ... <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" /> </provider> </application>
创建file_paths.xml(在res/xml目录下)
<?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>
3. 步骤二:修改拍照按钮的点击逻辑
不再使用默认的缩略图返回,而是指定输出文件路径:
private File photoFile; private static final int REQUEST_IMAGE_CAPTURE = 100; private static final int REQUEST_PERMISSIONS = 200; // 在onCreate中初始化按钮 Button takePic = findViewById(R.id.btnTakePic); takePic.setOnClickListener(v -> { // 先检查权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSIONS); return; } // 创建保存图片的文件 try { photoFile = createImageFile(); } catch (IOException ex) { Toast.makeText(this, "创建图片文件失败", Toast.LENGTH_SHORT).show(); return; } // 获取文件Uri(适配Android 7.0+) Uri photoURI = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile); // 启动相机Intent Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); }); // 创建图片文件的方法 private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); return File.createTempFile( imageFileName, /* 前缀 */ ".jpg", /* 后缀 */ storageDir /* 存储目录 */ ); }
4. 步骤三:修改onActivityResult获取原图并处理旋转
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { // 从指定文件加载Bitmap Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath()); // 处理图片旋转 bitmap = rotateBitmap(bitmap, getImageRotation(photoFile.getAbsolutePath())); // 显示图片到ImageView imageView.setImageBitmap(bitmap); // 开始文字识别 recognizeTextFromBitmap(bitmap); } } // 获取图片的旋转角度 private int getImageRotation(String imagePath) { int rotation = 0; try { ExifInterface exif = new ExifInterface(imagePath); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: rotation = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: rotation = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: rotation = 270; break; } } catch (IOException e) { e.printStackTrace(); } return rotation; } // 旋转Bitmap private Bitmap rotateBitmap(Bitmap bitmap, int degrees) { if (degrees == 0 || bitmap == null) return bitmap; Matrix matrix = new Matrix(); matrix.setRotate(degrees, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); try { Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); bitmap.recycle(); return rotatedBitmap; } catch (OutOfMemoryError e) { e.printStackTrace(); return bitmap; } } // 文字识别方法 private void recognizeTextFromBitmap(Bitmap bitmap) { textRecognizer = new TextRecognizer.Builder(this).build(); if (!textRecognizer.isOperational()) { Toast.makeText(this, "TextRecognizer初始化失败", Toast.LENGTH_SHORT).show(); return; } Frame frame = new Frame.Builder().setBitmap(bitmap).build(); SparseArray<TextBlock> textBlocks = textRecognizer.detect(frame); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < textBlocks.size(); i++) { TextBlock textBlock = textBlocks.valueAt(i); stringBuilder.append(textBlock.getValue()).append("\n"); } Result.setText(stringBuilder.toString()); }
5. 步骤四:处理权限申请结果
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSIONS) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) { // 权限通过,重新触发拍照 takePic.performClick(); } else { Toast.makeText(this, "需要相机和存储权限才能使用", Toast.LENGTH_SHORT).show(); } } }
6. 调整activity_main.xml(添加拍照按钮)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" tools:context=".MainActivity"> <ImageView android:id="@+id/imageView" android:layout_width="0dp" android:layout_height="0dp" android:layout_margin="16dp" android:scaleType="centerCrop" app:layout_constraintBottom_toTopOf="@+id/btnTakePic" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/image" /> <Button android:id="@+id/btnTakePic" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="拍照识别文字" app:layout_constraintBottom_toTopOf="@+id/tvResult" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintVertical_bias="0.5" /> <TextView android:id="@+id/tvResult" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="32dp" android:text="识别结果" android:textSize="18sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
这样修改后,你就能获取到相机拍摄的原图,并且处理好旋转问题,TextRecognizer就能正常识别图片中的文字了。
内容的提问来源于stack exchange,提问作者Loving Android
相关产品推荐
相关产品推荐

