1535 lines
76 KiB
C#
1535 lines
76 KiB
C#
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<string> Options { get; set; }
|
|
public ObservableCollection<ButtonViewModel> 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<ContourList> _ContourCorrection = new ObservableCollection<ContourList>();
|
|
public ObservableCollection<ContourList> 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<IDrawObject> _DestDrawObjectList;
|
|
private double _Offset_x, _Offset_y, _Offset_t;
|
|
private int _Ref_x, _Ref_y;
|
|
private double _Ref_t;
|
|
private List<PathItem> _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<string> { "SMW", "Inzi", "LFW" };
|
|
CurrentButtons = new ObservableCollection<ButtonViewModel>();
|
|
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<double, double, double> 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<double> temp_dist = new List<double>();
|
|
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<double> lsPointRadius = new List<double>();
|
|
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<IDrawObject> 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<IDrawObject> 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;
|
|
}
|
|
} |