cell histogram

This commit is contained in:
EugeneTes
2026-04-07 14:52:20 +02:00
parent 371436d0c3
commit 931de47164
17 changed files with 917 additions and 11 deletions

View File

@@ -29,12 +29,12 @@
</Border>
<!-- Settings Panel -->
<Border DockPanel.Dock="Right" Width="220" Padding="12" Background="White">
<Border DockPanel.Dock="Right" Width="260" Padding="12" Background="White">
<ScrollViewer>
<StackPanel Spacing="8">
<TextBlock Text="Calibration Settings" FontWeight="Bold" FontSize="14" Foreground="Black" />
<Button Content="Calibrate" Command="{Binding RunCalibrationCommand}" Margin="0,4"
Background="Red" Foreground="White" FontWeight="Bold" />
<Button Content="Clear Images" Command="{Binding ClearCalibrationImagesCommand}" Margin="0,4"
@@ -53,13 +53,69 @@
</TextBlock>
<CheckBox Content="Apply Calibration" IsChecked="{Binding ApplyCalibration}"
IsEnabled="{Binding IsCalibrated}" Foreground="Black" Margin="0,4" />
<Separator Margin="0,8" />
<TextBlock Text="Pattern" FontWeight="Bold" FontSize="14" Foreground="Black" />
<TextBlock Text="Rows" Foreground="Black" />
<NumericUpDown Value="{Binding Rows}" Minimum="1" Maximum="200" Increment="1" FormatString="0" />
<TextBlock Text="Cols" Foreground="Black" />
<NumericUpDown Value="{Binding Cols}" Minimum="1" Maximum="200" Increment="1" FormatString="0" />
<TextBlock Text="Shape" Foreground="Black" />
<ComboBox ItemsSource="{Binding AvailableCellShapes}" SelectedItem="{Binding SelectedCellShape}" HorizontalAlignment="Stretch" />
<TextBlock Text="Padding (px)" Foreground="Black" />
<NumericUpDown Value="{Binding Padding}" Minimum="0" Maximum="500" Increment="1" FormatString="0" />
<Separator Margin="0,8" />
<TextBlock Text="ROI (px)" FontWeight="Bold" FontSize="14" Foreground="Black" />
<TextBlock Text="X" Foreground="Black" />
<NumericUpDown Value="{Binding RoiX}" Minimum="0" Maximum="100000" Increment="1" FormatString="0" />
<TextBlock Text="Y" Foreground="Black" />
<NumericUpDown Value="{Binding RoiY}" Minimum="0" Maximum="100000" Increment="1" FormatString="0" />
<TextBlock Text="Width" Foreground="Black" />
<NumericUpDown Value="{Binding RoiWidth}" Minimum="0" Maximum="100000" Increment="1" FormatString="0" />
<TextBlock Text="Height" Foreground="Black" />
<NumericUpDown Value="{Binding RoiHeight}" Minimum="0" Maximum="100000" Increment="1" FormatString="0" />
<Separator Margin="0,8" />
<Button Content="Set Reference" Command="{Binding SetReferenceHistogramCommand}" Margin="0,4"
Background="#2E7D32" Foreground="White" FontWeight="Bold" HorizontalAlignment="Stretch" />
<TextBlock Text="✓ Reference set" Foreground="LimeGreen" IsVisible="{Binding HasReferenceHistogram}" />
<TextBlock Text="Tolerance" Foreground="Black" Margin="0,4,0,0" />
<NumericUpDown Value="{Binding Tolerance}" Minimum="0" Maximum="1" Increment="0.05" FormatString="0.00" />
<Button Content="Test Pattern" Command="{Binding TestPatternCommand}" Margin="0,4"
Background="#1565C0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Stretch" />
<Separator Margin="0,8" />
<TextBlock Text="Recipe" FontWeight="Bold" FontSize="14" Foreground="Black" />
<TextBlock Foreground="Black">
<TextBlock.Text>
<MultiBinding StringFormat="Current: {0}">
<Binding Path="CurrentRecipeName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<Button Content="Save Recipe" Command="{Binding SaveRecipeCommand}" Margin="0,4"
Background="#6A1B9A" Foreground="White" FontWeight="Bold" HorizontalAlignment="Stretch" />
</StackPanel>
</ScrollViewer>
</Border>
<!-- Live Preview -->
<Border Background="#1A1A1A" Margin="4">
<Image Source="{Binding PreviewImage}" Stretch="Uniform" />
<Image x:Name="PreviewImageControl"
Source="{Binding PreviewImage}"
Stretch="Uniform" />
</Border>
</DockPanel>

