【问题标题】:Read QR Code in Unity with ARKit and ZXing使用 ARKit 和 ZXing 在 Unity 中读取二维码
【发布时间】:2018-11-22 13:10:50
【问题描述】:

我正在尝试使用以下库读取 QR 码:

  • ARKit
  • 志兴

然而,它似乎并不顺利。几个小时后,我仍然无法读出一个像样的二维码。 调试时我应用纹理来查看我的结果。由于纹理 Y,它看起来是红色的,但除此之外它还显示 QR 码。 解释纹理不会返回任何 ZXing 分析的数据。

这是我为此使用的以下代码:

#if UNITY_IOS && !UNITY_EDITOR
    // Update is called once per frame
    // BETTER: InvokeRepeating
    void Update()
    {
        if (!done) {
            ARTextureHandles handles = arSession.GetARVideoTextureHandles();
            //ARTextureHandles handles = UnityARSessionNativeInterface.GetARSessionNativeInterface().GetARVideoTextureHandles();
            if (handles.IsNull())
            {
                return;
            }
            if (handles.TextureY != System.IntPtr.Zero) {
                ReadQRCode (handles.TextureY);
            }
        }

}
#endif

private void ReadQRCode(System.IntPtr mtlTexPtr)
{
    Debug.Log("---------------");
    Debug.Log("Scanning...");

    Resolution currentResolution = Screen.currentResolution;

    tex = (UnityEngine.Texture2D)GameObject.Find("Camera").GetComponent<UnityARVideo>().m_ClearMaterial.GetTexture("_textureCbCr");

    tex.UpdateExternalTexture(mtlTexPtr);

    try
    {
        if(barCodeReader == null) {
            Debug.Log("Could not find barcorereader");
        }
        if(tex == null) {
            Debug.Log("Could not find texture");
        }

        var data = barCodeReader.Decode(tex.GetPixels32(), currentResolution.width, currentResolution.height);
        if (data != null)
        {
            Debug.Log("QR: " + data.Text);
        }
        else
        {
            Debug.Log("NO QR: " + "No QR code detected !");
        }
    }
    catch (Exception e)
    {
        Debug.LogError("Error reading QR");
        Debug.LogError(e.Message);
    }
}

