Someone manages to implement this solution for iPhone? http://ydaira.blogspot.de/2012/05/how-to-decode-qr-code-using-unity3d.html It just does not work. Also with another flipping. I would be very happy if someone can help me.
hey Russel, here is the code i modified from Ariady Putra using zXing lib. It cost me long hours, but thanks to the community finally it works for time issues it does not got a nice performance and I do not have much spare time to clearify for you. hope it could help you. public class qrCam : MonoBehaviour { private WebCamTexture camTexture; private Thread qrThread; private Texture2D tex; Texture2D rotImage; private Color32[] c; private Color32[] f; private sbyte[] d; private int W, H, WxH; private int x, y, z; bool ifDone; /*void OnDisable () { if(camTexture != null) { camTexture.Pause(); } }*/ /*void OnDestroy () { qrThread.Abort(); camTexture.Stop(); }*/ IEnumerator Start () { camTexture = new WebCamTexture(480,360,5); camTexture.Play(); while(true) { if(camTexture.didUpdateThisFrame ifDone == false) { tex = new Texture2D(camTexture.width, camTexture.height, TextureFormat.RGB24, false); W = camTexture.width; H = camTexture.height; WxH = W * H; Debug.Log(W + " " + H); ifDone = true; qrThread = new Thread(DecodeQR); qrThread.Start(); break; } else yield return null; } } void Update () { if(ifDone){ if(Time.frameCount % 30 == 0){ f = camTexture.GetPixels32(); tex.SetPixels32(f); tex = rotateTexture(tex,90); c = tex.GetPixels32(); //tex.Apply(); this.renderer.material.mainTexture = tex; } /*if(f != null){ tex1.LoadImage(f); this.renderer.material.mainTexture = tex1; }*/ } } void DecodeQR () { while(true) { if(c == null) { continue; } try { d = new sbyte[WxH]; z = 0; int tmp; for(y = H - 1; y >= 0; y--) { for(x = 0; x < W; x++) { d[z++] = (sbyte)(((int)c[y * W + x].r) << 16 | ((int)c[y * W + x].g) << 8 | ((int)c[y * W + x].b)); } } Debug.Log("Decode: " + new QRCodeReader().decode(d, W, H).Text); } catch(Exception e){ //Debug.Log(e.Message); continue; } } } Texture2D rotateTexture(Texture2D tex, float angle) { rotImage = new Texture2D(camTexture.width, camTexture.height, TextureFormat.RGB24, false); int x,y; float x1, y1, x2,y2; float x0 = 480; float y0 = rot_y (angle, -W/2.0f, -H/2.0f) + H/2.0f; float dx_x = rot_x (angle, 1.0f, 0.0f); float dx_y = rot_y (angle, 1.0f, 0.0f); float dy_x = rot_x (angle, 0.0f, 1.0f); float dy_y = rot_y (angle, 0.0f, 1.0f); //Debug.Log(x0 + " " + y0 + " " + dx_x + " " +dx_y + " " + dy_x + " " + dy_y); x1 = x0; y1 = y0; for (x = 0; x < W; x++) { x2 = x1; y2 = y1; for ( y = 0; y < H; y++) { x2 += dx_x; y2 += dx_y; rotImage.SetPixel( x, y, getPixel(tex,x2, y2)); } x1 += dy_x; y1 += dy_y; } rotImage.Apply(); return rotImage; } private Color getPixel(Texture2D tex, float x, float y) { Color pix; int x1 = (int) Mathf.Floor(x); int y1 = (int) Mathf.Floor(y); if(x1 > tex.width || x1 < 0 || y1 > tex.height || y1 < 0) { pix = Color.clear; } else { pix = tex.GetPixel(x1,y1); } return pix; } private float rot_x (float angle, float x, float y) { float cos = Mathf.Cos(angle/180.0f*Mathf.PI); float sin = Mathf.Sin(angle/180.0f*Mathf.PI); return (x * cos + y * (-sin)); } private float rot_y (float angle, float x, float y) { float cos = Mathf.Cos(angle/180.0f*Mathf.PI); float sin = Mathf.Sin(angle/180.0f*Mathf.PI); return (x * sin + y * cos); } }
Note that it's a 90º rotation, so there's no need for Sin and Cos. You may rotate a texture with something like this: Code (csharp): void rotateTexture(Texture2D tex) { int M = camTexture.width; int N = camTexture.height; Texture2D rotated = new Texture2D (N, M, TextureFormat.RGB24, false); for (int r = 0; r < M; r++) for (int c = 0; c < N; c++) rotated.SetPixel (c, M - 1 - r, tex.GetPixel(r, c)); rotated.Apply(); } But it needs a second transformation, that is also added to the GetPixel function. The whole thing would finally look like this: Code (csharp): using UnityEngine; using System.Collections; using System.Threading; using com.google.zxing.qrcode; public class qrCam : MonoBehaviour { private WebCamTexture camTexture; private Thread qrThread; private Texture2D tex; Texture2D rotImage; private Color32[] c; private Color32[] f; private sbyte[] d; private int W, H, WxH; private int x, y, z; bool camReady; QRCodeReader QR; string output; void OnDisable () { if(camTexture != null) { camTexture.Pause(); } } void OnDestroy () { qrThread.Abort(); camTexture.Stop(); } void Start () { QR = null; rotImage = null; StartCoroutine (Launch()); } IEnumerator Launch() { camTexture = new WebCamTexture(512, 512); camTexture.Play(); while (true) { if(camTexture.didUpdateThisFrame camReady == false) { tex = new Texture2D(camTexture.width, camTexture.height, TextureFormat.RGB24, false); W = camTexture.width; H = camTexture.height; WxH = W * H; Debug.Log(W + " " + H); camReady = true; qrThread = new Thread(DecodeQR); qrThread.Start(); break; } else yield return null; } } void Update () { if (camReady) { f = camTexture.GetPixels32(); tex.SetPixels32(f); correctIOSWebcamTexture(tex); c = rotImage.GetPixels32(); this.renderer.material.mainTexture = rotImage; } } void correctIOSWebcamTexture(Texture2D tex) { int M = camTexture.width; int N = camTexture.height; Destroy (rotImage); rotImage = new Texture2D (N, M, TextureFormat.RGB24, false); for (int r = 0; r < M; r++) for (int c = 0; c < N; c++) rotImage.SetPixel (c, M - 1 - r, tex.GetPixel(r, N - 1 - c)); rotImage.Apply(); } void DecodeQR () { while(true) { if(c == null) continue; try { d = new sbyte[WxH]; z = 0; int tmp; for(y = 0; y < H; y++) { for(x = 0; x < W; x++) { d[z++] = (sbyte)(((int)c[y * W + x].r) << 16 | ((int)c[y * W + x].g) << 8 | ((int)c[y * W + x].b)); } } if (QR == null) QR = new QRCodeReader(); output = QR.decode(d, W, H).Text; print (output); } catch { continue; } } } } But it would be nice avoiding the creation and destruction of textures in each step, as I did with QRCodeReader (avoiding a memory leak, by the way). It's not printing the QR code, however. I'll check all this once again tomorrow... it's quite late here and I'm tires. EDITED: As the texture is properly rotated, there's no need for the backwards vertical loop in the DecodeQR function, so y = 0; y < H; y++. But it still doesn't print the code. Still trying.
I think I've got it. First of all, there's no need to rotate the image to decode the QR code. We just need to change the DecodeQR loop to the one in my code above, using the texture that comes directly from camTexture!! That makes the whole thing ULTRA fast, of course. And if you want to properly visualize the camera on a plane, simply rotate and scale it properly. I use a plane that, when imported, faces the default camera (so its axis correspond to the World's axis). Such a plane must simply be rotated 90 degrees on the Z plane and scaled x -1.0 in the x dimension. And that's all! That way the update loop looks like this: Code (csharp): void Update () { if (camReady) { c = camTexture.GetPixels32(); this.renderer.material.mainTexture = camTexture; } } and the Decode function like this: Code (csharp): void DecodeQR () { while(true) { if(c == null) continue; try { d = new sbyte[WxH]; z = 0; int tmp; for(y = 0; y < H; y++) { for(x = 0; x < W; x++) { d[z++] = (sbyte)(((int)c[y * W + x].r) << 16 | ((int)c[y * W + x].g) << 8 | ((int)c[y * W + x].b)); } } if (QR == null) QR = new QRCodeReader(); output = QR.decode(d, W, H).Text; print (output); } catch { continue; } } } And that's simply real time on an iPad 2
Brilliant work but I'm getting the error of missing a Renderer to the Camera of the script. Is there a possibility that you can put up a unity package or point me in the right direction? What I've done so far is as below: - I created a new script with your code in it - created a new camera and attached a new renderer texture as the target texture The error comes on during runtime and there isn't anything showing. Many Thanks
But I never used a 'render to texture', because I just own the basic version! It's a simple texture, which is applied to a plane. So: it's not the camera being rendered to a texture, just a simple texture being update by the webcam. Try doing it like that : )
Thanks but I still don't see why its not working on mine. Would you please send me a link to download the unity package instead? It is so frustrating that the code is there but I'm not able to make it work... Many thanks
If anyone still interested in this take a look here: http://forum.unity3d.com/threads/qr...ty-in-2015-what-happened.307465/#post-2629554