最近几年二维码是越来越火了,特别是随着移动端的便利性,走到哪里都是扫一扫。二维码支付、二维码扫描登录、二维码扫描关注加好友.....越来越多的应用也都加上了二维码扫描的功能,作为移动开发者,对这些新奇的东西当然要尝试一下了。在查阅了一下网上的资料后,自己算是对二维码的扫描和生生成有了个初步的了解,写个笔记,以后想集成进项目时,也会方便很多。

首先,什么是二维码?

二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。 ”

百科的解释如此。既然有二维码,那么肯定有一维码。相信你们对一维码认识的更早,因为一维码。最为常见的就是各种包装商品或者书籍后面的条码。当然本项目也是支持一维码的识别的。

二维码在不同的语言和平台下有不同的支持库,Android当然是选择java支持库了,这个项目是google的大神开发的ZXing库。github地址是:https://github.com/zxing/zxing。

相信大家都和我一样,下载后,都在考虑那怎么样集成进去项目里试一试了?因为这个库文件还是很大的。我们选择自己想要的即可。

首先你得找到zxing.jar包,并添加到项目库中,其次你需要这几个包和里面的文件,包名我改了点。然后将对应的资源也引进去,注意其是放在values文件夹下的。

其中carmera包,是对相机的初始化和一些配置处理;decoding是对相机扫描回的结果的分析处理;view是扫描框和接口处理回调。

项目里还有其他2个包,里面结构如下:

其中MainActivity是程序主入口,CustomScanViewActivity是自定义扫描窗口的FragmentActivity,CaptureFragment是自定义扫描窗口的view,在这进行相机的初始化,和处理扫描结果。扫描成功后将扫描的结果和二维码当作参数传递到handleDecode方法里进行处理,这里采用的是接口回调的方式,进行处理:

 /*** 处理扫描结果** @param result* @param barcode*/public void handleDecode(Result result, Bitmap barcode) {inactivityTimer.onActivity();playBeepSoundAndVibrate();if (result == null || TextUtils.isEmpty(result.getText())) {if (analyzeCallback != null) {analyzeCallback.onAnalyzeFailed();}} else {if (analyzeCallback != null) {analyzeCallback.onAnalyzeSuccess(barcode, result.getText());}}}

接口函数

 /*** 解析二维码结果接口函数*/public interface AnalyticCallback{public void onAnalyzeSuccess(Bitmap mBitmap, String result);public void onAnalyzeFailed();}

解析方法

/*** 解析二维码图片方法* @param mBitmap* @param analyzeCallback*/public static void analyticBitmap(Bitmap mBitmap, AnalyticCallback analyzeCallback) {MultiFormatReader multiFormatReader = new MultiFormatReader();// 解码的参数Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(2);// 可以解析的编码类型Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();if (decodeFormats == null || decodeFormats.isEmpty()) {decodeFormats = new Vector<BarcodeFormat>();// 这里设置可扫描的类型decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);//条形码decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);//二维码decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);//其他码}hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);// 设置解析配置参数multiFormatReader.setHints(hints);// 开始对图像资源解码Result rawResult = null;try {int width = mBitmap.getWidth();int height = mBitmap.getHeight();int[] pixels = new int[width * height];mBitmap.getPixels(pixels, 0, width, 0, 0, width, height);RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);rawResult = multiFormatReader.decode(new BinaryBitmap(new HybridBinarizer(source)));} catch (Exception e) {e.printStackTrace();}if (rawResult != null) {if (analyzeCallback != null) {analyzeCallback.onAnalyzeSuccess(mBitmap, rawResult.getText());}} else {if (analyzeCallback != null) {analyzeCallback.onAnalyzeFailed();}}}

由上面可以看出,我把一维码也添加进去了,也就支持扫条形码了。当然还可以扫描本地的二维码图片,首先我们要打开本地的图库,这里有2个方法,但是有个方法有点小bug,他打不开我自己的截图,因为他打开的是手机里的图库(相册)应用,而截图不在图库里,所以不能添加(我华为荣耀手机是这样的,不知道其他型号手机是否是这样),为此我采用了另外一个方法,列出系统图片文件夹表,让用户自己选择。

方法一:

   Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType("image/*");//打开的是相册 startActivityForResult(intent, REQUEST_IMAGE);

然后在onActivityResult里进行接收处理

      Uri uri = data.getData();ContentResolver mContentResolver= getContentResolver();Bitmap mBitmap = MediaStore.Images.Media.getBitmap(mContentResolver, uri);//根据给定的图片uri,将其转换为bitmap

通过给定的uri转换为Bitmap,接着调用我们的接口函数

       QRCodeUtils.analyticBitmap(mBitmap, new QRCodeUtils.AnalyticCallback() {@Overridepublic void onAnalyzeSuccess(Bitmap mBitmap, String result) {Toast.makeText(MainActivity.this, "解析结果: " + result,1).show();}@Overridepublic void onAnalyzeFailed() {Toast.makeText(MainActivity.this, "解析图片失败", 1).show();}});

但是通过上面的那个打开本地图库的方法找不到截图文件,于是我采用了这个方法

      Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);//打开的是所有图片文件夹列表startActivityForResult(intent, REQUEST_IMAGE);

