CtrEditor/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs

355 lines
12 KiB
C#

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.Simulacion;
using System.IO;
using System.Windows.Media.Imaging;
using Tesseract;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV;
using System.Drawing;
using Image = System.Windows.Controls.Image;
using Point = System.Drawing.Point;
using Rectangle = System.Windows.Shapes.Rectangle;
using Size = System.Drawing.Size;
using Ookii.Dialogs.Wpf;
namespace CtrEditor.ObjetosSim.Extraccion_Datos
{
/// <summary>
/// Interaction logic for ucBuscarCoincidencias.xaml
/// </summary>
///
public partial class osBuscarCoincidencias : osBase, IosBase
{
private osBase _osMotor = null;
private simTransporte SimGeometria;
public static string NombreClase()
{
return "Search Templates";
}
private string nombre = NombreClase();
public override string Nombre
{
get => nombre;
set => SetProperty(ref nombre, value);
}
[ObservableProperty]
bool search_templates;
partial void OnSearch_templatesChanged(bool oldValue, bool newValue)
{
if (Search_templates)
BuscarCoincidencias();
Search_templates = false;
}
public override void TopChanged(float value)
{
base.TopChanged(value);
Search_templates = false;
}
public override void LeftChanged(float value)
{
base.LeftChanged(value);
Search_templates = false;
}
[ObservableProperty]
public float ancho;
partial void OnAnchoChanged(float value)
{
Search_templates = false;
}
[ObservableProperty]
public float alto;
partial void OnAltoChanged(float value)
{
Search_templates = false;
}
public override void OnTimerAfterMovement()
{
}
[ObservableProperty]
public int n_Repeat_X;
[ObservableProperty]
public int n_Repeat_Y;
[ObservableProperty]
public float offset_Repeat_X;
[ObservableProperty]
public float offset_Repeat_Y;
[ObservableProperty]
public float angulo;
[ObservableProperty]
string tag_extract;
[ObservableProperty]
string clase;
[ObservableProperty]
string tag_name;
[ObservableProperty]
float opacity_oculto;
[ObservableProperty]
bool show_debug_ocr;
[ObservableProperty]
float threshold;
public osBuscarCoincidencias()
{
Ancho = 1;
Alto = 1;
Angulo = 0;
Opacity_oculto = 0.1f;
}
private void ShowPreviewWindow(Stream imageStream)
{
// Create a new window for preview
Window previewWindow = new Window
{
Title = "Preview Captured Image",
Width = 500,
Height = 500,
Content = new Image
{
Source = BitmapFrame.Create(imageStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad),
Stretch = Stretch.Uniform
}
};
previewWindow.ShowDialog();
}
private async void BuscarCoincidencias()
{
var progressDialog = new ProgressDialog
{
WindowTitle = "Procesando",
Text = "Buscando coincidencias...",
ShowTimeRemaining = true,
ShowCancelButton = false
};
progressDialog.DoWork += (sender, e) => BuscarCoincidenciasAsync(progressDialog);
progressDialog.RunWorkerCompleted += (sender, e) =>
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
};
progressDialog.Show();
}
private void BuscarCoincidenciasAsync(ProgressDialog progressDialog)
{
// Reset the Canvas children
Application.Current.Dispatcher.Invoke(() =>
{
var clearShapes = _mainViewModel.MainCanvas.Children.OfType<System.Windows.Shapes.Shape>().Where(s => s.Tag as string == "BuscarCoincidencias").ToList();
foreach (var shape in clearShapes)
{
_mainViewModel.MainCanvas.Children.Remove(shape);
}
if (_mainViewModel?.MainCanvas.Children[0] is Image imagenDeFondo)
{
// Asegurarse de que la imagen origen está disponible
if (imagenDeFondo.Source is BitmapSource bitmapSource)
{
progressDialog.ReportProgress(10);
// Obtener los DPI de la imagen original
float originalDpiX = (float)bitmapSource.DpiX;
float originalDpiY = (float)bitmapSource.DpiY;
// Estándar DPI en el que el Canvas renderiza la imagen
float canvasDpiX = 96; // WPF usually renders at 96 DPI
float canvasDpiY = 96;
// Calcular el ratio de escala entre el Canvas y la imagen original
float scaleFactorX = originalDpiX / canvasDpiX;
float scaleFactorY = originalDpiY / canvasDpiY;
// Ajustar las coordenadas de recorte en función del ratio de escala
int x = (int)MeterToPixels(Left * scaleFactorX);
int y = (int)MeterToPixels(Top * scaleFactorY);
int width = (int)MeterToPixels(Ancho * scaleFactorX);
int height = (int)MeterToPixels(Alto * scaleFactorY);
// Validar y ajustar el tamaño del recorte para que se mantenga dentro de los límites de la imagen
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x + width > bitmapSource.PixelWidth) width = bitmapSource.PixelWidth - x;
if (y + height > bitmapSource.PixelHeight) height = bitmapSource.PixelHeight - y;
// Recortar el área deseada utilizando las coordenadas ajustadas
CroppedBitmap croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect(x, y, width, height));
// Convertir CroppedBitmap a Mat directamente
Mat templateMat = BitmapSourceToMat(croppedBitmap);
int scale = 4;
// Convertir la plantilla a escala de grises y redimensionarla
Mat templateGray = new Mat();
CvInvoke.CvtColor(templateMat, templateGray, ColorConversion.Bgr2Gray);
Mat templateGrayResized = new Mat();
CvInvoke.Resize(templateGray, templateGrayResized, new Size(templateGray.Width / scale, templateGray.Height / scale), 0, 0, Inter.Linear);
progressDialog.ReportProgress(20);
// Cargar la imagen principal completa en un Mat
Mat mainImageMat = BitmapSourceToMat(bitmapSource);
// Convertir la imagen principal a escala de grises y redimensionarla
Mat mainImageGray = new Mat();
CvInvoke.CvtColor(mainImageMat, mainImageGray, ColorConversion.Bgr2Gray);
Mat mainImageGrayResized = new Mat();
CvInvoke.Resize(mainImageGray, mainImageGrayResized, new Size(mainImageGray.Width / scale, mainImageGray.Height / scale), 0, 0, Inter.Linear);
progressDialog.ReportProgress(50);
// Realizar la coincidencia de plantillas
Mat result = new Mat();
CvInvoke.MatchTemplate(mainImageGray, templateGray, result, TemplateMatchingType.CcoeffNormed);
// Establecer un umbral de coincidencia
if (Threshold < 0.4)
Threshold = 0.4f;
double threshold = Threshold;
int ConteoPositivos = 0;
// Obtener los puntos que superan el umbral
float[] resultArray = result.GetData(false) as float[];
if (resultArray != null)
{
for (int i = 0; i < resultArray.Length; i++)
{
if (resultArray[i] >= threshold)
{
int row = i / result.Cols;
int col = i % result.Cols;
// Crear y agregar el rectángulo al Canvas (ajustando por la escala)
Rectangle matchRect = new Rectangle
{
Stroke = new SolidColorBrush(Colors.Red),
StrokeThickness = 2,
Width = width / scaleFactorX,
Height = height / scaleFactorY,
Tag = "BuscarCoincidencias"
};
Canvas.SetLeft(matchRect, col / scaleFactorX);
Canvas.SetTop(matchRect, row / scaleFactorY);
Canvas.SetZIndex(matchRect, 40);
_mainViewModel.MainCanvas.Children.Add(matchRect);
ConteoPositivos++;
progressDialog.ReportProgress(90);
if (ConteoPositivos > 20)
return;
}
}
}
}
}
});
}
// Método para convertir BitmapSource a Mat
private Mat BitmapSourceToMat(BitmapSource bitmapSource)
{
Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapSource));
enc.Save(outStream);
bitmap = new Bitmap(outStream);
}
return bitmap.ToMat();
}
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
// crear el objeto de simulacion
base.ucLoaded();
}
}
public partial class ucBuscarCoincidencias : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public ucBuscarCoincidencias()
{
InitializeComponent();
this.Loaded += OnLoaded;
this.Unloaded += OnUnloaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
Datos?.ucUnLoaded();
}
public void Resize(float width, float height)
{
if (Datos is osBuscarCoincidencias datos)
{
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(height);
}
}
public void Move(float LeftPixels, float TopPixels)
{
if (Datos != null)
{
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
}
}
public void Rotate(float Angle)
{
if (Datos != null)
if (Datos is osBuscarCoincidencias datos)
datos.Angulo = Angle;
}
public void Highlight(bool State) { }
public int ZIndex()
{
return 1;
}
}
}