CameraX 封装二维码扫描组件
时间:2022-07-26
本文章向大家介绍CameraX 封装二维码扫描组件,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
简介
cameraX已经出来有一段时间了,现在已经从alpha版本到现在的beta3版本。其中内部的代码版本跨度特别大,而且资料相对来说只有官方的demo比较可以参考,所以最近完成了项目的开发之后,把经验分享一下提供给各位。
仓库地址
二维码扫描小优化
- 去除zxing额外支持的格式(有争议的点,其实并没有特别大的差距) MultiFormatReader的decodeWithState()是使用方的入口方法,内部调用了decodeInternal(),输入是相机的一帧数据,如果抛了NotFoundException,则表示没找到二维码;如果返回了Result,则表示找到了二维码,并解析完成。 其中,readers变量是一个数组,数组的大小表示支持的条码格式个数,zxing原本因为支持很多格式,因此这个数组长度比较长。当拿到相机的一帧数据后,需要去检测是否是所有支持格式的某一个格式,每一种格式的检测都需要花费一些时间,因此这个遍历对于我们是不必要的。如果将zxing内部定制成只支持QR Code格式,那么就免去了额外的格式检测。
- 扫描区域放大到全局 去除项目中的扫描区域,将图像识别区域放大到整张区域,这样增加了二维码的边界情况,不需要特意的对准屏幕的扫描区域。
- 将相机升级到jetpack的CameraX 谷歌已经在官方提供了对于camera2的整合包,集成在CamreaX,而且CameraX内部有对于图片分析的接口,所以我们在这个接口中会对原来的二维码扫描进行一次转移,然后构建一个线程池专门去处理二维码扫描的分析器。 class CameraXModule(private val view: AutoZoomScanView) { private var lensFacing: Int = CameraSelector.LENS_FACING_BACK private var preview: Preview? = null private var imageAnalyzer: ImageAnalysis? = null private lateinit var cameraExecutor: ExecutorService private var camera: Camera? = null private lateinit var qrCodeAnalyzer: QRCodeAnalyzer private lateinit var mLifecycleOwner: LifecycleOwner fun bindWithCameraX(function: (Result) -> Unit, lifecycleOwner: LifecycleOwner) { mLifecycleOwner = lifecycleOwner val metrics = DisplayMetrics().also { view.display.getRealMetrics(it) } Log.d(TAG, "Screen metrics:
- 自动放大 当二维码很小很远时,自动放大能大大加快检测二维码的速度。QRCodeReader的decode()是二维码检测的主方法,分为两步: (1)大致判断是否存在二维码; val source = PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false) val binarizer = HybridBinarizer(source) val bitmap = BinaryBitmap(binarizer) val detectorResult = Detector(bitmap.blackMatrix).detect(map) 复制代码 private fun calculateDistance(resultPoint: Array<ResultPoint>): Int { val point1X = resultPoint[0].x.toInt() val point1Y = resultPoint[0].y.toInt() val point2X = resultPoint[1].x.toInt() val point2Y = resultPoint[1].y.toInt() return sqrt( (point1X - point2X.toDouble()).pow(2.0) + (point1Y - point2Y.toDouble()).pow(2.0) ).toInt() } 复制代码先要获取到当前区域内是否存在二维码,其次计算二维码的距离。 (2)所以我们需要做的就是先检测该图像区域内是否有一个二维码,同时计算二维码的大小,和图像比例进行一次大小换算,如果发现二维码过小的情况下,自动放大图片区域。 private fun zoomCamera(points: Array<ResultPoint>, image: BinaryBitmap): Boolean { val qrWidth = calculateDistance(points) * 2 val imageWidth = image.blackMatrix.width.toFloat() val zoomInfo = camera?.cameraInfo?.zoomState?.value zoomInfo?.apply { if (qrWidth < imageWidth / 8) { Log.i("BarcodeAnalyzer", "resolved!!! =
- 双击放大 当前二维码扫描中没有调整焦距的功能,所以我们在这次调整中对其进行了一次双击放大的开发。 通过监控双击事件实现对应监听。 private val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() { override fun onDoubleTap(e: MotionEvent?): Boolean { cameraXModule.setZoomRatio(cameraXModule.getZoomRatio() + 1) return super.onDoubleTap(e) } override fun onSingleTapUp(e: MotionEvent?): Boolean { e?.apply { cameraXModule.setFocus(x, y) } return super.onSingleTapUp(e) } }) 复制代码
- 单击对焦 当前的对焦模式采取的是自动对焦,我们对对焦进行了一次增强,单击制定位置之后会对该区域进行一次对焦。 参考上面代码
简单使用
- 引入依赖
implementation 'com.github.leifzhang:QrCodeLibrary:0.0.1'
- 在布局xml中加入AutoZoomScanView
<com.kronos.camerax.qrcode.AutoZoomScanView
android:id="@+id/scanView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
复制代码
- 先申请camera权限并绑定lifecycle
AndPermission.with(this)
.runtime()
.permission(Permission.Group.CAMERA)
.onGranted { permissions: List? ->
scanView.bindWithLifeCycle(this@MainActivity)
}
.onDenied { permissions: List? -> }
.start()
- 二维码结果回调,之后重新打开分析逻辑
scanView.setOnQrResultListener { view: View, s: String ->
Toast.makeText(
this@MainActivity, s,
Toast.LENGTH_LONG
).show()
scanView.reStart()
}
- 开源API测试工具 Hitchhiker v0.7更新 - Schedule的对比diff
- com.mysql.jdbc.exceptions.jdbc4.CommunicationsE...
- 简陋的swift carthage copy-frameworks 辅助脚本
- 【自问自答】关于 Swift 的几个疑问
- 高级PHP应用程序漏洞审核技术【一】
- 【读书笔记】The Swift Programming Language (Swift 4.0.3)
- Ubuntu 下mysql常用操作
- JDK1.8源码(五)——java.util.ArrayList 类
- 代码审计入门总结
- ubuntu mysql启动|停止|重启
- JDK1.8源码(四)——java.util.Arrays 类
- JDK1.8源码(三)——java.lang.String 类
- JDK1.8源码(二)——java.lang.Integer 类
- Java关键字——instanceof
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Rust闭包的虫洞穿梭
- TS 设计模式08 - 发布订阅模式
- GrowingIO 数据采集 iOS SDK 测试实践
- Kubernetes 1.19.0——Pod(2)
- 极速40分钟写出SQLite数据展示与导出功能【技术创作101训练营】
- opencv cudacodec VideoReader 报错
- Flutter中富文件标签的解决方案
- JDK 15已发布,你所要知道的都在这里!
- [Concent速成] (1) 定义和共享模块状态
- 利用JS代码批量自动取消抖音关注
- 开机报错/dev/vda1 contains a file system with errors,check forced.
- centos内核的删除或修改
- chkconfig学习笔记
- 3分钟短文:说说Laravel通用缓存Cache的使用技巧
- 【技术创作101训练营】想用代码改变世界?先用好Git和Github!