Beispiel #1
0
        /// <summary>
        /// Updates a collection of points constituting a pattern for recognition. Zero point is at the center.
        /// </summary>
        /// <param name="patternSize">For chessbord, count the inner corners</param>
        /// <param name="transform">The transform must be scaled to fit the aspect of the pattern</param>
        /// <param name="patternType">OpenCv supported pattern type</param>
        /// <param name="patternPointsWorldSpace">Point collection</param>
        public static void UpdateWorldSpacePatternPoints(Vector2Int patternSize, Matrix4x4 patternToWorldMatrix, PatternType patternType, Vector2 patternBorderSizeUV, ref MatOfPoint3f pointsWorldSpace)
        {
            bool isAsym = patternType == PatternType.AsymmetricCircleGrid;

            // Instantiate array.
            int cornerCount = patternSize.y * patternSize.x;

            if (pointsWorldSpace == null || pointsWorldSpace.rows() != cornerCount)
            {
                pointsWorldSpace = new MatOfPoint3f();
                pointsWorldSpace.alloc(cornerCount);
            }

            // Fill.
            int     c    = 0;
            Vector2 size = Vector2.one - patternBorderSizeUV * 2;
            Vector2 step = new Vector2(size.x / (patternSize.x - 1f + (isAsym ? 0.5f : 0)), size.y / (patternSize.y - 1f));

            for (int ny = 0; ny < patternSize.y; ny++)
            {
                float y = 1 - patternBorderSizeUV.y - ny * step.y - 0.5f;
                for (int nx = 0; nx < patternSize.x; nx++, c++)
                {
                    float   x     = patternBorderSizeUV.x + nx * step.x - 0.5f;
                    Vector3 point = new Vector3(x, y, 0);
                    if (isAsym && ny % 2 == 1)
                    {
                        point.x += step.x * 0.5f;
                    }
                    point = patternToWorldMatrix.MultiplyPoint3x4(point);
                    pointsWorldSpace.WriteVector3(point, c);
                }
            }
        }