处理时换成这样的

           Cursor cursor = getContentResolver().query(data.getData(), null, null, null, null);if (cursor.moveToFirst()) {photo_path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));Log.e("图片路径-----》", photo_path);}cursor.close();Bitmap mBitmap= getDecodeAbleBitmap(photo_path);

通过uri去查询ContntResolver,返回的是个coursor对象,然后将其类似于读取数据库一样读出来,得到路径名,接着将本地图片文件转换为bitmao,为避免图片过大,先进行压缩处理。

 private static Bitmap getDecodeAbleBitmap(String picturePath) {try {BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(picturePath, options);int sampleSize = options.outHeight / 400;if (sampleSize <= 0)sampleSize = 1;options.inSampleSize = sampleSize;options.inJustDecodeBounds = false;return BitmapFactory.decodeFile(picturePath, options);} catch (Exception e) {return null;}}

得到bitmap对象后,接下来的步骤就一样了,调用工具类进行解析。

如果对扫描框想更改大小、刷新速度或者外观的,可以在viewfinderView中进行修改

/** Copyright (C) 2008 ZXing authors** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.example.zxing.view;import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;import com.example.qrcodedemo.R;
import com.google.zxing.ResultPoint;
import com.example.zxing.camera.CameraManager;import java.util.Collection;
import java.util.HashSet;/*** 自定义组件实现,扫描功能*/
public final class ViewfinderView extends View {/*** 刷新界面的时间*/private static final long ANIMATION_DELAY = 10L;private static final int OPAQUE = 0xFF;private final Paint paint;private Bitmap resultBitmap;private final int maskColor;private final int resultColor;private final int resultPointColor;private Collection<ResultPoint> possibleResultPoints;private Collection<ResultPoint> lastPossibleResultPoints;// 扫描框边角颜色private int innercornercolor;// 扫描框边角长度private int innercornerlength;// 扫描框边角宽度private int innercornerwidth;// 扫描线移动的yprivate int scanLineTop;// 扫描线移动速度private int SCAN_VELOCITY;// 扫描线Bitmap scanLight;public ViewfinderView(Context context, AttributeSet attrs) {super(context, attrs);paint = new Paint();Resources resources = getResources();maskColor = resources.getColor(R.color.viewfinder_mask);resultColor = resources.getColor(R.color.result_view);resultPointColor = resources.getColor(R.color.possible_result_points);possibleResultPoints = new HashSet<ResultPoint>(5);scanLight = BitmapFactory.decodeResource(resources,R.drawable.scan_light);//扫描线initInnerRect(context, attrs);}/*** 初始化内部框的大小* * @param context* @param attrs*/private void initInnerRect(Context context, AttributeSet attrs) {TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.innerrect);// 扫描框距离顶部int innerMarginTop = ta.getInt(R.styleable.innerrect_inner_margintop,-1);if (innerMarginTop != -1) {CameraManager.FRAME_MARGINTOP = dip2px(context, innerMarginTop);}// 扫描框的宽度int innerrectWidth = ta.getInt(R.styleable.innerrect_inner_width, 210);CameraManager.FRAME_WIDTH = dip2px(context, innerrectWidth);// 扫描框的高度int innerrectHeight = ta.getInt(R.styleable.innerrect_inner_height, 210);CameraManager.FRAME_HEIGHT = dip2px(context, innerrectHeight);// 扫描框边角颜色innercornercolor = ta.getColor(R.styleable.innerrect_inner_corner_color,Color.parseColor("#45DDDD"));// 扫描框边角长度innercornerlength = ta.getInt(R.styleable.innerrect_inner_corner_length, 65);// 扫描框边角宽度innercornerwidth = ta.getInt(R.styleable.innerrect_inner_corner_width,15);// 扫描bitmapDrawable drawable = ta.getDrawable(R.styleable.innerrect_inner_scan_bitmap);if (drawable != null) {}// 扫描控件scanLight = BitmapFactory.decodeResource(getResources(), ta.getResourceId(R.styleable.innerrect_inner_scan_bitmap,R.drawable.scan_light));// 扫描速度SCAN_VELOCITY = ta.getInt(R.styleable.innerrect_inner_scan_speed, 10);ta.recycle();}@Overridepublic void onDraw(Canvas canvas) {Rect frame = CameraManager.get().getFramingRect();if (frame == null) {return;}int width = canvas.getWidth();int height = canvas.getHeight();// Draw the exterior (i.e. outside the framing rect) darkenedpaint.setColor(resultBitmap != null ? resultColor : maskColor);canvas.drawRect(0, 0, width, frame.top, paint);canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1,paint);canvas.drawRect(0, frame.bottom + 1, width, height, paint);if (resultBitmap != null) {// Draw the opaque result bitmap over the scanning rectanglepaint.setAlpha(OPAQUE);canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);} else {drawFrameBounds(canvas, frame);drawScanLight(canvas, frame);Collection<ResultPoint> currentPossible = possibleResultPoints;Collection<ResultPoint> currentLast = lastPossibleResultPoints;if (currentPossible.isEmpty()) {lastPossibleResultPoints = null;} else {possibleResultPoints = new HashSet<ResultPoint>(5);lastPossibleResultPoints = currentPossible;paint.setAlpha(OPAQUE);paint.setColor(resultPointColor);for (ResultPoint point : currentPossible) {canvas.drawCircle(frame.left + point.getX(), frame.top+ point.getY(), 6.0f, paint);}}if (currentLast != null) {paint.setAlpha(OPAQUE / 2);paint.setColor(resultPointColor);for (ResultPoint point : currentLast) {canvas.drawCircle(frame.left + point.getX(), frame.top+ point.getY(), 3.0f, paint);}}postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top,frame.right, frame.bottom);}}/*** 绘制移动扫描线** @param canvas* @param frame*/private void drawScanLight(Canvas canvas, Rect frame) {if (scanLineTop == 0) {scanLineTop = frame.top;}if (scanLineTop >= frame.bottom - 30) {scanLineTop = frame.top;} else {scanLineTop += SCAN_VELOCITY;}Rect scanRect = new Rect(frame.left, scanLineTop, frame.right,scanLineTop + 30);canvas.drawBitmap(scanLight, null, scanRect, paint);}/*** 绘制取景框边框** @param canvas* @param frame*/private void drawFrameBounds(Canvas canvas, Rect frame) {paint.setColor(innercornercolor);paint.setStyle(Paint.Style.FILL);int corWidth = innercornerwidth;int corLength = innercornerlength;// 左上角canvas.drawRect(frame.left, frame.top, frame.left + corWidth, frame.top+ corLength, paint);canvas.drawRect(frame.left, frame.top, frame.left + corLength,frame.top + corWidth, paint);// 右上角canvas.drawRect(frame.right - corWidth, frame.top, frame.right,frame.top + corLength, paint);canvas.drawRect(frame.right - corLength, frame.top, frame.right,frame.top + corWidth, paint);// 左下角canvas.drawRect(frame.left, frame.bottom - corLength, frame.left+ corWidth, frame.bottom, paint);canvas.drawRect(frame.left, frame.bottom - corWidth, frame.left+ corLength, frame.bottom, paint);// 右下角canvas.drawRect(frame.right - corWidth, frame.bottom - corLength,frame.right, frame.bottom, paint);canvas.drawRect(frame.right - corLength, frame.bottom - corWidth,frame.right, frame.bottom, paint);}public void drawViewfinder() {resultBitmap = null;invalidate();}public void addPossibleResultPoint(ResultPoint point) {possibleResultPoints.add(point);}/*** 根据手机的分辨率从 dp 的单位 转成为 px(像素)*/public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}}

至此,扫描二维码和解析本地图片二维码已介绍完了,接下来是如何生成二维码的介绍。

生成二维码采用的是这个方法

    BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);

这个方法得到的是一个bit二维矩阵,然后通过2个for循环,将其放置进一个一维的数组中

           int[] pixels = new int[width * height];//下面这里按照二维码的算法,逐个生成二维码的图片,//两个for循环是图片横列扫描的结果for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){if (bitMatrix.get(x, y)){pixels[y * width + x] = 0xff000000;//当然我们也可以自己更改颜色}else{pixels[y * width + x] = 0xffffffff;}}}

最后生成二维码bitmap

          //生成二维码图片的格式,使用ARGB_8888Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);

如果想对扫描的界面想增加点自己的按钮或者功能的,因为采用的是fragment,也可以替换,实现定制扫描的UI界面

1,在新的activity中定义我们的布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/activity_second"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/second_button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="取消"android:layout_marginTop="20dp"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:layout_marginBottom="10dp"android:layout_gravity="bottom|center_horizontal"/><FrameLayoutandroid:id="@+id/fl_my_container"android:layout_width="match_parent"android:layout_height="match_parent"></FrameLayout></FrameLayout>

启动id为fl_my_container的FrameLayout就是我们需要替换的扫描组件,也就是说我们会将我们定义的扫描Fragment替换到id为fl_my_container的FrameLayout的位置。而上面的button是我们添加的一个额外的控件,在这里你可以添加任意的控件,各种UI效果等。具体可以看下面在Activity的初始化过程。

