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

如何在Camera Source中用ML Kit TextRecognizer替换GMS TextRecognizer

问题

我的应用通过SurfaceView相机持续检测文本并显示到TextView,原代码使用GMS TextRecognizer实现。现在想替换为ML Kit TextRecognizer,保持相同的连续识别逻辑,但两者API存在差异:原GMS通过setProcessor处理检测结果,而ML Kit的TextRecognizer需调用process(image)异步处理图像,不清楚如何协调两者,请求最简单的替换方案。

原代码:

cameraView = findViewById(R.id.surface_view);
textView = findViewById(R.id.text_view);

// 1
final TextRecognizer textRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
if (!textRecognizer.isOperational()) {
    Log.w("MainActivity", "Detected dependence are not found ");
} else {
    cameraSource = new CameraSource.Builder(getApplicationContext(), textRecognizer)
            .setFacing(CameraSource.CAMERA_FACING_BACK)
            .setRequestedPreviewSize(1280, 1024)
            .setRequestedFps(2.0f)
            .setAutoFocusEnabled(true)
            .build();

    // 2
    cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                if (ActivityCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
                    ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CAMERA},
                            RequestCameraPermission);
                }
                cameraSource.start(cameraView.getHolder());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            cameraSource.stop();
        }
    });

    // 4
    textRecognizer.setProcessor(new Detector.Processor<TextBlock>() {
        @Override
        public void release() {

        }

        @Override
        public void receiveDetections(Detector.Detections<TextBlock> detections) {
            final SparseArray<TextBlock> items = detections.getDetectedItems();
            if (items.size() != 0 ){
                textView.post(new Runnable() {
                    @Override
                    public void run() {
                        StringBuilder stringBuilder = new StringBuilder();
                        for (int i = 0 ;i < items.size();i++){
                            TextBlock item = items.valueAt(i);
                            stringBuilder.append(item.getValue());
                            stringBuilder.append("\n");
                        }
                        textView.setText(stringBuilder.toString());
                        Log.d("Text",stringBuilder.toString());
                    }
                });
            }
        }
    });
}
最简单替换方案

核心思路是放弃原GMS的Detector绑定逻辑,改用CameraSource.PreviewCallback获取相机帧,再传给ML Kit异步识别。以下是完整修改后的代码:

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;

// ... 其他原有导入

public class MainActivity extends AppCompatActivity {
    private SurfaceView cameraView;
    private TextView textView;
    private CameraSource cameraSource;
    private static final int RequestCameraPermission = 1001;
    // ML Kit 文本识别器
    private TextRecognizer mlKitTextRecognizer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        cameraView = findViewById(R.id.surface_view);
        textView = findViewById(R.id.text_view);

        // 初始化ML Kit文本识别器
        mlKitTextRecognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);

        // 创建CameraSource,不再传入GMS的TextRecognizer
        cameraSource = new CameraSource.Builder(getApplicationContext(), null)
                .setFacing(CameraSource.CAMERA_FACING_BACK)
                .setRequestedPreviewSize(1280, 1024)
                .setRequestedFps(2.0f)
                .setAutoFocusEnabled(true)
                .build();

        // 设置预览回调,获取相机每一帧图像
        cameraSource.setPreviewCallback(new CameraSource.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                // 将相机帧转换为ML Kit的InputImage
                Camera.Size size = camera.getParameters().getPreviewSize();
                int rotation = getWindowManager().getDefaultDisplay().getRotation();
                InputImage image = InputImage.fromByteArray(data, size.width, size.height, rotation,
                        InputImage.IMAGE_FORMAT_NV21);

                // 调用ML Kit异步识别文本
                mlKitTextRecognizer.process(image)
                        .addOnSuccessListener(text -> {
                            // 处理识别结果并更新TextView
                            StringBuilder stringBuilder = new StringBuilder();
                            for (Text.TextBlock block : text.getTextBlocks()) {
                                stringBuilder.append(block.getText());
                                stringBuilder.append("\n");
                            }
                            // 在主线程更新UI
                            textView.post(() -> textView.setText(stringBuilder.toString()));
                            Log.d("Text", stringBuilder.toString());
                        })
                        .addOnFailureListener(e -> Log.w("MainActivity", "文本识别失败", e));
            }
        });

        // SurfaceHolder回调逻辑保持不变
        cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA)
                            != PackageManager.PERMISSION_GRANTED) {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.CAMERA}, RequestCameraPermission);
                        return;
                    }
                    cameraSource.start(cameraView.getHolder());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                cameraSource.stop();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 释放ML Kit识别器资源
        if (mlKitTextRecognizer != null) {
            mlKitTextRecognizer.close();
        }
        if (cameraSource != null) {
            cameraSource.release();
        }
    }

    // 处理相机权限申请结果
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == RequestCameraPermission) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                try {
                    cameraSource.start(cameraView.getHolder());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

关键修改点说明

  • 移除原GMS的TextRecognizer及setProcessor逻辑,改用ML Kit的TextRecognition.getClient()创建识别器
  • 创建CameraSource时不再传入Detector,改为传入null
  • 添加PreviewCallback获取相机预览帧,将帧数据转换为ML Kit要求的InputImage(注意处理屏幕旋转角度,确保识别方向正确)
  • 在ML Kit的onSuccess回调中遍历TextBlock拼接文本,主线程更新TextView
  • 在onDestroy中释放ML Kit识别器和CameraSource资源

内容的提问来源于stack exchange,提问作者Clint William Theron

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:36:10