实现二维码识别的流程

  1. 开启Camera
  2. 创建ImageReader
  3. 通过ImageReader获取surface对像
  4. 设置surface对象给camera并启动preview
  5. 当有preview数据产生时ImageReader的onImageAvailable回调会被调用
  6. 调用ImageReader 的acquireLatestImage()方法获取image数据
  7. 把image数据传递给QRCodeReader进行识别

启动camera

这里我已经把Camera2封装成CameraHolder
,通过CameraHolder可以方便的操作Camera。首先生成一个CameraHolder的对象,然后在activity调用onCreate的时候开启camera。

    private val cameraHolder by lazy {CameraHolder(glSurfaceView.context)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)cameraHolder.cameraId = CAMERA_REAR//设置后置摄像头启动cameraHolder.open().invalidate()//启动camera}

定义QRCodeDecoder用于解析二维码数据

这个类还是比较简单的,首先需要生成一个ImageReader对象用于接收camera的preview的数据,然后还需要一个QRCodeReader对象用于解析二维码。我们创建ImageReader的时候需要指定图像的宽高和编码格式,我设置的编码格式为ImageFormat.YUV_420_888。编码格式的设置影响到ImageReader的输出Buffer内容。我们需要根据设置的编码格式从ImageReader输出的Buffer中读取图像数据。然后将Buffer中读取的数据传递给QRCodeReader进行解析。