在Activity中执行Fragment的初始化操作

 protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);/*** 执行扫面Fragment的初始化操作*/CaptureFragment captureFragment = new CaptureFragment();// 为二维码扫描界面设置定制化界面QRCodeUtils.setFragmentArgs(captureFragment, R.layout.my_camera);captureFragment.setAnalyzeCallback(analyzeCallback);/*** 替换我们的扫描控件*/                                                                                                                                                        getSupportFragmentManager().beginTransaction().replace(R.id.fl_my_container, captureFragment).commit();}

注意:因为用到了fragment,假如你集成的是activity,那你要导入v4包,否则在调用getSupportFragmentManager时,会找不到调用方法。

而此activity此时要改成要继承于FragmentActivity。

在上面的onCreate方法中,我们调用了QRCodeUtils.setFragmentArgs(captureFragment, R.layout.my_camera);方法。该方法主要用于修改扫描界面扫描框与透明框相对位置的,与若不调用的话,其会显示默认的组件效果,而如果调用该方法的话,可以修改扫描框与透明框的相对位置等UI效果,我们可以看一下my_camera布局文件的实现。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="fill_parent"android:layout_height="fill_parent" ><SurfaceViewandroid:id="@+id/preview_view"android:layout_width="wrap_content"android:layout_height="wrap_content"/><com.example.zxing.view.ViewfinderViewandroid:id="@+id/viewfinder_view"android:layout_width="wrap_content"android:layout_height="wrap_content"app:inner_width="180"app:inner_height="180"app:inner_margintop="120"app:inner_corner_color="@color/scan_corner_color"app:inner_corner_length="60"app:inner_corner_width="10"app:inner_scan_bitmap="@drawable/scan_image"app:inner_scan_speed="10"/></FrameLayout>