View File

@@ -1,13 +1,22 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media.Imaging;
using LindtLeerformPlugin.ViewModels;
namespace LindtLeerformPlugin.Views;
public partial class CalibrationWindow : Window
{
private static readonly Cursor HandCursor = new(StandardCursorType.Hand);
private static readonly Cursor DefaultCursor = new(StandardCursorType.Arrow);
public CalibrationWindow()
{
InitializeComponent();
PreviewImageControl.PointerMoved += OnPreviewPointerMoved;
PreviewImageControl.PointerPressed += OnPreviewPointerPressed;
PreviewImageControl.PointerExited += OnPreviewPointerExited;
}
protected override void OnClosing(WindowClosingEventArgs e)
@@ -15,4 +24,64 @@ public partial class CalibrationWindow : Window
(DataContext as CalibrationWindowViewModel)?.Dispose();
base.OnClosing(e);
}
private (int x, int y)? ToImageCoordinates(Avalonia.Point pointerPos)
{
if (PreviewImageControl.Source is not Bitmap bitmap)
return null;
var ctrlSize = PreviewImageControl.Bounds.Size;
var imgSize = bitmap.Size;
if (ctrlSize.Width <= 0 || ctrlSize.Height <= 0 || imgSize.Width <= 0 || imgSize.Height <= 0)
return null;
var scale = System.Math.Min(ctrlSize.Width / imgSize.Width, ctrlSize.Height / imgSize.Height);
var displayW = imgSize.Width * scale;
var displayH = imgSize.Height * scale;
var offsetX = (ctrlSize.Width - displayW) / 2;
var offsetY = (ctrlSize.Height - displayH) / 2;
var imgX = (pointerPos.X - offsetX) / scale;
var imgY = (pointerPos.Y - offsetY) / scale;
if (imgX < 0 || imgY < 0 || imgX >= imgSize.Width || imgY >= imgSize.Height)
return null;
return ((int)imgX, (int)imgY);
}
private void OnPreviewPointerMoved(object? sender, PointerEventArgs e)
{
if (DataContext is not CalibrationWindowViewModel vm)
return;
var coords = ToImageCoordinates(e.GetPosition(PreviewImageControl));
if (coords == null)
{
PreviewImageControl.Cursor = DefaultCursor;
return;
}
var cellIndex = vm.HitTestCell(coords.Value.x, coords.Value.y);
PreviewImageControl.Cursor = cellIndex.HasValue ? HandCursor : DefaultCursor;
}
private void OnPreviewPointerExited(object? sender, PointerEventArgs e)
{
PreviewImageControl.Cursor = DefaultCursor;
}
private async void OnPreviewPointerPressed(object? sender, PointerPressedEventArgs e)
{
if (DataContext is not CalibrationWindowViewModel vm)
return;
if (!e.GetCurrentPoint(PreviewImageControl).Properties.IsLeftButtonPressed)
return;
var coords = ToImageCoordinates(e.GetPosition(PreviewImageControl));
if (coords == null)
return;
await vm.ShowCellHistogramAsync(coords.Value.x, coords.Value.y, this);
}
}

View File

@@ -0,0 +1,26 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LindtLeerformPlugin.ViewModels"
x:Class="LindtLeerformPlugin.Views.CellHistogramWindow"
x:DataType="vm:CellHistogramViewModel"
Title="{Binding Title}"
Width="720" Height="600"
Background="#1A1A1A"
WindowStartupLocation="CenterOwner">
<ScrollViewer>
<StackPanel Spacing="12" Margin="16">
<TextBlock Text="Reference (learned)" FontWeight="Bold" Foreground="White" FontSize="14" />
<Border Background="#0A0A0A" Padding="4">
<Image Source="{Binding ReferenceImage}" Stretch="Uniform" Height="220" />
</Border>
<TextBlock Text="Selected cell" FontWeight="Bold" Foreground="White" FontSize="14" Margin="0,8,0,0" />
<Border Background="#0A0A0A" Padding="4">
<Image Source="{Binding CellImage}" Stretch="Uniform" Height="220" />
</Border>
<TextBlock Text="{Binding DistanceText}" Foreground="LightGray" FontSize="13" Margin="0,8,0,0" />
</StackPanel>
</ScrollViewer>
</Window>

View File

@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace LindtLeerformPlugin.Views;
public partial class CellHistogramWindow : Window
{
public CellHistogramWindow()
{
InitializeComponent();
}
}