Use of Vuforia Engine along with Magic Leap Marker Tracking

Hello!
I'm trying to develop an application in which i track a QR code through Vuforia, and in the meanwhile i track an object composed of Aruco/AprilTag markers. Both of methods work independently, but not together. Vuforia stops as soon as ML Marker Tracking is started.
If i'm not in mistake, i understood that vuforia uses RGB cam (CV cam maybe?) and the way i'm using marker tracking is through World Cameras. Is there a way to use both at the same moment?
What i want to achieve is a setup in which Vuforia uses RGB-CV camera, MLMarkerTracking uses World Cameras and i'm still be able to capture/stream through RGB Camera.
Is it possibile as you know?

Thank you in advance for any help, at the moment i'm using unity 2022.3, Magic leap os/sdk and so on from May 2024 update.

Hey stradio95!

Thanks for reaching out!

I tried reproducing the issue you're having on my end.
Using the latest ML OS and Unity SDK, I setup a sample scene that streamed the RGB camera to a Quad object. I then attempted to enable marker tracking using the world camera to see if it would interrupt the live camera stream.

I was able to use marker tracking without interrupting the live camera stream at all. So I was unable to reproduce this issue where accessing the camera from 2 processes interrupts one of them.

I'm currently attempting to try this same thing but with Vuforia to see if the service gets interrupted at any point.

I will let you know if I can reproduce this using Vuforia or not!

For reference in case it could help, here is the marker tracking script I used. In the editor, I set the camera hint to World Camera.

public class MarkerTrackerExample : MonoBehaviour
{
    [Header("Marker Tracker Settings")]
    // QR Code marker size to use (in meters).
    public float QRCodeSize = 0.1f;

    // Aruco marker size to use (in meters).
    public float ArucoMarkerSize = 0.1f;

    // The marker types that are enabled for this scanner. Enable markers by
    // combining any number of <c> MarkerType </c> flags using '|' (bitwise 'or').
    public MLMarkerTracker.MarkerType MarkerTypes = MLMarkerTracker.MarkerType.Aruco_April| MLMarkerTracker.MarkerType.QR;

    // Aruco dictionary to use.
    public MLMarkerTracker.ArucoDictionaryName ArucoDicitonary = MLMarkerTracker.ArucoDictionaryName.DICT_5X5_100;

    // Represents the different tracker profiles used to optimize marker tracking in difference use cases.
    public MLMarkerTracker.Profile TrackerProfile = MLMarkerTracker.Profile.Custom;

    [Header("Marker Tracker Custom Profile")]

    // A hint to the back-end the max frames per second hat should be analyzed.
    public MLMarkerTracker.FPSHint FPSHint;

    // A hint to the back-end the resolution that should be used.
    public MLMarkerTracker.ResolutionHint ResolutionHint;

    // A hint to the back-end for the cameras that should be used.
    public MLMarkerTracker.CameraHint CameraHint;

    // In order to improve performance, the detectors don't always run on the full
    // frame.Full frame analysis is however necessary to detect new markers that
    // weren't detected before. Use this option to control how often the detector may
    // detect new markers and its impact on tracking performance.
    public MLMarkerTracker.FullAnalysisIntervalHint FullAnalysisIntervalHint;

    // This option provides control over corner refinement methods and a way to
    // balance detection rate, speed and pose accuracy. Always available and
    // applicable for Aruco and April tags.
    public MLMarkerTracker.CornerRefineMethod CornerRefineMethod;

    // Run refinement step that uses marker edges to generate even more accurate
    // corners, but slow down tracking rate overall by consuming more compute.
    // Aruco/April tags only.
    public bool UseEdgeRefinement;


    private Dictionary<string, GameObject> _markers = new Dictionary<string, GameObject>();
    private ASCIIEncoding _asciiEncoder = new System.Text.ASCIIEncoding();
    private MLMarkerTracker.TrackerSettings _markerSettings;
    //Enable scanning on start?
    private bool _enableMarkerScanning = true;

#if UNITY_ANDROID
    private void OnEnable()
    {
        MLMarkerTracker.OnMLMarkerTrackerResultsFoundArray += OnMLMarkerTrackerResultsFoundArray;
    }