Beispiel #2
0
        void UpdateCirclePatternSize()
        {
            if (_state == State.Initiating || _state == State.BlindCalibration)
            {
                _circlePatternSize = defaultCirclesPatternSize;
            }
            else
            {
                const int circlePatternSizeYMin = 7;
                const int desiredPixelsPerCirclePatternSegment = 25;                                               // 50px is recommended, but for a 720p camera, this will give too fex dots.
                float     desiredCirclePatternNumAspect        = _chessPatternSize.x / (_chessPatternSize.y) / 2f; // 3f / 4f / 2f;

                float patternDistance             = Vector3.Distance(_mainCamera.transform.position, _circlePatternTransform.position);
                float patternHeight               = _chessPatternTransform.localScale.y;
                float viewHeightAtPatternPosition = Mathf.Tan(_mainCamera.fieldOfView * Mathf.Deg2Rad * 0.5f) * patternDistance * 2;
                int   circlePatternPixelHeight    = (int)((patternHeight / viewHeightAtPatternPosition) * _cameraTexture.height);
                int   optimalPatternSizeY         = Mathf.Max(circlePatternSizeYMin, Mathf.FloorToInt(circlePatternPixelHeight / (float)desiredPixelsPerCirclePatternSegment));
                int   optimalPatternSizeX         = Mathf.FloorToInt(optimalPatternSizeY * desiredCirclePatternNumAspect);
                _circlePatternSize = TrackingToolsHelper.GetClosestValidPatternSize(new Vector2Int(optimalPatternSizeX, optimalPatternSizeY), TrackingToolsHelper.PatternType.AsymmetricCircleGrid);
            }

            _circlePatternPointCount = _circlePatternSize.x * _circlePatternSize.y;

            if (_circlePointsProjectorRenderImageMat != null && _circlePointsProjectorRenderImageMat.rows() == _circlePatternPointCount)
            {
                return;
            }

            if (_circlePointsProjectorRenderImageMat != null)
            {
                _circlePointsProjectorRenderImageMat.release();
            }
            if (_circlePointsRealModelMat != null)
            {
                _circlePointsRealModelMat.release();
            }
            if (_circlePointsDetectedWorldMat != null)
            {
                _circlePointsDetectedWorldMat.release();
            }
            _circlePointsProjectorRenderImageMat.alloc(_circlePatternPointCount);
            _circlePointsRealModelMat.alloc(_circlePatternPointCount);
            _circlePointsDetectedWorldMat.alloc(_circlePatternPointCount);

            // Render pattern to texture.
            _circlePatternBorderSizeUV = TrackingToolsHelper.RenderPattern(_circlePatternSize, TrackingToolsHelper.PatternType.AsymmetricCircleGrid, 2048, ref _circlePatternTexture, ref _patternRenderMaterial, circlePatternBorder, true);
            _circlePatternBoardMaterial.mainTexture = _circlePatternTexture;

            // Update transform to match.
            float circleTextureAspect = _circlePatternTexture.width / (float)_circlePatternTexture.height;
            float borderProportion    = (_circlePatternSize.y - 1 + 2f) / (_circlePatternSize.y - 1f);              // Asymmetric patttern tiles are half the height.

            _circlePatternTransform.localScale = new Vector3(circleTextureAspect, 1, 0) * _chessPatternTransform.localScale.y * borderProportion;

            if (_state == State.TrackedCalibration || _state == State.Testing)
            {
                _circlePatternTransform.localPosition = -Vector3.right * (_chessCirclePatternCenterOffset / 1000f);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Creates a collection of points constituting a pattern for recognition. Measured in millimeters.
        /// In real space, y increases upwards. Since the first point is at upper-left corner, y starts high and decrease.
        /// </summary>
        /// <param name="patternSize">For chessbord, count the inner corners</param>
        /// <param name="tileSize">Measured in millimeters</param>
        /// <param name="patternType">OpenCv supported pattern type</param>
        /// <returns>Points in real space (mm)</returns>
        public static MatOfPoint3f CreateRealModelPatternPoints(Vector2Int patternSize, int tileSize, PatternType patternType)
        {
            bool isAsym = patternType == PatternType.AsymmetricCircleGrid;

            int          cornerCount            = patternSize.y * patternSize.x;
            Vector2Int   boardSize              = patternSize * tileSize;
            MatOfPoint3f chessCornersModelSpace = new MatOfPoint3f();

            chessCornersModelSpace.alloc(cornerCount);
            int c = 0;

            _temp3d[2] = 0;
            for (int y = 0; y < patternSize.y; y++)
            {
                for (int x = 0; x < patternSize.x; x++, c++)
                {
                    _temp3d[0] = x * tileSize + (isAsym && y % 2 == 1 ? tileSize * 0.5 : 0);
                    _temp3d[1] = boardSize.y - y * tileSize * (isAsym ? 0.5f : 1f);
                    chessCornersModelSpace.put(c, 0, _temp3d);
                }
            }
            return(chessCornersModelSpace);
        }
Beispiel #4
0
        void Awake()
        {
            // Create UI.
            if (!_containerUI)
            {
                _containerUI = new GameObject("CameraPoser").AddComponent <RectTransform>();
                _containerUI.transform.SetParent(_canvas.transform);
            }
            CanvasGroup wrapperGroup = _containerUI.GetComponent <CanvasGroup>();

            if (!wrapperGroup)
            {
                wrapperGroup = _containerUI.gameObject.AddComponent <CanvasGroup>();
            }
            wrapperGroup.alpha = _alpha;
            Image backgroundImage = new GameObject("Background").AddComponent <Image>();

            backgroundImage.transform.SetParent(_containerUI.transform);
            _rawImageUI = new GameObject("CameraImage").AddComponent <RawImage>();
            _rawImageUI.transform.SetParent(_containerUI.transform);
            _rawImageUI.uvRect         = _flipTexture ? new UnityEngine.Rect(0, 1, 1, -1) : new UnityEngine.Rect(0, 0, 1, 1);
            _rawImageRect              = _rawImageUI.GetComponent <RectTransform>();
            _uiMaterial                = new Material(Shader.Find("Hidden/SingleChannelTexture"));
            _rawImageUI.material       = _uiMaterial;
            _aspectFitterUI            = _rawImageUI.gameObject.AddComponent <AspectRatioFitter>();
            _aspectFitterUI.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth;
            backgroundImage.color      = Color.black;
            ExpandRectTransform(_containerUI);
            ExpandRectTransform(backgroundImage.GetComponent <RectTransform>());
            ExpandRectTransform(_rawImageRect);
            _userPointRects  = new RectTransform[pointCount];
            _userPointImages = new Image[pointCount];
            for (int p = 0; p < pointCount; p++)
            {
                GameObject pointObject = new GameObject("Point" + p);
                pointObject.transform.SetParent(_rawImageRect);
                Image pointImage = pointObject.AddComponent <Image>();
                pointImage.color = Color.cyan;
                RectTransform pointRect = pointObject.GetComponent <RectTransform>();
                pointRect.sizeDelta = Vector2.one * 5;
                SetAnchoredPosition(pointRect, defaultPointPositions[p]);
                pointRect.anchoredPosition = Vector3.zero;
                Text pointLabel = new GameObject("Label").AddComponent <Text>();
                pointLabel.text = p.ToString();
                pointLabel.transform.SetParent(pointRect);
                pointLabel.rectTransform.anchoredPosition = Vector2.zero;
                pointLabel.rectTransform.sizeDelta        = new Vector2(_fontSize, _fontSize) * 2;
                pointLabel.font     = _font;
                pointLabel.fontSize = _fontSize;
                _userPointRects[p]  = pointRect;
                _userPointImages[p] = pointImage;
            }

            // Hide.
            //if( !_interactable ) _containerUI.transform.gameObject.SetActive( false );

            // Prepare OpenCV.
            _noDistCoeffs         = new MatOfDouble(new double[] { 0, 0, 0, 0 });
            _rVec                 = new Mat();
            _tVec                 = new Mat();
            _anchorPointsImage    = new Point[pointCount];
            _anchorPointsWorld    = new Point3[pointCount];
            _anchorPointsImageMat = new MatOfPoint2f();
            _anchorPointsWorldMat = new MatOfPoint3f();
            _anchorPointsImageMat.alloc(pointCount);
            _anchorPointsWorldMat.alloc(pointCount);
            for (int p = 0; p < pointCount; p++)
            {
                _anchorPointsImage[p] = new Point();
                _anchorPointsWorld[p] = new Point3();
            }

            // Load files.
            if (Intrinsics.TryLoadFromFile(_intrinsicsFileName, out _intrinsics))
            {
                enabled = false;
                return;
            }
            LoadCircleAnchorPoints();

            // Update variables.
            if (!Application.isEditor)
            {
                OnValidate();
            }
        }