上面我们自定义的扫描控件的布局文件,下面我们看一下默认的扫描框的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent" ><SurfaceViewandroid:id="@+id/preview_view"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center" /><com.example.zxing.view.ViewfinderViewandroid:id="@+id/viewfinder_view"android:layout_width="wrap_content"android:layout_height="wrap_content" /></FrameLayout>

好了,项目介绍到这里了,总体来说,效果功能都实现了,待实际需求时,可以直接集成更改即可。源码地址: 点我下载

参考别人的github项目,发现别人的扫描速度稍微快一点,以后有待研究。https://github.com/bingoogolapple/BGAQRCode-Android

注:解决关于扫描时出现图片拉伸的问题。

如果是直接引用的zxing包里面的camera文件时,可能会出现扫描的二维码在扫描框内出现拉伸问题,因为Zxing包里的二维码扫描默认是横屏扫描的,改为竖屏后出现比例问题,所以要修正过来。

可以在camera包里面的CameraConfigurationManager.java文件里的

void initFromCameraParameters(Camera camera)方法

在 Log.d(TAG, "Screen resolution: " + screenResolution);这句之后增加

        Point screenResolutionForCamera = new Point();  screenResolutionForCamera.x = screenResolution.x;  screenResolutionForCamera.y = screenResolution.y;  // preview size is always something like 480*320, other 320*480  if (screenResolution.x < screenResolution.y) {  screenResolutionForCamera.x = screenResolution.y;  screenResolutionForCamera.y = screenResolution.x;  }  

然后将

cameraResolution = getCameraResolution(parameters, screenResolution);  

注释掉,改为:

cameraResolution = getCameraResolution(parameters, screenResolutionForCamera); 

这样就可以了,解决图片拉伸的问题。

8/15日更新
增加二维码生成识别容错率

在我们生产二维码的时候,有时二维码中间放logo的话,识别起来比不放困难点,但是logo又不能太小,否则就起不到宣传认识效果,太大了后识别就稍微困难点了。一方面我们的图片大小要适中,另一方面又要增加二维码的识别容错率,这样可以加快识别速度。

默认的二维码容错率是ErrorCorrectionLevel.L

在QRCodeWriter源码中(位置是com.google.zxing.qrcode)可以看到有默认值

ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;int quietZone = QUIET_ZONE_SIZE;if (hints != null) {ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel) hints.get(EncodeHintType.ERROR_CORRECTION);if (requestedECLevel != null) {errorCorrectionLevel = requestedECLevel;}Integer quietZoneInt = (Integer) hints.get(EncodeHintType.MARGIN);if (quietZoneInt != null) {quietZone = quietZoneInt;}}

可以看出他是通过一个hashtable.get获得的,为此,我们可以通过put去修改,将我们要设置的值传进去。

            Hashtable hints = new Hashtable();hints.put(EncodeHintType.CHARACTER_SET, "utf-8");//设置编码格式,否则中文会识别不了hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);//容错率默认是7%,现改为30%

后面的BitMatrix不用变。

如果上面有什么纰漏或者对上面有什么疑问,欢迎留言探讨!!!

