Unity, Vuforia & ZXing – Barcode scanning in AR games


I’ve been struggling with finding a good barcode scanner/QR code reader that works with Unity and doesn’t kill the framerate.  Given that I also have an AR application I thought that I would try to incorporate Vuforia with ZXing to get the best of both worlds and the good news is that it works pretty well and is very fast.  I’m attaching a download here of the package that contains a Unity friendly version of the C# port of ZXing together with my mulithreading manager Loom class.  Then here is an example of a script that will scan barcodes and/or QR codes and fire an event and send a message to a target object when something is decoded.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;
using com.google.zxing.qrcode;
using com.google.zxing.multi;
using com.google.zxing.common;
using com.google.zxing;
using com.google.zxing.client.result;

[AddComponentMenu("System/VuforiaScanner")]
public class VuforiaScanner : MonoBehaviour
{
	public QCARBehaviour vuforia;
	public bool barcode;
	public GameObject target;

	public static event Action<ParsedResult, string> Scanned = delegate {};
	public static event Action<string> ScannedQRCode = delegate {};
	public static event Action<string> ScannedBarCode = delegate {};

	bool decoding;
	bool initGray;
	MultiFormatReader mfReader = new MultiFormatReader();
	QRCodeReader qrReader = new QRCodeReader();

	void Update()
	{
		if(vuforia == null)
			return;
		if(vuforia.enabled && !initGray)
		{
                     //Wait 1/4 seconds for the device to initialize (otherwise it seems to crash sometimes)
		     initGray = true;
		     Loom.QueueOnMainThread(()=>{
	                      initGray = CameraDevice.Instance.SetFrameFormat(Image.PIXEL_FORMAT.GRAYSCALE, true);
		     }, 0.25f);
		}
		if (vuforia.enabled && CameraDevice.Instance != null && !decoding)
		{
			var image = CameraDevice.Instance.GetCameraImage(Image.PIXEL_FORMAT.GRAYSCALE);
			if (image != null)
			{
				decoding = true;

				Loom.RunAsync(() =>
				{
					try
					{
						var bitmap = new BinaryBitmap(new HybridBinarizer(new RGBLuminanceSource(image.Pixels, image.BufferWidth, image.BufferHeight, true)));
						Result data;
						if (barcode)
						{
							var reader = new MultiFormatReader();
							data = reader.decode(bitmap);
						}
						else
						{
							var reader = new QRCodeReader();
							data = reader.decode(bitmap);
						}
						if (data != null)
						{
							Loom.QueueOnMainThread(() => {
								if (data.BarcodeFormat == BarcodeFormat.QR_CODE)
								{
									ScannedQRCode(data.Text);
									if(target != null)
									{
										target.SendMessage("ScannedQRCode", data.Text, SendMessageOptions.DontRequireReceiver);
									}
								}
								if (data.BarcodeFormat != BarcodeFormat.QR_CODE)
								{
									ScannedBarCode(data.Text);
									if(target != null)
									{
										target.SendMessage("ScannedBarCode", data.Text, SendMessageOptions.DontRequireReceiver);
									}

								}
								var parsedResult = ResultParser.parseResult(data);
								if(target != null)
								{
									target.SendMessage("Scanned", parsedResult, SendMessageOptions.DontRequireReceiver);
								}
								Scanned(parsedResult, data.Text);
								decoding = false;
							});
						}
					}
					catch (Exception e)
					{
						decoding = false;
					}
				});

			}

		}
	}

}

, , , ,

  1. #1 by Michael on July 19, 2012 - 8:57 pm

    Hi Mike,

    nice solution.
    I took your code and modified it so that it works with ZXing.Net.
    ZXing.Net is an up-to-date port of zxing. ZXing.Net was created and is maintained by me.
    Since version 0.7 ZXing.Net provides a Unity-friendly assembly.
    I couldn’t test the functionality of my version of your sample yet but it compiles successfully.
    You can find it here if you are interested:
    https://zxingnet.svn.codeplex.com/svn/trunk/Clients/VuforiaDemo
    If not or if it is not ok for you drop me an email and feel free to remove my comment.

    Regards,
    MIchael

    • #2 by whydoidoit on July 19, 2012 - 9:00 pm

      Brilliant – wish I’d found that before 🙂

  2. #3 by Giovanni Landi on July 20, 2012 - 11:25 am

    Thank you for your brilliant work!!!
    How would you then send the read string to a GUIText?
    I’m trying to make it work on an iphone…

    Ciao!

    Giovanni

    • #4 by whydoidoit on July 20, 2012 - 12:06 pm

      Thanks 🙂

      So if you use that script in the article the easiest way to do what you want is to set the “target” variable in the inspector to the object that contains your GUIText and then write a script with a ScannedQRCode function that you attach to that object.

      Something like this:

      public GUIText qrCodeLabel;

      void ScannedQRCode(string text)
      {
      qrCodeLabel.text = text;
      }

    • #5 by whydoidoit on July 20, 2012 - 12:08 pm

      Or ScannedBarCode or both depending on what you want!

Leave a comment