'Opencv for Unity - Camera position inaccurate by factor of ~2

I am having an issue getting accurate aruco pose estimation. The transform of the AR object relative to camera is a factor ~2 smaller than it should be. In the screenshot below, the camera is z=.40m away from the marker in real-space, but the AR object is only ~.20m away in virtual space.

I thought it might be something with the length parameters I measured off the chessboard or aruco markers?

I used these functions:

Aruco.estimatePoseSingleMarkers (corners, markerLength, camMatrix, distCoeffs, rvecs, tvecs);

where markerLength = 0.122m and is the distance across the 4x4 aruco (not including the black boarder)

    private void EstimatePoseCanonicalMarker (Mat rgbMat)
    {
        Aruco.estimatePoseSingleMarkers (corners, markerLength, camMatrix, distCoeffs, rvecs, tvecs);

        for (int i = 0; i < ids.total (); i++) {
            using (Mat rvec = new Mat (rvecs, new OpenCVForUnity.CoreModule.Rect (0, i, 1, 1)))
            using (Mat tvec = new Mat (tvecs, new OpenCVForUnity.CoreModule.Rect (0, i, 1, 1))) {
                // In this example we are processing with RGB color image, so Axis-color correspondences are X: blue, Y: green, Z: red. (Usually X: red, Y: green, Z: blue)
                Calib3d.drawFrameAxes (rgbMat, camMatrix, distCoeffs, rvec, tvec, markerLength * 0.5f);

                // This example can display the ARObject on only first detected marker.
                if (i == 0) {
                    UpdateARObjectTransform (rvec, tvec);
                }
            }
        }
    }

and:

CalcChessboardCorners (patternSize, squareSize, objectPoint, markerType);

where squareSize = .0245m and is the distance(m) between 1 square on the chessboard

    private void CalcChessboardCorners (Size patternSize, float squareSize, MatOfPoint3f corners, MarkerType markerType)
    {
        if ((int)(patternSize.width * patternSize.height) != corners.rows ()) {
            Debug.Log ("Invalid corners size.");
            corners.create ((int)(patternSize.width * patternSize.height), 1, CvType.CV_32FC3);
        }

        const int cn = 3;
        float[] cornersArr = new float[corners.rows () * cn];
        int width = (int)patternSize.width;
        int height = (int)patternSize.height;

        switch (markerType) {
        default:
        case MarkerType.ChessBoard:
        case MarkerType.CirclesGlid:
            for (int i = 0; i < height; ++i) {
                for (int j = 0; j < width; ++j) {
                    cornersArr [(i * width * cn) + (j * cn)] = j * squareSize;
                    cornersArr [(i * width * cn) + (j * cn) + 1] = i * squareSize;
                    cornersArr [(i * width * cn) + (j * cn) + 2] = 0;
                }
            }
            corners.put (0, 0, cornersArr);

            break;
        case MarkerType.AsymmetricCirclesGlid:
            for (int i = 0; i < height; ++i) {
                for (int j = 0; j < width; ++j) {
                    cornersArr [(i * width * cn) + (j * cn)] = (2 * j + i % 2) * squareSize;
                    cornersArr [(i * width * cn) + (j * cn) + 1] = i * squareSize;
                    cornersArr [(i * width * cn) + (j * cn) + 2] = 0;
                }
            }
            corners.put (0, 0, cornersArr);

            break;
        }
    }

I've tried doubling some of these values and recalibrating to see if it makes the z value close to .40m but it doesn't seem to change. Which makes me feel kind of clueless. I take about 50 calibration photos and they're pretty diverse. I try to capture a range of depth and angle on the camera.

Any ideas?

Thanks and let me know if you need more info.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source