    private void Start()
    {
        // Unity has it's own value for Enum called Everything and sets it to -1
        MarkerTypes = (int)MarkerTypes == -1 ? MLMarkerTracker.MarkerType.All : MarkerTypes;

        // If we are using a custom profile, create the profile before creating the tracker settings
        if (TrackerProfile == MLMarkerTracker.Profile.Custom)
        {
            MLMarkerTracker.TrackerSettings.CustomProfile customProfile = MLMarkerTracker.TrackerSettings.CustomProfile.Create(FPSHint, ResolutionHint, CameraHint, FullAnalysisIntervalHint, CornerRefineMethod, UseEdgeRefinement);
            _markerSettings = MLMarkerTracker.TrackerSettings.Create(
                _enableMarkerScanning, MarkerTypes, QRCodeSize, ArucoDicitonary, ArucoMarkerSize, TrackerProfile, customProfile);
        }
        else
        {
            _markerSettings = MLMarkerTracker.TrackerSettings.Create(
                _enableMarkerScanning, MarkerTypes, QRCodeSize, ArucoDicitonary, ArucoMarkerSize, TrackerProfile);
        }


        MLMarkerTracker.SetSettingsAsync(_markerSettings).GetAwaiter().GetResult();
    }

    private void OnDisable()
    {
        MLMarkerTracker.OnMLMarkerTrackerResultsFoundArray -= OnMLMarkerTrackerResultsFoundArray;
    }

    private void OnMLMarkerTrackerResultsFoundArray(MLMarkerTracker.MarkerData[] dataArray)
    {
        Debug.Log("MARKER TRACKER FOUND ARRAY, PROCESSING...");
        foreach (MLMarkerTracker.MarkerData data in dataArray)
        {
            ProcessSingleMarker(data);
        }
    }

    private void ProcessSingleMarker(MLMarkerTracker.MarkerData data)
    {
        string id = "";
        float markerSize = .01f;

        switch (data.Type)
        {
            case MLMarkerTracker.MarkerType.Aruco_April:
                id = data.ArucoData.Id.ToString();
                markerSize = ArucoMarkerSize;
                break;

            case MLMarkerTracker.MarkerType.QR:
                id = _asciiEncoder.GetString(data.BinaryData.Data, 0, data.BinaryData.Data.Length);
                markerSize = QRCodeSize;
                break;
            case MLMarkerTracker.MarkerType.EAN_13:
            case MLMarkerTracker.MarkerType.UPC_A:
                id = _asciiEncoder.GetString(data.BinaryData.Data, 0, data.BinaryData.Data.Length);
                Debug.Log("No pose is given for marker type " + data.Type + " value is " + data.BinaryData.Data);
                break;
        }

        if (!string.IsNullOrEmpty(id))
        {
            if (_markers.ContainsKey(id))
            {
                GameObject marker = _markers[id];
                marker.transform.position = data.Pose.position;
                marker.transform.rotation = data.Pose.rotation;
            }
            else
            {
                //Create a primitive cube
                GameObject marker = GameObject.CreatePrimitive(PrimitiveType.Cube);
                //Render the cube with the default URP shader
                //marker.AddComponent<Renderer>();
                //marker.GetComponent<Renderer>().material = new Material(Shader.Find("Universal Render Pipeline/Lit"));

                marker.transform.localScale = new Vector3(markerSize, markerSize, markerSize);
                marker.transform.position = data.Pose.position;
                marker.transform.rotation = data.Pose.rotation;
                Debug.Log($"CREATING CUBE AT POSITION {marker.transform.position}");
                _markers.Add(id, marker);
            }
        }
    }
#endif
}

hi @cfeist ,
thank you for your response!

