30

I've been playing with the sample code from the new Google Barcode API. It overlays a box and the barcode value over the live camera feed of a barcode. (Also faces)

I can't tell how to return a barcode value to my app. A) How to tell when a detection event has occurred and B) how to access the ravValue for use in other parts of my app. Can anyone help with this?

https://developers.google.com/vision/multi-tracker-tutorial

https://github.com/googlesamples/android-vision

UPDATE: Building on @pm0733464's answer, I added a callback interface (called onFound) to the Tracker class that I could access in the Activity. Adapting the Google multi-tracker sample:

GraphicTracker:

class GraphicTracker<T> extends Tracker<T> {
    private GraphicOverlay mOverlay;
    private TrackedGraphic<T> mGraphic;
    private Callback mCallback;

    GraphicTracker(GraphicOverlay overlay, TrackedGraphic<T> graphic, Callback callback) {
        mOverlay = overlay;
        mGraphic = graphic;
        mCallback = callback;
    }

    public interface Callback {
        void onFound(String barcodeValue);
    }

    @Override
    public void onUpdate(Detector.Detections<T> detectionResults, T item) {
        mCallback.onFound(((Barcode) item).rawValue);
        mOverlay.add(mGraphic);
        mGraphic.updateItem(item);
    }

BarcodeTrackerFactory :

class BarcodeTrackerFactory implements MultiProcessor.Factory<Barcode> {
    private GraphicOverlay mGraphicOverlay;
    private GraphicTracker.Callback mCallback;

    BarcodeTrackerFactory(GraphicOverlay graphicOverlay, GraphicTracker.Callback callback) {
        mGraphicOverlay = graphicOverlay;
        mCallback = callback;
    }

