Android二维码的优化大法

本文探讨了如何优化zxing库在Android上的二维码扫描性能,包括提高扫描精度、选择合适的图像处理算法和调整相机参数。通过使用全幅图像数据、优化DecodeHintType配置以及对比GlobalHistogramBinarizer和HybridBinarizer算法,实现更高的识别精度。此外,还讨论了图像大小、相机预览倍数和聚焦时间调整对识别效果的影响,以及在Android Studio中引入Zxing库的注意事项。
摘要由CSDN通过智能技术生成

现如今zxing是作为普遍二维码库扫描封装的较好的库了,但是我们都知道zxing代码是开源的,是可以更改的,那么我就来看看要提高识别率的问题要怎么处理?

扫描精度问题:

使用过zxing自带的二维码扫描程序来识别二维码的童鞋应该知道,zxing二维码的扫描程序很慢,而且有可能扫不出来。zxing在配置相机参数和二维码扫描程序参数的时候,配置都比较保守,兼顾了低端手机,并且兼顾了多种条形码的识别。如果说仅仅是拿zxing项目来扫描和识别二维码的话,完全可以对项目中的一些配置做精简,并针对二维码的识别做优化。

PlanarYUVLuminanceSource

官方的解码程序主要是下边这段代码:

private void decode(byte[] data, int width, int height) { 
long start = System.currentTimeMillis(); Result rawResult = null;
// 构造基于平面的YUV亮度源,即包含二维码区域的数据源 PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
if (source != null) {
// 构造二值图像比特流,使用HybridBinarizer算法解析数据源 BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); try {
// 采用MultiFormatReader解析图像,可以解析多种数据格式 rawResult = multiFormatReader.decodeWithState(bitmap); } catch (ReaderException re) {
// continue } finally { multiFormatReader.reset(); } } ···
// Hanlder处理解析失败或成功的结果 ··· }

再来看看YUV亮度源是怎么构造的,在CameraManager里,首先获取预览图像的聚焦框矩形getFramingRect(),这个聚焦框的矩形大小是根据屏幕的宽高值来做计算的,官方定义了最小和最大的聚焦框大小,分别是240240和1200675,即最多的聚焦框大小为屏幕宽高的5/8。获取屏幕的聚焦框大小后,还需要做从屏幕分辨率到相机分辨率的转换才能得到预览聚焦框的大小,这个转换在getFramingRectInPreview()里完成。这样便完成了亮度源的构造。

private static final int MIN_FRAME_WIDTH = 240;
private static final int MIN_FRAME_HEIGHT = 240;
private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920
private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080

/**  * A factory method to build the appropriate LuminanceSource object based on the format of the preview buffers, as  * described by Camera.Parameters.  *  * @param data A preview frame.  * @param width The width of the image.  * @param height The height of the image.  * @return A PlanarYUVLuminanceSource instance.  */
public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
// 取得预览框内的矩形 Rect rect = getFramingRectInPreview(); if (rect == null) { return null; }
// Go ahead and assume it's YUV rather than die. return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect.height(), false); }

/**  * Like {@link #getFramingRect} but coordinates are in terms of the preview frame, not UI / screen.  *  * @return {@link Rect} expressing barcode scan area in terms of the preview size  */
public synchronized Rect getFramingRectInPreview() { if (framingRectInPreview == null) { Rect framingRect = getFramingRect(); if (framingRect == null) { return null; }
// 获取相机分辨率和屏幕分辨率 Rect rect = new Rect(framingRect); Point cameraResolution = configManager.getCameraResolution(); Point screenResolution = configManager.getScreenResolution(); if (cameraResolution == null || screenResolution == null) { // Called early, before init even finished return null; }
// 根据相机分辨率和屏幕分辨率的比例对屏幕中央聚焦框进行调整 rect.left = rect.left * cameraResolution.x / screenResolution.x; rect.right = rect.right * cameraResolution.x / screenResolution.x; rect.top = rect.top * cameraResolution.y / screenResolution.y; rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y; framingRectInPreview = rect; }
return framingRectInPreview; }

/**  * Calculates the framing rect which the UI should draw to show the user where to place the barcode. This target  * helps with alignment as well as forces the user to hold the device far enough away to ensure the image will be in  * focus.  *  * @return The rectangle to draw on screen in window coordinates.  */
public synchronized Rect getFramingRect() { if (framingRect == null) { if (camera == null) { return null; }
// 获取屏幕的尺寸像素 Point screenResolution = configManager.getScreenResolution(); if (screenResolution == null) { // Called early, before init even finished return null; }
// 根据屏幕的宽高找到最合适的矩形框宽高值 int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); // 取屏幕中间的,宽为width,高为height的矩形框 int leftOffset = (screenResolution.x - width) / 2; int topOffset = (screenResolution.y - height) / 2; framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height); Log.d(TAG, "Calculated framing rect: " + framingRect); }
return framingRect; }

private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) { int dim = 5 * resolution / 8;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值