跟着移动设备的普及和摄像头的高像素化,利用相机进行文本辨认成为了一种流行的办法。MLKit 是 Google 提供的一款机器学习工具包,其间包含了丰厚的图画和言语处理功用,包含文本辨认。PreviewView 是 Android Jetpack 的一部分,它提供了一个方便的预览相机图画的视图组件。结合 MLKit 和 PreviewView,咱们能够轻松构建出一个功用强大的文本辨认应用程序。

增加依靠

为了运用 MLKit 和 PreviewView,咱们需求在项目的 build.gradle 文件中增加相应的依靠项。以下是所需的依靠项:

// camera
def camerax_version = "1.2.1"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-video:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"
implementation "androidx.camera:camera-extensions:${camerax_version}"
// To recognize Chinese script
implementation 'com.google.mlkit:text-recognition-chinese:16.0.0'

以上依靠项包含了与相机操作和中文文本辨认相关的库。

XML 布局

在布局文件中,咱们需求增加一个 PreviewView(相机预览视图),一个按钮用于开端/中止文本辨认,以及一个用于显现辨认成果的 TextView。以下是布局文件的示例代码:

<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
    tools:context=".MainActivity">
    <androidx.camera.view.PreviewView
        android:id="@+id/pre_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
    <Button
        android:id="@+id/btn_operation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="点击中止文本辨认"
        android:layout_marginHorizontal="16dp" />
    <TextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:padding="6dp" />
</LinearLayout>

上述布局文件包含了一个笔直摆放的 LinearLayout,其间包含了一个 PreviewView、一个按钮和一个用于显现辨认成果的 TextView。

代码完结

在代码完结部分,首先检查相机权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.CAMERA"/>
</manifest>

在权限被颁发时初始化相机,进行文本辨认。咱们设置按钮的点击事情监听器,根据当前相机的状况履行相应的操作。当按钮被点击时,咱们会根据相机的状况开端或中止文本辨认,默许处于辨认状况中。

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private var cameraProvider: ProcessCameraProvider? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        requestPermission()
        binding.btnOperation.setOnClickListener {
            cameraProvider?.let {
                binding.btnOperation.text = "点击开端文本辨认"
                cameraProvider?.unbindAll()
                cameraProvider = null
            } ?: run {
                binding.btnOperation.text = "点击中止文本辨认"
                setupCamera()
            }
        }
    }
    // 其他办法和完结代码...
}

onCreate() 办法中,咱们设置了按钮的点击事情监听器。当按钮被点击时,咱们根据当前的相机状况履行相应的操作。假如相机已经初始化并正在运行,咱们会中止文本辨认并开释相机资源。假如相机未初始化或已中止,咱们将开端文本辨认并设置相机。

接下来,咱们完结了恳求相机权限的办法 requestPermission(),并在 onCreate() 办法中调用它。在 onRequestPermissionsResult() 办法中,咱们检查相机权限的授权成果。假如权限被颁发,咱们将调用 setupCamera() 办法初始化相机。假如权限被拒绝,咱们将显现一个简略的提示音讯。

/**
* 恳求相机权限
*/
private fun requestPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_CODE)
    } else {
        setupCamera()
    }
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == CAMERA_PERMISSION_CODE) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            setupCamera()
        } else {
            Toast.makeText(this, "权限被拒绝", Toast.LENGTH_SHORT).show()
        }
    }
}

requestPermission() 办法中,咱们检查相机权限并恳求授权。假如权限已被颁发,咱们将调用 setupCamera() 办法初始化相机。

/**
* 设置相机
*/
private fun setupCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    cameraProviderFuture.addListener({
        val cameraProvider = cameraProviderFuture.get()
        bindPreview(cameraProvider)
    }, ContextCompat.getMainExecutor(this))
}

setupCamera() 办法中,咱们运用 ProcessCameraProvider 获取相机实例,并经过 bindPreview() 办法将相机与 PreviewView 绑定。

/**
* 绑定 preview
*/
private fun bindPreview(cameraProvider: ProcessCameraProvider) {
    this.cameraProvider = cameraProvider
    val preview = Preview.Builder().build()
    val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
    preview.setSurfaceProvider(binding.preView.surfaceProvider
)
    val analysis = ImageAnalysis.Builder()
        .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888)
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .build()
    analysis.setAnalyzer(Executors.newSingleThreadExecutor(), this::analyzeImage)
    cameraProvider.bindToLifecycle(this, cameraSelector, preview, analysis)
}

bindPreview() 办法中,咱们创立了一个 Preview 实例,并将其与默许后置摄像头绑定。然后,咱们设置 PreviewView 的 SurfaceProvider,并创立一个 ImageAnalysis 实例用于图画剖析。经过设置图画剖析器的回调办法,咱们能够在每帧图画上履行文本辨认。

/**
* 解析文本
*/
@SuppressLint("UnsafeOptInUsageError")
private fun analyzeImage(imageProxy: ImageProxy) {
    val image = imageProxy.image ?: return
    val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees)
    val recognizer = TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())
    recognizer.process(inputImage)
        .addOnSuccessListener { result ->
            binding.tvContent.text = result.text
        }
        .addOnCompleteListener {
            // 开释ImageProxy目标 
            imageProxy.close()
        }
        .addOnFailureListener {
            // 处理辨认过程中的过错
            it.printStackTrace()
            imageProxy.close()
        }
}

经过完结了 analyzeImage() 办法,用于剖析图画并履行文本辨认。在该办法中,咱们首先将 ImageProxy 转换为 InputImage,然后创立一个中文文本辨认器。接下来,咱们运用辨认器对图画进行处理,并在成功完结时更新 TextView 的内容。不管成功与否,最后都会关闭 ImageProxy。这儿假如咱们想辨认图片(Bitmap)中的文字能够调用 InputImage.fromBitmap 办法即可。

演示

Ok,到这儿咱们文本辨认的功用 demo 就完结了, 看看效果吧:

总结

经过结合 MLKit 和 PreviewView,咱们能够轻松完结 Android 应用程序中的文本辨认功用。在本篇文章中,咱们具体讲解了怎么运用 MLKit 和 PreviewView 完结文本辨认。感兴趣的小伙伴可参考 Demo 地址:TextRecognition