android-vision
android-vision copied to clipboard
Can't read QRCode with different colors
The regular qrcodes are black with white background. They are working like a charm.
But I have here hundred of cards with a white qrcode on a blue background. And I can't make the android vision recognize these qrcodes with different colors. Every qrcode reader from the Google Play works perfectly. But I can't read them using android vision api.
I've played with different colors here and the problem seems to be the with background. Every qrcode with dark color with white background works. But if i change the white background, it stops working.
Any solution for this? Any parameters that I can change? I'm trying to avoid using an external lib as we have the native support.
Sorry if this is not a issue, but I've searched a lot without success and I can read without problems using other apps. But I'm not sure if they are using the new api. Thanks!
Right, the barcode API generally doesn't support color-inverted codes. There's no parameter or option to control this at the moment. Though some APIs support them, I don't believe it's a common feature.
For a workaround, you could preprocess the colors in the bitmap before passing them to the barcode API (perhaps inverting colors on alternate frames).
Would you mind sharing an example image of the QR codes you are trying to read?
I was about to start the approach you suggested. I'm just worried about the performance. Ideas how to do this on the fly without losing performance?
Here are an example of the qrcode I'm testing.
I'd suggest trying to preprocess the image in Java first. If that isn't fast enough for your needs, try JNI or RenderScript.
Hi,
Will this be included in any release? The workaround that pchx suggested may work but it disables black on white qrs.
Fancy QRs (inverted colour included) are becoming increasingly common.
For now, as my application is in hands of few users, I've included an option to turn on the camera negative effect during the capture.
It's not the best workaround, but we need something fast and processing the image on the fly was not a good option.
@Nom4d3 not sure if you need this still but this does the job.
class MyQRDetector extends Detector<Barcode> {
private Detector<Barcode> mDelegate;
MyQRDetector(Detector<Barcode> delegate) {
mDelegate = delegate;
}
public Bitmap invertBitmap(Bitmap src)
{
int height = src.getHeight();
int width = src.getWidth();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
ColorMatrix matrixGrayscale = new ColorMatrix();
matrixGrayscale.setSaturation(0);
ColorMatrix matrixInvert = new ColorMatrix();
matrixInvert.set(new float[]
{
-1.0f, 0.0f, 0.0f, 0.0f, 255.0f,
0.0f, -1.0f, 0.0f, 0.0f, 255.0f,
0.0f, 0.0f, -1.0f, 0.0f, 255.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f
});
matrixInvert.preConcat(matrixGrayscale);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrixInvert);
paint.setColorFilter(filter);
canvas.drawBitmap(src, 0, 0, paint);
return bitmap;
}
public Bitmap createBlackAndWhite(Bitmap src) {
int width, height;
height = src.getHeight();
width = src.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(src, 0, 0, paint);
return bmpGrayscale;
}
public SparseArray<Barcode> detect(Frame frame) {
// *** add your custom frame processing code here
SparseArray<Barcode> detections;
YuvImage yuvImage = new YuvImage(frame.getGrayscaleImageData().array(), ImageFormat.NV21, frame.getMetadata().getWidth(), frame.getMetadata().getHeight(), null);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, frame.getMetadata().getWidth(), frame.getMetadata().getHeight()), 100, byteArrayOutputStream);
byte[] jpegArray = byteArrayOutputStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);
if (bitmap != null) {
Bitmap BWBitmap = createBlackAndWhite(bitmap);
frame = new Frame.Builder()
.setBitmap(BWBitmap)
.setRotation(frame.getMetadata().getRotation())
.build();
detections = mDelegate.detect(frame);
Bitmap InvertedBitmap = invertBitmap(BWBitmap);
if (detections.size() == 0) {
frame = new Frame.Builder()
.setBitmap(InvertedBitmap)
.setRotation(frame.getMetadata().getRotation())
.build();
}
}
detections = mDelegate.detect(frame);
return detections;
}
public boolean isOperational() {
return mDelegate.isOperational();
}
public boolean setFocus(int id) {
return mDelegate.setFocus(id);
}
}
I found a faster solution for invert colors (8ms vs 200ms) https://gist.github.com/jacklt/4627f9e773aaebea12f2bce357446dc8
In Kotlin: Invert ByteArray color
frame.grayscaleImageData.array().let { b ->
val max = 0xFFFFFFFF
ByteArray(b.size) { (max - b[it].toInt()).toByte() }
}
and wrap in ByteBuffer!
#prefmatters (Colt McAnlis) ;)
I improved googles example app "barcode-reader" to detect both inverted colored barcodes and regular ones.
I did so by editing "CameraSource" class, package: "com.google.android.gms.samples.vision.barcodereader.ui.camera".
I added a parameter: private boolean isInverted = false;
and changed function void setNextFrame(byte[] data, Camera camera)
:
void setNextFrame(byte[] data, Camera camera) {
synchronized (mLock) {
if (mPendingFrameData != null) {
camera.addCallbackBuffer(mPendingFrameData.array());
mPendingFrameData = null;
}
if (!mBytesToByteBuffer.containsKey(data)) {
Log.d(TAG,
"Skipping frame. Could not find ByteBuffer associated with the image " +
"data from the camera.");
return;
}
mPendingTimeMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
mPendingFrameId++;
if (!isInverted){
for (int y = 0; y < data.length; y++) {
data[y] = (byte) ~data[y];
}
isInverted = true;
} else {
isInverted = false;
}
mPendingFrameData = mBytesToByteBuffer.get(data);
// Notify the processor thread if it is waiting on the next frame (see below).
mLock.notifyAll();
}
}
It solves the problem perfectly!
Can you read this colored QR Code ?
I can't read the inverted DataMatrix
not read:
Read:
Is it possible to fix it?
Let me know if someone told you a solution I'm trying that in flutter, same problem with datamatrix
Let me know if someone told you a solution I'm trying that in flutter, same problem with datamatrix
I haven't found a solution. I started using a physical scanner.