I'm using a code very simple to the one you've posted, as suggested in magic leap examples i'm able to start the marker tracking with custom setting.
My problem is similar to the one in this post: Vuforia cannot be used together with ML2 Marker Tracking - Vuforia Engine - Magic Leap 2 Developer Forums,
but i'm not able to maintain Vuforia working even if i use World-Cameras for ML Marker Tracking. Is it possible that vuforia now uses even world cameras for tracking?

Ahh I see.

I'm still working on getting you a good answer here!

Are you using Magic Leap OpenXR for this project?

@stradiot95

After looking into it a bit more, Vuforia hasn't changed their use of the camera's to my knowledge.
Even so, it should still be possible to use Vuforia alongside ML Marker Tracking.

I was able to use ML Marker Tracking and Vuforia at the same time with no issue.

I used this as my marker tracking script.

using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.XR.MagicLeap;

public class MarkerTrackerExample : MonoBehaviour
{
    public float QrCodeMarkerSize = 0.1f;
    public float ArucoMarkerSize = 0.1f;
    public MLMarkerTracker.MarkerType Type = MLMarkerTracker.MarkerType.QR;
    public MLMarkerTracker.ArucoDictionaryName ArucoDict = MLMarkerTracker.ArucoDictionaryName.DICT_5X5_100;
    public MLMarkerTracker.Profile Profile = MLMarkerTracker.Profile.Default;

    private Dictionary<string, GameObject> _markers = new Dictionary<string, GameObject>();
    private ASCIIEncoding _asciiEncoder = new System.Text.ASCIIEncoding();


#if UNITY_ANDROID
    private void OnEnable()
    {
        MLMarkerTracker.OnMLMarkerTrackerResultsFound += OnTrackerResultsFound;
    }

    private void Start()
    {
        MLMarkerTracker.TrackerSettings trackerSettings = MLMarkerTracker.TrackerSettings.Create(
            true, Type, QrCodeMarkerSize, ArucoDict, ArucoMarkerSize, Profile);
        _ = MLMarkerTracker.SetSettingsAsync(trackerSettings);
    }

    private void OnDisable()
    {
        MLMarkerTracker.OnMLMarkerTrackerResultsFound -= OnTrackerResultsFound;
        _ = MLMarkerTracker.StopScanningAsync();
    }

    private void OnTrackerResultsFound(MLMarkerTracker.MarkerData data)
    {
        string id = "";
        float markerSize = .01f;

        switch (data.Type)
        {
            case MLMarkerTracker.MarkerType.Aruco_April:
                id = data.ArucoData.Id.ToString();
                markerSize = ArucoMarkerSize;
                break;

            case MLMarkerTracker.MarkerType.QR:
                id = _asciiEncoder.GetString(data.BinaryData.Data, 0, data.BinaryData.Data.Length);
                markerSize = QrCodeMarkerSize;
                break;
            case MLMarkerTracker.MarkerType.EAN_13:
            case MLMarkerTracker.MarkerType.UPC_A:
                id = _asciiEncoder.GetString(data.BinaryData.Data, 0, data.BinaryData.Data.Length);
                Debug.Log("No pose is given for marker type " + data.Type + " value is " + data.BinaryData.Data);
                break;
        }

        if (!string.IsNullOrEmpty(id))
        {
            if (_markers.ContainsKey(id))
            {
                GameObject marker = _markers[id];
                marker.transform.position = data.Pose.position;
                marker.transform.rotation = data.Pose.rotation;
            }
            else
            {
                //Create a primitive cube
                GameObject marker = GameObject.CreatePrimitive(PrimitiveType.Cube);
                marker.transform.position = data.Pose.position;
                marker.transform.rotation = data.Pose.rotation;
                marker.transform.localScale = new Vector3(markerSize, markerSize, markerSize);
                _markers.Add(id, marker);
            }
        }
    }
#endif
}

When using this, please ensure that you set the profile to Large_FOV in the inspector

image (6)

1 Like

In the current project I'm still with the old sdk, but this is the last one, so maybe I can directly upgrade.
Anyway I will try with built in profiles instead of creating a custom one. Let u know asap!
And thank you very much for the inspection and tests :smiley:

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.