OpenCV 标记 Z 轴不正确变换
OpenCV Marker Z axis incorrect transform
我在 OSX 上使用 C#、.NET Core 2.1 和 OpenCvSharp 库。
我正在尝试将标记轴很好地打印在摄像机镜头上,但不幸的是我的 Z 轴变得异常。似乎无论我做了多少次校准(甚至尝试了 100 次),投影点总是在 (-1,-1,-1) 附近。
知道是什么原因造成的吗?下面的代码。
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);
}
}
}
已排序,需要从 0.025f
更改为 1
var objp = MatOfPoint3f.FromArray(Create3DChessboardCorners(size, 1));
我在 OSX 上使用 C#、.NET Core 2.1 和 OpenCvSharp 库。
我正在尝试将标记轴很好地打印在摄像机镜头上,但不幸的是我的 Z 轴变得异常。似乎无论我做了多少次校准(甚至尝试了 100 次),投影点总是在 (-1,-1,-1) 附近。
知道是什么原因造成的吗?下面的代码。
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);
}
}
}
已排序,需要从 0.025f
更改为 1
var objp = MatOfPoint3f.FromArray(Create3DChessboardCorners(size, 1));