OpenCV标记Z轴错误转换

时间:2018-09-13 13:38:37

标签: c# .net opencv opencvsharp aruco

我在OSX上使用C#、. NET Core 2.1和OpenCvSharp库。

我正试图在相机镜头上很好地打印标记轴,但不幸的是我的Z轴疯了。似乎无论我进行了多少次校准(甚至尝试了100次),投影点始终都在(-1,-1,-1)附近。

任何想法可能是什么原因造成的?下面的代码。

Insane Z axis

private static async Task DetectMarkers(string output)
{
    var rms = 0.0;
    var calib = 100;
    var size = new Size(9, 6);
    var frameSize = Size.Zero;
    var distortion = new Mat();
    var imgPoints = new List<MatOfPoint2f>();
    var objPoints = new List<MatOfPoint3f>();
    var criteria = new TermCriteria(CriteriaType.Eps | CriteriaType.MaxIter, 30, 0.001);
    var objp = MatOfPoint3f.FromArray(Create3DChessboardCorners(size, 0.025f));
    using (var capture = new VideoCapture(0))
    using (var paramters = DetectorParameters.Create())
    using (var camera = new MatOfDouble(Mat.Eye(3, 3, MatType.CV_64FC1)))
    using (var dictionary = CvAruco.GetPredefinedDictionary(PredefinedDictionaryName.Dict4X4_50))
    {
        while (capture.Grab() && calib > 0)
        {
            using (var image = capture.RetrieveMat())
            using (var gray = new Mat())
            {
                frameSize = image.Size();
                Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);
                if (Cv2.FindChessboardCorners(gray, size, out Point2f[] corners))
                {
                    objPoints.Add(objp);
                    imgPoints.Add(MatOfPoint2f.FromArray(corners.ToArray()));
                    var corners2 = Cv2.CornerSubPix(gray, corners, new Size(11, 11), new Size(-1, -1), criteria);
                    Cv2.DrawChessboardCorners(image, size, corners2, true);
                    image.SaveImage(output);
                    calib--;
                    await Task.Delay(100);
                }
                image.SaveImage(output);
            }
        }
        rms = Cv2.CalibrateCamera(objPoints, imgPoints, frameSize, camera, distortion, out var rvectors, out var tvectors, CalibrationFlags.UseIntrinsicGuess | CalibrationFlags.FixK5);
        using (var newCamera = Cv2.GetOptimalNewCameraMatrix(camera, distortion, frameSize, 1, frameSize, out var roi))
        {
            await Task.Delay(1);
            while (capture.Grab())
            {
                using (var undistorted = new Mat())
                using (var image = capture.RetrieveMat())
                {
                    Cv2.Undistort(image, undistorted, camera, distortion, newCamera);
                    CvAruco.DetectMarkers(undistorted, dictionary, out Point2f[][] corners, out int[] ids, paramters, out Point2f[][] rejected);
                    if (ids.Any())
                    {
                        CvAruco.DrawDetectedMarkers(undistorted, corners, ids);
                        using (var rvecs = new Mat())
                        using (var tvecs = new Mat())
                        {
                            CvAruco.EstimatePoseSingleMarkers(corners, 0.065f, newCamera, distortion, rvecs, tvecs);
                            for (var i = 0; i < ids.Length; i++)
                            {
                                var rvec = rvecs.Get<Vec3d>(i);
                                var tvec = tvecs.Get<Vec3d>(i);
                                DrawAxis(undistorted, newCamera, distortion, rvec, tvec, 0.05f);
                            }
                        }
                    }
                    undistorted.SaveImage(output);
                }
            }
        }
    }
}

private static void DrawAxis(Mat image, InputArray camera, InputArray distortion, Vec3d rvec, Vec3d tvec, float length)
{
    if (image.Total() == 0 || (image.Channels() != 1 && image.Channels() != 3))
    {
        throw new ArgumentException(nameof(image));
    }
    if (length <= 0)
    {
        throw new ArgumentException(nameof(length));
    }
    // project axis points
    var axisPoints = new MatOfPoint3f()
    {
        new Point3f(0, 0, 0),
        new Point3f(length, 0, 0),
        new Point3f(0, length, 0),
        new Point3f(0, 0, length),
    };
    var imagePoints = new MatOfPoint2f();
    Cv2.ProjectPoints(axisPoints, InputArray.Create(new[] { rvec }), InputArray.Create(new[] { tvec }), camera, distortion, imagePoints);
    // draw axis lines
    Cv2.Line(image, imagePoints.Get<Point2f>(0), imagePoints.Get<Point2f>(1), new Scalar(0, 0, 255), 3);
    Cv2.Line(image, imagePoints.Get<Point2f>(0), imagePoints.Get<Point2f>(2), new Scalar(0, 255, 0), 3);
    Cv2.Line(image, imagePoints.Get<Point2f>(0), imagePoints.Get<Point2f>(3), new Scalar(255, 0, 0), 3);
}

private static IEnumerable<Point3f> Create3DChessboardCorners(Size boardSize, float squareSize)
{
    for (int y = 0; y < boardSize.Height; y++)
    {
        for (int x = 0; x < boardSize.Width; x++)
        {
            yield return new Point3f(x * squareSize, y * squareSize, 0);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

已排序,需要从0.025f更改为1

var objp = MatOfPoint3f.FromArray(Create3DChessboardCorners(size, 1));