    @Override
    public Tracker<Barcode> create(Barcode barcode) {
        BarcodeGraphic graphic = new BarcodeGraphic(mGraphicOverlay);
        return new GraphicTracker<>(mGraphicOverlay, graphic, mCallback);
    }
}

Main Activity:

BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(mGraphicOverlay, new GraphicTracker.Callback() {
    @Override
    public void onFound(String barcodeValue) {
        Log.d(TAG, "Barcode in Multitracker = " + barcodeValue);
    }
});
MultiProcessor<Barcode> barcodeMultiProcessor = new MultiProcessor.Builder<>(barcodeFactory).build();
barcodeDetector.setProcessor(barcodeMultiProcessor);
Scott
  • 3,663
  • 8
  • 33
  • 56
  • I'm interested in your opinion so far. What are your experiences with the API: How well is it recognizing barcodes? Also when it's a bit dark? Is it fast? So overall: Is it better performing than zxing? And lastly, can you provide a complete example? – Dante Aug 16 '15 at 15:22
  • There is a new barcode reader sample app on GitHub: https://github.com/googlesamples/android-vision/tree/master/visionSamples/barcode-reader – pm0733464 Sep 28 '15 at 15:30
  • 1
    @Dante The code you shared with `callback` was very helpful for me. Thanks a lot! – Snow Blind Feb 18 '16 at 18:11
  • A couple of points to note here. First the callback will come from another thread, so a runOnUiThread will be required when the callback is invoked if you intend to do an UI actions. Second, the callback is a reference to the activity so you must take care when managing it. Still, the solution seems to work and I have no idea why Google Play services doesn't have a built in option to just return as soon as a barcode is scanned. If they were thinking they might replace ANY existing libraries, all of which work exactly that way. – Chris Jun 10 '16 at 19:55
  • You can give this library a try, its based on the sample from Google [MVBarcodeReader](https://github.com/iamMehedi/MVBarcodeReader) – Mehedi Oct 08 '16 at 13:45
  • The interface is throwing npe. Have you tested it on a real device? – The_Martian Jan 26 '17 at 20:24
  • Yes, but not in over a year. Ask a new question with all of your details and error and reference this one – Scott Jan 26 '17 at 21:41

1 Answers1

41

Directly using the barcode detector

One approach is to use the barcode detector directly on a bitmap, like this:

BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
Frame frame = new Frame.Builder().setBitmap(bitmap).build();
SparseArray<Barcode> barcodes = barcodeDetector.detect(frame);
if (barcodes.size() > 0) {
    // Access detected barcode values
}

Receiving notifications

Another approach is to set up a pipeline structure for receiving detected barcodes from camera preview video (see the MultiTracker example on GitHub). You'd define your own Tracker to receive detected barcodes, like this:

class BarcodeTrackerFactory implements MultiProcessor.Factory<Barcode> {
    @Override
    public Tracker<Barcode> create(Barcode barcode) {
        return new MyBarcodeTracker();
    }
} 

class MyBarcodeTracker extends Tracker<Barcode> {
    @Override
    public void onUpdate(Detector.Detections<Barcode> detectionResults, Barcode barcode) {
        // Access detected barcode values
    }
 }

A new instance of this tracker is created for each barcode, with the onUpdate method receiving the detected barcode value.

You then set up the camera source to continuously stream images into the detector, receiving the results in your tracker:

BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory();
barcodeDetector.setProcessor(
    new MultiProcessor.Builder<>(barcodeFactory).build());

mCameraSource = new CameraSource.Builder(context, barcodeDetector)
    .setFacing(CameraSource.CAMERA_FACING_BACK)
    .setRequestedPreviewSize(1600, 1024)
    .build();

Later, you'd either start the camera source directly or use it in conjunction with a view that shows the camera preview (see the MultiTracker example for more details).

pm0733464
  • 2,862
  • 14
  • 16
  • Thank you so much - using the onUpdate of the Tracker looks like it is the callback I'm looking for. With the way the classes are set up in the example with the Factories and Builders, I didn't realize to look inside Tracker class. – Scott Aug 15 '15 at 21:50
  • FYI, using your answer I added a callback interface to the Tracker class so I could access the barcode from the main activity. I updated my question to include this solution. Please feel free to correct me if I've overlooked something. – Scott Aug 16 '15 at 04:37
  • 1
    Looks good. If you only need to handle barcodes in your app (and not faces), this could be simplified by changing GraphicTracker to inherit from Tracker rather than being generic. That way, you wouldn't need to cast the item to (Barcode) in onUpdate. – pm0733464 Aug 16 '15 at 14:09
  • 1
    Just a note, remember to add ` ` to your `AndroidManifest.xml`. – Ivan Morgillo Aug 24 '15 at 15:53
  • @pm0733464 can we generate qrcode using google play sevice? – Bhoomika Brahmbhatt Mar 28 '16 at 06:37
  • How can I get barcode id in case of few barcodes have been scanned at the same time? Count of scanned barcodes could be get as following: `detectionResults.getDetectedItems().size()`. – Konstantin Konopko May 19 '16 at 09:47
  • In the example above, a new instance of MyBarcodeTracker will be created for each barcode detected. You can either get the barcode id delivered to each of these instances or get the ids by iterating over the detectionResults. See the barcode accessors here: https://developers.google.com/android/reference/com/google/android/gms/vision/barcode/Barcode#nested-class-summary – pm0733464 May 19 '16 at 14:25
  • Thank you. I'm new to java and don't know class can be named "a.b" (`BarcodeDetector.Builder`). How to use `public BarcodeDetector.Builder setBarcodeFormats (int format)` ? (`BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build(); barcodeDetector.Builder(context).setBarcodeFormats (QR_CODE);` does not do. – Alex Martian May 21 '16 at 04:38
  • Tried this `BarcodeDetector.Builder barcodeDetectorBuilder = new BarcodeDetector.Builder(context); barcodeDetectorBuilder.setBarcodeFormats(BarcodeDetector.Builder.QR_CODE); BarcodeDetector barcodeDetector = new barcodeDetectorBuilder.build();`, but two errors on `BarcodeDetector.Builder.QR_CODE` and `barcodeDetectorBuilder.build()` - even however Studio suggests `build` method after `new barcodeDetectorBuilder.` – Alex Martian May 21 '16 at 05:15
  • Solved my issue. `BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).setBarcodeFormats(Barcode.QR_CODE).build();` – Alex Martian May 21 '16 at 13:13
  • @pm0733464 your comment saved a lot of my time – rookieDeveloper Sep 02 '16 at 15:02
  • Github link in the answer is broken, [here is a proper one](https://github.com/googlesamples/android-vision/tree/master/visionSamples/multi-tracker). – Vsevolod Krasnov Nov 10 '18 at 09:22