using Aurora.Api; using Aurora.Api.DataType; using Aurora.View; using VisionCommon; using Hermes; using Matrox.MatroxImagingLibrary; 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 MilPattern; using MilCommon; using VisionCommonUI; using VisionCommonUI.Resources; using System.Collections.Generic; using System.Windows.Shapes; using System.Windows.Controls.Primitives; namespace MilUI { /// /// Interaction logic for ImageMaskView.xaml /// public partial class ImageMaskView : UserControl, IDisposable { private MIL_ID _displayId = MIL.M_NULL; 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 MIL_ID _systemId = MIL.M_NULL; private MIL_ID _modelImageId = MIL.M_NULL; private MIL_ID _overlayId = MIL.M_NULL; private MIL_ID _graphicContext = MIL.M_NULL; private MIL_ID _graphicList = MIL.M_NULL; private MIL_ID _trainOriginLabel = MIL.M_NULL; private MIL_ID COLOR_TRANSPARENT; private MIL_ID COLOR_MASK = MIL.M_COLOR_DARK_MAGENTA; private GCHandle ThisPtr; private MIL_DISP_HOOK_FUNCTION_PTR MouseRightDownHookFuncPtr; private MIL_DISP_HOOK_FUNCTION_PTR MouseRightUpHookFuncPtr; private MIL_DISP_HOOK_FUNCTION_PTR MouseMoveHookFuncPtr; private MIL_DISP_HOOK_FUNCTION_PTR MouseWheelHookFuncPtr; private MilGraphics _milOriginGraphics; private MilGraphics _milGridGraphics; private Cross _curTrainOriginInModel; private int _crossLength = 100; private int _maskSize = 5; private bool _isMaskEnabled = true; private bool _isMouseRightDown = false; private const double ZOOM_STEP = 0.1; public ImageMaskView( PatternAgentBase patternAgent, PatternInfo patternInfo) { InitializeComponent(); _patternAgent = patternAgent; _patternInfo = patternInfo; CMD_SetMaskSize = new DelegateCommand(SetMaskSize); AllocMil(); InitMaskColor(); LoadModelImageToDisplay(); LoadMaskImageToOverlay(); LoadTrainOriginInModel(); UpdateMouseCursor(_maskSize); SetHookFunc(); DataContext = this; } private void InitMaskColor() { MIL.MdispInquire(_displayId, MIL.M_TRANSPARENT_COLOR, ref COLOR_TRANSPARENT); COLOR_MASK = MIL.M_COLOR_DARK_MAGENTA; } private void AllocMil() { _systemId = _patternInfo.MilSystemId; if (_systemId != MIL.M_NULL) { MIL.MdispAlloc(_systemId, MIL.M_DEFAULT, "M_DEFAULT", MIL.M_DEFAULT, ref _displayId); MIL.MgraAlloc(_systemId, ref _graphicContext); MIL.MgraAllocList(_systemId, MIL.M_DEFAULT, ref _graphicList); MIL.MdispControl(_displayId, MIL.M_MOUSE_USE, MIL.M_ENABLE); MIL.MdispControl(_displayId, MIL.M_SCALE_DISPLAY, MIL.M_ENABLE); MIL.MdispControl(_displayId, MIL.M_CENTER_DISPLAY, MIL.M_ENABLE); MIL.MdispControl(_displayId, MIL.M_MOUSE_CURSOR_CHANGE, MIL.M_DISABLE); MIL.MdispControl(_displayId, MIL.M_GRAPHIC_LIST_INTERACTIVE, MIL.M_ENABLE); MIL.MdispControl(_displayId, MIL.M_ASSOCIATED_GRAPHIC_LIST_ID, _graphicList); MIL.MdispControl(_displayId, MIL.M_BACKGROUND_COLOR, MIL.M_RGB888(37, 37, 37)); _milOriginGraphics = new MilGraphics(_displayId, _graphicList); _milGridGraphics = new MilGraphics(_displayId, _graphicList); } } public void Dispose() { MIL.MbufFree(_modelImageId); MIL.MgraFree(_graphicList); MIL.MgraFree(_graphicContext); MIL.MdispFree(_displayId); } private void LoadModelImageToDisplay() { var patternMask = _patternAgent.GetPattern(_patternInfo) as IPatternMask; _modelImageId = patternMask.GetColorModelImage(); MIL.MdispSelectWindow(_displayId, _modelImageId, winFormPanel.Handle); MIL.MdispControl(_displayId, MIL.M_OVERLAY, MIL.M_ENABLE); MIL.MdispInquire(_displayId, MIL.M_OVERLAY_ID, ref _overlayId); MIL.MdispControl(_displayId, MIL.M_OVERLAY_CLEAR, MIL.M_DEFAULT); } private void LoadMaskImageToOverlay() { var patternMask = _patternAgent.GetPattern(_patternInfo) as IPatternMask; patternMask.DrawMaskImage(_overlayId); } private void LoadTrainOriginInModel() { var trainParam = _patternAgent.GetTrainParam(_patternInfo) as ImageTrainParam; _crossLength = (int)(trainParam.TrainRoi.Width * 0.5); _curTrainOriginInModel = trainParam.TrainOriginInModel.Clone() as Cross; DisplayDrawer.AddCross( _displayId, _graphicContext, _graphicList, ColorConverter.ConvertColor(eColor.Orange), _milOriginGraphics, new Cross(_curTrainOriginInModel.Origin, _crossLength)); _trainOriginLabel = _milOriginGraphics.GetLastLabel(); } private void SetHookFunc() { ThisPtr = GCHandle.Alloc(this); MouseRightDownHookFuncPtr = new MIL_DISP_HOOK_FUNCTION_PTR(MouseLeftDownHookFunc); MouseRightUpHookFuncPtr = new MIL_DISP_HOOK_FUNCTION_PTR(MouseLeftUpHookFunc); MouseMoveHookFuncPtr = new MIL_DISP_HOOK_FUNCTION_PTR(MouseMoveHookFunc); MouseWheelHookFuncPtr = new MIL_DISP_HOOK_FUNCTION_PTR(MouseWheelHookFunc); MIL.MdispHookFunction(_displayId, MIL.M_MOUSE_RIGHT_BUTTON_DOWN, MouseRightDownHookFuncPtr, GCHandle.ToIntPtr(ThisPtr)); MIL.MdispHookFunction(_displayId, MIL.M_MOUSE_RIGHT_BUTTON_UP, MouseRightUpHookFuncPtr, GCHandle.ToIntPtr(ThisPtr)); MIL.MdispHookFunction(_displayId, MIL.M_MOUSE_MOVE, MouseMoveHookFuncPtr, GCHandle.ToIntPtr(ThisPtr)); MIL.MdispHookFunction(_displayId, MIL.M_MOUSE_WHEEL, MouseWheelHookFuncPtr, GCHandle.ToIntPtr(ThisPtr)); } public MIL_INT MouseLeftDownHookFunc(MIL_INT HookType, MIL_ID EventID, IntPtr UserDataPtr) { _isMouseRightDown = true; DrawMask(GetMousePoint(EventID)); return 0; } public MIL_INT MouseLeftUpHookFunc(MIL_INT HookType, MIL_ID EventID, IntPtr UserDataPtr) { _isMouseRightDown = false; UpdateMaskRegionButtonState(); return 0; } public MIL_INT MouseMoveHookFunc(MIL_INT HookType, MIL_ID EventID, IntPtr UserDataPtr) { if (_isMouseRightDown) { DrawMask(GetMousePoint(EventID)); } return 0; } public MIL_INT MouseWheelHookFunc(MIL_INT HookType, MIL_ID EventID, IntPtr UserDataPtr) { UpdateMouseCursor(_maskSize); return 0; } private void DrawMask(Point drawPoint) { if (_isMaskEnabled) { DrawMaskRect(drawPoint, COLOR_MASK); } else { DrawMaskRect(drawPoint, COLOR_TRANSPARENT); } } public void DrawMaskRect(Point drawPoint, MIL_ID color) { double maskHalfSize = (double)_maskSize / 2; var lt = new ImagePoint( drawPoint.X - maskHalfSize, drawPoint.Y - maskHalfSize); var rb = new ImagePoint( lt.X + (_maskSize - 1), lt.Y + (_maskSize - 1)); MIL.MgraColor(_graphicContext, color); MIL.MgraRectFill( _graphicContext, _overlayId, lt.X, lt.Y, rb.X, rb.Y); } private Point GetMousePoint(MIL_ID EventID) { double x = 0; double y = 0; MIL.MdispGetHookInfo(EventID, MIL.M_MOUSE_POSITION_BUFFER_X, ref x); MIL.MdispGetHookInfo(EventID, MIL.M_MOUSE_POSITION_BUFFER_Y, ref y); return new Point(x, 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) { FitImage(MilEnvironment.GetImageSize(_modelImageId)); UpdateMouseCursor(_maskSize); } private void ZoomPlus_Button_Click(object sender, RoutedEventArgs e) { RelativeZoomImage(ZOOM_STEP); UpdateMouseCursor(_maskSize); } public int RelativeZoomImage(double zoom) { try { double curZoomX = 0; double curZoomY = 0; MIL.MdispInquire(_displayId, MIL.M_ZOOM_FACTOR_X, ref curZoomX); MIL.MdispInquire(_displayId, MIL.M_ZOOM_FACTOR_Y, ref curZoomY); return AbsZoomImage(curZoomX + zoom, curZoomY + zoom); } catch (Exception e) { _logger.FuncE(e.Message); } return E1.GENERIC; } public int AbsZoomImage(double zoomX, double zoomY) { try { if (zoomX > 0 && zoomY > 0) { MIL.MdispZoom(_displayId, zoomX, zoomY); } return E1.OK; } catch (Exception e) { _logger.FuncE(e.Message); } return E1.GENERIC; } private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) { var imageSize = MilEnvironment.GetImageSize(_modelImageId); FitImage(imageSize); } public int FitImage(ImageSize imageSize) { try { if (_displayId != MIL.M_NULL && MilEnvironment.Instance.HasValidLicense()) { if (MilEnvironment.IsImageSizeNull(imageSize)) { return E1.GENERIC; } double zoomX = (double)winFormPanel.Width / imageSize.Width; double zoomY = (double)winFormPanel.Height / imageSize.Height; // 이미지 원본의 비율을 유지하면서 영상의 모든 영역이 디스플레이에 출력되어야 한다. double minZoom = Math.Min(zoomX, zoomY); if (minZoom > 0) { MIL.MdispZoom(_displayId, minZoom, minZoom); } } return E1.OK; } catch (Exception e) { _logger.FuncE(e.Message); } return E1.GENERIC; } private void SaveMask_Button_Click(object sender, RoutedEventArgs e) { MIL_ID grayMaskImage = MilEnvironment.GetCompatibleGrayImageBuffer(_overlayId); ConvertMaskColorToGrayImage(_overlayId, grayMaskImage); var patternMask = _patternAgent.GetPattern(_patternInfo) as IPatternMask; patternMask.SetMaskImage(grayMaskImage); patternMask.SetTrainOrigin(_curTrainOriginInModel); ((IPatternFinder)patternMask).Save(); MilEnvironment.FreeImage(grayMaskImage); MessageBoxUtil.ShowMessageBoxOk(StrTokens.MSG_O_SaveCompleted); } private void ConvertMaskColorToGrayImage(MIL_ID colorMaskImage, MIL_ID grayMaskImage) { MIL.MbufClearCond(grayMaskImage, 255, MIL.M_NULL, MIL.M_NULL, colorMaskImage, MIL.M_EQUAL, COLOR_MASK); } private void SetMaskSize(object obj) { var size = Convert.ToInt32(obj.ToString()); _maskSize = size; UpdateMouseCursor(_maskSize); } private void UpdateMouseCursor(int maskSize) { winFormPanel.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 (winFormPanel.Width < cursorSize || winFormPanel.Height < cursorSize) { cursorSize = Math.Min(winFormPanel.Width, winFormPanel.Height); } return cursorSize; } private double GetCurZoomFactor() { double zoomFactor = 0; MIL.MdispInquire(_displayId, MIL.M_ZOOM_FACTOR_X, ref zoomFactor); return zoomFactor; } 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) { MIL.MdispControl(_displayId, MIL.M_OVERLAY_CLEAR, MIL.M_DEFAULT); ClearAllMaskRegionButtons(); } private void ClearAllMaskRegionButtons() { foreach (ToggleButton toggleButton in gridMaskRegion.Children) { toggleButton.IsChecked = false; toggleButton.Background = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Colors.WhiteSmoke); } } 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) { if (_milOriginGraphics.HasGraphicLabel(_trainOriginLabel)) { _curTrainOriginInModel = new Cross((_curTrainOriginInModel.Origin + moveOffset) as ImagePoint); _milOriginGraphics.Clear(); DisplayDrawer.AddCross( _displayId, _graphicContext, _graphicList, ColorConverter.ConvertColor(eColor.Orange), _milOriginGraphics, new Cross(_curTrainOriginInModel.Origin, _crossLength)); _trainOriginLabel = _milOriginGraphics.GetLastLabel(); } } private void TrainOrigin_Center_Button_Click(object sender, RoutedEventArgs e) { _curTrainOriginInModel = new Cross(MilEnvironment.GetImageCenter(_modelImageId)); _milOriginGraphics.Clear(); DisplayDrawer.AddCross( _displayId, _graphicContext, _graphicList, ColorConverter.ConvertColor(eColor.Orange), _milOriginGraphics, new Cross(_curTrainOriginInModel.Origin, _crossLength)); _trainOriginLabel = _milOriginGraphics.GetLastLabel(); } 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.SetMaskToOverlay( _graphicContext, _overlayId, COLOR_MASK, rowCount, colCount, index1d); toggleButton.Background = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Colors.DarkMagenta); } else { MaskRegionUtil.SetMaskToOverlay( _graphicContext, _overlayId, COLOR_TRANSPARENT, rowCount, colCount, index1d); toggleButton.Background = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Colors.WhiteSmoke); } } 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(); UpdateGridLine(); } 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() { MIL_ID grayMaskImage = MIL.M_NULL; try { var rowCount = GetMaskLayoutRowCount(); var colCount = GetMaskLayoutColCount(); grayMaskImage = GetGrayMaskImageFromOverlay(); for (int i = 0; i < gridMaskRegion.Children.Count; i++) { var toggleButton = gridMaskRegion.Children[i] as ToggleButton; SetMaskRegionButtonState(grayMaskImage, toggleButton, rowCount, colCount, i); } } catch (Exception e) { _logger.E(e.Message); } finally { MilEnvironment.FreeImage(grayMaskImage); } } private MIL_ID GetGrayMaskImageFromOverlay() { MIL_ID grayMaskImage = MilEnvironment.GetCompatibleGrayImageBuffer(_overlayId); ConvertMaskColorToGrayImage(_overlayId, grayMaskImage); return grayMaskImage; } private void SetMaskRegionButtonState( MIL_ID grayMaskImage, ToggleButton toggleButton, int rowCount, int colCount, int index1d) { var threshold = 126; var brightness = GetMaskRegionBrightness(grayMaskImage, rowCount, colCount, index1d); if (threshold < brightness.Avg) { CheckMaskRegionButton(toggleButton); } else { UncheckMaskRegionButton(toggleButton); } } private BrightnessResult GetMaskRegionBrightness( MIL_ID grayMaskImage, int rowCount, int colCount, int index1d) { MIL_ID maskRegionImage = MIL.M_NULL; var brightness = new BrightnessResult(new ImagePoint(), 0, 0, 0); try { var grayImageSize = MilEnvironment.GetImageSize(grayMaskImage); var rectangle = MaskRegionUtil.GetMaskRectangle( grayImageSize.Width, grayImageSize.Height, rowCount, colCount, index1d); var roi = new ROI( new ImagePoint( rectangle.Left + (rectangle.Width * 0.5), rectangle.Top + (rectangle.Height * 0.5)), rectangle.Width, rectangle.Height); maskRegionImage = MilEnvironment.CropImage(grayMaskImage, roi); brightness = MilEnvironment.GetBrightness(maskRegionImage, new ImagePoint()); } catch (Exception e) { _logger.E(e.Message); } finally { MilEnvironment.FreeImage(maskRegionImage); } 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 = MilEnvironment.GetImageSize(_overlayId); var rowCount = GetMaskLayoutRowCount(); var colCount = GetMaskLayoutColCount(); var lines = new List>(); // 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.Left, 0); var lineEnd = new ImagePoint(rectangle.Left, imageSize.Height); var drawOffset = new ImagePoint(-0.5, -0.5); 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.Top); var lineEnd = new ImagePoint(imageSize.Width, rectangle.Top); var drawOffset = new ImagePoint(-0.5, -0.5); var horizontalLine = new Line( lineStart + drawOffset as ImagePoint, lineEnd + drawOffset as ImagePoint); lines.Add(horizontalLine); } _milGridGraphics.Clear(); DisplayDrawer.AddLines( _displayId, _graphicContext, _graphicList, MIL.M_COLOR_LIGHT_GRAY, _milGridGraphics, lines); } } }