using CCDCount.MODEL.ShuLiModel; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CCDCount.DLL.Tools { public static class LineScanCameraCalibrator { /// /// 计算线阵相机X和Y方向的单像素精度 /// 线阵相机在X方向(像素方向)和Y方向(扫描方向)有不同的缩放系数 /// /// 已知物理距离的点对集合 /// 实际物理距离(单位:mm) /// 包含X和Y方向单像素精度的结构体 public static PixelScale CalculateLineScanPixelScale(List knownPairs, double actualDistance) { if (knownPairs == null || knownPairs.Count == 0) throw new ArgumentException("至少需要一个点对来进行校准"); List xScales = new List(); List yScales = new List(); foreach (var pair in knownPairs) { int deltaX = pair.Point2.X - pair.Point1.X; int deltaY = pair.Point2.Y - pair.Point1.Y; // 计算像素欧几里得距离 double pixelDistance = Math.Sqrt(deltaX * deltaX + deltaY * deltaY); if (pixelDistance == 0) continue; // 避免除零错误 // 计算每像素的物理距离(缩放因子) double scalePerPixel = actualDistance / pixelDistance; // 对于线阵相机,我们需要根据X和Y方向的贡献来分解缩放因子 // X方向精度 = 总缩放因子 * |ΔX| / 像素距离 // Y方向精度 = 总缩放因子 * |ΔY| / 像素距离 if (Math.Abs(deltaX) > double.Epsilon) { double xScale = scalePerPixel * Math.Abs(deltaX) / pixelDistance; xScales.Add(xScale); } if (Math.Abs(deltaY) > double.Epsilon) { double yScale = scalePerPixel * Math.Abs(deltaY) / pixelDistance; yScales.Add(yScale); } } // 计算平均值作为最终精度 double avgXScale = xScales.Count > 0 ? xScales.Average() : 1.0; double avgYScale = yScales.Count > 0 ? yScales.Average() : 1.0; return new PixelScale(avgXScale, avgYScale); } /// /// 使用更精确的方法计算线阵相机的像素精度 /// 分别处理纯X方向、纯Y方向和对角线方向的点对 /// /// 纯水平方向点对(Y坐标相同) /// 纯垂直方向点对(X坐标相同) /// 对角线方向点对 /// 实际物理距离(单位:mm) /// 包含X和Y方向单像素精度的结构体 public static PixelScale CalculatePreciseLineScanPixelScale( List horizontalPairs, List verticalPairs, List diagonalPairs, double actualDistance) { double xScale = 1.0, yScale = 1.0; // 优先使用纯水平方向点对计算X方向精度 if (horizontalPairs != null && horizontalPairs.Count > 0) { var xScales = new List(); foreach (var pair in horizontalPairs) { if (pair.Point1.Y != pair.Point2.Y) continue; // 确保是水平方向 int deltaX = pair.Point2.X - pair.Point1.X; if (Math.Abs(deltaX) > 0) { xScales.Add(actualDistance / Math.Abs(deltaX)); } } if (xScales.Count > 0) xScale = xScales.Average(); } // 优先使用纯垂直方向点对计算Y方向精度 if (verticalPairs != null && verticalPairs.Count > 0) { var yScales = new List(); foreach (var pair in verticalPairs) { if (pair.Point1.X != pair.Point2.X) continue; // 确保是垂直方向 int deltaY = pair.Point2.Y - pair.Point1.Y; if (Math.Abs(deltaY) > 0) { yScales.Add(actualDistance / Math.Abs(deltaY)); } } if (yScales.Count > 0) yScale = yScales.Average(); } // 如果缺少某个方向的纯方向点对,使用对角线点对进行补充 if (horizontalPairs == null || horizontalPairs.Count == 0) { // 从对角线点对中估算X方向精度 if (diagonalPairs != null && diagonalPairs.Count > 0) { var xScalesFromDiagonal = new List(); foreach (var pair in diagonalPairs) { int deltaX = pair.Point2.X - pair.Point1.X; int deltaY = pair.Point2.Y - pair.Point1.Y; double pixelDistance = Math.Sqrt(deltaX * deltaX + deltaY * deltaY); if (pixelDistance > 0) { double scalePerPixel = actualDistance / pixelDistance; if (Math.Abs(deltaX) > double.Epsilon) { double xScaleFromDiagonal = scalePerPixel * Math.Abs(deltaX) / pixelDistance; xScalesFromDiagonal.Add(xScaleFromDiagonal); } } } if (xScalesFromDiagonal.Count > 0 && xScale == 1.0) // 只在没有纯水平点对时更新 xScale = xScalesFromDiagonal.Average(); } } if (verticalPairs == null || verticalPairs.Count == 0) { // 从对角线点对中估算Y方向精度 if (diagonalPairs != null && diagonalPairs.Count > 0) { var yScalesFromDiagonal = new List(); foreach (var pair in diagonalPairs) { int deltaX = pair.Point2.X - pair.Point1.X; int deltaY = pair.Point2.Y - pair.Point1.Y; double pixelDistance = Math.Sqrt(deltaX * deltaX + deltaY * deltaY); if (pixelDistance > 0) { double scalePerPixel = actualDistance / pixelDistance; if (Math.Abs(deltaY) > double.Epsilon) { double yScaleFromDiagonal = scalePerPixel * Math.Abs(deltaY) / pixelDistance; yScalesFromDiagonal.Add(yScaleFromDiagonal); } } } if (yScalesFromDiagonal.Count > 0 && yScale == 1.0) // 只在没有纯垂直点对时更新 yScale = yScalesFromDiagonal.Average(); } } return new PixelScale(xScale, yScale); } /// /// 使用已知的像素精度计算两点间的物理距离 /// /// 第一个点 /// 第二个点 /// 像素精度 /// 物理距离(单位:mm) public static double CalculatePhysicalDistance(Point point1, Point point2, PixelScale scale) { int deltaX = point2.X - point1.X; int deltaY = point2.Y - point1.Y; // 使用各自的像素精度计算X和Y方向的物理距离 double physicalDistanceX = Math.Abs(deltaX) * scale.XScale; double physicalDistanceY = Math.Abs(deltaY) * scale.YScale; // 使用勾股定理计算实际距离 return Math.Sqrt( Math.Pow(physicalDistanceX, 2) + Math.Pow(physicalDistanceY, 2) ); } /// /// 自动分类点对为水平、垂直和对角线方向 /// /// 所有点对 /// 输出:纯水平方向点对 /// 输出:纯垂直方向点对 /// 输出:对角线方向点对 public static void ClassifyPointPairs( List allPairs, out List horizontalPairs, out List verticalPairs, out List diagonalPairs) { horizontalPairs = new List(); verticalPairs = new List(); diagonalPairs = new List(); foreach (var pair in allPairs) { int deltaX = pair.Point2.X - pair.Point1.X; int deltaY = pair.Point2.Y - pair.Point1.Y; if (deltaY == 0 && Math.Abs(deltaX) > 0) { // 水平方向点对(Y坐标相同) horizontalPairs.Add(pair); } else if (deltaX == 0 && Math.Abs(deltaY) > 0) { // 垂直方向点对(X坐标相同) verticalPairs.Add(pair); } else { // 对角线方向点对 diagonalPairs.Add(pair); } } } } /// /// 存储X和Y方向的像素精度 /// public struct PixelScale { public double XScale { get; set; } // X方向单像素精度 (mm/pixel) public double YScale { get; set; } // Y方向单像素精度 (mm/pixel) public PixelScale(double xScale, double yScale) { XScale = xScale; YScale = yScale; } public override string ToString() { return $"XScale: {XScale:F6} mm/pixel, YScale: {YScale:F6} mm/pixel"; } } }