using OpenCvSharp; using OpenCvSharp.Aruco; using TraceCad.Vision.Calibration; using Xunit; namespace TraceCad.Tests; public sealed class SheetCalibratorTests { [Fact] public void CalibrateDetectsSyntheticA4SheetMarkers() { const double pixelsPerMillimetre = 4.0; var template = ReferenceSheetTemplate.DefaultA4(); using var sheet = new Mat( (int)Math.Round(template.HeightMm * pixelsPerMillimetre), (int)Math.Round(template.WidthMm * pixelsPerMillimetre), MatType.CV_8UC3, Scalar.White); var dictionary = CvAruco.GetPredefinedDictionary(PredefinedDictionaryName.Dict5X5_1000); foreach (var marker in template.Markers) { using var markerImage = new Mat(); dictionary.GenerateImageMarker( marker.Id, (int)Math.Round(marker.SizeMm * pixelsPerMillimetre), markerImage, 1); using var markerColor = new Mat(); Cv2.CvtColor(markerImage, markerColor, ColorConversionCodes.GRAY2BGR); var target = new Rect( (int)Math.Round(marker.TopLeftMm.X * pixelsPerMillimetre), (int)Math.Round(marker.TopLeftMm.Y * pixelsPerMillimetre), markerColor.Width, markerColor.Height); markerColor.CopyTo(new Mat(sheet, target)); } var tempDirectory = Directory.CreateTempSubdirectory("easytrace-calibration-test-").FullName; try { var imagePath = Path.Combine(tempDirectory, "sheet.png"); Cv2.ImWrite(imagePath, sheet); var result = new SheetCalibrator().Calibrate(imagePath, tempDirectory, template); Assert.True(result.Success, result.Message); Assert.Equal(8, result.MatchedMarkerCount); Assert.Equal(0.125, result.MmPerPixel, 9); Assert.Equal("perspective + marker residual warp", result.CorrectionMode); Assert.True(File.Exists(result.CorrectedImagePath)); } finally { Directory.Delete(tempDirectory, recursive: true); } } }