using Aurora.View; using System; using System.Collections.Generic; using System.Windows.Input; using OpenCvSharp; using System.Linq; using OpenCvSharp.WpfExtensions; using System.Windows.Media.Imaging; using System.Windows.Forms; using Matrox.MatroxImagingLibrary; using Aurora.Api; using Aurora.Api.Control; using MilCommon; using VisionCommon; using System.IO; using System.Diagnostics; using System.Configuration; using CoreUnit.Control.UserControl.Canvas; //using System.Windows.Shapes; using Aurora; using Point = OpenCvSharp.Point; using Rect = OpenCvSharp.Rect; using Size = OpenCvSharp.Size; using System.Collections.ObjectModel; using CoreUnit.Scanner.UserControl.ScannerCanvas; using System.Reactive.Linq; using Application = System.Windows.Application; using WeldingCommon.Sequences; using WeldingCommon.Vision.WeldingObjectGenerator.PathEditorLibrary; using WeldingCommon; using WeldingCommon.Vision.WeldingObjectGenerator; using WeldingCommon.Utils; using WeldingCommon.Data; using System.Reactive.Concurrency; using System.Text.RegularExpressions; using WeldingCommon.Settings; using OpenCvSharp.Flann; using static CoreUnit.Control.UserControl.Canvas.ZigZag; using System.ComponentModel; namespace WeldingCommon.Views { public class UCConvEdgeObjectViewModel : NotifyPropertyChangedBase { private readonly Logger Log = new Logger("ConvEdgeObject"); private readonly IAuroraEnvironment _auroraEnv; public ObservableCollection Options { get; set; } public ObservableCollection CurrentButtons { get; set; } public string _selectedOption; public string SelectedOption { get { return _selectedOption; } set { _selectedOption = value; OnPropertyChanged(nameof(SelectedOption)); UpdateButtons(); } } #region Binding Property private BitmapSource _OriginImage; public BitmapSource OriginImage { get => _OriginImage; set => SetProperty(ref _OriginImage, value); } private BitmapSource _MaskedImage; public BitmapSource MaskedImage { get => _MaskedImage; set => SetProperty(ref _MaskedImage, value); } private BitmapSource _ResultImage; public BitmapSource ResultImage { get => _ResultImage; set => SetProperty(ref _ResultImage, value); } private double _CVThreshold; public double CVThreshold { get => _CVThreshold; set => SetProperty(ref _CVThreshold, value); } private int _CVShrinkPixel; public int CVShrinkPixel { get => _CVShrinkPixel; set => SetProperty(ref _CVShrinkPixel, value); } private int _CVShrinkPixel2; public int CVShrinkPixel2 { get => _CVShrinkPixel2; set => SetProperty(ref _CVShrinkPixel2, value); } private int _CVShrinkPixel3; public int CVShrinkPixel3 { get => _CVShrinkPixel3; set => SetProperty(ref _CVShrinkPixel3, value); } private int _CVShrinkPixel4; public int CVShrinkPixel4 { get => _CVShrinkPixel4; set => SetProperty(ref _CVShrinkPixel4, value); } private double _Radius; public double Radius { get => _Radius; set => SetProperty(ref _Radius, value); } private int _Margin; public int Margin { get => _Margin; set => SetProperty(ref _Margin, value); } private int _PointNum; public int PointNum { get => _PointNum; set => SetProperty(ref _PointNum, value); } private double _DetectPointPercent; public double DetectPointPercent { get => _DetectPointPercent; set => SetProperty(ref _DetectPointPercent, value); } private int _CVMorpIterations; public int CVMorpIterations { get => _CVMorpIterations; set => SetProperty(ref _CVMorpIterations, value); } private int _CVMorpMaskSize; public int CVMorpMaskSize { get => _CVMorpMaskSize; set => SetProperty(ref _CVMorpMaskSize, value); } private double _MILThreshold; public double MILThreshold { get => _MILThreshold; set => SetProperty(ref _MILThreshold, value); } private double _MILFillGapDist; public double MILFillGapDist { get => _MILFillGapDist; set => SetProperty(ref _MILFillGapDist, value); } private double _MILShrinkDist; public double MILShrinkDist { get => _MILShrinkDist; set => SetProperty(ref _MILShrinkDist, value); } private double _CVInnerCircleSize; public double CVInnerCircleSize { get => _CVInnerCircleSize; set => SetProperty(ref _CVInnerCircleSize, value); } private double _CVOuterCircleSize; public double CVOuterCircleSize { get => _CVOuterCircleSize; set => SetProperty(ref _CVOuterCircleSize, value); } private double _DrawObjectDistanceRange; public double DrawObjectDistanceRange { get => _DrawObjectDistanceRange; set => SetProperty(ref _DrawObjectDistanceRange, value); } private double _DrawObjectLengthSumDiffRange; public double DrawObjectLengthSumDiffRange { get => _DrawObjectLengthSumDiffRange; set => SetProperty(ref _DrawObjectLengthSumDiffRange, value); } private double _DrawObjectDistanceMin; public double DrawObjectDistanceMin { get => _DrawObjectDistanceMin; set => SetProperty(ref _DrawObjectDistanceMin, value); } private double _DrawObjectDistanceMax; public double DrawObjectDistanceMax { get => _DrawObjectDistanceMax; set => SetProperty(ref _DrawObjectDistanceMax, value); } private double _DrawObjectArcLengthMax; public double DrawObjectArcLengthMax { get => _DrawObjectArcLengthMax; set => SetProperty(ref _DrawObjectArcLengthMax, value); } private double _DrawObjectCenterXYDiffRange; public double DrawObjectCenterXYDiffRange { get => _DrawObjectCenterXYDiffRange; set => SetProperty(ref _DrawObjectCenterXYDiffRange, value); } private double _MergeDist; public double MergeDist { get => _MergeDist; set => SetProperty(ref _MergeDist, value); } private uint _MaxArcRadius; public uint MaxArcRadius { get => _MaxArcRadius; set => SetProperty(ref _MaxArcRadius, value); } private uint _LineTolerance; public uint LineTolerance { get => _LineTolerance; set => SetProperty(ref _LineTolerance, value); } private uint _ArcTolerance; public uint ArcTolerance { get => _ArcTolerance; set => SetProperty(ref _ArcTolerance, value); } private float _LineDefualtWidth; public float LineDefualtWidth { get => _LineDefualtWidth; set => SetProperty(ref _LineDefualtWidth, value); } private int _ObjectNumber; public int ObjectNumber { get => _ObjectNumber; set => SetProperty(ref _ObjectNumber, value); } private ObservableCollection _ContourCorrection = new ObservableCollection(); public ObservableCollection ContourCorrection { get => _ContourCorrection; set => SetProperty(ref _ContourCorrection, value); } private double _ReferenceX; public double ReferenceX { get => _ReferenceX; set => SetProperty(ref _ReferenceX, value); } private double _ReferenceY; public double ReferenceY { get => _ReferenceY; set => SetProperty(ref _ReferenceY, value); } private double _ReferenceTh; public double ReferenceTh { get => _ReferenceTh; set => SetProperty(ref _ReferenceTh, value); } private double _OffsetX; public double OffsetX { get => _OffsetX; set => SetProperty(ref _OffsetX, value); } private double _OffsetY; public double OffsetY { get => _OffsetY; set => SetProperty(ref _OffsetY, value); } private double _OffsetTh; public double OffsetTh { get => _OffsetTh; set => SetProperty(ref _OffsetTh, value); } public ICommand CMD_LoadImage { get; } public ICommand CMD_CheckRadiusImage { get; } public ICommand CMD_DetectImage { get; } public ICommand CMD_SaveImage { get; } public ICommand CMD_SaveCSV { get; } public ICommand CMD_GenerateDrawingObject { get; } public ICommand CMD_VisionTypeChanged { get; } public ICommand CMD_OffsetTypeChanged { get; } public ICommand CMD_ObjectGenTypeChanged { get; } public ICommand CMD_CenterDetectTest { get; } public ICommand CMD_RecommendDetectParam { get; } public ICommand CMD_RecipeUpdate { get; } public ICommand CMD_OffsetUpdate { get; } public ICommand CMD_OffsetSave { get; } public ICommand CMD_FindReference { get; } public ICommand CMD_FindObject { get; } public ICommand CMD_RecipeUpdateObject { get; } // Flying vision + Detect Image + Generate Object + Welding Sequence public ICommand CMD_FlyingSeqStart { get; } public ICommand CMD_FlyingSeqRun { get; } public ICommand CMD_FlyingSeqStop { get; } public ICommand CMD_SystemParamSave { get; } #endregion private readonly ISequenceEntry _SequenceEntry; private readonly IEventObservable _EventObservable = Application.Current.AuroraEnv().EventObservable; private ISequence _ManualRunRCC; private ISequence _AutoRunSMWSeq_wo_Scout; private ISequence _AutoRunSMWSeq_Scout; #region MIL Property MIL_ID Edge_Contour_Context = MIL.M_NULL; MIL_ID Edge_Result = MIL.M_NULL; MIL_ID MedgeCalculate_graphicContext = MIL.M_NULL; MIL_ID MedgeCalculate_graphicList = MIL.M_NULL; MIL_ID MILGrayImage = MIL.M_NULL; MIL_ID MilBinaryImage = MIL.M_NULL; MIL_ID MILImage = MIL.M_NULL; #endregion private Mat _LoadImageMat; private Mat _DetectImageMat; private Mat _ConvImageMat; private Mat _MaskedImageMat; private ObjectGenerator _ObjGenerator; private CameraAgentBase _CameraAgent; private Stopwatch _Stopwatch; private string _ImagePath; private string _VisionType = "OpenCV"; private string _OffsetType = "Manual"; private string _ObjectGenType = "Auto"; private Point _CenterPoint; private Point[][] _MaxContour; private double[] _XCoordinates; private double[] _YCoordinates; private Point[][] _EdgePoints; private List _DestDrawObjectList; private double _Offset_x, _Offset_y, _Offset_t; private int _Ref_x, _Ref_y; private double _Ref_t; private List _PathList; private WeldingCommon.Settings.SystemParameter _SystemParam; private ISettingEntry _SettingEntry; private static ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; private double _CenterX; private double _CenterY; private double _ImageWidth; private double _ImageHeight; private UnitPoint _Obejct_Center; private Point[][] _MinContour; private double _PixelResolution; private SequenceDialog _SequenceDialog; private Arc.eDirection _Draw_direction; public UCConvEdgeObjectViewModel(IAuroraEnvironment aurora) { Options = new ObservableCollection { "SMW", "Inzi", "LFW" }; CurrentButtons = new ObservableCollection(); SelectedOption = Options[0]; CMD_LoadImage = new DelegateCommand(PerformCmdLoadImage); CMD_CheckRadiusImage = new DelegateCommand(PerformCmdCheckRadiusImage); CMD_DetectImage = new DelegateCommand(PerformCmdDetectImage); CMD_SaveImage = new DelegateCommand(PerformCmdSaveImage); CMD_SaveCSV = new DelegateCommand(PerformCmdSaveCSV); CMD_GenerateDrawingObject = new DelegateCommand(PerformCmdGenerateDrawingObject); CMD_VisionTypeChanged = new DelegateCommand(PerformCmdVisionTypeChanged); CMD_OffsetTypeChanged = new DelegateCommand(PerformCmdOffsetTypeChanged); CMD_ObjectGenTypeChanged = new DelegateCommand(PerformCmdObjectGenTypeChanged); CMD_CenterDetectTest = new DelegateCommand(PerformCmdCenterDetectTest); CMD_RecommendDetectParam = new DelegateCommand(PerformCmdRecommendDetectParam); CMD_RecipeUpdate = new DelegateCommand(PerformCmdRecipeUpdate); CMD_OffsetUpdate = new DelegateCommand(PerformCmdOffsetUpdate); CMD_OffsetSave = new DelegateCommand(PerformCmdOffsetSave); CMD_FindReference = new DelegateCommand(PerformCmdFindReference); CMD_FindObject = new DelegateCommand(PerformCmdFindObject); CMD_RecipeUpdateObject = new DelegateCommand(PerformCmdRecipeUpdateObject); CMD_FlyingSeqStart = new DelegateCommand(PerformCmdFlyingSeqStart); CMD_FlyingSeqRun = new DelegateCommand(PerformCmdFlyingSeqRun); CMD_FlyingSeqStop = new DelegateCommand(PerformCmdFlyingSeqStop); CMD_SystemParamSave = new DelegateCommand(PerformCmdSystemParameterSave); _auroraEnv = aurora; _SequenceEntry = _auroraEnv.SequenceEntry; _ManualRunRCC = _SequenceEntry[CommonSequenceIds.SeqManualRunRCC]; _EventObservable.AsObservable(CommonSequenceIds.SeqManualRunRCC) .ObserveOn(Application.Current.Dispatcher) .Subscribe(OnUpdateManualRunResult); var fovInfo = VisionRecipeManager.GetFovInfos().FirstOrDefault(); _CameraAgent = CameraAgentManager.GetCameraAgent(fovInfo); _SystemParam = aurora.SettingEntry[CommonSettingIds.SystemParameter] as WeldingCommon.Settings.SystemParameter; _SettingEntry = aurora.SettingEntry; _Stopwatch = new Stopwatch(); _PixelResolution = ((_SystemParam.CameraPixelSize) / _SystemParam.LensMagnification) / 1000.0; _ObjGenerator = new ObjectGenerator(0, 0, _PixelResolution); if (_SystemParam.OffsetType == eOffsetType.manual) { _ObjGenerator.SetOffsetType("Manual"); } else { _ObjGenerator.SetOffsetType("CSV"); } if (_SystemParam.OffsetCSVFile != null) { _ObjGenerator.setOffsetTable(_SystemParam.OffsetCSVFile, _SystemParam.LensMagnification, _SystemParam.CameraPixelSize); } else { Log.W("Not exist CSV OffsetTable of Systemparameter"); } UpdateButtons(); #region Initialize Property CVThreshold = _SystemParam.CVThreshold; CVMorpIterations = _SystemParam.CVMorpIterations; CVMorpMaskSize = _SystemParam.CVMorpMaskSize; CVShrinkPixel = _SystemParam.CVShrinkPixel; CVShrinkPixel2 = _SystemParam.CVShrinkPixel2; CVShrinkPixel3 = _SystemParam.CVShrinkPixel3; CVShrinkPixel4 = _SystemParam.CVShrinkPixel4; Radius = _SystemParam.Radius; Margin = _SystemParam.Margin; PointNum = _SystemParam.PointNum; DetectPointPercent = _SystemParam.DetectPointPercent; // % MILThreshold = 10; MILFillGapDist = 20; MILShrinkDist = 40; CVInnerCircleSize = _SystemParam.CVInnerCircleSize; // mm CVOuterCircleSize = _SystemParam.CVOuterCircleSize; // mm MergeDist = _SystemParam.dMergeDist; MaxArcRadius = _SystemParam.nMaxArcRadius; LineTolerance = _SystemParam.nLineTolerance; ArcTolerance = _SystemParam.nArcTolerance; LineDefualtWidth = _SystemParam.fLineDefualtWidth; ObjectNumber = _SystemParam.ObjectNumber; DrawObjectDistanceMin = _SystemParam.DrawObjectDistanceMin; // mm DrawObjectDistanceMax = _SystemParam.DrawObjectDistanceMax; // mm DrawObjectDistanceRange = _SystemParam.DrawObjectDistanceRange; // mm DrawObjectLengthSumDiffRange = _SystemParam.DrawObjectLengthSumDiffRange; // mm DrawObjectArcLengthMax = _SystemParam.DrawObjectArcLengthMax; // mm DrawObjectCenterXYDiffRange = _SystemParam.DrawObjectCenterXYDiffRange; #endregion } private void UpdateButtons() { CurrentButtons.Clear(); if (SelectedOption == "SMW") { CurrentButtons.Add(new ButtonViewModel("Check Radius", CMD_CheckRadiusImage)); CurrentButtons.Add(new ButtonViewModel("Edge Detect", CMD_DetectImage)); CurrentButtons.Add(new ButtonViewModel("Generate Object", CMD_GenerateDrawingObject)); CurrentButtons.Add(new ButtonViewModel("Recipe Update", CMD_RecipeUpdate)); CurrentButtons.Add(new ButtonViewModel("Save Offset Table", CMD_OffsetSave)); CurrentButtons.Add(new ButtonViewModel("Update Offset Table", CMD_OffsetUpdate)); } else if (SelectedOption == "Inzi") { CurrentButtons.Add(new ButtonViewModel("Find Reference", CMD_FindReference)); CurrentButtons.Add(new ButtonViewModel("Find Offset", CMD_FindObject)); CurrentButtons.Add(new ButtonViewModel("Recipe Update", CMD_RecipeUpdateObject)); } else if (SelectedOption == "LFW") { CurrentButtons.Add(new ButtonViewModel("Find Reference", CMD_FindReference)); CurrentButtons.Add(new ButtonViewModel("Find Offset", CMD_FindObject)); CurrentButtons.Add(new ButtonViewModel("Recipe Update", CMD_RecipeUpdateObject)); } CommandManager.InvalidateRequerySuggested(); } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void PerformCmdSystemParameterSave(object obj) { var result = MessageDialog.Show(Application.Current.MainWindow, "RCC", $"Save RCC parameters in system parameters??", MessageDialog.Type.AffirmativeAndNegative); if (result == MessageDialog.Result.Negative) { return; } _SystemParam.CVThreshold = CVThreshold; _SystemParam.CVShrinkPixel = CVShrinkPixel; _SystemParam.CVShrinkPixel2 = CVShrinkPixel2; _SystemParam.CVShrinkPixel3 = CVShrinkPixel3; _SystemParam.CVShrinkPixel4 = CVShrinkPixel4; _SystemParam.Margin = Margin; // mm _SystemParam.Radius = Radius; // mm _SystemParam.PointNum = PointNum; // divide count _SystemParam.DetectPointPercent = DetectPointPercent; // % _SystemParam.dMergeDist = MergeDist; _SystemParam.nMaxArcRadius = MaxArcRadius; _SystemParam.nLineTolerance = LineTolerance; _SystemParam.nArcTolerance = ArcTolerance; _SystemParam.fLineDefualtWidth = LineDefualtWidth; _SystemParam.ObjectNumber = ObjectNumber; _SystemParam.DrawObjectDistanceMin = DrawObjectDistanceMin; // mm _SystemParam.DrawObjectDistanceMax = DrawObjectDistanceMax; // mm _SystemParam.DrawObjectDistanceRange = DrawObjectDistanceRange; // mm _SystemParam.DrawObjectLengthSumDiffRange = DrawObjectLengthSumDiffRange; // mm _SystemParam.DrawObjectArcLengthMax = DrawObjectArcLengthMax; // mm _SystemParam.DrawObjectCenterXYDiffRange = DrawObjectCenterXYDiffRange; //mm _SystemParam.ReferenceX = _Ref_x; //mm _SystemParam.ReferenceY = _Ref_y; //mm _SystemParam.ReferenceTh = _Ref_t; //deg _SettingEntry.Save(CommonSettingIds.SystemParameter, _SystemParam, "RCC"); } private void PerformCmdVisionTypeChanged(object obj) { _VisionType = (string)obj; } private void PerformCmdOffsetTypeChanged(object obj) { _OffsetType = (string)obj; _ObjGenerator.SetOffsetType(_OffsetType); } private void PerformCmdObjectGenTypeChanged(object obj) { _ObjectGenType = (string)obj; _ObjGenerator.SetOffsetType(_ObjectGenType); } private void PerformCmdSaveImage(object obj) { SaveFileDialog sfd = new SaveFileDialog(); sfd.Filter = "JPEG Image|*.jpg|PNG Image|*.png|Bitmap Image|*.bmp"; sfd.Title = "Save an Image File"; sfd.DefaultExt = "jpg"; // 기본 확장자를 설정합니다. sfd.FileName = string.Format($"ResultImage_{DateTime.Now.Month}_{DateTime.Now.Day}_{DateTime.Now.ToString("HHmmss")}.jpg"); // 기본 파일 이름을 설정합니다. DialogResult dr = sfd.ShowDialog(); if (dr == DialogResult.OK) { string savepath = sfd.FileName; //bitmapSource를 이미지 파일로 저장 BitmapEncoder encoder = new JpegBitmapEncoder(); using (FileStream stream = new FileStream(savepath, FileMode.Create)) { encoder.Frames.Add(BitmapFrame.Create(ResultImage)); encoder.Save(stream); } } } private void PerformCmdSaveCSV(object obj) { if (_MaxContour != null) { SaveContoursToCsv(_MaxContour); } //Jin : 미사용 //switch (_VisionType) { // case "OpenCV": // if (_MaxContour != null) { // SaveContoursToCsv(_MaxContour); // } else { // SaveCenterToCsv(_CenterX, _CenterY); // } // break; // case "MIL": // SaveCoordinatesToCsv(_XCoordinates, _YCoordinates); // break; //} } private void PerformCmdGenerateDrawingObject(object obj) { GenerateDrawingObject(); } private void GenerateDrawingObject() { _ObjGenerator.SetInterlockProperties(DrawObjectDistanceRange, DrawObjectArcLengthMax, DrawObjectLengthSumDiffRange, DrawObjectCenterXYDiffRange); if (!GetArcInfoFromRecipe()) { return; } // MaxContour가 0일 경우 예외처리 if (_MaxContour[0].Count() < 1) { Log.E("MaxContour is Null"); return; } // maxContour 를 보내자 if (_VisionType == "OpenCV") { _ObjGenerator.SetPolygonFromList(_MaxContour); } else { _ObjGenerator.SetPolygonFromList(_EdgePoints); } if (_ObjectGenType == "ArcByAngle") _ObjGenerator.CalculateAutoPathAngle(ObjectNumber); else _ObjGenerator.CalculateAutoPath(_MergeDist, _MaxArcRadius, _LineTolerance, _ArcTolerance); _ObjGenerator.ConvertPathItemToDrawingObjects(LineDefualtWidth, out _DestDrawObjectList); if (_ObjGenerator.CheckInterlockDrawingObjectPosition(_DestDrawObjectList) == false) { MessageUtil.CreateAndShowMessageDialog("DrawObject Interlock check.", "Invalid DrawObject is found."); } _ObjGenerator.SaveDrawingObjectsToCSV(_DestDrawObjectList, "Manual"); double dpathlength = 0; foreach (var item in _DestDrawObjectList) { if (item is Line) { if (((Line)item).MadebyRCC) { dpathlength += ((Line)item).Distance; } } else if (item is Arc) { if (((Arc)item).MadebyRCC) { dpathlength += ((Arc)item).Length; } } } _ObjGenerator.GetAutoPath(out _PathList); DrawObject(); } private void SaveCoordinatesToCsv(double[] xCoordinates, double[] yCoordinates) { string savepath = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "EdgeContour", string.Format($"{_VisionType}_{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}_{DateTime.Now.ToString("HHmmss")}.csv")); try { using (StreamWriter writer = new StreamWriter(savepath)) { writer.WriteLine("X,Y"); for (int i = 0; i < xCoordinates.Length; i++) { writer.WriteLine($"{xCoordinates[i]},{yCoordinates[i]}"); } } } catch (Exception e) { Log.E(e.Message); } } private void SaveOffsetToCsv(double[] offset, double[] theta) { string savepath = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "EdgeContour", "Manual", string.Format($"Offset_{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}_{DateTime.Now.Hour}_{DateTime.Now.Minute}.csv")); try { using (StreamWriter writer = new StreamWriter(savepath)) { writer.WriteLine("Theta,Offset"); for (int i = 0; i < offset.Length; i++) { writer.WriteLine($"{theta[i]},{offset[i]}"); } } MessageUtil.CreateAndShowMessageDialog("Completed", $"Offset table is saved as {savepath}"); } catch (Exception e) { Log.E(e.Message); } } private void PerformCmdOffsetUpdate(object obj) { OpenFileDialog ofd = new OpenFileDialog(); DialogResult dr = ofd.ShowDialog(); string csvpath = ""; if (dr == DialogResult.OK) { csvpath = ofd.FileName; } if (csvpath == "") { return; } _ObjGenerator.setOffsetTable(csvpath, _SystemParam.LensMagnification, _SystemParam.CameraPixelSize); } private void SaveContoursToCsv(Point[][] maxcotours) { string folderPath = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "EdgeContour", "Manual"); string filepath = Path.Combine(folderPath, string.Format($"EdgeContour_{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}_{DateTime.Now:HHmmss}.csv")); try { if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } using (StreamWriter writer = new StreamWriter(filepath)) { int index = 0; writer.WriteLine("Index,X_pixel,Y_pixel,X_mm,Y_mm"); foreach (var contour in maxcotours) { foreach (var point in contour) { index++; double convertX = (point.X - _ImageWidth / 2) * (_SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000; double convertY = (-point.Y + _ImageHeight / 2) * (_SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000; writer.WriteLine($"{index},{point.X},{point.Y},{convertX},{convertY}"); } } } } catch (Exception e) { Log.E(e.Message); } } private void SaveCenterToCsv(double dCenterX, double dCenterY) { string savepath = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "EdgeContour", "Manual", string.Format($"CenterDetect_{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}.csv")); try { if (!File.Exists(savepath)) { using (StreamWriter writer = new StreamWriter(savepath, false)) { writer.WriteLine("DateTime, CenterX, CenterY"); writer.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")}, {dCenterX}, {dCenterY}"); } } else { using (StreamWriter writer = new StreamWriter(savepath, true)) { writer.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")}, {dCenterX}, {dCenterY}"); } } } catch (Exception e) { Log.E(e.Message); } } private void PerformCmdCheckRadiusImage(object obj) { if (_MaskedImageMat == null) { MessageUtil.CreateAndShowMessageDialog("Detect Edge is failed.", "Detect Edge is failed. Please Load image."); return; } _Stopwatch.Start(); int Radius_Pixel = (int)(((Radius * _SystemParam.LensMagnification) / _SystemParam.CameraPixelSize) * 1000.0); //objGenerator.FindEdge(ConvImg, Radius_Pixel, Margin, PointNum, CVThreshold, CVShrinkPixel, DetectPointPercent, out maxContour); _ObjGenerator.FindCenterPoint(_ConvImageMat, CVThreshold, out _CenterPoint); _Stopwatch.Stop(); Log.I($"OpenCV Time : {(float)_Stopwatch.ElapsedMilliseconds}"); _Stopwatch.Reset(); //UpdateDateCorrection(maxContour); //DrawCVEdgeContour(maxContour); DrawCenterPointRadius(_CenterPoint, Radius_Pixel); } private void PerformCmdDetectImage(object obj) { if (_MaskedImageMat == null) { MessageUtil.CreateAndShowMessageDialog("Detect Edge is failed.", "Detect Edge is failed. Please Load image."); return; } int centerX = 0, centerY = 0; var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; foreach (var item in _ScannerCanvasUserCtrl.Model.Layers[0].Objects) { if (item is Arc) { Arc arc = (Arc)item; centerX = (int)(arc.Center.X * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageWidth / 2); centerY = (int)(-arc.Center.Y * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageHeight / 2); break; } } _Stopwatch.Start(); //Autorun과 동일하게 할려면 Mil to mat 부터 진행해야하나 여기서는 EdgeDetect 시간만 확인 //maxContour = objGenerator.FindMaxContour(MaskedImg, CVThreshold, CVMorpIterations, CVMorpMaskSize); //maxContour = objGenerator.FindMaxContour(MaskedImg, CVThreshold, CVShrinkPixel); int Radius_Pixel = (int)(((Radius * _SystemParam.LensMagnification) / _SystemParam.CameraPixelSize) * 1000.0); _ObjGenerator.FindEdge(_ConvImageMat, Radius_Pixel, Margin, PointNum, CVThreshold, centerX, centerY, CVShrinkPixel, CVShrinkPixel2, CVShrinkPixel3, CVShrinkPixel4, DetectPointPercent, out _MaxContour); //maxContour = objGenerator.ReSizeFindMaxContour(ConvImg, 2, CVThreshold, CVShrinkPixel); _Stopwatch.Stop(); Log.I($"OpenCV Time : {(float)_Stopwatch.ElapsedMilliseconds}"); _Stopwatch.Reset(); UpdateDateCorrection(_MaxContour); DrawCVEdgeContour(_MaxContour); } private void UpdateDateCorrection(Point[][] maxContours) { if (maxContours.Count() < 1) { return; } if (ContourCorrection.Count() != 0) { ContourCorrection.Clear(); } // MaxContour가 0일 경우 예외처리 if (_MaxContour[0].Count() < 1) { Log.E("MaxContour is Null"); return; } int index = 0; foreach (var contour in maxContours) { foreach (var point in contour) { ContourList cLItem = new ContourList(); cLItem.Index = index++; cLItem.VisionX = point.X; cLItem.VisionY = point.Y; ContourCorrection.Add(cLItem); } } } private void DrawCenterPointRadius(Point center_point, double radius) { // Draw the contour on the image _DetectImageMat = _ConvImageMat.Clone(); if (_VisionType == "OpenCV") { Cv2.Circle(_DetectImageMat, center_point, 8, new Scalar(0, 255, 0), -1); Cv2.Circle(_DetectImageMat, center_point, (int)radius, new Scalar(0, 255, 0), 2); } else { //Cv2.DrawContours(detectImg, maxContour, -1, new Scalar(0, 255, 0), 2); Cv2.Circle(_DetectImageMat, center_point, 3, new Scalar(0, 255, 0), -1); Cv2.Circle(_DetectImageMat, center_point, (int)radius, new Scalar(0, 255, 0), 2); } ResultImage = _DetectImageMat.ToBitmapSource(); } private void DrawCVEdgeContour(Point[][] maxContour) { // Draw the contour on the image _DetectImageMat = _ConvImageMat.Clone(); // MaxContour가 0일 경우 예외처리 if (maxContour[0].Count() < 1) { ResultImage = _DetectImageMat.ToBitmapSource(); //Log.E("MaxContour is Null"); return; } if (_VisionType == "OpenCV") { Cv2.DrawContours(_DetectImageMat, maxContour, -1, new Scalar(0, 255, 0), 2); } else { Cv2.DrawContours(_DetectImageMat, maxContour, -1, new Scalar(0, 0, 255), 2); } ResultImage = _DetectImageMat.ToBitmapSource(); } private void DrawCVCenterContour(Point[][] minContour) { // Draw the contour on the image _DetectImageMat = _ConvImageMat.Clone(); Rect minRect = Cv2.BoundingRect(minContour[0]); double centerX = minRect.X + (minRect.Width / 2); double centerY = minRect.Y + (minRect.Height / 2); double mCenterX = (((centerX - _DetectImageMat.Width / 2) * _SystemParam.CameraPixelSize) / _SystemParam.LensMagnification) / 1000.0; double mCenterY = (((_DetectImageMat.Height / 2 - centerY) * _SystemParam.CameraPixelSize) / _SystemParam.LensMagnification) / 1000.0; _CenterX = mCenterX; _CenterY = mCenterY; Cv2.DrawContours(_DetectImageMat, minContour, -1, new Scalar(0, 255, 0), 2); Cv2.Line(_DetectImageMat, new Point(centerX - 50, centerY), new Point(centerX + 50, centerY), new Scalar(0, 0, 255), 5); Cv2.Line(_DetectImageMat, new Point(centerX, centerY - 50), new Point(centerX, centerY + 50), new Scalar(0, 0, 255), 5); ResultImage = _DetectImageMat.ToBitmapSource(); MessageUtil.CreateAndShowMessageDialog("Circle Find Success", string.Format("{0:0.00} , {1:0.00}", mCenterX, mCenterY)); } private void PerformCmdLoadImage(object obj) { OpenFileDialog ofd = new OpenFileDialog(); DialogResult dr = ofd.ShowDialog(); if (dr == DialogResult.OK) { _ImagePath = ofd.FileName; } if (_ImagePath == null) { return; } #region OpenCV _LoadImageMat = Cv2.ImRead(_ImagePath); OriginImage = _LoadImageMat.ToBitmapSource(); _ConvImageMat = _LoadImageMat.Clone(); _ObjGenerator.SetImageSize(_LoadImageMat.Width, _LoadImageMat.Height); _ImageWidth = _LoadImageMat.Width; _ImageHeight = _LoadImageMat.Height; _MaskedImageMat = _ObjGenerator.MaskingImage(_ConvImageMat, CVInnerCircleSize, CVOuterCircleSize); MaskedImage = _MaskedImageMat.ToBitmapSource(); #endregion //#region MIL ////buffer 설정, buffer 사이즈는 가져온 이미지의 사이즈로 넣어줘야함.. //MIL.MbufAllocColor(MilEnvironment.Instance.GetSystem(_cameraAgent._CamConfig.CamConnConfig.BoardSlotPos), 3, loadImg.Width, loadImg.Height, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_DISP + MIL.M_PROC, ref MILImage); ////이미지 로드 //MIL.MbufLoad(imagepath, MILImage); ////WPF Bitmapsource로 변환 //int width = (int)MIL.MbufInquire(MILImage, MIL.M_SIZE_X, MIL.M_NULL); //int height = (int)MIL.MbufInquire(MILImage, MIL.M_SIZE_Y, MIL.M_NULL); ////int stride = width; // Assuming 8-bit grayscale image //int stride = width * 3; // Assuming 24-bit BRG image //byte[] imageData = new byte[width * height * 3]; ////MIL.MbufGet(MILImage, imageData); // 8-bit일 경우 사용 //MIL.MbufGetColor(MILImage, MIL.M_PACKED + MIL.M_BGR24, MIL.M_ALL_BANDS, imageData); ////8-bit 1ch gray일 경우 사용 ////BitmapSource bitmapSource = BitmapSource.Create( //// width, height, 96, 96, System.Windows.Media.PixelFormats.Gray8, null, imageData, stride); ////32-bit 3ch bgr //BitmapSource bitmapSource = BitmapSource.Create( // width, height, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null, imageData, stride); ////Convert bitmapsource to Mat //ConvImg = bitmapSource.ToMat(); //// MIL 해제 //MIL.MbufFree(MILImage); //#endregion //int width = loadImg.Width; //int height = loadImg.Height; //int stride = width * 3; //byte[] imageData = new byte[width * height * 3]; //imageData = loadImg.ToBytes(); //BitmapSource bitmapSource = BitmapSource.Create( // loadImg.Width, loadImg.Height, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null, loadImg.Data, loadImg.Step()); //ConvImg = bitmapSource.ToMat(); // WPF Image 컨트롤에 설정 //OriginImage = bitmapSource; } private void FindMilEdgeContour(double milThreshold, double milFillGapDist) { var camConfig = VisionEnv.AuroraEnv.DeviceManager.GetDeviceConfig(eCamId.CAM1.ToString()) as CamConfig; MIL_ID MilSystem = MilEnvironment.Instance.GetSystem(camConfig.CamConnConfig.BoardType, camConfig.CamConnConfig.BoardSlotPos); // Control Block for Disp //MIL.MbufImport(imagepath, MIL.M_DEFAULT, MIL.M_RESTORE + MIL.M_NO_GRAB + MIL.M_NO_COMPRESS, MilSystem, ref MILImage); MIL.MbufRestore(_ImagePath, MilSystem, ref MILImage); MIL.MgraAlloc(MilSystem, ref MedgeCalculate_graphicContext); MIL.MgraAllocList(MilSystem, MIL.M_DEFAULT, ref MedgeCalculate_graphicList); MIL.MedgeAlloc(MilSystem, MIL.M_CONTOUR, MIL.M_DEFAULT, ref Edge_Contour_Context); //MIL 컬러이미지를 Gray 이미지로 컨버팅 MIL.MbufAlloc2d(MilSystem, MIL.MbufInquire(MILImage, MIL.M_SIZE_X, MIL.M_NULL), MIL.MbufInquire(MILImage, MIL.M_SIZE_Y, MIL.M_NULL), 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC + MIL.M_DISP, ref MILGrayImage); MIL.MimConvert(MILImage, MILGrayImage, MIL.M_RGB_TO_L); MIL.MbufAlloc2d(MilSystem, MIL.MbufInquire(MILGrayImage, MIL.M_SIZE_X, MIL.M_NULL), MIL.MbufInquire(MILGrayImage, MIL.M_SIZE_Y, MIL.M_NULL), 1 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC + MIL.M_DISP, ref MilBinaryImage); MIL.MimBinarize(MILGrayImage, MilBinaryImage, MIL.M_FIXED + MIL.M_GREATER_OR_EQUAL, milThreshold, MIL.M_NULL); //MIL.MimBinarize(MILGrayImage, MilBinaryImage, MIL.M_BIMODAL + MIL.M_GREATER_OR_EQUAL, MIL.M_NULL, MIL.M_NULL); // Control Block for Edge Contour Context //MIL.MedgeControl(Edge_Contour_Context, MIL.M_MOMENT_ELONGATION, MIL.M_ENABLE); MIL.MedgeControl(Edge_Contour_Context, MIL.M_FILL_GAP_DISTANCE, milFillGapDist); MIL.MedgeControl(Edge_Contour_Context, MIL.M_CHAIN_ALL_NEIGHBORS, MIL.M_ENABLE); MIL.MedgeControl(Edge_Contour_Context, MIL.M_FERET_MAX_DIAMETER + MIL.M_SORT1_DOWN, MIL.M_ENABLE); // Set edge detection parameters MIL.MedgeAllocResult(MilSystem, MIL.M_DEFAULT, ref Edge_Result); // Calculate the edges. MIL.MedgeCalculate(Edge_Contour_Context, MilBinaryImage, MIL.M_NULL, MIL.M_NULL, MIL.M_NULL, Edge_Result, MIL.M_DEFAULT); // Exclude inner chains based on area MIL_INT numberOfEdges = 0; MIL.MedgeGetResult(Edge_Result, MIL.M_DEFAULT, MIL.M_NUMBER_OF_CHAINS + MIL.M_TYPE_MIL_INT, ref numberOfEdges); if (numberOfEdges > 0) { double[] diameters = new double[numberOfEdges]; MIL.MedgeGetResult(Edge_Result, MIL.M_DEFAULT, MIL.M_FERET_MAX_DIAMETER, diameters); double maxdiameter = diameters.Max(); //가장 값인 큰 파라미터인 엣지 선택 MIL.MedgeSelect(Edge_Result, MIL.M_INCLUDE_ONLY, MIL.M_FERET_MAX_DIAMETER, MIL.M_EQUAL, maxdiameter, MIL.M_NULL); // Retrieve the coordinates of the selected edge MIL_INT numberOfPoints = 0; MIL.MedgeGetResult(Edge_Result, MIL.M_DEFAULT, MIL.M_NUMBER_OF_CHAINED_EDGELS + MIL.M_TYPE_MIL_INT, ref numberOfPoints); if (numberOfPoints > 0) { _XCoordinates = new double[numberOfPoints]; _YCoordinates = new double[numberOfPoints]; MIL.MedgeGetResult(Edge_Result, MIL.M_DEFAULT, MIL.M_CHAIN_X, _XCoordinates); MIL.MedgeGetResult(Edge_Result, MIL.M_DEFAULT, MIL.M_CHAIN_Y, _YCoordinates); // Now xCoordinates and yCoordinates arrays contain the x and y coordinates of the edge points // Calculate the center of the circle double centerX = _XCoordinates.Average(); double centerY = _YCoordinates.Average(); for (int i = 0; i < numberOfPoints; i++) { double dx = _XCoordinates[i] - centerX; double dy = _YCoordinates[i] - centerY; double distance = Math.Sqrt(dx * dx + dy * dy); // Move the point inward by shrinkDistance double newDistance = distance - MILShrinkDist; double scale = newDistance / distance; _XCoordinates[i] = centerX + dx * scale; _YCoordinates[i] = centerY + dy * scale; } _EdgePoints = new Point[1][]; _EdgePoints[0] = new Point[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { _EdgePoints[0][i] = new Point((int)_XCoordinates[i], (int)_YCoordinates[i]); } } //MIL_INT remainingEdges = 0; //MIL.MedgeGetResult(Edge_Result, MIL.M_DEFAULT, MIL.M_NUMBER_OF_CHAINS + MIL.M_TYPE_MIL_INT, ref remainingEdges); //Log.I($"{remainingEdges}"); } } private void DrawObject() { if (_PathList == null) { return; } _DetectImageMat = _ConvImageMat.Clone(); foreach (var item in _PathList) { if (item != null) { if (item.GetType() == PathItem._PathType.Line) { Point P1; Int64 P1X, P1Y; Point P2; Int64 P2X, P2Y; item.GetStart(out P1X, out P1Y); P1.X = Convert.ToInt32(P1X); P1.Y = Convert.ToInt32(P1Y); item.GetEnd(out P2X, out P2Y); P2.X = Convert.ToInt32(P2X); P2.Y = Convert.ToInt32(P2Y); Cv2.Line(_DetectImageMat, P1, P2, new Scalar(0, 0, 255), 6); } else if (item.GetType() == PathItem._PathType.Arc) { Point P1; Int64 P1X, P1Y; Point P2; Int64 P2X, P2Y; item.GetStart(out P1X, out P1Y); P1.X = Convert.ToInt32(P1X); P1.Y = Convert.ToInt32(P1Y); item.GetEnd(out P2X, out P2Y); P2.X = Convert.ToInt32(P2X); P2.Y = Convert.ToInt32(P2Y); Point PCenter; Int64 PX, PY; item.GetCenter(out PX, out PY); PCenter.X = Convert.ToInt32(PX); PCenter.Y = Convert.ToInt32(PY); double radius = Convert.ToDouble(item.GetRadius()); double dStartAngle = Math.Atan2((P1.Y - PCenter.Y), (P1.X - PCenter.X)) * (180 / Math.PI); double dEndAngle = Math.Atan2((P2.Y - PCenter.Y), (P2.X - PCenter.X)) * (180 / Math.PI); if (dStartAngle < 0) { dStartAngle += 360; } if (dEndAngle < 0) { dEndAngle += 360; } //if (PCenter.X < 0 || PCenter.Y < 0 || radius < 1000 || radius > 3000) //{ // Cv2.Line(detectImg, P1, P2, new Scalar(0, 0, 255), 5); // continue; //} //if (dStartAngle < 90 && dEndAngle > 270) { // dEndAngle -= 360; //} //if (dStartAngle > 270 && dEndAngle < 90) { // dStartAngle -= 360; //} if (_Draw_direction == Arc.eDirection.CW) { if (dEndAngle < dStartAngle) dEndAngle += 360; } else { if (dStartAngle < dEndAngle) dStartAngle += 360; } Cv2.Ellipse(_DetectImageMat, PCenter, new Size(radius, radius), 0, dStartAngle, dEndAngle, new Scalar(0, 0, 255), 6); } } } ResultImage = _DetectImageMat.ToBitmapSource(); } private void PerformCmdCenterDetectTest(object obj) { _MinContour = FindMinContourForCenter(_ConvImageMat, CVThreshold); DrawCVCenterContour(_MinContour); } private void PerformCmdRecommendDetectParam(object obj) { var result = MessageDialog.Show(Application.Current.MainWindow, "RCC", $"Recommend EdgeDetect parameters(Threshold, ShrinkPixel)?", MessageDialog.Type.AffirmativeAndNegative); if (result == MessageDialog.Result.Negative) { return; } // 최소값, 최대값 정해두고 그 안에서 찾자. 이거까지 parameter 로 뺄 필요는 없을듯 // mask image 로 할경우 ConvImg 를 MaskedImg 로 바꿔줄 것 // Pixel의 Center와 Pixel간 거리의 min, max를 구해서 minmax의 차이가 가장 작은 threshold를 추천한다 //double Threshold = 3; // Check Radius를 사용하여 센터의 위치가 맞는 최소값을 기준으로 시작 double Threshold = CVThreshold; int loopcnt = 20; // Threshold 시작부터 cnt 까지 증가하면서 찾는다. Func GetDistance = (x, y) => Math.Sqrt(x * x + y * y); //double range = 9999; //double RecommandedThreshold = 10; double RecommandedThreshold = CVThreshold; double min_dist = 9999; double contour_min_dist = 9999; //List temp_dist = new List(); int centerX = 0, centerY = 0; foreach (var item in _ScannerCanvasUserCtrl.Model.Layers[0].Objects) { if (item is Arc) { Arc arc = (Arc)item; centerX = (int)(arc.Center.X * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageWidth / 2); centerY = (int)(-arc.Center.Y * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageHeight / 2); break; } } int Radius_Pixel = (int)(((Radius * _SystemParam.LensMagnification) / _SystemParam.CameraPixelSize) * 1000.0); for (int i = 0; i < loopcnt; i++) { //maxContour = objGenerator.ReSizeFindMaxContour(ConvImg, 2, Threshold, CVShrinkPixel); //objGenerator.FindEdge(ConvImg, 1508, 10, 3600, Threshold, CVShrinkPixel, out maxContour); _ObjGenerator.FindEdge(_ConvImageMat, Radius_Pixel, Margin, PointNum, Threshold, centerX, centerY, CVShrinkPixel, CVShrinkPixel2, CVShrinkPixel3, CVShrinkPixel4, DetectPointPercent, out _MaxContour); //Point2f centroid = objGenerator.CalculateCentroid(maxContour[0]); //if (Single.IsNaN(centroid.X) || Single.IsNaN(centroid.Y)) continue; // min/max가 아닌 Check Radius를 통해 입력한 Radius 길이로 비교(min_dist) //double min = 9999; //double max = -9999; for (int j = 0; j < _MaxContour[0].Length; j++) { //double dist = GetDistance(maxContour[0][j].X - centroid.X, maxContour[0][j].Y - centroid.Y); // Contour의 무게 중심 기준이 아닌, Check Radius를 토대로 찾은 센터를 기준으로 진행 double dist = GetDistance(_MaxContour[0][j].X - _CenterPoint.X, _MaxContour[0][j].Y - _CenterPoint.Y); //if (dist < min) // min = dist; //if (dist > max) // max = dist; double diff_dist = Math.Abs(Radius_Pixel - dist); if (diff_dist < contour_min_dist) { contour_min_dist = diff_dist; } } //if (range > max - min) //{ // range = max - min; // RecommandedThreshold = Threshold; //} //temp_dist.Add(contour_min_dist); if (min_dist > contour_min_dist) { min_dist = contour_min_dist; RecommandedThreshold = Threshold; } Threshold = Threshold + 1; } CVThreshold = RecommandedThreshold; _ObjGenerator.FindEdge(_ConvImageMat, Radius_Pixel, Margin, PointNum, CVThreshold, centerX, centerY, CVShrinkPixel, CVShrinkPixel2, CVShrinkPixel3, CVShrinkPixel4, DetectPointPercent, out _MaxContour); UpdateDateCorrection(_MaxContour); DrawCVEdgeContour(_MaxContour); _ObjGenerator.SetInterlockProperties(DrawObjectDistanceRange, DrawObjectArcLengthMax, DrawObjectLengthSumDiffRange, DrawObjectCenterXYDiffRange); if (!GetArcInfoFromRecipe()) { return; } //객체 생성 후 객체의 시작점을 기준으로 센터까지의 거리를 구해서 평균 한 후 기존 arc의 반지름과의 차이가 가작 작은 값을 추천한다 int loopShrinkcnt = 60; //double dMinLengthDiff = 9999; double dMinRadiusDiff = 9999; int ShrinkPixel = 0; //int Radius_Pixel = (int)(((Radius * _systemParam.LensMagnification) / _systemParam.CameraPixelSize) * 1000.0); for (int i = 0; i < loopShrinkcnt; i++) { //maxContour = objGenerator.ReSizeFindMaxContour(ConvImg, 2, CVThreshold, i); _ObjGenerator.FindEdge(_ConvImageMat, Radius_Pixel, Margin, PointNum, CVThreshold, centerX, centerY, CVShrinkPixel, CVShrinkPixel2, CVShrinkPixel3, CVShrinkPixel4, DetectPointPercent, out _MaxContour); if (_VisionType == "OpenCV") { _ObjGenerator.SetPolygonFromList(_MaxContour); } else { _ObjGenerator.SetPolygonFromList(_EdgePoints); } _ObjGenerator.CalculateAutoPath(MergeDist, MaxArcRadius, LineTolerance, ArcTolerance); _ObjGenerator.ConvertPathItemToDrawingObjects(LineDefualtWidth, out _DestDrawObjectList); _ObjGenerator.CheckInterlockDrawingObjectPosition(_DestDrawObjectList); // objGenerator.fDetectedContourRadius 는 가장 먼 point 로 Radius 를 구해줘서 ShrinkPixel이 크게 잡힌다. // point 들의 평균이 가장 작은 것으로 고쳐주자. //double radiusdiff = Math.Abs(objGenerator.m_OriginArc.Radius - objGenerator.fDetectedContourRadius); double radiusdiff = 0; List lsPointRadius = new List(); foreach (var item in _DestDrawObjectList) { lsPointRadius.Add(GetDistance((item.PF1.X - _ObjGenerator.DetectedContourCenter.X), (item.PF1.Y - _ObjGenerator.DetectedContourCenter.Y))); } radiusdiff = Math.Abs(lsPointRadius.Average() - _ObjGenerator.m_OriginArc.Radius); if (radiusdiff < dMinRadiusDiff) { dMinRadiusDiff = radiusdiff; ShrinkPixel = i; } //double lengthdiff = Math.Abs(objGenerator.m_OriginArc.Length - objGenerator.dPathLengthSum); //if (lengthdiff < dMinLengthDiff) //{ // dMinLengthDiff = lengthdiff; // ShrinkPixel = i; //} } CVShrinkPixel = ShrinkPixel; //maxContour = objGenerator.ReSizeFindMaxContour(ConvImg, 2, CVThreshold, CVShrinkPixel); _ObjGenerator.FindEdge(_ConvImageMat, Radius_Pixel, Margin, PointNum, CVThreshold, centerX, centerY, CVShrinkPixel, CVShrinkPixel2, CVShrinkPixel3, CVShrinkPixel4, DetectPointPercent, out _MaxContour); UpdateDateCorrection(_MaxContour); DrawCVEdgeContour(_MaxContour); //GenerateDrawingObject(obj); GenerateDrawingObject(); } private void PerformCmdRecipeUpdate(object obj) { var result = MessageDialog.Show(Application.Current.MainWindow, "RCC", $"Update the RCC object in the Recipe?", MessageDialog.Type.AffirmativeAndNegative); if (result == MessageDialog.Result.Negative) { return; } RecipeUpdate(); } private void PerformCmdRecipeUpdateObject(object obj) { var result = MessageDialog.Show(Application.Current.MainWindow, "Update Recipe", $"Update the object in the Recipe?", MessageDialog.Type.AffirmativeAndNegative); if (result == MessageDialog.Result.Negative) { return; } RecipeUpdateObject(); } public void PerformCmdOffsetSave(object obj) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Multiselect = true; DialogResult dr = ofd.ShowDialog(); if (dr != DialogResult.OK || ofd.FileNames.Length == 0) { return; } var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; Point2f ObjectCenter = new Point2f(1, 1); double r = 0; int centerX = 0, centerY = 0; foreach (var item in _ScannerCanvasUserCtrl.Model.Layers[0].Objects) { if (item is Arc) { Arc arc = (Arc)item; ObjectCenter = new Point2f((float)(_ImageWidth / 2 + arc.Center.X * _SystemParam.LensMagnification / _SystemParam.CameraPixelSize * 1000.0), (float)(_ImageHeight / 2 - arc.Center.Y * _SystemParam.LensMagnification / _SystemParam.CameraPixelSize * 1000.0)); r = arc.Radius * _SystemParam.LensMagnification / _SystemParam.CameraPixelSize * 1000.0; centerX = (int)(arc.Center.X * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageWidth / 2); centerY = (int)(-arc.Center.Y * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageHeight / 2); break; } } int Radius_Pixel = (int)(((Radius * _SystemParam.LensMagnification) / _SystemParam.CameraPixelSize) * 1000.0); int img_cnt = 0; double[] offset_list = new double[3600]; double[] theta_list = new double[3600]; foreach (String file in ofd.FileNames) { Point[][] EdgeList; _LoadImageMat = Cv2.ImRead(file); if (_SystemParam.OffsetType == eOffsetType.CSV) _ObjGenerator.SetOffsetType("Manual"); _ObjGenerator.FindEdge(_LoadImageMat, Radius_Pixel, Margin, 3600, CVThreshold, centerX, centerY, 0, 0, 0, 0, DetectPointPercent, out EdgeList); if (_SystemParam.OffsetType == eOffsetType.CSV) _ObjGenerator.SetOffsetType("CSV"); if (EdgeList[0].Length != 3600) { Log.E($"Failed to Find 3600 points in {file}"); MessageUtil.CreateAndShowMessageDialog("Error", $"Failed to Find 3600 points in {file}"); return; } Point2f ContourCenter = _ObjGenerator.CalculateCentroid(EdgeList[0]); var d = Math.Sqrt((ContourCenter.X - ObjectCenter.X) * (ContourCenter.X - ObjectCenter.X) + (ContourCenter.Y - ObjectCenter.Y) * (ContourCenter.Y - ObjectCenter.Y)); double theta2 = 0; if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y >= ContourCenter.Y) { theta2 = Math.Atan((ObjectCenter.Y - ContourCenter.Y) / (ObjectCenter.X - ContourCenter.X)); } else if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y <= ContourCenter.Y) { theta2 = Math.Atan((-ObjectCenter.Y + ContourCenter.Y) / (ObjectCenter.X - ContourCenter.X)); } else if (ObjectCenter.X <= ContourCenter.X && ObjectCenter.Y < ContourCenter.Y) { theta2 = Math.Atan((ContourCenter.X - ObjectCenter.X) / (ContourCenter.Y - ObjectCenter.Y)); } else { theta2 = Math.Atan((ContourCenter.X - ObjectCenter.X) / (ObjectCenter.Y - ContourCenter.Y)); } for (int i = 0; i < 3600; i++) { double theta = 0; double theta1 = 0.1 * i * Math.PI / 180; theta_list[i] = 0.1 * i; if (EdgeList[0][i].X > ContourCenter.X && EdgeList[0][i].Y >= ContourCenter.Y) { if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y >= ContourCenter.Y) { theta = Math.Max(theta1 - theta2, theta2 - theta1); } else if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y <= ContourCenter.Y) { theta = theta1 + theta2; } else if (ObjectCenter.X <= ContourCenter.X && ObjectCenter.Y < ContourCenter.Y) { theta = Math.PI / 2 + theta1 + theta2; if (theta > Math.PI) theta = 2 * Math.PI - theta; } else { theta = theta2 + Math.PI / 2 - theta1; } } else if (EdgeList[0][i].X > ContourCenter.X && EdgeList[0][i].Y <= ContourCenter.Y) { if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y >= ContourCenter.Y) { theta = theta1 + theta2; } else if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y <= ContourCenter.Y) { theta = Math.Max(theta1 - theta2, theta2 - theta1); } else if (ObjectCenter.X <= ContourCenter.X && ObjectCenter.Y < ContourCenter.Y) { theta = theta2 + Math.PI / 2 - theta1; } else { theta = Math.PI / 2 + theta1 + theta2; if (theta > Math.PI) theta = 2 * Math.PI - theta; } } else if (EdgeList[0][i].X <= ContourCenter.X && EdgeList[0][i].Y < ContourCenter.Y) { if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y >= ContourCenter.Y) { theta = Math.PI / 2 + theta1 + theta2; if (theta > Math.PI) theta = 2 * Math.PI - theta; } else if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y <= ContourCenter.Y) { theta = theta1 + Math.PI / 2 - theta2; } else if (ObjectCenter.X <= ContourCenter.X && ObjectCenter.Y < ContourCenter.Y) { theta = Math.Max(theta1 - theta2, theta2 - theta1); } else { theta = Math.PI - theta1 - theta2; } } else { if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y >= ContourCenter.Y) { theta = theta1 + Math.PI / 2 - theta2; } else if (ObjectCenter.X > ContourCenter.X && ObjectCenter.Y <= ContourCenter.Y) { theta = Math.PI / 2 + theta1 + theta2; if (theta > Math.PI) theta = 2 * Math.PI - theta; } else if (ObjectCenter.X <= ContourCenter.X && ObjectCenter.Y < ContourCenter.Y) { theta = Math.PI - theta1 - theta2; } else { theta = Math.Max(theta1 - theta2, theta2 - theta1); } } var edge_distance = Math.Sqrt((EdgeList[0][i].X - ContourCenter.X) * (EdgeList[0][i].X - ContourCenter.X) + (EdgeList[0][i].Y - ContourCenter.Y) * (EdgeList[0][i].Y - ContourCenter.Y)); var object_distance = d * Math.Cos(theta) + Math.Sqrt(d * d * Math.Sin(theta) * Math.Sin(theta) + r * r); var my_offset = (edge_distance - object_distance) * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification / 1000.0; offset_list[i] = (offset_list[i] * img_cnt + my_offset) / (img_cnt + 1); } img_cnt += 1; } SaveOffsetToCsv(offset_list, theta_list); return; } private Point[][] FindMinContourForCenter(Mat oriImg, double threshold) { // Convert to grayscale Mat grayImg = new Mat(); Cv2.CvtColor(oriImg, grayImg, ColorConversionCodes.BGR2GRAY); // Apply threshold Mat thresImg = new Mat(); Cv2.Threshold(grayImg, thresImg, threshold, 200, ThresholdTypes.BinaryInv); // Find contours Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(thresImg, out contours, out hierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple); //string InvertedImgfilePath = Path.Combine(ConfigurationManager.AppSettings.Get("DATA_PATH"), "_vision", "EdgeContour", "ImgTest", // string.Format($"InvertedImg{DateTime.Now.Year}_{DateTime.Now.Month}_{DateTime.Now.Day}.jpg")); //Cv2.ImWrite(InvertedImgfilePath, InvertedImg); int minWidth = 150; int minWSize = int.MaxValue; int minCntNo = 0; for (int i = 0; i < contours.Length; i++) { Rect rect = Cv2.BoundingRect(contours[i]); if (rect.Width < minWidth) { continue; } if (minWSize > rect.Width) { minWSize = rect.Width; minCntNo = i; } } // Create an empty image to draw the minimum contour Mat minCntImg = Mat.Zeros(oriImg.Size(), MatType.CV_8UC1); // Draw the minimum contour Cv2.DrawContours(minCntImg, contours, minCntNo, Scalar.White, -1); // Find the contour again in the drawn image Point[][] minContour; Cv2.FindContours(minCntImg, out minContour, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple); return minContour; } private void RecipeUpdate() { // Recipe 에서 볼수 있도록 한 임시 함수. // 저장누르면 recipe 가 바뀌므로 주의 // Recipe 의 Layer 0번을 받아온다 var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; for (int i = 0; i < (_ScannerCanvasUserCtrl.Model.Layers.Length); i++) { List sourcelist = _ScannerCanvasUserCtrl.Model.Layers[i].Objects; _ObjGenerator.ReplaceRCCObject(sourcelist, _DestDrawObjectList); } _ScannerCanvasUserCtrl.Update(); mainPage.UpdateObjetsInTreeView(); } private void RecipeUpdateObject() { // Recipe 에서 볼수 있도록 한 임시 함수. // 저장누르면 recipe 가 바뀌므로 주의 // Recipe 의 Layer 0번을 받아온다 var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; for (int i = 0; i < (_ScannerCanvasUserCtrl.Model.Layers.Length); i++) { List sourcelist = _ScannerCanvasUserCtrl.Model.Layers[i].Objects; _ObjGenerator.ReplaceObject(sourcelist, _Offset_x, _Offset_y, _Offset_t, _Obejct_Center); } _ScannerCanvasUserCtrl.Update(); mainPage.UpdateObjetsInTreeView(); } private void PerformCmdFindObject(object obj) { _DetectImageMat = _ConvImageMat.Clone(); _Stopwatch.Start(); Point[][] out_contours; var (offsetX, offsetY, _, offsetT, cX_pixel, cY_pixel, ScX_pixel, ScY_pixel, radius) = _ObjGenerator.FindOffset(_ConvImageMat, CVThreshold, _Ref_x, _Ref_y, _Ref_t, out out_contours, SelectedOption); if (out_contours[0].Length == 0) { Log.E("Failed to Find Objects"); MessageUtil.CreateAndShowMessageDialog("Error", "Failed to Find Objects"); return; } Cv2.DrawContours(_DetectImageMat, out_contours, 0, new Scalar(0, 255, 255), 3); if (SelectedOption == "Inzi") { Cv2.Circle(_DetectImageMat, new Point(cX_pixel, cY_pixel), (int)radius, new Scalar(0, 255, 255), 3); Cv2.DrawContours(_DetectImageMat, out_contours, 1, new Scalar(0, 255, 255), 3); RotatedRect rotatedRect = Cv2.MinAreaRect(out_contours[1]); Point2f[] vertices = rotatedRect.Points(); for (int i = 0; i < 4; i++) { Cv2.Line(_DetectImageMat, (Point)vertices[i], (Point)vertices[(i + 1) % 4], new Scalar(0, 255, 0), 2); } Cv2.Circle(_DetectImageMat, new Point(cX_pixel, cY_pixel), 20, new Scalar(0, 0, 255), -1); Cv2.Circle(_DetectImageMat, new Point(ScX_pixel, ScY_pixel), 20, new Scalar(0, 0, 255), -1); cX_pixel -= _ConvImageMat.Width / 2; cY_pixel = (_ConvImageMat.Height / 2 - cY_pixel); _Obejct_Center = new UnitPoint((cX_pixel * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0, (cY_pixel * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0); (_Offset_x, _Offset_y, _Offset_t) = ((offsetX * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0, (offsetY * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0, offsetT); } else { int px = ScX_pixel; int py = ScY_pixel; Cv2.Line(_DetectImageMat, new Point(cX_pixel, cY_pixel), new Point(px, py), new Scalar(0, 255, 0), 2); cX_pixel -= _ConvImageMat.Width / 2; cY_pixel = (_ConvImageMat.Height / 2 - cY_pixel); _Obejct_Center = new UnitPoint((cX_pixel * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0, (cY_pixel * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0); (_Offset_x, _Offset_y, _Offset_t) = ((offsetX * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0, (offsetY * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0, offsetT); _Offset_t = _Offset_t * Math.PI / 180; } _Stopwatch.Stop(); Log.I($"Elapsed Time : {(float)_Stopwatch.ElapsedMilliseconds}"); Log.I($"Center Offset: ({(float)_Offset_x}(mm), {(float)_Offset_y}(mm)), Theta Offset: {(float)(_Offset_t * 180 / Math.PI)},"); _Stopwatch.Reset(); ResultImage = _DetectImageMat.ToBitmapSource(); OffsetX = _Offset_x; OffsetY = _Offset_y; OffsetTh = _Offset_t * 180 / Math.PI; //deg } private void PerformCmdFindReference(object obj) { _DetectImageMat = _ConvImageMat.Clone(); _Stopwatch.Start(); Point[][] out_contours; if (SelectedOption == "LFW") { //ref_x = 2412; ref_y = 1832; var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; foreach (var item in _ScannerCanvasUserCtrl.Model.Layers[0].Objects) { if (item is Arc) { Arc arc = (Arc)item; _Ref_x = (int)(arc.Center.X * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageWidth / 2); _Ref_y = (int)(-arc.Center.Y * 1000.0 / _SystemParam.CameraPixelSize * _SystemParam.LensMagnification + _ImageHeight / 2); break; } } } var (_, _, theta, _, cX_pixel, cY_pixel, ScX_pixel, ScY_pixel, radius) = _ObjGenerator.FindOffset(_ConvImageMat, CVThreshold, _Ref_x, _Ref_y, 0, out out_contours, SelectedOption); if (out_contours[0].Length == 0) { Log.E("Failed to Find Objects"); MessageUtil.CreateAndShowMessageDialog("Error", "Failed to Find Objects"); return; } _Stopwatch.Stop(); Log.I($"Elapsed Time : {(float)_Stopwatch.ElapsedMilliseconds}"); Cv2.DrawContours(_DetectImageMat, out_contours, 0, new Scalar(0, 255, 255), 3); if (SelectedOption == "Inzi") { Cv2.Circle(_DetectImageMat, new Point(cX_pixel, cY_pixel), (int)radius, new Scalar(0, 255, 255), 3); RotatedRect rotatedRect = Cv2.MinAreaRect(out_contours[1]); Point2f[] vertices = rotatedRect.Points(); for (int i = 0; i < 4; i++) { Cv2.Line(_DetectImageMat, (Point)vertices[i], (Point)vertices[(i + 1) % 4], new Scalar(0, 255, 0), 2); } Cv2.Circle(_DetectImageMat, new Point(cX_pixel, cY_pixel), 20, new Scalar(0, 0, 255), -1); Cv2.Circle(_DetectImageMat, new Point(ScX_pixel, ScY_pixel), 20, new Scalar(0, 0, 255), -1); } else { int px = ScX_pixel; int py = ScY_pixel; Cv2.Line(_DetectImageMat, new Point(cX_pixel, cY_pixel), new Point(px, py), new Scalar(0, 255, 0), 2); theta = theta * Math.PI / 180; } _Ref_x = cX_pixel; _Ref_y = cY_pixel; _Ref_t = theta; cX_pixel -= _ConvImageMat.Width / 2; cY_pixel = (_ConvImageMat.Height / 2 - cY_pixel); var ref_x_mm = (cX_pixel * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0; var ref_y_mm = (cY_pixel * _SystemParam.CameraPixelSize / _SystemParam.LensMagnification) / 1000.0; var ref_th_deg = theta * 180 / Math.PI; Log.I($"Center: ({Math.Round(ref_x_mm, 2)}(mm), {Math.Round(ref_y_mm, 2)}(mm)), Theta: {ref_th_deg},"); _Stopwatch.Reset(); ResultImage = _DetectImageMat.ToBitmapSource(); //mm로 표시해주기 위해서 Log로 남기는 변수를 띄워준다 ReferenceX = Math.Round(ref_x_mm, 2); ReferenceY = Math.Round(ref_y_mm, 2); ReferenceTh = ref_th_deg; } private bool GetArcInfoFromRecipe() { // 여러개 쓸수 있지만 일단 한개부터 해보자 // 우선 첫번째 layer 만 해보자 var mainPage = CommonHelper.GetMainPage(); _ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching; foreach (var item in _ScannerCanvasUserCtrl.Model.Layers[0].Objects) { if (item is Arc) { Arc arc = (Arc)item; if (arc.RCCArc == true) { _ObjGenerator.SetBaseArc(arc); _Draw_direction = arc.Direction; return true; // 우선 한개라서 여기서 return. 여러개 할때는 삭제할것. 여러개하려면 arc 를 list 로 보내야할듯. } } } // 여기까지 오면 Arc 등록이 안된것임. MessageUtil.CreateAndShowMessageDialog("Check the recipe.", "RCC Arc Unit is not in Recipe."); return false; } #region Flying Vision + Detect Image + Generate Object + Welding Sequence Functions private void PerformCmdFlyingSeqStart(object obj) { var result = MessageDialog.Show(Application.Current.MainWindow, "Scanner Scout", $"Start RCC Sequence?", MessageDialog.Type.AffirmativeAndNegative); if (result == MessageDialog.Result.Negative) { return; } _SequenceDialog = new SequenceDialog($"RCC Sequence is running...") { Owner = Application.Current.MainWindow }; if (SequenceRunState.Idle == _AutoRunSMWSeq_Scout.RunState && SequenceRunState.Idle == _AutoRunSMWSeq_wo_Scout.RunState && SequenceRunState.Idle == _ManualRunRCC.RunState) { // parameter 를 넘길 방법은? _SequenceDialog.Show(); _ManualRunRCC.Start(new ScoutSeqParams(VisionRecipeManager.GetFovInfos()[0], eDisplayType.Machine_B), OnCompleted); Log.I("SMW_RCC Manual Run Start"); } else { Log.I("Check AutoRunSeq or ManualRunSeq Run State"); } } private void OnCompleted(SequenceActionResult result) { Application.Current.Dispatcher.InvokeAsync(() => { if (_SequenceDialog != null) { _SequenceDialog.Close(); } MessageDialog.Show(Application.Current.MainWindow, "Sequence", "Complete."); }); } private void PerformCmdFlyingSeqRun(object obj) { const string RCCRUNCMD = "RCCRunCmd"; var bRCCRunCmd = _ManualRunRCC.SearchContext(RCCRUNCMD); bRCCRunCmd = true; } private void PerformCmdFlyingSeqStop(object obj) { _ManualRunRCC.Stop(); Application.Current.Dispatcher.InvokeAsync(() => { if (_SequenceDialog != null) { _SequenceDialog.Close(); } MessageDialog.Show(Application.Current.MainWindow, "Sequence", "Stop."); }); } private void OnCompleted(int result) { // 호출 방법은? MessageDialog.Show(Application.Current.MainWindow, "Sequence", "Complete."); } private void OnUpdateManualRunResult(EventMessage obj) { try { var updateManualRunResult = obj.Param as UpdateManualRunResult; if (updateManualRunResult != null) { _ConvImageMat = updateManualRunResult.ResultImage; _PathList = updateManualRunResult.PathItemList; } DrawObject(); } catch (Exception ex) { } } #endregion public class ContourList { public int Index { get; set; } public float VisionX { get; set; } public float VisionY { get; set; } //public int ScannerX { get; set; } //public int ScannerY { get; set; } } } } public class ButtonViewModel { public string Name { get; set; } public ICommand Command { get; set; } public ButtonViewModel(string name, ICommand command) { Name = name; Command = command; } }