private void ProcessMarkerUpdate()
        {
            HashSet <int> updatedMarkerIds = new HashSet <int>();

            foreach (var marker in markers)
            {
                updatedMarkerIds.Add(marker.Key);
                float size = 0;
                if (markerDetector.TryGetMarkerSize(marker.Key, out size))
                {
                    var markerTopLeftPosition = CalcTopLeftFromCenter(marker.Value.Position, marker.Value.Rotation, size);
                    var markerRotation        = marker.Value.Rotation;

                    if (showDebugVisuals)
                    {
                        GameObject detectedMarkerDebugVisual = null;
                        detectedMarkerDebugVisuals.TryGetValue(marker.Key, out detectedMarkerDebugVisual);
                        detectedMarkerDebugVisualHelper.CreateOrUpdateVisual(ref detectedMarkerDebugVisual, markerTopLeftPosition, markerRotation, size * Vector3.one);
                        detectedMarkerDebugVisuals[marker.Key] = detectedMarkerDebugVisual;
                    }

                    Vector3 arucoTopLeftPosition;
                    if (markerDetector is ArUcoMarkerDetector)
                    {
                        arucoTopLeftPosition = markerTopLeftPosition;
                    }
                    else
                    {
                        var originToQRCode = Matrix4x4.TRS(markerTopLeftPosition, markerRotation, Vector3.one);
                        arucoTopLeftPosition = originToQRCode.MultiplyPoint(new Vector3(-1.0f * ((2.0f * (size * markerPaddingRatio)) + (size)), 0, 0));
                    }
                    // We assume that the calculated marker has the same orientation as the detected code marker because they are on the same plane/2d calibration board.
                    var arucoRotation = marker.Value.Rotation;

                    if (showDebugVisuals)
                    {
                        GameObject arucoDebugVisual = null;
                        calculatedMarkerDebugVisuals.TryGetValue(marker.Key, out arucoDebugVisual);
                        calculatedMarkerDebugVisualHelper.CreateOrUpdateVisual(ref arucoDebugVisual, arucoTopLeftPosition, arucoRotation, size * Vector3.one);
                        calculatedMarkerDebugVisuals[marker.Key] = arucoDebugVisual;
                    }

                    var markerPair = new MarkerPair();
                    markerPair.id = marker.Key;
                    markerPair.qrCodeMarkerCorners = CalculateMarkerCorners(markerTopLeftPosition, markerRotation, size);
                    markerPair.arucoMarkerCorners  = CalculateMarkerCorners(arucoTopLeftPosition, arucoRotation, size);

                    lock (markerPairs)
                    {
                        markerPairs[marker.Key] = markerPair;
                    }
                }
            }

            RemoveUnobservedItemsAndDestroy(detectedMarkerDebugVisuals, updatedMarkerIds);
            RemoveUnobservedItemsAndDestroy(calculatedMarkerDebugVisuals, updatedMarkerIds);
        }
        private void ProcessQRCodeUpdate()
        {
            HashSet <int> updatedMarkerIds = new HashSet <int>();

            foreach (var marker in qrCodeMarkers)
            {
                updatedMarkerIds.Add(marker.Key);
                float size = 0;
                if (qrCodeMarkerDetector.TryGetMarkerSize(marker.Key, out size))
                {
                    var qrCodePosition = marker.Value.Position;
                    var qrCodeRotation = marker.Value.Rotation;

                    if (showDebugVisuals)
                    {
                        GameObject qrCodeDebugVisual = null;
                        qrCodeDebugVisuals.TryGetValue(marker.Key, out qrCodeDebugVisual);
                        qrCodeDebugVisualHelper.CreateOrUpdateVisual(ref qrCodeDebugVisual, qrCodePosition, qrCodeRotation, size * Vector3.one);
                        qrCodeDebugVisuals[marker.Key] = qrCodeDebugVisual;
                    }

                    var originToQRCode = Matrix4x4.TRS(qrCodePosition, qrCodeRotation, Vector3.one);
                    var arucoPosition  = originToQRCode.MultiplyPoint(new Vector3(-1.0f * ((2.0f * (size * markerPaddingRatio)) + (size)), 0, 0));
                    // We assume that the aruco marker has the same orientation as the qr code marker because they are on the same plane/2d calibration board.
                    var arucoRotation = marker.Value.Rotation;

                    if (showDebugVisuals)
                    {
                        GameObject arucoDebugVisual = null;
                        arucoDebugVisuals.TryGetValue(marker.Key, out arucoDebugVisual);
                        arucoDebugVisualHelper.CreateOrUpdateVisual(ref arucoDebugVisual, arucoPosition, arucoRotation, size * Vector3.one);
                        arucoDebugVisuals[marker.Key] = arucoDebugVisual;
                    }

                    var markerPair = new MarkerPair();
                    markerPair.id = marker.Key;
                    markerPair.qrCodeMarkerCorners = CalculateMarkerCorners(qrCodePosition, qrCodeRotation, size);
                    markerPair.arucoMarkerCorners  = CalculateMarkerCorners(arucoPosition, arucoRotation, size);

                    lock (markerPairs)
                    {
                        markerPairs[marker.Key] = markerPair;
                    }
                }
            }

            RemoveUnobservedItemsAndDestroy(qrCodeDebugVisuals, updatedMarkerIds);
            RemoveUnobservedItemsAndDestroy(arucoDebugVisuals, updatedMarkerIds);
        }