专栏首页逮虾户CameraX 封装二维码扫描组件

CameraX 封装二维码扫描组件

简介

cameraX已经出来有一段时间了,现在已经从alpha版本到现在的beta3版本。其中内部的代码版本跨度特别大,而且资料相对来说只有官方的demo比较可以参考,所以最近完成了项目的开发之后,把经验分享一下提供给各位。

仓库地址

究极花里胡哨camreaX二维码扫描

二维码扫描小优化

  1. 去除zxing额外支持的格式(有争议的点,其实并没有特别大的差距) MultiFormatReader的decodeWithState()是使用方的入口方法,内部调用了decodeInternal(),输入是相机的一帧数据,如果抛了NotFoundException,则表示没找到二维码;如果返回了Result,则表示找到了二维码,并解析完成。 其中,readers变量是一个数组,数组的大小表示支持的条码格式个数,zxing原本因为支持很多格式,因此这个数组长度比较长。当拿到相机的一帧数据后,需要去检测是否是所有支持格式的某一个格式,每一种格式的检测都需要花费一些时间,因此这个遍历对于我们是不必要的。如果将zxing内部定制成只支持QR Code格式,那么就免去了额外的格式检测。
  2. 扫描区域放大到全局 去除项目中的扫描区域,将图像识别区域放大到整张区域,这样增加了二维码的边界情况,不需要特意的对准屏幕的扫描区域。
  3. 将相机升级到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:
  4. 自动放大 当二维码很小很远时,自动放大能大大加快检测二维码的速度。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!!! =
  5. 双击放大 当前二维码扫描中没有调整焦距的功能,所以我们在这次调整中对其进行了一次双击放大的开发。 通过监控双击事件实现对应监听。 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) } }) 复制代码
  6. 单击对焦 当前的对焦模式采取的是自动对焦,我们对对焦进行了一次增强,单击制定位置之后会对该区域进行一次对焦。 参考上面代码

简单使用

  1. 引入依赖
implementation 'com.github.leifzhang:QrCodeLibrary:0.0.1'
  1. 在布局xml中加入AutoZoomScanView
    <com.kronos.camerax.qrcode.AutoZoomScanView
        android:id="@+id/scanView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
复制代码
  1. 先申请camera权限并绑定lifecycle
    AndPermission.with(this)
            .runtime()
            .permission(Permission.Group.CAMERA)
            .onGranted { permissions: List? ->
                scanView.bindWithLifeCycle(this@MainActivity)
            }
            .onDenied { permissions: List? -> }
            .start()
  1. 二维码结果回调,之后重新打开分析逻辑
 scanView.setOnQrResultListener { view: View, s: String ->
            Toast.makeText(
                this@MainActivity, s,
                Toast.LENGTH_LONG
            ).show()
            scanView.reStart()
        }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android IO监控 | 性能监控系列

    公司的一款app最近在上架厂商的过程中,被对方指出了IO读写过于频繁,然后不给上架。但是IO读写的操作非常零散,而且很多第三方框架内都会有写入操作,所以就变得非...

    逮虾户
  • Okhttp如何开启的Http2.0

    但是我一直有些疑惑,Http2.0为什么后端支持了前端就能直接访问2.0版本了,Okhttp如何开启的Http2.0呢?

    逮虾户
  • View的有效曝光监控(上)|RecyclerView 篇

    我:之前我是把我们广告的曝光监控放在广告的模型层,然后在bindview的时候做一次曝光的,然后内部做了一次曝光防抖动,避免多次曝光。

    逮虾户
  • Kafka源码系列之topic创建分区分配及leader选举

    一,基本介绍 本文讲解依然是基于kafka源码0.8.2.2。假如阅读过前面的文章应该知道,用户的admin指令都是通过Zookeeper发布给kafka的Co...

    Spark学习技巧
  • 跟我学Kafka之Controller控制器详解(一)

    Kafka集群中的其中一个Broker会被选举为Controller,主要负责Partition管理和副本状态管理,也会执行类似于重分配Partition之类的...

    小程故事多
  • 快速学习-SpringBoot简介

    SpringBoot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品:

    cwl_java
  • 知道临时死区你才能更好的使用 JS 变量

    正确的答案是:第一个代码片段会报 ReferenceError: Cannot access 'Car' before initialization 错误。第二...

    前端小智@大迁世界
  • 通俗易懂设计模式解析——迭代器模式

      今天我们一起看看行为模式中的迭代器模式,迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。在系统开发中简单说可以理解成遍历。这种模式用于...

    小世界的野孩子
  • C#开发BIMFACE系列29 服务端API之获取模型数据14:获取图纸列表

    一个三维模型中可能包含对应多张二维图纸列表,本篇主要介绍如何获取模型文件对应的图纸列表。

    张传宁老师
  • 高并发架构系列:Redis的基本介绍,五种数据类型及应用场景分析

    Redis数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。

    用户5546570

扫码关注云+社区

领取腾讯云代金券