Android开源库之使用ZXing开源库生成二维码及识别本地二维码图片

一、生成二维码

生成二维码比较简单,ZXing官方的demo中也有该功能,直接贴出提取的代码:
/**
     * 生成二维码图片
     *
     * @param str
     * @return
     */
    public static Bitmap createBarcode(String str) {
        Bitmap bitmap = null;
        BitMatrix result = null;
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        try {
            result = multiFormatWriter.encode(str, BarcodeFormat.QR_CODE, 200, 200);

            int w = result.getWidth();
            int h = result.getHeight();
            int[] pixels = new int[w * h];
            for (int y = 0; y < h; y++) {
                int offset = y * w;
                for (int x = 0; x < w; x++) {
                    pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
                }
            }
            bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, w, 0, 0, w, h);

            LogUtils.d(TAG + "-w-" + w);
            LogUtils.d(TAG + "-h-" + h);
            LogUtils.d(TAG + "-width-" + bitmap.getWidth());
            LogUtils.d(TAG + "-height-" + bitmap.getHeight());

        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

二、识别本地二维码图片

在实现该功能时,走了写弯路;一开始呢,我是计划着根据用摄像头扫描二维码的功能,抽取出最后识别图片的方法,最终找到了DecodeHandler类下的方法:
private void decode(byte[] data, int width, int height)

本以为使用该方法,将图片转化成byte数组就可以了,实时证明想的太简单了,无法识别二维码。
后来就百度下,发现网上有两种实现方式,一种基于PlanarYUVLuminanceSource,另一种RGBLuminanceSource,这是两种图片数据编码方式(YUV和RGB)的不同解析方法。而DecodeHandler下的decode方法中的使用就是基于PlanarYUVLuminanceSource的实现,这就说明参数byte数组data,不是简单的将bitmap转换成byte[]数组这么简单,而是需要先将bitmap转换成像素数组int[] pixel,再将像素数组int[] pixel根据RGB转YUV公式:
Y=0.299R+0.587G+0.114B;
U=-0.147R-0.289G+0.436B;
V=0.615R-0.515G-0.1B;
转换成byte[] yuv,而这个byte数组yuv才是真正用来传入DecodeHandler下decode方法的参数;
下面贴出分别基于RGB和YUV两种方式的识别本地二维码图片的方法:
1、基于RGB方式
/**
     * 解析二维码(使用解析RGB编码数据的方式)
     *
     * @param path
     * @return
     */
    public static Result decodeBarcodeRGB(String path) {
        if (TextUtils.isEmpty(path)) {
            return null;
        }
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inSampleSize = 1;
        Bitmap barcode = BitmapFactory.decodeFile(path, opts);
        Result result = decodeBarcodeRGB(barcode);
        barcode.recycle();
        barcode = null;
        return result;
    }

    /**
     * 解析二维码 (使用解析RGB编码数据的方式)
     *
     * @param barcode
     * @return
     */
    public static Result decodeBarcodeRGB(Bitmap barcode) {
        int width = barcode.getWidth();
        int height = barcode.getHeight();
        int[] data = new int[width * height];
        barcode.getPixels(data, 0, width, 0, 0, width, height);
        RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);
        BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
        QRCodeReader reader = new QRCodeReader();
        Result result = null;
        try {
            result = reader.decode(bitmap1);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (ChecksumException e) {
            e.printStackTrace();
        } catch (FormatException e) {
            e.printStackTrace();
        }
        barcode.recycle();
        barcode = null;
        return result;
    }

2、基于YUV方法
/**
     * 解析二维码(使用解析YUV编码数据的方式)
     *
     * @param path
     * @return
     */
    public static Result decodeBarcodeYUV(String path) {
        if (TextUtils.isEmpty(path)) {
            return null;
        }
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inSampleSize = 1;
        Bitmap barcode = BitmapFactory.decodeFile(path, opts);
        Result result = decodeBarcodeYUV(barcode);
        barcode.recycle();
        barcode = null;
        return result;
    }

    /**
     * 解析二维码(使用解析YUV编码数据的方式)
     *
     * @param barcode
     * @return
     */
    public static Result decodeBarcodeYUV(Bitmap barcode) {
        if (null == barcode) {
            return null;
        }
        int width = barcode.getWidth();
        int height = barcode.getHeight();
        //以argb方式存放图片的像素
        int[] argb = new int[width * height];
        barcode.getPixels(argb, 0, width, 0, 0, width, height);
        //将argb转换为yuv
        byte[] yuv = new byte[width * height * 3 / 2];
        encodeYUV420SP(yuv, argb, width, height);
        //解析YUV编码方式的二维码
        Result result = decodeBarcodeYUV(yuv, width, height);

        barcode.recycle();
        barcode = null;
        return result;
    }

    /**
     * 解析二维码(使用解析YUV编码数据的方式)
     *
     * @param yuv
     * @param width
     * @param height
     * @return
     */
    private static Result decodeBarcodeYUV(byte[] yuv, int width, int height) {
        long start = System.currentTimeMillis();
        MultiFormatReader multiFormatReader = new MultiFormatReader();
        multiFormatReader.setHints(null);

        Result rawResult = null;
        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(yuv, width, height, 0, 0,
                width, height, false);
        if (source != null) {
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            try {
                rawResult = multiFormatReader.decodeWithState(bitmap);
            } catch (ReaderException re) {
                re.printStackTrace();
            } finally {
                multiFormatReader.reset();
                multiFormatReader = null;
            }
        }
        long end = System.currentTimeMillis();
        LogUtils.d(TAG + " --barcode decode in " + (end - start) + " ms");
        return rawResult;
    }


    /**
     * RGB转YUV的公式是:
     * Y=0.299R+0.587G+0.114B;
     * U=-0.147R-0.289G+0.436B;
     * V=0.615R-0.515G-0.1B;
     *
     * @param yuv
     * @param argb
     * @param width
     * @param height
     */
    private static void encodeYUV420SP(byte[] yuv, int[] argb, int width, int height) {
        // 帧图片的像素大小
        final int frameSize = width * height;
        // ---YUV数据---
        int Y, U, V;
        // Y的index从0开始
        int yIndex = 0;
        // UV的index从frameSize开始
        int uvIndex = frameSize;
        // ---颜色数据---
        int R, G, B;
        int rgbIndex = 0;
        // ---循环所有像素点,RGB转YUV---
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {
                R = (argb[rgbIndex] & 0xff0000) >> 16;
                G = (argb[rgbIndex] & 0xff00) >> 8;
                B = (argb[rgbIndex] & 0xff);
                //
                rgbIndex++;
                // well known RGB to YUV algorithm
                Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
                U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
                V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
                Y = Math.max(0, Math.min(Y, 255));
                U = Math.max(0, Math.min(U, 255));
                V = Math.max(0, Math.min(V, 255));
                // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
                // meaning for every 4 Y pixels there are 1 V and 1 U. Note the sampling is every other
                // pixel AND every other scan line.
                // ---Y---
                yuv[yIndex++] = (byte) Y;
                // ---UV---
                if ((j % 2 == 0) && (i % 2 == 0)) {
                    //
                    yuv[uvIndex++] = (byte) V;
                    //
                    yuv[uvIndex++] = (byte) U;
                }
            }
        }
    }