class QRCodeDecoder(w: Int, h: Int, private val callback: (String) -> Unit) : ImageReader.OnImageAvailableListener {private val frameThread = HandlerThread("frame thread")private val frameHandler: Handlerprivate val imageReader: ImageReaderprivate val bufferByte: ByteArrayprivate var qrCodeResult: String? = nullprivate val qrCodeReader = QRCodeReader()private val hints: Hashtable<DecodeHintType, Any> = Hashtable<DecodeHintType, Any>()init {frameThread.start()frameHandler = Handler(frameThread.looper)imageReader = ImageReader.newInstance(w, h, ImageFormat.YUV_420_888, 2)imageReader.setOnImageAvailableListener(this, frameHandler)bufferByte = ByteArray(w * h * 2)hints[DecodeHintType.CHARACTER_SET] = "utf-8" // 设置二维码内容的编码hints[DecodeHintType.POSSIBLE_FORMATS] = BarcodeFormat.QR_CODELog.d("QRCodeDecoder", " w:$w h:$h")}//当有解析结果后如果还需要继续解析时,我们需要调用这个方法进行重置。重置后decoder才可以继续工作。fun reset() {qrCodeResult = null}//camera启动preview的时候需要添加这个surface到camera用于接收数据fun getSurface(): Surface = imageReader.surfaceoverride fun onImageAvailable(reader: ImageReader?) {reader?.let {//获取image队列中最新的一条数据并释放老的数据val image = it.acquireLatestImage()if (TextUtils.isEmpty(qrCodeResult)) {var offset = 0//读取y数据image.planes[0].buffer.get(bufferByte, offset, image.planes[0].buffer.limit())offset += image.planes[0].buffer.limit()//读取u数据image.planes[1].buffer.get(bufferByte, offset, image.planes[1].buffer.limit())offset += image.planes[1].buffer.limit()//读取v数据image.planes[2].buffer.get(bufferByte, offset, image.planes[2].buffer.limit())//通过yuv数据buffer生成qrCodeReader的输入对象val source = PlanarYUVLuminanceSource(bufferByte, image.width, image.height, 0, 0, image.width, image.height, false)//二值化后的位图数据val tempBitmap = BinaryBitmap(HybridBinarizer(source))try {qrCodeResult = qrCodeReader.decode(tempBitmap, hints)?.textcallback.invoke(qrCodeResult ?: "")} catch (e: Exception) {e.printStackTrace()}}//读完image数据后需要回收image。image.close()}}fun release() {imageReader.close()frameThread.quitSafely()}
}

启动camera的preview

QRCodeDecoder创建了一个ImageReader,我们可以将ImageReader的surface设置给camera用于接收数据。这里设置了两个surface,另一个surface用于将preview内容显示在手机屏幕上。为了提高二维码的识别速度,我将ImageReader的surface设置的更小一些。CameraHolder设置surface后自动进入preview模式。

nodesRender.runInRender {//屏幕显示用的preview最大为1920var size = cameraHolder.previewSizes.first { size -> size.width <= 1920 && size.height <= 1920 }updatePreviewNode(size.width,size.height)//QRCodeDecoder解析的图片尺寸最大为640size = cameraHolder.previewSizes.first { size -> size.width <= 640 && size.height <= 640 }qrCodeDecoder?.release()qrCodeDecoder = QRCodeDecoder(size.width, size.height) { ret ->//当二维码识别成功后这个回调会被调用showQRCodeResult(ret)}cameraHolder.setSurface(cameraPreviewNode!!.combineSurfaceTexture.surface,qrCodeDecoder?.getSurface()).invalidate()}

总结

整个流程还是比较简单的,并且经过测试发现识别速度还是挺快的。跟zxing的demo程序比较,这个实现还是比较简单的。并且没有过多的冗余内容,比较适合集成到应用中实现简单的二维码识别功能。

git地址

https://github.com/mjlong123123/Render/tree/prototype/qrcode

我的公众号已经开通,公众号会同步发布。
欢迎关注我的公众号

Camera2实现二维码扫描功能(qrcode scanner)相关推荐

  1. Android实现二维码扫描功能(四)-ZXing识别图片二维码,相册选图

    简介 上一篇 Android实现二维码扫描功能(三)-闪光灯控制介绍了光线较弱情况下开启闪光灯来辅助二维码识别的方法. 本篇我们介绍如何识别相册中的图片(含二维码) 动态演示 使用模拟器录制了动画演示 ...

  2. Android实现二维码扫描功能-ZXing识别图片二维码,相册选图

    文章目录 1.演示 2.权限问题 3.实现步骤 4.工具类 5.图片Uri处理(重要更新) 1.演示 2.权限问题 部分朋友在打开相册时遇到读写权限未授权的问题,我在开发的时候没有遇到,也没有注册读写 ...

  3. Android直播带货系统中如何实现二维码扫描功能

    自李佳琦的出现将直播带货成功的引向了"巅峰",为了响应众平台和用户的需求,开发Android直播带货系统成为当下的开发热潮.那么在平时的直播软件中,登录.分享.支付等场景中经常出现 ...

  4. iOS 自带二维码扫描功能的实现

    #自从iOS7以后中新增了二维码扫描功能.因此可以在不借助第三方类库的情况下简单的写出二维码的扫描功能: 原生的二维码扫描功能在AVFoundation框架下,所以在使用原生的二维码扫描功能时要先导入 ...

  5. 基于MUI框架的使用HTML5+实现的二维码扫描功能

                                                                               Barcode的一个实现案例 一.简介 Barco ...

  6. JavaCV/OpenCV 二维码扫描功能

    JavaCV/OpenCV 二维码扫描功能 怎样配置工程就不再赘述,不清楚的读者可以网上查找资料,二维码扫描功能通过JavaCV实现起来还是挺简单的,主要OpenCV中QRCodeDetector提供 ...

  7. Flutter 3.X二维码扫描功能

    Flutter 3.X二维码扫描功能 1. pubspec.yaml文件添加依赖 2使用 3. 源代码 4.第二种方式 4.1 pubspec.yaml文件添加依赖 4.2 使用 源代码 1. pub ...

  8. 使用安卓实现一个二维码扫描功能(基于Android Studio)

    二维码扫描使用很广泛,在这里记录二维码扫描的功能,需要导入第三方的类库. 步骤一:在项目中导入第三方的类库,导入方法:往Android Studio中导入第三方类库文件这篇博客中有详细记录 步骤二:定 ...

  9. Android实现二维码扫描功能(一)ZXing插件接入

    简介 关于Android扫描二维码的功能实现,网上有很多相关资料.在对比之后,选用了前辈了修改过的ZXing直接接入到项目中,特制作此demo,介绍整个过程. (最新更新)本篇文章讲解的接入方法对部分 ...

最新文章

  1. python中根据URL获得数据库的名称及IP
  2. ROS修改pkg与node名字
  3. _catboost.CatBoostError: C:/Program Files (x86)/Go Agent/pipelines/BuildMaster/catboost.git/catboost
  4. 这一年,信息技术领域上演的“断舍离”
  5. 一些.net命令行工具的使用
  6. ubuntu server 10.04 NFS 添加共享目录
  7. Python 日常练习1
  8. TMG之恶意网址检查
  9. 初识ES-安装IK分词器
  10. java什么时候新建进程_创建名为“ {java}”的线程(即轻量级进程)是为了什么?...
  11. 软件以人为本1 - 序 - 写于上海2011 ScrumGathering会后
  12. npm 升级所有依赖包
  13. 2022 腾讯云 阿里云返佣政策对比
  14. 盘点澳洲留学性价比较高城市
  15. 六类网线钳能压五类水晶头吗_六类网线可以用五类水晶头不?
  16. 程序员需要学会宏观看待问题
  17. 微信分享次数统计、微信公众号分享关注统计
  18. 手机修改设备信息之安装xposed框架
  19. Symbol - 看似平凡的Symbol其实我们每天都在用 - 对象操作
  20. 常用品牌交换机端口镜像(Port Mirroring)配置

热门文章

  1. 【Telegram】开启允许权限让你的TG可以实现bot直接监控频道
  2. 数据库原理及应用与实践 SQL Sever 笔记
  3. Android 获取来电号码和去电号码
  4. 基于D65的标准颜色视觉匹配
  5. 大型机增速超过混合云太多,这个季度IBM Z营收增长88%
  6. sql server 2014 sql语句
  7. USACO 2021 January Contest, Bronze. Problem 1. Uddered but not Herd
  8. 每周大数据论文(二)Data Mining with Big Data
  9. 2010年医师资格考试新变革
  10. 由于目标计算机积极拒绝,无法连接(10061)