/* * Copyright (c) 2025 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora.Api; using Aurora.Api.DataType; using Aurora.View; using VisionCommon; using Hermes; using Cognex.VisionPro; using Cognex.VisionPro.Display; using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using Brush = System.Windows.Media.Brush; using Brushes = System.Windows.Media.Brushes; using Pen = System.Windows.Media.Pen; using Size = System.Windows.Size; using Point = System.Windows.Point; using Cursor = System.Windows.Forms.Cursor; using CogPattern; using CogCommon; using VisionCommonUI; using Cognex.VisionPro.PMAlign; using VisionCommonUI.Resources; using System.Collections.Generic; using System.Windows.Controls.Primitives; namespace CogUI { /// /// Interaction logic for ImageMaskView.xaml /// public partial class ImageMaskView : UserControl, IDisposable { public Window ParentWindow { get; set; } public ICommand CMD_SetMaskSize { get; } public IEnumerable MaskLayoutItems { get; } = MaskRegionUtil.GetMaskLayout(); private Logger _logger = new Logger("ImageMaskView"); private PatternAgentBase _patternAgent; private PatternInfo _patternInfo; private CogMaskGraphic _maskGraphic; private ICogImage _modelImage = null; private Cross _curTrainOrigin; private int _crossLength = 200; private int _maskSize = 5; private bool _isMaskEnabled = true; private const double ZOOM_STEP = 0.1; public ImageMaskView( PatternAgentBase patternAgent, PatternInfo patternInfo) { InitializeComponent(); _patternAgent = patternAgent; _patternInfo = patternInfo; CMD_SetMaskSize = new DelegateCommand(SetMaskSize); InitCogDisplay(); CreateMaskGraphic(); LoadModelImageToDisplay(); LoadMaskImageToOverlay(); LoadTrainOriginInModel(); UpdateMouseCursor(_maskSize); DataContext = this; } private void InitCogDisplay() { cogDisplay.AutoFitWithGraphics = true; cogDisplay.VerticalScrollBar = false; cogDisplay.HorizontalScrollBar = false; cogDisplay.BackColor = System.Drawing.Color.Black; cogDisplay.AutoFit = true; cogDisplay.DoubleClick += OnDoubleClick; } private void OnDoubleClick(object sender, EventArgs e) { cogDisplay?.Fit(true); } private void CreateMaskGraphic() { if (_maskGraphic == null) { _maskGraphic = new CogMaskGraphic(); _maskGraphic.Color = CogColorConstants.DarkGrey; } } public void Dispose() { CogEnvironment.FreeImage(_modelImage); _maskGraphic?.Dispose(); DisplayDrawer.ClearGraphics(cogDisplay); cogDisplay.DoubleClick -= OnDoubleClick; } private void LoadModelImageToDisplay() { var patternMask = _patternAgent.GetPattern(_patternInfo) as IPatternMask; _modelImage = patternMask.GetModelImage(); // mark Image cogDisplay.Image = _modelImage; DisplayDrawer.AddTrainEdge(cogDisplay, _patternAgent, _patternInfo); } private void LoadMaskImageToOverlay(ImageMaskEditWindow maskEditWidnow = null) { if (maskEditWidnow == null) { maskEditWidnow = new ImageMaskEditWindow(cogDisplay.Image, _patternAgent, _patternInfo); } var maskEditTool = maskEditWidnow.GetMaskEditTool(); CogColorConstants color; CogMaskGraphicTransparencyConstants maskGraphicTransparency; _maskGraphic.Image = (CogImage8Grey)maskEditTool.MaskImage; maskEditTool.GetColorAndTransparencyMap(0, out color, out maskGraphicTransparency); _maskGraphic.SetTransparencyMap(0, maskGraphicTransparency); _maskGraphic.SetColorMap(0, color); DisplayDrawer.AddMask(cogDisplay, color, _maskGraphic, CogConstants.KEY_MASK); } private void LoadTrainOriginInModel() { var trainParam = _patternAgent.GetTrainParam(_patternInfo) as ImageTrainParam; _crossLength = (int)(trainParam.TrainRoi.Width * 0.5); _curTrainOrigin = trainParam.TrainOrigin.Clone() as Cross; AddCross(trainParam); } private void OnMouseWheel(object sender, System.Windows.Forms.MouseEventArgs e) { UpdateMouseCursor(_maskSize); } private Point GetMousePoint(System.Windows.Forms.MouseEventArgs e) { var screenPoint = new ImagePoint(e.X, e.Y); var imagePoint = TransformScreenPointToImagePoint(screenPoint); return new Point(imagePoint.X, imagePoint.Y); } private void ZoomMinus_Button_Click(object sender, RoutedEventArgs e) { RelativeZoomImage(ZOOM_STEP * (-1)); UpdateMouseCursor(_maskSize); } private void FitImage_Button_Click(object sender, RoutedEventArgs e) { cogDisplay.Fit(true); UpdateMouseCursor(_maskSize); } private void ZoomPlus_Button_Click(object sender, RoutedEventArgs e) { RelativeZoomImage(ZOOM_STEP); UpdateMouseCursor(_maskSize); } public int RelativeZoomImage(double zoom) { try { double curZoom = cogDisplay.Zoom; return AbsZoomImage(curZoom + zoom); } catch (Exception e) { _logger.FuncE(e.Message); } return E1.GENERIC; } public int AbsZoomImage(double zoom) { try { if (zoom > 0) { cogDisplay.Zoom = zoom; } return E1.OK; } catch (Exception e) { _logger.FuncE(e.Message); } return E1.GENERIC; } public ImagePoint TransformScreenPointToImagePoint(ImagePoint src) { string screenSpace = "*"; string imageSpace = "@"; var transform = cogDisplay.GetTransform(imageSpace, screenSpace); double transformedX, transformedY; transform.MapPoint(src.X, src.Y, out transformedX, out transformedY); return new ImagePoint(transformedX, transformedY); } private void MaskEditTool_Button_Click(object sender, RoutedEventArgs e) { var maskEditWidnow = new ImageMaskEditWindow( cogDisplay.Image, _patternAgent, _patternInfo); maskEditWidnow.SetMaskImage(_maskGraphic.Image); if (maskEditWidnow.ShowDialog() == true) { LoadMaskImageToOverlay(maskEditWidnow); UpdateMaskRegionButtonState(); RefreshUI(); } } private void SaveMask_Button_Click(object sender, RoutedEventArgs e) { var patternMask = _patternAgent.GetPattern(_patternInfo) as IPatternMask; patternMask.SetMaskImage(_maskGraphic.Image); patternMask.SetTrainOrigin(_curTrainOrigin); ((IPatternFinder)patternMask).Save(); MessageBoxUtil.ShowMessageBoxOk(StrTokens.MSG_O_SaveCompleted); } private void SetMaskSize(object obj) { var size = Convert.ToInt32(obj.ToString()); _maskSize = size; UpdateMouseCursor(_maskSize); } private void UpdateMouseCursor(int maskSize) { Application.Current.Dispatcher.BeginInvoke( new System.Action(() => { cogDisplay.Cursor = GetCursor(maskSize); })); } private Cursor GetCursor(int maskSize) { var cursorSize = GetCursorSize(maskSize); if (_isMaskEnabled) { return WinformCursorHelper.CreateRectCursor( Brushes.Magenta, new Pen(Brushes.Magenta, 1), new Size(cursorSize, cursorSize)); } else { return WinformCursorHelper.CreateRectCursor( Brushes.Transparent, new Pen(Brushes.Orange, 2), new Size(cursorSize, cursorSize)); } } private int GetCursorSize(int maskSize) { var curZoomFactor = GetCurZoomFactor(); var cursorSize = (int)Math.Floor(maskSize * curZoomFactor); if (cursorSize < 1) { cursorSize = 1; } else if (cogDisplay.Width < cursorSize || cogDisplay.Height < cursorSize) { cursorSize = Math.Min(cogDisplay.Width, cogDisplay.Height); } return cursorSize; } private double GetCurZoomFactor() { return cogDisplay.Zoom; } private void EnableMask_Button_Click(object sender, RoutedEventArgs e) { _isMaskEnabled = true; UpdateMouseCursor(_maskSize); } private void EnableEraser_Button_Click(object sender, RoutedEventArgs e) { _isMaskEnabled = false; UpdateMouseCursor(_maskSize); } private void ClearMask_Button_Click(object sender, RoutedEventArgs e) { _maskGraphic.Image.Dispose(); //MIL.MdispControl(_cogDisplay, MIL.M_OVERLAY_CLEAR, MIL.M_DEFAULT); } private void Cancel_Button_Click(object sender, RoutedEventArgs e) { ParentWindow?.Close(); } private void TrainOrigin_Left_Up_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint( GetTrainOriginMoveStep() * (-1), GetTrainOriginMoveStep() * (-1))); } private void TrainOrigin_Right_Up_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint( GetTrainOriginMoveStep(), GetTrainOriginMoveStep() * (-1))); } private void TrainOrigin_Up_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint( 0, GetTrainOriginMoveStep() * (-1))); } private void TrainOrigin_Left_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint( GetTrainOriginMoveStep() * (-1), 0)); } private void TrainOrigin_Right_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint( GetTrainOriginMoveStep(), 0)); } private void TrainOrigin_Left_Down_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint( GetTrainOriginMoveStep() * (-1), GetTrainOriginMoveStep())); } private void TrainOrigin_Down_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint(0, GetTrainOriginMoveStep())); } private void TrainOrigin_Right_Down_Button_Click(object sender, RoutedEventArgs e) { MoveTrainOrigin(new ImagePoint( GetTrainOriginMoveStep(), GetTrainOriginMoveStep())); } private double GetTrainOriginMoveStep() { return Convert.ToDouble(trainOriginMoveStep.Value); } private void MoveTrainOrigin(ImagePoint moveOffset) { var trainParam = _patternAgent.GetTrainParam(_patternInfo) as ImageTrainParam; _curTrainOrigin = new Cross((_curTrainOrigin.Origin + moveOffset) as ImagePoint); DisplayDrawer.RemoveInteractiveGraphic(cogDisplay, CogConstants.KEY_MASK_CROSS); AddCross(trainParam); } private void TrainOrigin_Center_Button_Click(object sender, RoutedEventArgs e) { var trainParam = _patternAgent.GetTrainParam(_patternInfo) as ImageTrainParam; _curTrainOrigin = new Cross(CogEnvironment.GetImageCenter(_modelImage)); _curTrainOrigin.Origin.X += trainParam.TrainRoi.Left; _curTrainOrigin.Origin.Y += trainParam.TrainRoi.Top; DisplayDrawer.RemoveInteractiveGraphic(cogDisplay, CogConstants.KEY_MASK_CROSS); AddCross(trainParam); } private void AddCross(ImageTrainParam trainParam) { DisplayDrawer.AddCross( cogDisplay, CogColorConstants.Orange, new Cross(_curTrainOrigin.Origin.Clone() as ImagePoint, trainParam.TrainRoi.Angle, _crossLength), CogConstants.KEY_MASK_CROSS); } private void Set_MaskRegion_Button_Click(object sender, RoutedEventArgs e) { var toggleButton = sender as ToggleButton; var index1d = Convert.ToInt32(toggleButton.Tag.ToString()); var rowCount = GetMaskLayoutRowCount(); var colCount = GetMaskLayoutColCount(); if ((bool)toggleButton.IsChecked) { MaskRegionUtil.SetMaskToMaskImage( _maskGraphic.Image, 0, rowCount, colCount, index1d); toggleButton.Background = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Colors.DarkMagenta); } else { MaskRegionUtil.SetMaskToMaskImage( _maskGraphic.Image, 255, rowCount, colCount, index1d); toggleButton.Background = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Colors.WhiteSmoke); } RefreshUI(); } private int GetMaskLayoutRowCount() { var maskLayout = GetMaskLayout(); return MaskRegionUtil.GetMaskLayoutRowCount(maskLayout); } private int GetMaskLayoutColCount() { var maskLayout = GetMaskLayout(); return MaskRegionUtil.GetMaskLayoutColCount(maskLayout); } private string GetMaskLayout() { return comboBoxMaskLayout.SelectedItem.ToString(); } private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { UpdateMaskRegion(); } private void UpdateMaskRegion() { var rowCount = GetMaskLayoutRowCount(); var colCount = GetMaskLayoutColCount(); UpdateMaskRegion(rowCount, colCount); UpdateMaskRegionButtonState(); RefreshUI(); } private void UpdateMaskRegion(int rowCount, int colCount) { gridMaskRegion.Children.Clear(); gridMaskRegion.RowDefinitions.Clear(); gridMaskRegion.ColumnDefinitions.Clear(); for (int i = 0; i < rowCount; i++) { gridMaskRegion.RowDefinitions.Add(new RowDefinition()); } for (int i = 0; i < colCount; i++) { gridMaskRegion.ColumnDefinitions.Add(new ColumnDefinition()); } for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) { for (int colIndex = 0; colIndex < colCount; colIndex++) { var button = CreateMaskRegionButton(rowCount, colCount, rowIndex, colIndex); Grid.SetRow(button, rowIndex); Grid.SetColumn(button, colIndex); gridMaskRegion.Children.Add(button); } } } private ToggleButton CreateMaskRegionButton( int rowCount, int colCount, int rowIndex, int colIndex) { var button = new ToggleButton(); button.Margin = new Thickness(5); button.Tag = ((rowIndex * colCount) + colIndex).ToString(); button.Click += Set_MaskRegion_Button_Click; CheckMaskRegionButton(button); return button; } private void UpdateMaskRegionButtonState() { try { var rowCount = GetMaskLayoutRowCount(); var colCount = GetMaskLayoutColCount(); var maskImage = _maskGraphic.Image; for (int i = 0; i < gridMaskRegion.Children.Count; i++) { var toggleButton = gridMaskRegion.Children[i] as ToggleButton; SetMaskRegionButtonState(maskImage, toggleButton, rowCount, colCount, i); } } catch (Exception e) { _logger.E(e.Message); } } private void SetMaskRegionButtonState( ICogImage maskImage, ToggleButton toggleButton, int rowCount, int colCount, int index1d) { var threshold = 126; var brightness = GetMaskRegionBrightness(maskImage, rowCount, colCount, index1d); if (brightness.Avg <= threshold) { CheckMaskRegionButton(toggleButton); } else { UncheckMaskRegionButton(toggleButton); } } private BrightnessResult GetMaskRegionBrightness( ICogImage maskImage, int rowCount, int colCount, int index1d) { var brightness = new BrightnessResult(new ImagePoint(), 0, 0, 0); try { var grayImageSize = CogEnvironment.GetImageSize(maskImage); var rectangle = MaskRegionUtil.GetMaskRectangle( grayImageSize.Width, grayImageSize.Height, rowCount, colCount, index1d); var roi = new ROI( new ImagePoint(rectangle.CenterX, rectangle.CenterY), (int)rectangle.Width, (int)rectangle.Height); var cropImage = CogEnvironment.CropImage(maskImage, roi); brightness = CogEnvironment.GetBrightness(cropImage, roi.Center); } catch (Exception e) { _logger.E(e.Message); } return brightness; } private void CheckMaskRegionButton(ToggleButton toggleButton) { toggleButton.IsChecked = true; toggleButton.Background = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Colors.DarkMagenta); } private void UncheckMaskRegionButton(ToggleButton toggleButton) { toggleButton.IsChecked = false; toggleButton.Background = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Colors.WhiteSmoke); } private void UpdateGridLine() { var imageSize = CogEnvironment.GetImageSize(_maskGraphic.Image); var rowCount = GetMaskLayoutRowCount(); var colCount = GetMaskLayoutColCount(); var lines = new List>(); var trainParam = _patternAgent.GetTrainParam(_patternInfo) as ImageTrainParam; // Vertical lines for (int colIndex = 1; colIndex < colCount; colIndex++) { var rectangle = MaskRegionUtil.GetMaskRectangle( imageSize.Width, imageSize.Height, rowCount, colCount, 1, colIndex); var lineStart = new ImagePoint(rectangle.X, 0); var lineEnd = new ImagePoint(rectangle.X, imageSize.Height); var drawOffset = new ImagePoint( trainParam.TrainRoi.Left, trainParam.TrainRoi.Top); var verticalLine = new Line( lineStart + drawOffset as ImagePoint, lineEnd + drawOffset as ImagePoint); lines.Add(verticalLine); } // Horizontal lines for (int rowIndex = 1; rowIndex < rowCount; rowIndex++) { var rectangle = MaskRegionUtil.GetMaskRectangle( imageSize.Width, imageSize.Height, rowCount, colCount, rowIndex, 1); var lineStart = new ImagePoint(0, rectangle.Y); var lineEnd = new ImagePoint(imageSize.Width, rectangle.Y); var drawOffset = new ImagePoint( trainParam.TrainRoi.Left, trainParam.TrainRoi.Top); var horizontalLine = new Line( lineStart + drawOffset as ImagePoint, lineEnd + drawOffset as ImagePoint); lines.Add(horizontalLine); } DisplayDrawer.AddLines(cogDisplay, CogColorConstants.LightGrey, lines, CogConstants.KEY_MASK); } private void RefreshUI() { cogDisplay.InteractiveGraphics.Clear(); UpdateGridLine(); DisplayDrawer.AddTrainEdge(cogDisplay, _patternAgent, _patternInfo); DisplayDrawer.AddMask(cogDisplay, CogColorConstants.DarkRed, _maskGraphic, CogConstants.KEY_MASK); MoveTrainOrigin(new ImagePoint()); } } }