CameraX + 华为ScanKit:二维码扫描的终极解决方案

本文介绍如何集成华为ScanKit提升CameraX扫码性能,包括UI优化、集成步骤及手势支持等,提供丰富的代码示例。

在这里插入图片描述

年初写了一篇CameraX的使用文章,帮到了一些朋友,也收到了一些建议。正值最近了解到华为ScanKit在扫码场景下的优秀表现,决定集成该方案,并进行一些功能改进。

之前做的Demo略显简陋,本次改进也对UI进行了调整。主要是给顶部操作栏添加了半透明背景,同时给切换按钮添加了半透明边框以提高对比度。另外对拍摄和录制场景的一些配色做了改动。

在这里插入图片描述

1. 华为ScanKit是什么

ScanKit可以提供便捷的二维码与条形码扫描、解析、生成能力,帮助您快速构建应用内的扫码功能。

它拥有诸多优势,包括支持多达13种码格式,在反光、污损、畸变、模糊等复杂场景下亦能良好识别,在远距离扫码的情况下能自适应放大码体,还支持多码识别功能等等。

ScanKit给开发者提供了四种集成模式,包括固定扫码界面的Default View Mode,自定义扫码界面的Customized View Mode,以及完全由开发者自定义画面和扫码流程的Bitmap ModeMultiProcessor Mode

前两种模式的扫码流程均由ScanKit控制,其内部采用Camera1实现。如果要集成到CameraX上的话,只能选择后两种模式。MultiProcessor Mode适用于多码识别的场景,本次先集成单码识别的Bitmap Mode

华为ScanKit更加详细的资料可查阅官网:
https://developer.huawei.com/consumer/cn/hms/huawei-scankit

以及易冬大神的完整演示:

https://juejin.cn/post/6967890062423883783

2. 扫码方案的选择

之前的扫码方案采用的是Zxing,本次集成ScanKit之后,为了对比学习将Zxing的使用也进行了保留。在点击扫码按钮之后,底部会弹出扫码方案的选择Fragment,选择之后通过ViewModel将对应的方案告知CameraX的ImageAnalysis。

在这里插入图片描述

※ Google的ML Kit是一个更为强大的OCR解决方案,后面也将集成进来

大家可能比较关心ScanKit相较于Zxing的优势,可以参考如下这篇测评文章:
https://developer.huawei.com/consumer/cn/forum/topic/0201248342859390343?fid=18

这篇文章里提到ScanKit在远距离扫码、码体倾斜、模糊扫码等场景下的识别速度和成功率都要优于Zxing。大家也可以使用本文的Demo,分别选择Zxing和ScanKit两个方案,实际对比一下扫码体验。

3. 集成ScanKit

在project的gradle文件里添加ScanKit的仓库地址,app的gradle文件里添加依赖,即可快速集成。※Demo依赖了识别能力更为出色的scanplus依赖包

// build.gradle
buildscript {
    repositories {
        ...
        mavenCentral()
        maven {url 'https://developer.huawei.com/repo/'}
    }
}

allprojects {
    repositories {
        ...
        mavenCentral()
        maven {url 'https://developer.huawei.com/repo/'}
    }
}
// app/build.gradle
dependencies {
    ...
    // Huawei scan kit
    implementation 'com.huawei.hms:scanplus:1.3.2.300'
}

3.1 ImageProxy转换Bitmap

CameraX图像分析ImageAnalysis回传的图像实例ImageProxy是YUV格式的,需要先通过YuvImage将其转换为Bitmap,之后再调用ScanKit的Bitmap扫码模式。

private fun proxyToBitmap(image: ImageProxy): Bitmap {
   
   
    val planes: Array<ImageProxy.PlaneProxy> = image.planes
    val yBuffer: ByteBuffer = planes[0].buffer
    val uBuffer: ByteBuffer = planes[1].buffer
    val vBuffer: ByteBuffer = planes[2].buffer

    val ySize: Int = yBuffer.remaining()
    val uSize: Int = uBuffer.remaining()
    val vSize: Int = vBuffer.remaining()

    val nv21 = ByteArray(ySize + uSize + vSize)
    yBuffer.get(nv21, 0, ySize)
    vBuffer.get(nv21, ySize, vSize)
    uBuffer.get(nv21, ySize + vSize, uSize)

    val yuvImage = YuvImage(nv21, ImageFormat.NV21, image.width, image.height, null)
    val out = ByteArrayOutputStream()
    yuvImage.compressToJpeg(Rect(0, 0, yuvImage.width, yuvImage.height), 75, out)

    val imageBytes = out.toByteArray()
    val opt = BitmapFactory.Options()
    opt.inPreferredConfig = Bitmap.Config.ARGB_8888

    var bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size, opt)
    return bitmap
}

3.2 调用Bitmap扫码模式

创建下ScanKit专用的扫码参数,并将转换得到的Bitmap实例传递给ScanUtil,即可开始识别。返回的识别结果包括内容、坐标、四角位置等信息,被封装到HmsScan对象里。ScanUtil识别完成后实际返回的是HmsScan数组,其第一个元素即为单码的识别结果。HmsScan对象的originalValue属性则是解析出来的内容。

class HuaweiScanAnalysis: RealTimeAnalysis {
   
   
    override fun analyzeContent(imageProxy: ImageProxy, context: Context): AnalysisResult {
   
   
        val bitmap = proxyToBitmap(imageProxy)
        imageProxy.close()

        // 创建ScanKit扫码的参数
        val options = HmsScanAnalyzerOptions.Creator()
            .setHmsScanTypes(HmsScan.ALL_SCAN_TYPE)
            .setPhotoMode(false)
            .create()

        // 得到扫码结果
        val result = ScanUtil.decodeWithBitmap
评论 19
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechMerger

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值