Android 文本识别:MLKIT + PreviewView

news2024/10/7 4:37:29

在这里插入图片描述
随着移动设备的普及和摄像头的高像素化,利用相机进行文本识别成为了一种流行的方式。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 就实现了, 看看效果吧:

textreconition.gif

总结

通过结合 MLKit 和 PreviewView,我们可以轻松实现 Android 应用程序中的文本识别功能。在本篇文章中,我们详细讲解了如何使用 MLKit 和 PreviewView 实现文本识别。感兴趣的小伙伴可参考 Demo 地址:TextRecognition

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/569442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2 files found with path ‘lib/arm64-v8a/libwechatbacktrace.so‘ from inputs

2 files found with path lib/arm64-v8a/libwechatbacktrace.so from inputs 解决方案&#xff0c;在app module的build.gradle里面的 android { } 块里面添加&#xff1a; packagingOptions {exclude lib/arm64-v8a/libwechatbacktrace.so} 如果有多个&#xff0c;就再增加行…

“宝石与石头”:一道简单却巧妙的力扣算法题

本篇博客会讲解力扣“771. 宝石与石头”的解题思路&#xff0c;这是题目链接。 先来审题&#xff1a; 以下是输出示例&#xff1a; 以下是提示&#xff1a; 本题可以使用数组模拟哈希表来实现。先把宝石字符串中的字符标识到数组的对应位置&#xff0c;每次拿石头字符串中的…

ChatGpt免费的镜像网站

目录 1.ChatGpt 简介 2.ChatGpt 免费网站合集 2.1 https://chat21.zhulei.xyz/ 2.2 Vega AI 创作平台 2.3 AI文本工具站 2.4 FancyPig (jqrai.one) 2.5 AiDuTu 1.ChatGpt 简介 ChatGPT是美国人工智能研究实验室OpenAI新推出的一种人工智能技术驱动的自然语言处理工具&…

geotools简介

geotools简介 官网 https://docs.geotools.org/latest/userguide/index.html 架构图 特性 1. 主要特性 Geotools主要提供各种GIS算法&#xff0c;实现各种数据格式的读写和显示。在显示方面要差一些&#xff0c;只是用Swing实现了地图的简单查看和操作。用户可以根据Geoto…

运营-17.留存

如何定义留存 某段时间内的新增用户&#xff0c;经过一段时间后&#xff0c;又继续使用应用的被认作是留存 用户&#xff0c;这部分用户占当时新增用户的比例即是留存率&#xff0c;即用户没有流失&#xff1b; 例如&#xff1a; 5月份新增用户200&#xff0c;这200人在6月份启…

Abaqus——悬臂梁问题之工字梁实例

参考 有限元基础-第7课&#xff08;悬臂梁问题&#xff09;-2022年_哔哩哔哩_bilibili 实例 软件 Abaqus 2022 方法 通过线形式建模 具体操作 建模 1.打开部件的模块&#xff0c;创建一个零件。Name&#xff1a;自定义命名&#xff1b;Modeling Space&#xff1a;梁的空…

认识Vue中组件利器-插槽Slot-案例介绍

一. 插槽的使用 1.1. 认识插槽slot 在开发中&#xff0c;我们会经常封装一个个可复用的组件&#xff1a; 前面我们会通过props传递给组件一些数据&#xff0c;让组件来进行展示&#xff1b; 但是为了让这个组件具备更强的通用性&#xff0c;我们不能将组件中的内容限制为固定…

项目总结:YOLOv8 人体姿态估计 跌倒检测

细节贴&#xff1a; YOLOv8 人体姿态估计 跌倒检测_爱钓鱼的歪猴的博客-CSDN博客 yolov8-pose的输出中有17个人体关键点 在胸膛处计算出一个中心点&#xff0c;腰部计算出一个中心点&#xff0c;连线&#xff0c;做一个直角三角形&#xff0c;求角的大小。 当角大于60度&…

基础篇009.1 STM32驱动RC522 RFID模块之一:基础知识

目录 1. RFID概述 1.1 RFID工作原理 1.2 RFID分类 1.3 RFID模块 1.4 RFID卡片 1.5 IC卡和ID卡介绍 1.6 IC卡和ID的区分 2. Mifare卡结构原理 2.1 Mifare卡概述 2.2 Mifare非接触式 IC 卡性能简介&#xff08;M1&#xff09; 2.2.1 Mifare S50与Mifare S70 2.2.2 S5…

蓝牙spp协议