注:对于YUV和RGB的理解, 引用知乎上看到的资料
作者:祥子
链接:https://www.zhihu.com/question/56384589/answer/154035486
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 Android相机预览的时候支持几种不同的格式,从图像的角度(ImageFormat)来说有NV16、NV21、YUY2、YV12、RGB_565和JPEG,从像素的角度(PixelFormat)来说,有YUV422SP、YUV420SP、YUV422I、YUV420P、RGB565和JPEG,它们之间的对应关系可以从Camera.Parameters.cameraFormatForPixelFormat(int)
方法中得到。 针对YUV编码的数据,有PlanarYUVLuminanceSource这个类去处理,而针对RGB编码的数据,则用RGBLuminanceSource去处理。大部分二维码的识别都是基于二值化的方法,在色域的处理上,YUV的二值化效果要优于RGB, 而我们的摄像头,或者从相册取到的图片,都是RGB图像,  RGB的缺点很明显,不直观,不均匀,对设备还有依赖性。采用YUV色彩空间的重要性是它的信号亮度Y和色度亮度U,V是分离的;RGB转YUV的公式是:Y=0.299R+0.587G+0.114B;U=-0.147R-0.289G+0.436B;V=0.615R-0.515G-0.1B;



猜你喜欢

转载自blog.csdn.net/super_spy/article/details/69382321
今日推荐