Android二维码扫描开发(一):实现思路与原理
现在二维码已经非常普及了,那么二维码的扫描与处理也成为了Android开发中的一个必要技能。网上有很多关于Android中二维码处理的帖子,大都是在讲开源框架zxing用法,然后贴贴代码就完了,并没有一个系统的分析和原理解析。其中涉及到的Camera的操作和YUV图像处理,也大都没有详细的介绍。所以我自己写了这篇文章,把Android二维码的开发来从头捋一下。
本例界面如下图所示,代码链接在文章最下方。
二维码处理流程分为几个步骤:
- 初始化相机,设置一些相机参数;
- 绑定SurfaceView,在SurfaceView上显示预览图像;
- 获取相机的一帧图像;
- 对图像进行一定的预处理,只保留亮度信息,成为灰度图像;
- 对灰度图像进行二维码解析,解析成功进入下一步,不成功回到第③步;
- 返回解析结果并退出。
流程图如下图所示:
一、初始化相机
相机使用的是android.hardware.Camera这个类,在Android 5.0之后,推荐使用更强大的android.hardware.Camera2这个类,为了兼容更低版本Android系统,我们在这里仍然使用Camera类来实现。
Camera可以通过setDisplayOrientation()方法设置预览图像的方向,旋转度数只能是0、90、180、270中的一个,根据需求,本例中设置为90度。
Camera还可以通过Camera.Parameters类设置预览图像的分辨率,但是只能在气可支持的分辨率中选择一个,不能随便设置,我们需要根据屏幕大小,在其中选出一个最佳的预览图像分辨率,太大浪费资源,太小会显示不清楚,具体选择方法,在代码中有,这里就不细述了。
Camera可以通过setPreviewFormat()方法来设置预览图像的数据格式,推荐选择的有ImageFormat.NV21和ImageFormat.YV12,默认是NV21。NV21属于YUV图像,和RGB图像有所不同,YUV图像在下一篇会有详细介绍。
注意在使用Camera时,需要在AndroidManifest.xml里声明一些权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />
二、绑定SurfaceView
在SurfaceView创建好后,通过Camera类的setPreviewDisplay()方法,将SurfaceHolder传入Camera。
调用Camera的startPreview()方法,Camera捕捉到的图像就会显示到SurfaceView上了。
三、获取一帧图像
调用Camera的setOneShotPreviewCallback(PreviewCallback cb)方法,可以请求获取一帧图像,获取到图像后,会调用PreviewCallback的onPreviewFrame(byte[] data, Camera camera)方法,其中的data参数就是图像的YUV数据了。
四、图像预处理
根据二维码的原理,我们只需要图像的亮度信息来进行二维码解析,所以我们要把获取到的彩色图像转换为灰度图像。YUV图像转换为灰度图像的方法,以及RGB图像转换为灰度图像的方法,在后续文章中会有介绍,这里只说原理,具体实现就不再赘述。
五、二维码解析
在这里,二维码解析使用的是google的zxing开源框架,把上一步处理后的灰度图像,封装为zxing的LuminanceSource,再封装为zxing的BinaryBitmap,然后就可以进行二维码解析了。
值得一提的是,利用zxing解析二维码是耗时操作,为避免ANR,需要写到子线程中来处理。
具体代码在这里就不贴了,后续章节中将会对zxing的使用及LuminanceSource的处理做详细解答。
六、解析结果
本例中,除了返回解析到的字符串之外,还对LuminanceSource增加了一个renderCroppedGreyScaleBitmap()方法,用来生成处理好的灰度图像Bitmap。
二维码扫描的大致流程和原理就叙述到这里了,下一篇将会对YUV图像进行详细的介绍。
源码地址:https://github.com/xushanmeng/QRCodeScannerDemo
- 育碧与研究所共同开发的AI,是什么样的?
- 大家都在关注AI,但这些事你可能并不知道!
- AI—未来医疗
- 微信小程序新功能上线 一键连Wi-Fi手机变门禁卡
- 使用xUnit为.net core程序进行单元测试(中)
- Asp.Net 用Jquery和一般处理程序实现无刷新上传大文件
- WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用
- WCF技术剖析之十四:泛型数据契约和集合数据契约(上篇)
- WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)
- WCF技术剖析(卷1)之前言
- WCF技术剖析(卷1)之目录
- WCF技术剖析(卷1)之推荐序
- 谈谈基于SQL Server 的Exception Handling[上篇]
- 谈谈WCF中的Data Contract(4):WCF Data Contract Versioning
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Python闭包及装饰器运行原理解析
- Django中Q查询及Q()对象 F查询及F()对象用法
- keras.layer.input()用法说明
- python入门:argparse浅析 nargs='+'作用
- PHP7导出Excel报ERR_EMPTY_RESPONSE解决方法
- YII框架行为behaviors用法示例
- 浅谈Python里面None True False之间的区别
- python如何导入依赖包
- 深入理解Python 多线程
- Yii2框架自定义验证规则操作示例
- 浅析PHP 中move_uploaded_file 上传中文文件名失败
- 结束运行python的方法
- 解析Tensorflow之MNIST的使用
- 面向新手解析python Beautiful Soup基本用法
- 基于keras中的回调函数用法说明