公司有个项目是这样的:要求扫条形码能识别上面的数字。于是选用了zxing进行扫码,可一定要吐槽的是:太慢了,一个条形码要扫5-10秒才能识别。于是换用了zbar进行扫码。
zbar的速度很快,秒扫,但后面发现一个严重的问题,太不准了!不准到一个条形码我能扫到好多种结果出来。例如下图:
这个图使用zbar我扫到3-5种不同的结果出来,当然,也有个办法能防止zbar扫出错误的结果:
改一下CaptureActivity的PreviewCallback:
PreviewCallback previewCb = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = scanner.scanImage(barcode);
if (result != 0) {
previewing = false;
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
SymbolSet syms = scanner.getResults();
Symbol bestSym = null;
for (Symbol sym : syms) {
if(bestSym == null || bestSym.getQuality()< sym.getQuality()){
bestSym = sym;
}
}
if(bestSym == null)
return;
int quality = bestSym.getQuality();
Intent intent = new Intent();
intent.putExtra("BarCode", quality>2?bestSym.getData():"");
intent.putExtra("hasBarCode", quality>2);
setResult(RESULT_OK, intent);
finish();
}
}
};
这里如果quality<2就算扫码失败,进行相应处理,可无语的是仍然不准。。。。
于是我问老大能用zxing吗?老大吐槽说:zxing扫条形码太慢了。。。于是我抓耳挠腮,想着解决问题的办法。
想到了如下方法:
1.找个新的扫码框架处理
2.改进zbar,让它识别率变高
3.改进zxing,让它识别速度变快
结果是失败了,没有合适的扫码框架,所有扫码都是在zbar或zxing基础上进行改进的,所以这条跳过
想了一下2一定是整个算法都要改了,可能要改c代码,这方面勉强看的懂比较弱,估计耗时会很久,于是还是选3.找到了http://blog.csdn.net/f820306455/article/details/54137182这篇文章,给了比较大的启发,图像算法什么的完全不会,但把握会的地方改了一下,基本秒扫。下面讲一下改造步骤。
a.全屏扫样式更改
CameraManager.java
需要更改buildLuminanceSource()方法:
public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
return new PlanarYUVLuminanceSource(data, width, height, 0, 0,
width, height);
}
但单单这样改不行,会无法识别,需要去除外部的遮盖框,直接用全屏扫码:
ViewfinderView.java
需要更改onDraw():
public void onDraw(Canvas canvas) {
postInvalidateDelayed(ANIMATION_DELAY, 0, 0,
getWidth(), getHeight());
}
b.去掉传递图片(一般只需要扫码的条码号或者网址,扫码图片本身我们不关心,如果需要这部分需要对这个图片进行压缩处理,不然会出错)
MipActivityCapture.java
这里需要删掉handleDecode里面的bundle.putParcelable("bitmap", barcode);
,barcode这个参数也可以不用传递了。
相应的在CaptureActivityHandler.java的handleMessage中只需要传递msg.obj,下面这句可以删掉:
Bitmap barcode = bundle == null ? null :
(Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
然后把DecodeHandler.java的decode()方法也改一下:
删掉下面的部分
Bundle bundle = new Bundle();
bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
message.setData(bundle);
AutoFocusCallback.java的AUTOFOCUS_INTERVAL_MS的值改为500L【如果调整了相机形变建议1000L-1500L】,这个值不能过小,不然扫码还没扫全对焦已经结束了。会导致扫码结果不准
修改CameraConfigurationManager的setDesiredCameraParameters():
去掉setZoom(parameters);
改为:
这个是指相机倍数,建议1/5-1/10,1/5识别速度更快,1/10的视野更舒服
1/10:
1/5:
拍摄距离大概在25厘米左右
parameters.setZoom(parameters.getMaxZoom() / 10);
这样就可以了。
注意:资源没有进行相机音频权限申请,请打开引用权限进行测试,或者自己申请相关权限。
资源地址:http://download.csdn.net/download/yu_duan_hun/10261413
后面无意按照:http://blog.csdn.net/qq_1991/article/details/53586408的第二点改了(第一点不要改无用且扫码失效),解决。实测发现这样会导致识别率降低,识别速度变慢,而且出现一定的错误几率。尤其是条形码很长的时候,以前秒扫的,现在难以识别了,请开发的各位考虑
防止链接失效,这里贴一下:
找到CameraConfigurationManager类的setDesiredCameraParameters(Camera camera)方法,将其中的代码注释,然后添加如下代码:
Camera.Parameters parameters = camera.getParameters();
List.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
int position = 0;
if(supportedPreviewSizes.size() > 2){
position = supportedPreviewSizes.size() / 2 + 1;// supportedPreviewSizes.get();
}else {
position = supportedPreviewSizes.size() / 2;
}
int width = supportedPreviewSizes.get(position).width;
int height = supportedPreviewSizes.get(position).height;
camera.setDisplayOrientation(90);
cameraResolution.x = width;
cameraResolution.y = height;
parameters.setPreviewSize(width, height);
setFlash(parameters);
setZoom(parameters);
camera.setParameters(parameters);