USB摄像头预览识别二维码

2,270 阅读5分钟

每日一景

前言


二维码现在用的超级多,其实它就是一种编码,把字符串编码保存成一个图片,我们扫描图片得到字符串就解码成功。

最有名的二维码解析库是 google 出品的 Zxing,网上也有很多的封装库,有自定义扫描窗口等,更多库请在这个库中搜索 二维码即可:

安卓各种图片框架

这些库采用的都是手机自带的摄像头,没有USB摄像头,悲催了。

USB摄像头拍照,摄像,网上有一个很牛的开源库:

UVCCamera

我也是参考了这个库,在其基础上开发,主要是采用了test4,开启服务来拍照,摄像。这里有几个坑,耽搁了一整天啊。

这里涉及两方面内容,识别代码和扫描界面

识别代码


代码里如何实现呢,一开始一点思路都没有啊。

手机摄像头预览识别,可参考:

github.com/bingoogolap…

那么USB摄像头如何实现呢,那么只能到 UVCCamera 这个库里去寻找答案,没办法,只能静下心来好好看。

我的二维码识别也采用了开源库:

github.com/yipianfengy…

这个库在使用中有小bug,我都提了PR,自行解决了。

我注意到,该库可以根据 Bitmap 对象识别,那么哪里会有这个对象呢,最先想到的是拍照,点击拍照的时候,一定会有这些数据,那么这些数据在哪里呢,一层一层的剥开,最终在RendererHolder 的 run 方法里找到偶遇 bitmap, 然后他识别二维码的代码移植到这里,点击拍照,果然能识别到二维码,哇哈,成功了一丝丝,最开始以为就先这样实现就可以的。

扫描结束后,要弹个窗口提示下扫描结果啊是不是,这个简单啊,用EventBus啊,然后EventBus一开挂,见证奇迹的时刻:

然而奇迹并没有出现,一直订阅不到,然后各种追寻,未果。

然后尝试了另一个开源库 Router,然而,这个库也没有成功,然后一天就这么嗖嗖的过去了,中间找到 Router的作者,我写了个demo给他,他看后提示我是不是 多进程,Router 和 EventBus 都是不支持多进程的。

我赶紧去确认了下,该拍照摄像service设置了远程标志:

android:process=":uvcservice"

没跑了,确实跨进程通信了。

那么,怎么搞呢,广播咯,于是用广播实现了扫描后的结果通知。

暂时实现的功能是点击拍照按钮,扫描二维码,这就结束了吗?

扫描界面


界面又该如何实现呢,比如实现微信类似的二维码识别界面。查看了很多自定义二维码识别的界面,都是自定义View,然后重写 onDraw 方法,自定义扫码边框及扫描动画,比如这里:

ViewfinderView

然后查看了下USB摄像库,显示画面的View是继承自 TextureView 的,然后想在此 TextureView 里也重写 onDraw实现,但是发现TextureView里的此方法是final的,也就是不能在绘制别的东西了。查看了下源码,里面的注释里有这样一段话:

It is important to note that only one producer can use the TextureView. For instance, if you use a TextureView to display the camera preview, you cannot use {@link #lockCanvas()} to draw onto the TextureView at the same time.

大体意思就是不能在TextureView上获取Canvas再绘制view,这样看来此路不通啊。

但是有了新的发现,这个发现正好解决了之前的预览识别问题,究竟是什么呢?

TextureView 的使用很简单,两步:

  1. 获取这个TextureView,
  2. 设置setSurfaceTextureListener,实现其四个方法

具体使用可查看下面两个文章:

TextureView 使用 TextureView+SurfaceTexture+OpenGL ES来播放视频(二)

在这个listener的源码中,发现 onSurfaceTextureUpdated 方法在每次变化的时候都会调用,也就是预览时会频繁调用,于是,在此方法里打印,果然如此,那么就可以在此方法里去实现预览识别啊。

想法不错,但是该如何去做呢,继续查看UVCCamera源码,发现,里面有个Callback的接口,该接口在拍照的fragment里有实现,但是没有具体实现,而该接口也没有update的调用,于是,我加了个方法:

onSurfaceUpdate(Surface surface);

并实现了该方法,那么剩下的就是在该方法里去扫描二维码,发现TextureView有个方法,getBitmap,这是极好的,通过此bitmap对象就可以扫描二维码了,bingo。

实际操作,确实也是这样的,哈哈,太棒了,此刻见证了一个真理:

源码是最好的老师

这样,无心插柳,解决了预览识别二维码的问题,但是界面还木有出来啊,怎么弄呢,不能Canvas绘制了,那么就在此TextureView周围添加一个边框吧。

至于扫描动画,也是设置的一个图片的平移动画,没什么可说的,有了思路,剩下的就好办了。

实际图如下:

代码已上传,请到这里查看:

UVCCameraZxing

关于识别图片二维码,也是支持的,很多库都有这个功能的,不难,enjoy!

当然,对于,条形码也是支持的,赶快使用起来吧。

最后,非常感谢您的阅读,有任何疑问,可以后面评论,谢谢!

神奇的安卓开发网站:androidcat.com/

安卓开源库收集整理:github.com/XXApple/And…

分享是一种美德,更是一种生活方式!!

也许你会说我是一个梦想者,但我不是唯一的一个。

悦分享,越快乐^_^

欢迎交流,转载请注明出处,谢谢!