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

来源:互联网 发布:信贷业务流程优化 编辑:程序博客网 时间:2024/06/06 00:16

一、生成二维码

生成二维码比较简单,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;



0 0
原创粉丝点击