private static CoordinateSystemGrid FindForLineCalibration(CalibrationHelper calibrationHelper) { CoordinateSystemGrid grid = new CoordinateSystemGrid(); RectangleF imageBounds = new RectangleF(PointF.Empty, calibrationHelper.ImageSize); // The clip window is an inflated version of the image to account for distortion. RectangleF clipWindow = imageBounds.CenteredScale(1.3f); // Create a fake plane to act as the user-defined projected plane. QuadrilateralF quadImage = new QuadrilateralF(imageBounds.Deflate(2.0f)); PointF a = calibrationHelper.GetPointFromRectified(quadImage.A); PointF b = calibrationHelper.GetPointFromRectified(quadImage.B); PointF d = calibrationHelper.GetPointFromRectified(quadImage.D); RectangleF plane = new RectangleF(0, 0, b.X - a.X, a.Y - d.Y); // Define the extended plane (for vanishing point replacement and drawing stop condition) as the reprojection of the whole image. QuadrilateralF extendedPlane = ReprojectImageBounds(calibrationHelper, new QuadrilateralF(imageBounds)); CalibrationPlane calibrator = new CalibrationPlane(); calibrator.Initialize(plane.Size, quadImage); PointF originImage = calibrationHelper.GetOrigin(); PointF originRectified = originImage; if (calibrationHelper.DistortionHelper != null && calibrationHelper.DistortionHelper.Initialized) { originRectified = calibrationHelper.DistortionHelper.Undistort(originImage); } calibrator.SetOrigin(originRectified); // From this point on we are mostly in the same situation as for plane calibration. // stepping size is the same in both directions. int targetSteps = 15; float width = extendedPlane.B.X - extendedPlane.A.X; float step = RangeHelper.FindUsableStepSize(width, targetSteps); CreateVerticalGridLines(grid, 0, -step, calibrator, clipWindow, plane, extendedPlane, true, false, PointF.Empty); CreateVerticalGridLines(grid, step, step, calibrator, clipWindow, plane, extendedPlane, true, false, PointF.Empty); CreateHorizontalGridLines(grid, 0, -step, calibrator, clipWindow, plane, extendedPlane, true, false, PointF.Empty); CreateHorizontalGridLines(grid, step, step, calibrator, clipWindow, plane, extendedPlane, true, false, PointF.Empty); return(grid); }
private static QuadrilateralF ReprojectImageBounds(CalibrationHelper calibrationHelper, QuadrilateralF quadImage) { // Project image bounds from image space to plane space, using the line calibration setup. // This can be used to define safe boundaries. // The method cannot be used with plane calibration as image points can be above the vanishing line. (reproject behind the camera). // The quad passed in is assumed to be a rectangle. if (calibrationHelper.CalibratorType != CalibratorType.Line) { throw new ArgumentException("Unsupported operation."); } PointF a = calibrationHelper.GetPointFromRectified(quadImage.A); PointF b = calibrationHelper.GetPointFromRectified(quadImage.B); PointF c = calibrationHelper.GetPointFromRectified(quadImage.C); PointF d = calibrationHelper.GetPointFromRectified(quadImage.D); QuadrilateralF plane = new QuadrilateralF(a, b, c, d); return(plane); }
private void CreateScatterPlot() { PlotModel model = new PlotModel(); model.PlotType = PlotType.Cartesian; model.Title = this.tbTitle.Text; double padding = 0.1; LinearAxis xAxis = new LinearAxis(); xAxis.MajorGridlineColor = OxyColor.FromArgb(40, 0, 0, 139); xAxis.MajorGridlineStyle = LineStyle.Solid; xAxis.MinorGridlineColor = OxyColor.FromArgb(20, 0, 0, 139); xAxis.MinorGridlineStyle = LineStyle.Solid; xAxis.Position = AxisPosition.Bottom; xAxis.MinimumPadding = 0.1; xAxis.MaximumPadding = 0.1; xAxis.Title = tbXAxis.Text; model.Axes.Add(xAxis); LinearAxis yAxis = new LinearAxis(); yAxis.MajorGridlineColor = OxyColor.FromArgb(40, 0, 0, 139); yAxis.MajorGridlineStyle = LineStyle.Solid; yAxis.MinorGridlineColor = OxyColor.FromArgb(20, 0, 0, 139); yAxis.MinorGridlineStyle = LineStyle.Solid; yAxis.MinimumPadding = 0.1; yAxis.MaximumPadding = 0.1; yAxis.Title = tbYAxis.Text; model.Axes.Add(yAxis); ScatterSeries series = new ScatterSeries(); series.MarkerType = MarkerType.Plus; series.MarkerStroke = OxyColors.Black; float yDataMinimum = float.MaxValue; float yDataMaximum = float.MinValue; float xDataMinimum = float.MaxValue; float xDataMaximum = float.MinValue; foreach (TimedPoint point in points) { PointF p = metadata.CalibrationHelper.GetPointAtTime(point.Point, point.T); series.Points.Add(new ScatterPoint(p.X, p.Y)); yDataMinimum = Math.Min(yDataMinimum, p.Y); yDataMaximum = Math.Max(yDataMaximum, p.Y); xDataMinimum = Math.Min(xDataMinimum, p.X); xDataMaximum = Math.Min(xDataMaximum, p.X); } model.Series.Add(series); if (metadata.CalibrationHelper.CalibratorType == CalibratorType.Plane) { cbCalibrationPlane.Checked = true; cbCalibrationPlane.Enabled = true; CalibrationHelper calibrator = metadata.CalibrationHelper; QuadrilateralF quadImage = calibrator.CalibrationByPlane_GetProjectedQuad(); PointF a = calibrator.GetPointFromRectified(quadImage.A); PointF b = calibrator.GetPointFromRectified(quadImage.B); PointF c = calibrator.GetPointFromRectified(quadImage.C); PointF d = calibrator.GetPointFromRectified(quadImage.D); rectangleAnnotation = new RectangleAnnotation(); rectangleAnnotation.MinimumX = a.X; rectangleAnnotation.MaximumX = b.X; rectangleAnnotation.MinimumY = d.Y; rectangleAnnotation.MaximumY = a.Y; rectangleAnnotation.Fill = OxyColor.FromArgb(96, 173, 223, 247); rectangleAnnotation.Layer = AnnotationLayer.BelowAxes; model.Annotations.Add(rectangleAnnotation); if (a.Y > yDataMaximum || d.Y < yDataMinimum) { yDataMaximum = Math.Max(yDataMaximum, a.Y); yDataMinimum = Math.Min(yDataMinimum, d.Y); double yPadding = (yDataMaximum - yDataMinimum) * padding; yAxis.Maximum = yDataMaximum + yPadding; yAxis.Minimum = yDataMinimum - yPadding; } if (b.X > xDataMaximum || a.X < xDataMinimum) { xDataMaximum = Math.Max(xDataMaximum, b.X); xDataMinimum = Math.Min(xDataMinimum, a.X); double xPadding = (xDataMaximum - xDataMinimum) * padding; xAxis.Maximum = xDataMaximum + xPadding; xAxis.Minimum = xDataMinimum - xPadding; } } else { cbCalibrationPlane.Checked = false; cbCalibrationPlane.Enabled = false; } plotScatter.Model = model; }
private static CoordinateSystemGrid FindForPlaneCalibration(CalibrationHelper calibrationHelper) { CoordinateSystemGrid grid = new CoordinateSystemGrid(); RectangleF imageBounds = new RectangleF(PointF.Empty, calibrationHelper.ImageSize); RectangleF clipWindow = imageBounds; CalibrationPlane calibrator = calibrationHelper.CalibrationByPlane_GetCalibrator(); RectangleF plane = new RectangleF(PointF.Empty, calibrator.Size); int targetSteps = 15; float stepVertical = 1.0f; float stepHorizontal = 1.0f; // The extended plane is used for vanishing point replacement and iteration stop condition. QuadrilateralF extendedPlane; bool orthogonal; if (!calibrator.QuadImage.IsRectangle) { // If perspective plane, define as 2n times the nominal plane centered on origin. orthogonal = false; float n = 4; PointF a = new PointF(-calibrator.Size.Width * n, calibrator.Size.Height * n); PointF b = new PointF(calibrator.Size.Width * n, calibrator.Size.Height * n); PointF c = new PointF(calibrator.Size.Width * n, -calibrator.Size.Height * n); PointF d = new PointF(-calibrator.Size.Width * n, -calibrator.Size.Height * n); extendedPlane = new QuadrilateralF(a, b, c, d); QuadrilateralF quadImage = calibrator.QuadImage; float projectedWidthLength = GeometryHelper.GetDistance(quadImage.A, quadImage.B); float scaledTargetHorizontal = targetSteps / (calibrationHelper.ImageSize.Width / projectedWidthLength); stepHorizontal = RangeHelper.FindUsableStepSize(plane.Width, scaledTargetHorizontal); float projectedHeightLength = GeometryHelper.GetDistance(quadImage.A, quadImage.D); float scaledTargetVertical = targetSteps / (calibrationHelper.ImageSize.Height / projectedHeightLength); stepVertical = RangeHelper.FindUsableStepSize(plane.Height, scaledTargetVertical); } else { // If flat plane (and no distortion) we know there is no way to get any vanishing point inside the image, // so we can safely use the whole image reprojection as an extended plane. orthogonal = true; QuadrilateralF quadImageBounds = new QuadrilateralF(imageBounds); PointF a = calibrationHelper.GetPointFromRectified(quadImageBounds.A); PointF b = calibrationHelper.GetPointFromRectified(quadImageBounds.B); PointF c = calibrationHelper.GetPointFromRectified(quadImageBounds.C); PointF d = calibrationHelper.GetPointFromRectified(quadImageBounds.D); extendedPlane = new QuadrilateralF(a, b, c, d); float width = extendedPlane.B.X - extendedPlane.A.X; stepHorizontal = RangeHelper.FindUsableStepSize(width, targetSteps); float height = extendedPlane.A.Y - extendedPlane.D.Y; stepVertical = RangeHelper.FindUsableStepSize(height, targetSteps); } //------------------------------------------------------------------------------------------------- // There is a complication with points behind the camera, as they projects above the vanishing line. // The general strategy is the following: // Find out if the vanishing point is inside the image. Reminder: parallel lines share the same vanishing point. // If it is not inside the image, there is no risk, so we take two points on the line and draw an infinite line that we clip against the image bounds. // If it is inside the image: // Take two points on the line and project them in image space. They are colinear with the vanishing point in image space. // Find on which side of the quadrilateral the vanishing point is. // If the vanishing point is above the quad, draw a ray from the top of the extended quad, down to infinity. // If the vanishing point is below the quad, draw a ray from the bottom of the extended quad, up to infinity. // // Stepping strategy: // We start at origin and progress horizontally and vertically until we find a gridline that is completely clipped out. //------------------------------------------------------------------------------------------------- // Vertical lines. PointF yVanish = new PointF(0, float.MinValue); bool yVanishVisible = false; Vector3 yv = calibrator.Project(new Vector3(0, 1, 0)); if (yv.Z != 0) { yVanish = new PointF(yv.X / yv.Z, yv.Y / yv.Z); yVanishVisible = clipWindow.Contains(yVanish); } CreateVerticalGridLines(grid, 0, -stepHorizontal, calibrator, clipWindow, plane, extendedPlane, orthogonal, yVanishVisible, yVanish); CreateVerticalGridLines(grid, stepHorizontal, stepHorizontal, calibrator, clipWindow, plane, extendedPlane, orthogonal, yVanishVisible, yVanish); // Horizontal lines PointF xVanish = new PointF(float.MinValue, 0); bool xVanishVisible = false; Vector3 xv = calibrator.Project(new Vector3(1, 0, 0)); if (xv.Z != 0) { xVanish = new PointF(xv.X / xv.Z, xv.Y / xv.Z); xVanishVisible = clipWindow.Contains(xVanish); } CreateHorizontalGridLines(grid, 0, -stepVertical, calibrator, clipWindow, plane, extendedPlane, orthogonal, xVanishVisible, xVanish); CreateHorizontalGridLines(grid, stepVertical, stepVertical, calibrator, clipWindow, plane, extendedPlane, orthogonal, xVanishVisible, xVanish); return(grid); }