我想扫描经典二维码和倒置(暗亮)二维码。该怎么办?
Posted
技术标签:
【中文标题】我想扫描经典二维码和倒置(暗亮)二维码。该怎么办?【英文标题】:I want to scan both classic and inverted (light on dark) QR codes. What to do? 【发布时间】:2015-07-11 02:38:59 【问题描述】:我正在使用已弃用的 Camera 类。我正在 onPreviewFrame(byte[] data, Camera camera) 方法中进行处理。 Zbar 扫描仪没有触发“尝试倒置”扫描的选项。我发现我可以在我的安卓相机上设置负色效果,它非常适合扫描倒置的二维码,但它会停止检测正常的二维码。
我正在尝试找到一种欺骗方法,例如让同一相机的 2 个实例,一个应用了负面效果,一个没有并且只显示无效果的一个,但它不会让我这样做。
每次显示一帧时都会调用下面的代码。
private Camera.PreviewCallback previewCb = new Camera.PreviewCallback()
public void onPreviewFrame(byte[] data, Camera camera)
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = scanner.scanImage(barcode);
这就是我设置我所说的负面影响的方式。
Camera.Parameters params = mCamera.getParameters();
params.setColorEffect(Camera.Parameters.EFFECT_NEGATIVE);
mCamera.setParameters(params);
另一种方法是处理我自己从预览回调中获得的 YUV 字节数组并应用负面效果,但我不确定如何在没有大量转换的情况下做到这一点。
有什么想法吗?
【问题讨论】:
请提供有关您尝试的详细信息..这将有助于大家回答这个问题.. 你有没有找到在深色背景下读取二维码的解决方案? 不,我没有,我放了一个按钮来切换相机颜色效果 【参考方案1】:在数周未找到任何答案/被误导之后,我设法让它来回转换 YUV 数据。在ZBarScannerView.java
这就是我的onPreviewFrame(..)
的样子:
@Override
public void onPreviewFrame(byte[] data, Camera camera)
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
int width = size.width;
int height = size.height;
switcher = !switcher;
if(DisplayUtils.getScreenOrientation(getContext()) == Configuration.ORIENTATION_PORTRAIT)
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
int tmp = width;
width = height;
height = tmp;
data = rotatedData;
Image barcode = new Image(width, height, "Y800");
if (switcher)
int[] pixels = applyGrayScale(data,width,height);
Bitmap bm = Bitmap.createBitmap(pixels,width,height, Bitmap.Config.ARGB_8888);
bm = MyUtils.createInvertedBitmap(bm, width, height);
pixels = new int[width*height];
bm.getPixels(pixels, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
encodeYUV420SP(data, pixels, bm.getWidth(), bm.getHeight());
barcode.setData(data);
int result = mScanner.scanImage(barcode);
if (result != 0)
stopCamera();
if(mResultHandler != null)
SymbolSet syms = mScanner.getResults();
Result rawResult = new Result();
for (Symbol sym : syms)
String symData = sym.getData();
if (!TextUtils.isEmpty(symData))
rawResult.setContents(symData);
rawResult.setBarcodeFormat(BarcodeFormat.getFormatById(sym.getType()));
break;
mResultHandler.handleResult(rawResult);
else
camera.setOneShotPreviewCallback(this);
也将其添加到课程中(来自Here):
void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height)
final int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;
int a, R, G, B, Y, U, V;
int index = 0;
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
a = (argb[index] & 0xff000000) >> 24; // a is not used obviously
R = (argb[index] & 0xff0000) >> 16;
G = (argb[index] & 0xff00) >> 8;
B = (argb[index] & 0xff) >> 0;
// 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;
// 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 scanline.
yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
if (j % 2 == 0 && index % 2 == 0)
yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
index++;
这负责在反转后将 int 数组转换回字节数组。
我还在使用这些代码 sn-ps,我在 stackExchange 上的某个地方(我记不起在哪里)在名为 MyUtils.java
的实用程序类中进行了一些小改动:
public class MyUtils
public static Integer sizeWidth;
public static Integer sizeHeight;
public static Bitmap createInvertedBitmap(Bitmap src, Integer width, Integer height)
sizeWidth = width;
sizeHeight = height;
ColorMatrix colorMatrix_Inverted =
new ColorMatrix(new float[]
-1, 0, 0, 0, 255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0);
ColorFilter ColorFilter_Sepia = new ColorMatrixColorFilter(
colorMatrix_Inverted);
Bitmap bitmap = Bitmap.createBitmap(sizeWidth, sizeHeight,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColorFilter(ColorFilter_Sepia);
canvas.drawBitmap(src, 0, 0, paint);
return bitmap;
public static int[] applyGrayScale(byte [] data, int width, int height)
int p;
int size = width*height;
int[] pixels = new int[size];
for(int i = 0; i < size; i++)
p = data[i] & 0xFF;
pixels[i] = 0xff000000 | p<<16 | p<<8 | p;
return pixels;
最后,在 ZBarScannerView 类范围内将Boolean switcher = true
添加到类中。变量“switcher”用于在检查反转或非反转代码之间切换。
请问您是否有任何问题,我为此苦苦挣扎了这么久,我觉得是的,并且答案可能需要进行一些编辑以提高可读性。
【讨论】:
我试过了,效果很好。谢谢你,Versa 很高兴听到 :)【参考方案2】:长期以来,我一直在尝试做同样的事情。而且还没有完全成功。无法判断这是否回答了问题。但是这个代码放在mBarcodeScannerView
中,并在mZBarScannerView
中用autoInvert()
调用它,虽然看起来很烦人,但您可以扫描正常和反转的二维码。基本上它只是经常在相机效果之间切换。
public void autoInvert()
// Don't think this line is needed.
// autoInvertOn = !autoInvertOn;
Runnable runAutoInvert = new Runnable()
@Override
public void run()
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Camera.Parameters parameters = mCamera.getParameters();
if (parameters.getSupportedColorEffects().contains(Camera.Parameters.EFFECT_NEGATIVE))
while (mCamera != null && autoInvertOn)
try
parameters = mCamera.getParameters();
parameters.setColorEffect(Camera.Parameters.EFFECT_NEGATIVE);
mCamera.setParameters(parameters);
Thread.sleep(800);
parameters = mCamera.getParameters();
parameters.setColorEffect(Camera.Parameters.EFFECT_NONE);
mCamera.setParameters(parameters);
Thread.sleep(800);
catch (InterruptedException e)
e.printStackTrace();
catch (Exception e1)
mCamera = null;
;
Thread autoInvertThread = new Thread(runAutoInvert);
autoInvertThread.start();
为了防止它在黑暗环境中伤害我的眼睛,我还在预览的顶部放置了一个黑色的、有点透明的视图,当它反转时。对我来说,这是我努力寻找更好的解决方案时的解决方案。
【讨论】:
看看我的另一个答案,它回答了这个问题并确认可以工作,留下这个,因为它可能会解决某人的相关问题。以上是关于我想扫描经典二维码和倒置(暗亮)二维码。该怎么办?的主要内容,如果未能解决你的问题,请参考以下文章