一.定义 Serial Port Profile,串口通讯协议&#xff0c;是完成蓝牙设备之间创建串口进行数据传输的一种协议。 串口通讯协议(SPP)定义了使用蓝牙进行RS232&#xff08;或类似&#xff09;串行电缆仿真的设备应使用的协议和过程。 此协议涵盖的方案通过虚拟串行端口抽象&#…

自己编写小程序背日语50音图

自己编写小程序来背日语50音图 这是个啥直接上代码测试效果图 这是个啥 简而言之呢就是最近心血来潮打算自学日语&#xff0c;学日语自然就要先从50音图开始&#xff0c;就是下面这个&#xff1a; 可以看出来50音图横向是按照a i u e o这5个元音顺序&#xff0c;纵向按照a ka…

企业门户网站有用吗?如何解决搭建难题?

随着智能化时代的逐渐成熟&#xff0c;信息产业如火朝天&#xff0c;越来越多的人对门户网站开始感兴趣&#xff0c;不少企业家也开始对门户网站的开发与建设跃跃欲试。门户网站&#xff0c;也就是一个应用框架&#xff0c;把各类应用系统、互联网资源、数据资源集合到一个信息…

80.确定和规划项目(步骤1和2)

你的第一个现实世界的项目 ● 你的第一份“工作”&#xff01;、 ● 你受雇为一家名为Omnifood的虚构公司设计并建立一个网站。 ● Omnifood是一家使用人工智能来创建和提供定制健康膳食计划的初创公司。 ● 他们为我们提供了网站的所有内容&#xff08;content.md&#xff09…

Redis 的 Rdb 或 Aof 持久化详解

文章结构 Redis 的持久化方案Rdb&#xff08;Redis Database) 方式设置持久化快照的条件持久化文件的存储目录Rdb 的优点Rdb 的缺点 Aof&#xff08;Append Only File&#xff09; 方式aop 的优点aop 的缺点 Redis 的持久化方案 Rdb&#xff08;Redis Database) 方式 Redis 默…

循环队列(C++)

循环队列是一种特殊的队列实现&#xff0c;在顺序队列的基础上进行了优化。通常&#xff0c;循环队列使用固定长度的数组来表示队列元素&#xff0c;头和尾指针挂钩形成循环的维度感知队列长度&#xff0c;并提高队列操作效率&#xff0c;因为这种结构需要的内存量比链表数据结…

论文翻译:DeepFilterNet

目录 摘要1. 引言2. DeepfilterNet2.1. 信号模型2.2. Deep Filtering2.3. 框架概述2.4. DNN模型2.5. 数据处理2.6. 损失函数 3. 实验3.1. 训练步骤3.2. 结果 4. 结论5. 参考文献 论文题目&#xff1a;DeepFilterNet: A Low Complexity Speech Enhancement Framework for Full-B…

MQTT与传统的HTTP协议对比,优势在哪里呢?

HTTP是应用最为广泛和流行的协议。但是MQTT在过去的几年里迅速取得了进展。在讨论物联网开发的时候&#xff0c;开发者必须在这两者之间作出选择。 MQTT集中于数据&#xff0c;而HTTP集中于文档。HTTP是一个用于客户端-服务器计算的请求-响应协议&#xff0c;它并非总是为移动设…

位图和布隆过滤器

目录 位图 布隆过滤器 位图 假设有1000 万个范围在1~ 1亿的整数。如何快速查找某个整数是否出现在这1000万个整数中? 当然&#xff0c;这个问题仍然可以使用哈希表来解决。不过&#xff0c;针对这个“特殊”问题&#xff0c;我们可以使用一种比较“特殊”的哈希表&#xff…

阿里云手动创建Nginx-Ingress

阿里云相关文档 1、在ACK管理控制台点击如下 应用市场–>筛选(以ack-ingress-nginx-v1为例)–>点击安装–>一键部署–>自己定义集群、命名空间以及ingress名称 1.20以下集群选中ack-ingress-nginx。 1.20及以上集群选中ack-ingress-nginx-v1。 应用市场 筛选…

Linux学习笔记 --- Linux基础命令Part2

2.9 查找命令(which、find&#xff09; 目标&#xff1a;1. 掌握使用which命令查找命令的程序文件 2. 掌握使用find命令查找指定文件 which命令 我们在前面学习的Linux命令&#xff0c;其实它们的本体就是一个个的二进制可执行程序。 和Windows系统中的.exe文件&#x…