| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- using System;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using Microsoft.Win32;
- using AutoFocusTool.Imaging;
- namespace AutoFocusTool
- {
- // 抓帧显示 / 实时预览 / 曝光增益 / 光源 / 存图
- public partial class MainWindow
- {
- private byte[] _lastFrame; // 最近一帧原始 BGR
- /// <summary>抓一帧并刷新显示+清晰度分。返回是否成功。</summary>
- private bool GrabAndShow()
- {
- if (_camera == null) { Log("无相机。"); return false; }
- int r = _camera.GrabRgb();
- if (r != 0) { Log($"抓帧失败(code={r})"); return false; }
- byte[] buf = _camera.GetSourceBuffer();
- if (buf == null) { Log("抓帧失败(缓冲为空,可能正在断开)"); return false; }
- _lastFrame = buf;
- // 中心 ROI(画面中央 50%)
- var roi = CenterRoi(_camWidth, _camHeight, 0.5);
- double score = Sharpness.Compute(buf, _camWidth, _camHeight, roi);
- var bmp = ImageConverter.ToBitmapSource(buf, _camWidth, _camHeight);
- Dispatcher.Invoke(() =>
- {
- ImgPreview.Source = bmp;
- TxtScore.Text = $"清晰度: {score:F1}";
- DrawRoiOverlay(roi);
- });
- return true;
- }
- private static System.Drawing.Rectangle CenterRoi(int w, int h, double frac)
- {
- int rw = (int)(w * frac), rh = (int)(h * frac);
- return new System.Drawing.Rectangle((w - rw) / 2, (h - rh) / 2, rw, rh);
- }
- // ── 抓一帧 ──
- private void BtnGrab_Click(object sender, RoutedEventArgs e)
- {
- LogAction("点击 抓一帧");
- Task.Run(() => GrabAndShow());
- }
- /// <summary>刷新"当前各参数值"显示(曝光/增益/Z/水平)。在UI线程调用。</summary>
- private void UpdateParamDisplay()
- {
- void Upd()
- {
- int exp = _camera?.Exposure ?? ParseInt(TxtExposure.Text, 0);
- string gain = $"R{ParseInt(TxtGainR.Text, 0)} G{ParseInt(TxtGainG.Text, 0)} B{ParseInt(TxtGainB.Text, 0)}";
- TxtCurValues.Text = $"当前值:曝光 {exp}×100µs({exp / 10.0}ms) | 增益 {gain} | Z {_lastZ} | 水平 {_lastH} | well {(_curWell > 0 ? _curWell.ToString() : "--")}";
- }
- if (Dispatcher.CheckAccess()) Upd(); else Dispatcher.BeginInvoke((Action)Upd);
- }
- // ── 实时预览 ──
- private void TglLive_Click(object sender, RoutedEventArgs e)
- {
- LogAction("点击 实时预览(切换)");
- if (TglLive.IsChecked == true)
- {
- _liveCts = new CancellationTokenSource();
- var token = _liveCts.Token;
- Log("实时预览开始。");
- Task.Run(async () =>
- {
- int frames = 0;
- var sw = System.Diagnostics.Stopwatch.StartNew();
- while (!token.IsCancellationRequested)
- {
- if (!_busy) GrabAndShow();
- frames++;
- if (sw.ElapsedMilliseconds >= 1000)
- {
- double fps = frames * 1000.0 / sw.ElapsedMilliseconds;
- Dispatcher.Invoke(() => TxtFps.Text = $"帧率: {fps:F1} fps");
- frames = 0; sw.Restart();
- }
- await Task.Delay(30, token).ContinueWith(_ => { });
- }
- }, token);
- }
- else
- {
- _liveCts?.Cancel();
- Log("实时预览停止。");
- }
- }
- // ── 曝光 ──
- private void BtnSetExp_Click(object sender, RoutedEventArgs e)
- {
- LogAction($"点击 设置曝光={TxtExposure.Text}");
- if (_camera == null) return;
- int exp = ParseInt(TxtExposure.Text, 400);
- int r = _camera.SetExposure(exp);
- Log($"设置曝光 {exp}×100µs = {exp / 10.0}ms (code={r})");
- UpdateParamDisplay();
- // P0-3: 设曝光后传感器需时间生效,等待+丢弃旧帧,再抓显示当前曝光的画面
- if (TglLive.IsChecked != true)
- Task.Run(() =>
- {
- Thread.Sleep(Math.Max(200, exp / 5)); // 至少2×曝光时间(单位100µs)
- if (_camera != null) _camera.GrabRgb(); // 丢弃旧曝光的帧
- GrabAndShow();
- });
- }
- // ── 增益 ──
- private void BtnSetGain_Click(object sender, RoutedEventArgs e)
- {
- LogAction($"点击 设置增益 R={TxtGainR.Text} G={TxtGainG.Text} B={TxtGainB.Text}");
- if (_camera == null) return;
- byte rr = (byte)ParseInt(TxtGainR.Text, 25);
- byte gg = (byte)ParseInt(TxtGainG.Text, 14);
- byte bb = (byte)ParseInt(TxtGainB.Text, 25);
- int r = _camera.SetGain(rr, gg, bb);
- Log($"设置增益 R{rr} G{gg} B{bb} (code={r})");
- UpdateParamDisplay();
- if (TglLive.IsChecked != true) Task.Run(() => GrabAndShow());
- }
- // ── 光源 ──
- private void BtnLedOn_Click(object sender, RoutedEventArgs e)
- {
- LogAction("点击 开光源");
- if (_motor == null) return;
- Task.Run(() => { _busy = true; bool ok = _motor.OpenLED(); _busy = false; Log($"开光源 {(ok ? "OK" : "失败")}"); });
- }
- private void BtnLedOff_Click(object sender, RoutedEventArgs e)
- {
- LogAction("点击 关光源");
- if (_motor == null) return;
- Task.Run(() => { _busy = true; bool ok = _motor.CloseLED(); _busy = false; Log($"关光源 {(ok ? "OK" : "失败")}"); });
- }
- // ── 存图 ──
- private void BtnSaveImg_Click(object sender, RoutedEventArgs e)
- {
- LogAction("点击 存图");
- if (_lastFrame == null) { Log("还没有图像。"); return; }
- var dlg = new SaveFileDialog
- {
- Filter = "BMP 图片|*.bmp",
- FileName = $"house{_current?.HouseSn}_{DateTime.Now:yyyyMMdd_HHmmss}.bmp"
- };
- if (dlg.ShowDialog() == true)
- {
- try
- {
- ImageConverter.SaveBmp(_lastFrame, _camWidth, _camHeight, dlg.FileName);
- Log($"已存图: {dlg.FileName}");
- }
- catch (Exception ex) { Log($"存图失败: {ex.Message}"); }
- }
- }
- }
- }
|