355 lines
12 KiB
C#
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;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|