You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:23:45