plugin system docs
custom buttons for plugins calibration functions for Leeform
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
using System.Globalization;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using OpenCvSharp;
|
||||
using VisionBuilder.UI.RaspberryAcquisition.Models;
|
||||
using VisionBuilder.UI.RaspberryAcquisition.Services;
|
||||
|
||||
namespace VisionBuilder.UI.RaspberryAcquisition.ViewModels;
|
||||
|
||||
public partial class MainWindowViewModel : ObservableObject, IDisposable
|
||||
{
|
||||
private const string CalibrationFile = "calibration.json";
|
||||
|
||||
private ConfigurableLibcameraSource? _source;
|
||||
private CancellationTokenSource? _previewCts;
|
||||
private Mat? _lastFrame;
|
||||
private Mat? _cameraMatrix;
|
||||
private Mat? _distCoeffs;
|
||||
|
||||
[ObservableProperty] private Avalonia.Media.Imaging.Bitmap? _previewImage;
|
||||
[ObservableProperty] private string _statusText = "Stopped";
|
||||
[ObservableProperty] private int _frameCount;
|
||||
[ObservableProperty] private bool _isRunning;
|
||||
[ObservableProperty] private bool _isCalibrated;
|
||||
|
||||
[ObservableProperty] private string _width = "2028";
|
||||
[ObservableProperty] private string _height = "1520";
|
||||
[ObservableProperty] private string _shutterSpeed = "10000";
|
||||
[ObservableProperty] private string _framerate = "2";
|
||||
[ObservableProperty] private string _awbGainRed = "3.86";
|
||||
[ObservableProperty] private string _awbGainBlue = "1.46";
|
||||
[ObservableProperty] private string _saveDirectory = "/home/oem/captures";
|
||||
[ObservableProperty] private string _calibrationDirectory = "/home/oem/captures";
|
||||
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
TryLoadCalibration();
|
||||
}
|
||||
|
||||
private void TryLoadCalibration()
|
||||
{
|
||||
if (!File.Exists(CalibrationFile)) return;
|
||||
|
||||
try
|
||||
{
|
||||
(_cameraMatrix, _distCoeffs) = CameraCalibrationService.LoadCalibration(CalibrationFile);
|
||||
IsCalibrated = true;
|
||||
StatusText = "Calibration loaded";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText = $"Calibration load error: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void StartCapture()
|
||||
{
|
||||
if (IsRunning) return;
|
||||
|
||||
var settings = BuildSettings();
|
||||
if (settings == null) return;
|
||||
|
||||
_source = new ConfigurableLibcameraSource(settings);
|
||||
_source.StatusChanged += status =>
|
||||
Dispatcher.UIThread.Post(() => StatusText = status);
|
||||
|
||||
_source.Start();
|
||||
IsRunning = true;
|
||||
|
||||
_previewCts = new CancellationTokenSource();
|
||||
_ = PreviewLoopAsync(_previewCts.Token);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void StopCapture()
|
||||
{
|
||||
if (!IsRunning) return;
|
||||
|
||||
_previewCts?.Cancel();
|
||||
_source?.Stop();
|
||||
_source?.Dispose();
|
||||
_source = null;
|
||||
IsRunning = false;
|
||||
StatusText = "Stopped";
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ApplySettings()
|
||||
{
|
||||
if (!IsRunning || _source == null) return;
|
||||
|
||||
var settings = BuildSettings();
|
||||
if (settings == null) return;
|
||||
|
||||
_source.UpdateSettings(settings);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SaveImage()
|
||||
{
|
||||
if (_lastFrame == null || _lastFrame.Empty()) return;
|
||||
|
||||
Directory.CreateDirectory(SaveDirectory);
|
||||
var filename = $"capture_{DateTime.Now:yyyyMMdd_HHmmss}.png";
|
||||
var path = Path.Combine(SaveDirectory, filename);
|
||||
Cv2.ImWrite(path, _lastFrame);
|
||||
StatusText = $"Saved: {filename}";
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CalibrateCamera()
|
||||
{
|
||||
try
|
||||
{
|
||||
StatusText = "Calibrating...";
|
||||
var data = CameraCalibrationService.Calibrate(CalibrationDirectory, new Size(9, 6));
|
||||
CameraCalibrationService.SaveCalibration(data, CalibrationFile);
|
||||
|
||||
_cameraMatrix?.Dispose();
|
||||
_distCoeffs?.Dispose();
|
||||
(_cameraMatrix, _distCoeffs) = CameraCalibrationService.LoadCalibration(CalibrationFile);
|
||||
|
||||
IsCalibrated = true;
|
||||
StatusText = $"Calibrated (RMS: {data.RmsError:F4})";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText = $"Calibration error: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PreviewLoopAsync(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested && _source != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var frame = await _source.GetImage(ct);
|
||||
|
||||
if (_cameraMatrix != null && _distCoeffs != null)
|
||||
{
|
||||
var corrected = new Mat();
|
||||
Cv2.Undistort(frame, corrected, _cameraMatrix, _distCoeffs);
|
||||
frame.Dispose();
|
||||
frame = corrected;
|
||||
}
|
||||
|
||||
_lastFrame?.Dispose();
|
||||
_lastFrame = frame;
|
||||
|
||||
var bitmap = ImageConverter.MatToAvaloniaBitmap(frame);
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
var old = PreviewImage;
|
||||
PreviewImage = bitmap;
|
||||
FrameCount = _source?.FrameCount ?? 0;
|
||||
old?.Dispose();
|
||||
});
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
StatusText = $"Preview error: {ex.Message}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CaptureSettings? BuildSettings()
|
||||
{
|
||||
if (!int.TryParse(Width, out var w) ||
|
||||
!int.TryParse(Height, out var h) ||
|
||||
!int.TryParse(ShutterSpeed, out var s) ||
|
||||
!int.TryParse(Framerate, out var f) ||
|
||||
!double.TryParse(AwbGainRed, CultureInfo.InvariantCulture, out var r) ||
|
||||
!double.TryParse(AwbGainBlue, CultureInfo.InvariantCulture, out var b))
|
||||
{
|
||||
StatusText = "Error: invalid settings values";
|
||||
return null;
|
||||
}
|
||||
|
||||
return new CaptureSettings
|
||||
{
|
||||
Width = w,
|
||||
Height = h,
|
||||
ShutterSpeed = s,
|
||||
Framerate = f,
|
||||
AwbGainRed = r,
|
||||
AwbGainBlue = b
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StopCapture();
|
||||
_lastFrame?.Dispose();
|
||||
_cameraMatrix?.Dispose();
|
||||
_distCoeffs?.Dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user