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; }
/** * 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;