/*
* 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());
}
}
}