【问题讨论】:

    标签: c# unity3d zxing arkit


    【解决方案1】:

    经过进一步挖掘,我发现了一个与 OpenCV 类似的示例。

    事实证明这对我很有效。

    public class FrameCapturer : MonoBehaviour {
    
        // Script Inputs
        public bool m_shouldCaptureOnNextFrame = false;
        public Color32[] m_lastCapturedColors;
    
        // Privates
        Texture2D m_centerPixTex;
    
        void Start()
        {
            Resolution currentResolution = Screen.currentResolution;
            m_centerPixTex = new Texture2D(currentResolution.width, currentResolution.height, TextureFormat.RGBA32, false);
        }
    
        void OnPostRender()
        {
    
            if (m_shouldCaptureOnNextFrame)
            {
                Resolution res = Screen.currentResolution;
                m_lastCapturedColors = GetRenderedColors();
                m_shouldCaptureOnNextFrame = false;
            }
        }
    
        // Helpers
        Color32[] GetRenderedColors()
        {
            Resolution currentResolution = Screen.currentResolution;
            m_centerPixTex.ReadPixels(new Rect(0, 0, currentResolution.width, currentResolution.height), 0, 0);
            m_centerPixTex.Apply();
    
            return m_centerPixTex.GetPixels32();
        }
    }
    

    我将它附加到主摄像头,AR 脚本也附加在该主摄像头下。然后我是二维码阅读器,我可以简单地使用以下内容:

    public class QRCodeReader : MonoBehaviour
    {
        public Camera cam;
        private BarcodeReader barCodeReader;
    
        FrameCapturer m_pixelCapturer;
    
        // Use this for initialization
        void Start()
        {
            barCodeReader = new BarcodeReader();
            Resolution currentResolution = Screen.currentResolution;
            m_pixelCapturer = cam.GetComponent<FrameCapturer>();
        }
    
        void Update()
        {
    
            Resolution currentResolution = Screen.currentResolution;
    
            try
            {
                Color32[] framebuffer = m_pixelCapturer.m_lastCapturedColors;
                if (framebuffer.Length == 0)
                {
                    return;
                }
    
                var data = barCodeReader.Decode(framebuffer, currentResolution.width, currentResolution.height);
                if (data != null)
                {
                    // QRCode detected.
                    Debug.Log(data);
                    Debug.Log("QR: " + data.Text);
    
                    //OnQrCodeRead(new QrCodeReadEventArgs() { text = data.Text });
                }
    
            }
            catch (Exception e)
            {
                Debug.LogError("Error reading QR");
                Debug.LogError(e.Message);
            }
    
            // skip 1 frame each time 
            // solves GetPixels() blocks for ReadPixels() to complete
            // https://medium.com/google-developers/real-time-image-capture-in-unity-458de1364a4c
            m_pixelCapturer.m_shouldCaptureOnNextFrame = true;
    
        }
    }
    

    我将此答案改编为的原始来源:https://github.com/realityenhanced/ARKitExperiments/blob/master/Assets/Scripts/CaptureCenterPixel.cs

    【讨论】:

    • 这可行,但要注意这会读取当前屏幕,因此还包括任何可见的 3D 对象
    【解决方案2】:

    我曾与 ZXing 和 ARkit 合作过,但从未合作过。

    试图让一些工作至少给你一个关于可能发生的事情的提示。

    作为 ARCameraManager 的子项,添加另一个(除了您的主 AR 摄像头)相机,并附加一个 ARVideo 脚本(删除诸如音频监听器、Flare 层和 guiLayer 之类的东西)另外添加以下脚本,它就在那里检索renderTexture:

    [RequireComponent(typeof(Camera))]
    public class WebcamFetcher : MonoBehaviour
    {
    private RenderTexture _vertical;
    private RenderTexture _horizontal;
    private Camera _camera;
    
    // Update is called once per frame
    public RenderTexture RenderTexture
    {
        get
        {
            var orientation = Screen.orientation;
            if (orientation == ScreenOrientation.Landscape || orientation == ScreenOrientation.LandscapeLeft || orientation == ScreenOrientation.LandscapeRight)
            {
                return _horizontal;
            }
            else
            {
                return _vertical;
            }
        }
    }
    
    // Use this for initialization
    void Start ()
    {
        _camera = GetComponent<Camera>();
        _horizontal = new RenderTexture(Screen.width, Screen.height, 24);
        _vertical = new RenderTexture(Screen.height, Screen.width, 24);
    }
    
    // Update is called once per frame
    void Update()
    {
        var orientation = Screen.orientation;
        if (orientation == ScreenOrientation.Landscape || orientation == ScreenOrientation.LandscapeLeft || orientation == ScreenOrientation.LandscapeRight)
        {
            _camera.targetTexture = _horizontal;
        }
        else
        {
            _camera.targetTexture = _vertical;
        }
    }
    

    }

    然后使用如下脚本:

    private string DecodeQR(Color32[] pixels, int width, int height)
    {
        try
        {
            IBarcodeReader barcodeReader = new BarcodeReader();
    
            // decode the current frame
            var result = barcodeReader.Decode(pixels, width, height);
    
            if (result != null)
            {
                return result.Text;
            }
        }
        catch (Exception ex) { Debug.LogError(ex.Message); }
        return null;
    }
    
    [SerializeField] Text QrDisplay; // A text field to display detected QRs to
    
    public void OnQrDetect() // a callback for a UI button
    {
        var texture = new Texture2D(_webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height);
        RenderTexture.active = _webcamFetcher.RenderTexture;
        texture.ReadPixels(new Rect(Vector2.zero, new Vector2(_webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height)), 0, 0);
    
        var qrText = DecodeQR(texture.GetPixels32(), _webcamFetcher.RenderTexture.width, _webcamFetcher.RenderTexture.height);
        if (qrText != null)
        {
            QrDisplay.text = qrText;
        }
    }
    

    为我工作。纹理检索可能不是最有效的。 但它有效 -> 这是可能的。

    【讨论】:

    • 感谢您的评论,我还添加了一个答案,其中解释了我选择的解决方案。
    • 问题现在回答了吗?还是开着?
    猜你喜欢
    • 2014-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    相关资源
    最近更新 更多