Android open source library using ZXing open source library to generate QR code and identify local QR code images

1. Generate QR code

It is relatively simple to generate a QR code. This function is also available in ZXing's official demo, and the extracted code is directly posted:
/**
     * Generate QR code image
     *
     * @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;
    }

2. Identify local QR code pictures

When implementing this function, I took a detour in writing; at the beginning, I planned to extract the final method of recognizing the picture based on the function of scanning the QR code with the camera, and finally found the method under the DecodeHandler class:
private void decode(byte[] data, int width, int height)

I thought that using this method, it would be enough to convert the picture into a byte array, but the real-time proof was too simple to recognize the QR code.
Later, I went to Baidu and found that there are two implementation methods on the Internet, one based on PlanarYUVLuminanceSource and the other RGBLuminanceSource, which are different analysis methods of the two image data encoding methods (YUV and RGB). The use of the decode method under DecodeHandler is based on the implementation of PlanarYUVLuminanceSource, which means that the parameter byte array data is not as simple as simply converting the bitmap into a byte[] array, but needs to first convert the bitmap into a pixel array int[] pixel, and then convert the pixel array int[] pixel according to the RGB to YUV formula:
Y=0.299R+0.587G+0.114B;
U=-0.147R-0.289G+0.436B;
V=0.615R-0.515G-0.1B;
Converted to byte[] yuv, and this byte array yuv is the parameter that is really used to pass in the decode method under DecodeHandler;
The methods for identifying local QR code images based on RGB and YUV are posted below:
1. Based on RGB method
/**
     * Parse QR code (using the method of parsing RGB encoded data)
     *
     * @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();
        bar code = null;
        return result;
    }

    /**
     * Parse QR code (using the method of parsing RGB encoded data)
     *
     * @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();
        bar code = null;
        return result;
    }

2. Based on YUV method
/**
     * Parse QR code (using the method of parsing YUV encoded data)
     *
     * @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();
        bar code = null;
        return result;
    }

    /**
     * Parse QR code (using the method of parsing YUV encoded data)
     *
     * @param barcode
     * @return
     */
    public static Result decodeBarcodeYUV(Bitmap barcode) {
        if (null == barcode) {
            return null;
        }
        int width = barcode.getWidth();
        int height = barcode.getHeight();
        //Store the pixels of the image in argb mode
        int[] argb = new int[width * height];
        barcode.getPixels(argb, 0, width, 0, 0, width, height);
        //Convert argb to yuv
        byte[] yuv = new byte[width * height * 3 / 2];
        encodeYUV420SP(yuv, argb, width, height);
        //Parse the QR code of YUV encoding method
        Result result = decodeBarcodeYUV(yuv, width, height);

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

    /**
     * Parse QR code (using the method of parsing YUV encoded data)
     *
     * @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;
    }


    /**
     * The formula for RGB to YUV is:
     * 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) {
        // pixel size of the frame image
        final int frameSize = width * height;
        // ---YUV data---
        int Y, U, V;
        // Y index starts from 0
        int yIndex = 0;
        // The index of UV starts from frameSize
        int uvIndex = frameSize;
        // ---Color data---
        int R, G, B;
        int rgbIndex = 0;
        // --- Loop through all pixels, RGB to 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.
                // ---AND---
                yuv [yIndex ++] = (byte) Y;
                // ---UV---
                if ((j % 2 == 0) && (i % 2 == 0)) {
                    //
                    yuv [uvIndex ++] = (byte) V;
                    //
                    yuv[uvIndex++] = (byte) U;
                }
            }
        }
    }

Note: For the understanding of YUV and RGB, refer to the information seen on Zhihu :
Author: Xiangzi
Link: https://www.zhihu.com/question/56384589/answer/154035486
Source: Zhihu
Copyright belongs to the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.

 Android camera supports several different formats when previewing, from the image perspective (ImageFormat), there are NV16, NV21, YUY2, YV12, RGB_565 and JPEG, from the pixel perspective (PixelFormat), there are YUV422SP, YUV420SP, YUV422I , YUV420P, RGB565 and JPEG, the correspondence between them can be obtained from Camera.Parameters.cameraFormatForPixelFormat(int)
method obtained. For YUV encoded data, there is the PlanarYUVLuminanceSource class to process, and for RGB encoded data, use RGBLuminanceSource to process. Most of the QR code recognition is based on the binarization method. In the processing of color gamut, the binarization effect of YUV is better than RGB, and our camera, or the pictures taken from the album, are all RGB For images, the disadvantages of RGB are obvious, unintuitive, uneven, and device-dependent. The importance of using the YUV color space is that its signal luminance Y and chrominance luminance U, V are separated; the formula for RGB to YUV is: Y=0.299R+0.587G+0.114B; U=-0.147R-0.289G +0.436B;V=0.615R-0.515G-0.1B;



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325988619&siteId=291194637