Прочитайте QR-код в Unity с помощью ARKit и ZXing - PullRequest
0 голосов
/ 22 ноября 2018

Я пытаюсь прочитать QR-код со следующими библиотеками:

  • ARKit
  • ZXing

Однако, похоже, это не такладиться.После нескольких часов мне все еще не удается прочитать приличный QR-код.При отладке я применяю текстуру, чтобы увидеть мой результат.Он выглядит красным из-за текстуры 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);
    }
}

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

После дальнейших раскопок я наткнулся на пример, в котором было что-то похожее на 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, где также прилагается под.Тогда, читатель кода qr, я мог бы просто использовать следующее:

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

0 голосов
/ 27 ноября 2018

Я работал с ZXing и ARkit, но никогда вместе.

Пытался заставить что-то работать, чтобы хотя бы дать вам подсказку о том, что может быть возможным.

Как ребенок вашегоARCameraManager, добавьте еще одну (дополнительно к вашей основной камере AR) камеру с прикрепленным к ней сценарием ARVideo (удалите такие вещи, как аудио Listener, слой 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;
    }
}

Сработало для меня.Поиск текстуры может быть не самым эффективным.НО это работает -> это возможно.

...