Android实现二维码扫描功能(二)-ZXing个性化与近距离识别优化

来源:互联网 发布:java交换两个数 编辑:程序博客网 时间:2024/06/11 06:02

简介

上一篇Android实现二维码扫描功能(一)-ZXing插件接入介绍了ZXing框架接入方法,已经可以初步集成扫码功能到项目中。

本篇我们对扫码界面进行优化,并对ZXing近距离无法识别的问题做出优化。

个性化定制

每个APP都有自己的表现形式,实现个性化扫码界面定制,主要有两个地方:

  1. activity_scanner.xml界面文件
  2. com.google.zxing.view.ViewfinderView扫码控件

下面分别来说明。

界面文件

activity_scanner.xml源码如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <include layout="@layout/toolbar_scanner" />    <FrameLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <SurfaceView            android:id="@+id/scanner_view"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_gravity="center" />        <com.google.zxing.view.ViewfinderView            android:id="@+id/viewfinder_content"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            app:corner_color="@color/corner_color"            app:frame_color="@color/viewfinder_frame"            app:label_text="二维码/条形码扫描"            app:label_text_color="@color/colorAccent"            app:laser_color="@color/laser_color"            app:mask_color="@color/viewfinder_mask"            app:result_color="@color/result_view"            app:result_point_color="@color/result_point_color" />    </FrameLayout></LinearLayout>

界面分析:

  • 顶层采用LinearLayout实现自上至下的方向,基本不用修改;
  • <include layout="@layout/toolbar_scanner" />引用toolbar布局文件,稍后给出,这里可以加入菜单项目、返回键等;
  • FrameLayout布局将相机可扫描窗口叠加在一起;
  • SurfaceView装载相机内容,即相机拍摄到的画面;
  • com.google.zxing.view.ViewfinderView扫码自定义View,主要由遮罩层、四个角的边框、扫描线等组成。

toolbar_scanner.xml,比较简单

<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/toolbar"    android:layout_width="match_parent"    android:layout_height="?attr/actionBarSize"    android:background="?attr/colorPrimary"    app:contentInsetStart="0dip">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center_vertical">        <ImageButton            android:id="@+id/btn_back"            android:layout_width="40dip"            android:layout_height="40dip"            android:background="?attr/selectableItemBackground"            android:padding="10dip"            android:scaleType="centerCrop"            android:src="@drawable/btn_back" />        <TextView            android:id="@+id/txt_title"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:text="扫描二维码"            android:textColor="@android:color/white"            android:textSize="18sp" />    </RelativeLayout></android.support.v7.widget.Toolbar>

可根据需求调整toolbar内容,这里我们就不多说。

扫码控件定制

现行使用的ViewfinderView已经是经过前辈修改过的版本,他们加入了边框和扫描线,基于这个版本我们再做一些调整。

1、提示文字的位置

现有的提示文字是在扫描框上面的
这里写图片描述
我们需要把它放置到扫描框下面,需要将源码中drawTextInfo方法调整一下:

//绘制文本  private void drawTextInfo(Canvas canvas, Rect frame) {    ...    canvas.drawText(labelText, frame.left + frame.width() / 2, frame.top - CORNER_RECT_HEIGHT, paint);  }

调整为:

//绘制文本  private void drawTextInfo(Canvas canvas, Rect frame) {    ...    canvas.drawText(labelText, frame.left + frame.width() / 2, frame.bottom + CORNER_RECT_HEIGHT * 1.5f, paint);  }

此处通过修改drawText的y坐标参数调整了文字位置,可以根据需要自行调整。

2、扫码框的位置

目前的扫码框整体位置偏下,不够美观,打算将位置往上调整一些。
修改com.google.zxing.camera.CameraManager类中的getFramingRect()方法,由

public Rect getFramingRect() {        ...        int leftOffset = (screenResolution.x - width) / 2;        int topOffset = (screenResolution.y - height) / 2;        ...        return framingRect;}

修改为

public Rect getFramingRect() {        ...        int leftOffset = (screenResolution.x - width) / 2;        int topOffset = (screenResolution.y - height) / 3;        ...        return framingRect;}

即topOffset有了减小,预览后如:
这里写图片描述

3、扫码框大小
由2我们可以看到getFramingRect()方法构造的矩形中有宽、高参数,通过修改这两个参数,可以完成扫码框大小变更。例如:

public Rect getFramingRect() {        ...        int width = screenResolution.x * 8 / 10;        int height = screenResolution.y * 8 / 10;        ...        return framingRect;}

则比原来的代码中放大了1/10,预览图(可对比2中图):
这里写图片描述

扫码识别优化

这里主要说一下近距离扫码识别不了的问题,关于扫码算法的改进涉猎不多,文尾给大家一篇文章参考。

ZXing在遇到二维码撑满扫码框的情况下识别不出结果,等多久、再聚焦都不可以,有朋友说扩大扫码框的大小可以解决这个问题,扩大后近距离扫码结果还是一致的,很难识别出来。

原因是原算法对摄像头采集的图像像素进行了裁剪,真正返回给识别算法的图像可能没有扫码框那么完整。

参考网络大神的帖子,我们将com.google.zxing.camera.CameraManager类中的buildLuminanceSource方法做了调整,不再返回剪裁后的图像。源码:

public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {        Rect rect = getFramingRectInPreview();        int previewFormat = configManager.getPreviewFormat();        String previewFormatString = configManager.getPreviewFormatString();        switch (previewFormat) {            // This is the standard Android format which all devices are REQUIRED to support.            // In theory, it's the only one we should ever care about.            case PixelFormat.YCbCr_420_SP:                // This format has never been seen in the wild, but is compatible as we only care                // about the Y channel, so allow it.            case PixelFormat.YCbCr_422_SP:                return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,                        rect.width(), rect.height());            default:                // The Samsung Moment incorrectly uses this variant instead of the 'sp' version.                // Fortunately, it too has all the Y data up front, so we can read it.                if ("yuv420p".equals(previewFormatString)) {                    return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,                            rect.width(), rect.height());                }        }        throw new IllegalArgumentException("Unsupported picture format: " +                previewFormat + '/' + previewFormatString);    }

修改为:

public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {        Rect rect = getFramingRectInPreview();        int previewFormat = configManager.getPreviewFormat();        String previewFormatString = configManager.getPreviewFormatString();        switch (previewFormat) {            // This is the standard Android format which all devices are REQUIRED to support.            // In theory, it's the only one we should ever care about.            case PixelFormat.YCbCr_420_SP:                // This format has never been seen in the wild, but is compatible as we only care                // about the Y channel, so allow it.            case PixelFormat.YCbCr_422_SP:                return new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height);            default:                // The Samsung Moment incorrectly uses this variant instead of the 'sp' version.                // Fortunately, it too has all the Y data up front, so we can read it.                if ("yuv420p".equals(previewFormatString)) {                    return new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height);                }        }        throw new IllegalArgumentException("Unsupported picture format: " +                previewFormat + '/' + previewFormatString);    }

主要改动的是new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height); 实际上就是将完整的相机图像内容返回,不做裁剪。

结语

本篇对ZXing扫码工具界面定制和扫码识别优化做了讲解,解决了ZXing近距离无法识别二维码的问题。
大家也可以顺着这个思路,做更多个性化定制和优化,完善扫码功能。

参考资料

http://iluhcm.com/2016/01/08/scan-qr-code-and-recognize-it-from-picture-fastly-using-zxing/

源码下载

csdn上已上传,下载地址:
http://download.csdn.net/detail/ahuyangdong/9915737

阅读全文
0 0
原创粉丝点击