149 lines
4.8 KiB
C#
149 lines
4.8 KiB
C#
using System.Windows;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using Emgu.CV;
|
|
using Emgu.CV.CvEnum;
|
|
using Emgu.CV.Structure;
|
|
using XP.Calibration.Core;
|
|
|
|
namespace XP.Calibration.Views;
|
|
|
|
/// <summary>
|
|
/// 旋转中心检测实时显示窗口
|
|
/// </summary>
|
|
public partial class RotationCenterProgressWindow : Window
|
|
{
|
|
private readonly int _plotSize = 800;
|
|
private readonly List<CircleDetectionResult> _detections = new();
|
|
private Image<Bgr, byte> _canvas;
|
|
|
|
public RotationCenterProgressWindow()
|
|
{
|
|
InitializeComponent();
|
|
_canvas = new Image<Bgr, byte>(_plotSize, _plotSize, new Bgr(0, 0, 0));
|
|
DrawCrossHair();
|
|
UpdateDisplay();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加一帧检测结果并更新显示 | Add detection result and update display
|
|
/// </summary>
|
|
public void AddDetection(CircleDetectionResult detection, int frameIndex, int totalFrames, int nDetecU, int nDetecV)
|
|
{
|
|
if (!detection.Success) return;
|
|
_detections.Add(detection);
|
|
|
|
// 在画布上绘制圆形标记(使用绝对坐标映射到画布)
|
|
double scaleX = (double)_plotSize / nDetecU;
|
|
double scaleY = (double)_plotSize / nDetecV;
|
|
double scale = Math.Min(scaleX, scaleY);
|
|
|
|
int cx = (int)(detection.AbsCenterX * scale);
|
|
int cy = (int)(detection.AbsCenterY * scale);
|
|
int r = (int)(detection.Radius * scale);
|
|
|
|
// 画填充圆(白色标记物)
|
|
CvInvoke.Circle(_canvas, new System.Drawing.Point(cx, cy), r, new MCvScalar(255, 255, 255), -1);
|
|
// 画中心点
|
|
CvInvoke.Circle(_canvas, new System.Drawing.Point(cx, cy), 2, new MCvScalar(0, 0, 0), -1);
|
|
|
|
DrawCrossHair();
|
|
UpdateDisplay();
|
|
UpdateStatus($"Frame {frameIndex + 1}/{totalFrames} - OK (OffX={detection.OffsetX:F1}, OffY={detection.OffsetY:F1})",
|
|
(double)(frameIndex + 1) / totalFrames * 100);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 显示拟合圆结果 | Show fitted circle result
|
|
/// </summary>
|
|
public void ShowFitResult(CircleFitResult fit, int nDetecU, int nDetecV)
|
|
{
|
|
double scaleX = (double)_plotSize / nDetecU;
|
|
double scaleY = (double)_plotSize / nDetecV;
|
|
double scale = Math.Min(scaleX, scaleY);
|
|
|
|
// 拟合圆心(转换为绝对坐标后映射到画布)
|
|
double absFitCx = fit.CenterX + nDetecU / 2.0;
|
|
double absFitCy = fit.CenterY + nDetecV / 2.0;
|
|
|
|
int fcx = (int)(absFitCx * scale);
|
|
int fcy = (int)(absFitCy * scale);
|
|
int fr = (int)(fit.Radius * scale);
|
|
|
|
// 画拟合圆
|
|
CvInvoke.Circle(_canvas, new System.Drawing.Point(fcx, fcy), fr, new MCvScalar(0, 200, 255), 2);
|
|
// 画拟合中心
|
|
CvInvoke.DrawMarker(_canvas, new System.Drawing.Point(fcx, fcy),
|
|
new MCvScalar(0, 0, 255), MarkerTypes.Cross, 20, 2);
|
|
|
|
DrawCrossHair();
|
|
UpdateDisplay();
|
|
UpdateStatus($"Fit done: R={fit.Radius:F1}px, dX={fit.DeltaX_um:F1}um, dY={fit.DeltaY_um:F1}um, PathR={fit.PathRadius_um:F1}um", 100);
|
|
}
|
|
|
|
public void UpdateStatus(string message, double progress)
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
StatusText.Text = message;
|
|
ProgressBar.Value = progress;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存当前画布为图片 | Save current canvas to file
|
|
/// </summary>
|
|
public void SaveCanvas(string filePath)
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
_canvas.Save(filePath);
|
|
});
|
|
}
|
|
|
|
private void DrawCrossHair()
|
|
{
|
|
int mid = _plotSize / 2;
|
|
CvInvoke.Line(_canvas, new System.Drawing.Point(mid, 0), new System.Drawing.Point(mid, _plotSize),
|
|
new MCvScalar(80, 80, 80), 1);
|
|
CvInvoke.Line(_canvas, new System.Drawing.Point(0, mid), new System.Drawing.Point(_plotSize, mid),
|
|
new MCvScalar(80, 80, 80), 1);
|
|
}
|
|
|
|
private void UpdateDisplay()
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
DisplayImage.Source = ToBitmapSource(_canvas);
|
|
});
|
|
}
|
|
|
|
private static BitmapSource ToBitmapSource(Image<Bgr, byte> image)
|
|
{
|
|
int width = image.Width;
|
|
int height = image.Height;
|
|
int stride = width * 3;
|
|
byte[] pixels = new byte[stride * height];
|
|
|
|
for (int y = 0; y < height; y++)
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
int idx = y * stride + x * 3;
|
|
pixels[idx] = image.Data[y, x, 0]; // B
|
|
pixels[idx + 1] = image.Data[y, x, 1]; // G
|
|
pixels[idx + 2] = image.Data[y, x, 2]; // R
|
|
}
|
|
|
|
var bitmap = BitmapSource.Create(width, height, 96, 96,
|
|
PixelFormats.Bgr24, null, pixels, stride);
|
|
bitmap.Freeze();
|
|
return bitmap;
|
|
}
|
|
|
|
protected override void OnClosed(EventArgs e)
|
|
{
|
|
_canvas?.Dispose();
|
|
base.OnClosed(e);
|
|
}
|
|
}
|