Android二维码识别与生成相关推荐

  1. QRCode - 二维码识别与生成

    来源:Yi'mouleng(@丶伊眸冷) 链接:http://t.cn/R40WxcM 前言 有关二维码的介绍,我这里不做过多说明, 可以直接去基维百科查看,附上链接QR code(https://e ...

  2. android二维码识别原理与测试方法

    首先看看二维码识别原理: 一.我们都是使用二维码生成工具制码,原理对于我们意义并不是很大,这里就不浪费地方复制黏贴了.二维码编码原理请google. 二.下面是与本次问题相关的一些经验. 1.    ...

  3. 【图像处理】QR二维码识别与生成matlab代码

    1 简介 QR二维码的识别技术是数字图像处理领域研究的一个热门课题.随着物联网的不断发展,QR二维码凭借其强大的信息存储能力,方便快捷的识读优点,安全可靠的编码技术,已经逐渐地应用于各个行业领域.同时 ...

  4. QRCode插件的使用(二维码识别与生成)

    功能1.输入一段文字,生成一个二维码 (1)从perfab文件夹里找到QRCodeEncodeController预设,拖入Hierarchy视图 (2)创建一个空物体,添加QREncodeTest. ...

  5. Android二维码识别率优化,Android Zxing 转换竖屏扫描且提高识别率的方法

    最近的一个Android需要用到扫码功能,用的是Zxing开源库.Zxing的集成就不说了,但是Zxing默认的是横屏扫码,在实际生产中并不适用,需要改为竖屏扫描. 转竖屏步骤: 1>. And ...

  6. android二维码扫描和生成

    http://www.open-open.com/lib/view/open1344150168061.html http://blog.csdn.net/shimiso/article/detail ...

  7. 基于Android的二维码识别系统的研究与实现(eclipse开发)

    目 录 1 Android系统开发背景与意义 1 1.1 Android系统平台的出现 1 1.2 Android系统的发展 1 1.3 Android系统架构的介绍 1 1.4 Android开放系 ...

  8. 二维码识别自动对焦放大,弱光补偿(仿微信、支付宝二维码识别)android

    博主之前遇到过一个需求就是android实现远距离,不同角度,不同光线环境下要实现二维码的自动对焦放大,弱光补偿检测打卡闪光灯,还有就是二维码四周因裁剪不当或色彩区分度不够导致无法识别的问题,需要自动 ...

  9. Android 二维码 生成和识别

    今天讲一下目前移动领域很常用的技术--二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS.Android.WP都有相关支持的软件.之前我就想了解二维码是如何工作,最近因为工作需要使用相关技术 ...

最新文章

  1. RocketMQ集群知识介绍
  2. 再送一波干货,测试2000线程并发下同时查询1000万条数据库表及索引优化
  3. 计算机负数次幂科学表示,负数的科学计数法怎么表示
  4. 《剑指 Offer I》刷题笔记 1 ~10 题
  5. 关于SQL语句中分号的问题
  6. 论文笔记_S2D.30_2017-CSVT_使用全卷积深度残差网络,作为分类问题,从单目图像估计深度
  7. 转载--认识迅雷界面引擎
  8. PHP 操作ini文件,读取及写入操作(代码)
  9. postgresql 解锁表
  10. oracle 索引详解 注:转自红黑联盟非原创
  11. 计算机右边键盘数字无效,巧妙解决电脑键盘右边的数字键失灵问题
  12. 《Real-Time Rendering 4th Edition》全文翻译 - 第7章 阴影(下)7.7 ~ 7.10
  13. 人工智能研究中心快递柜——代码分析十一
  14. html 选择第二个元素,css选择器,选中第二个p,实现第三个和第四个p的效果,
  15. cuteftp不能连接虚拟机的解决方法
  16. a标签rel=“external nofollow“ 有什么作用和external
  17. 拆解IncServer网络库
  18. Eclipse提示功能
  19. 为什么 Redis 不支持回滚(roll back)
  20. 论文笔记《Are You Talking to Me? Reasoned Visual Dialog Generation through Adversarial Learning》

热门文章

  1. 旅游电车(cogs 1175)
  2. 美国冰上曲棍球队有个AI聊天机器人,“吸粉”能力无人能敌
  3. c语言中生日蛋糕图片大全,生日蛋糕的句子及生日蛋糕图片大全
  4. 整理电脑,又挖到一个隐身的进程(第2版)
  5. JQuery的属性与样式操作
  6. 《深入浅出DPDK》读书笔记(十六):DPDK应用篇(基于DPDK的存储软件优化:SPDK)
  7. 接线端子名PH,XH,ZH的区别
  8. [黑马程序员C++笔记]P72-P83通讯录管理系统总体概览
  9. Android——摇一摇
  10. android制作圆角button