Posts Tagged ZXing

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;
					}
				});

			}

		}
	}

}

, , , ,

5 Comments