update toolblock for get circle center
This commit is contained in:
@@ -161,7 +161,6 @@ namespace WaferAlignment
|
||||
_dev.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
|
||||
_dev.MV_CC_StartGrabbing_NET();
|
||||
_dev.MV_CC_TriggerSoftwareExecute_NET();
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
@@ -195,7 +194,7 @@ namespace WaferAlignment
|
||||
try
|
||||
{
|
||||
_startAcqToken.Cancel();
|
||||
Thread.Sleep(20);
|
||||
Thread.Sleep(200);
|
||||
_imageAcquisitionTask.Wait(_stopAcqToken.Token);
|
||||
_imageAcquisitionTask.Dispose();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace ConVX.VXData
|
||||
/// <summary>
|
||||
/// 判断线程状态
|
||||
/// </summary>
|
||||
private AutoResetEvent _autoReset = null;
|
||||
//private AutoResetEvent _autoReset = null;
|
||||
/// <summary>
|
||||
/// 线程
|
||||
/// </summary>
|
||||
@@ -53,7 +53,7 @@ namespace ConVX.VXData
|
||||
public DataPostbox()
|
||||
{
|
||||
_queue = new ConcurrentQueue<CogImage8Grey>();
|
||||
_autoReset = new AutoResetEvent(false);//线程非终止状态
|
||||
//_autoReset = new AutoResetEvent(false);//线程非终止状态
|
||||
}
|
||||
/// <summary>
|
||||
/// 启动派发
|
||||
@@ -72,7 +72,7 @@ namespace ConVX.VXData
|
||||
try
|
||||
{
|
||||
RuningToken.Cancel();
|
||||
_autoReset.Set();//为了避免线程正在执行或等待状态
|
||||
//_autoReset.Set();//为了避免线程正在执行或等待状态
|
||||
await _task;
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
@@ -98,7 +98,7 @@ namespace ConVX.VXData
|
||||
//}
|
||||
|
||||
_queue.Enqueue(envelope);
|
||||
_autoReset.Set();
|
||||
//_autoReset.Set();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -110,7 +110,8 @@ namespace ConVX.VXData
|
||||
{
|
||||
if (_queue.IsEmpty)
|
||||
{
|
||||
_autoReset.WaitOne();
|
||||
//_autoReset.WaitOne();
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
101
WaferAlignment/FitCircleToolBlock.cs
Normal file
101
WaferAlignment/FitCircleToolBlock.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using Cognex.VisionPro;
|
||||
using Cognex.VisionPro.PMAlign;
|
||||
using Cognex.VisionPro.ToolBlock;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace WaferAdjust
|
||||
{
|
||||
public delegate void OnFitCircleResult(double x, double y, double r, double rms);
|
||||
internal class FitCircleToolBlock
|
||||
{
|
||||
private CogToolBlock cogToolBlock;
|
||||
private bool initialized = false;
|
||||
public event OnToolReady OnToolReady;
|
||||
public event OnFitCircleResult OnFitCircleResult;
|
||||
public CogImage8Grey FitCircleImage;
|
||||
public void Initialize(string vpp)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cogToolBlock != null)
|
||||
{
|
||||
cogToolBlock.Ran -= CogToolBlock_Ran;
|
||||
cogToolBlock.Dispose();
|
||||
cogToolBlock = null;
|
||||
}
|
||||
initialized = false;
|
||||
cogToolBlock = CogSerializer.LoadObjectFromFile(vpp) as CogToolBlock;
|
||||
cogToolBlock.Ran += CogToolBlock_Ran;
|
||||
initialized = true;
|
||||
OnToolReady?.Invoke(initialized);
|
||||
LogHelper.LogInfo("FitCircleToolBlock initialized successfully: " + vpp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError(ex.Message);
|
||||
}
|
||||
}
|
||||
private void CogToolBlock_Ran(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
FitCircleImage = cogToolBlock.Outputs["OutputImage"].Value as CogImage8Grey;
|
||||
OnFitCircleResult?.Invoke(Math.Round((double)cogToolBlock.Outputs["CenterX"].Value, 3),
|
||||
Math.Round((double)cogToolBlock.Outputs["CenterY"].Value, 3),
|
||||
Math.Round((double)cogToolBlock.Outputs["Radius"].Value, 3),
|
||||
Math.Round((double)cogToolBlock.Outputs["RMSError"].Value, 3));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError(ex.Message + ex.StackTrace);
|
||||
}
|
||||
}
|
||||
public void Run(Bitmap bmp, List<PointInfo> pointInfos)
|
||||
{
|
||||
try
|
||||
{
|
||||
CogImage8Grey image8Grey = new CogImage8Grey(bmp);
|
||||
Run(image8Grey, pointInfos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message);
|
||||
}
|
||||
}
|
||||
public void Run(CogImage8Grey image8Grey, List<PointInfo> pointInfos)
|
||||
{
|
||||
try
|
||||
{
|
||||
cogToolBlock.Inputs["OutputImage"].Value = image8Grey;
|
||||
CogFitCircleTool fitCircleTool = cogToolBlock.Tools["CogFitCircleTool1"] as CogFitCircleTool;
|
||||
fitCircleTool.RunParams.NumPoints = 0;
|
||||
foreach (var item in pointInfos)
|
||||
fitCircleTool.RunParams.AddPoint(item.X, item.Y);
|
||||
cogToolBlock.Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message);
|
||||
}
|
||||
}
|
||||
public bool Ready()
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
if (cogToolBlock != null)
|
||||
{
|
||||
cogToolBlock.Ran -= CogToolBlock_Ran;
|
||||
cogToolBlock.Dispose();
|
||||
cogToolBlock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
WaferAlignment/Form1.Designer.cs
generated
68
WaferAlignment/Form1.Designer.cs
generated
@@ -68,6 +68,10 @@
|
||||
this.nud_SizeX = new System.Windows.Forms.NumericUpDown();
|
||||
this.btn_Action = new System.Windows.Forms.Button();
|
||||
this.btn_ToZero = new System.Windows.Forms.Button();
|
||||
this.textBox2 = new System.Windows.Forms.TextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.textBox3 = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
@@ -93,6 +97,10 @@
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.textBox2);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.label1);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.textBox3);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.label2);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lbl_Time);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.txt_Time);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lbl_Times);
|
||||
@@ -167,7 +175,7 @@
|
||||
// lbl_Times
|
||||
//
|
||||
this.lbl_Times.AutoSize = true;
|
||||
this.lbl_Times.Location = new System.Drawing.Point(234, 15);
|
||||
this.lbl_Times.Location = new System.Drawing.Point(182, 17);
|
||||
this.lbl_Times.Name = "lbl_Times";
|
||||
this.lbl_Times.Size = new System.Drawing.Size(89, 12);
|
||||
this.lbl_Times.TabIndex = 30;
|
||||
@@ -175,7 +183,7 @@
|
||||
//
|
||||
// txt_Times
|
||||
//
|
||||
this.txt_Times.Location = new System.Drawing.Point(326, 12);
|
||||
this.txt_Times.Location = new System.Drawing.Point(274, 14);
|
||||
this.txt_Times.Name = "txt_Times";
|
||||
this.txt_Times.ReadOnly = true;
|
||||
this.txt_Times.Size = new System.Drawing.Size(129, 21);
|
||||
@@ -383,9 +391,9 @@
|
||||
//
|
||||
// btn_RunTest
|
||||
//
|
||||
this.btn_RunTest.Location = new System.Drawing.Point(481, 12);
|
||||
this.btn_RunTest.Location = new System.Drawing.Point(409, 14);
|
||||
this.btn_RunTest.Name = "btn_RunTest";
|
||||
this.btn_RunTest.Size = new System.Drawing.Size(161, 23);
|
||||
this.btn_RunTest.Size = new System.Drawing.Size(119, 23);
|
||||
this.btn_RunTest.TabIndex = 9;
|
||||
this.btn_RunTest.Text = "启动检测";
|
||||
this.btn_RunTest.UseVisualStyleBackColor = true;
|
||||
@@ -444,6 +452,7 @@
|
||||
0,
|
||||
0,
|
||||
-2147483648});
|
||||
this.nud_SizeY.ValueChanged += new System.EventHandler(this.nud_SizeY_ValueChanged);
|
||||
//
|
||||
// lbl_X
|
||||
//
|
||||
@@ -458,8 +467,13 @@
|
||||
//
|
||||
this.nud_SizeX.DecimalPlaces = 2;
|
||||
this.nud_SizeX.Location = new System.Drawing.Point(80, 137);
|
||||
this.nud_SizeX.Maximum = new decimal(new int[] {
|
||||
6,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nud_SizeX.Minimum = new decimal(new int[] {
|
||||
100,
|
||||
8,
|
||||
0,
|
||||
0,
|
||||
-2147483648});
|
||||
@@ -471,6 +485,7 @@
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nud_SizeX.ValueChanged += new System.EventHandler(this.nud_SizeX_ValueChanged);
|
||||
//
|
||||
// btn_Action
|
||||
//
|
||||
@@ -484,7 +499,7 @@
|
||||
//
|
||||
// btn_ToZero
|
||||
//
|
||||
this.btn_ToZero.Location = new System.Drawing.Point(17, 99);
|
||||
this.btn_ToZero.Location = new System.Drawing.Point(17, 95);
|
||||
this.btn_ToZero.Name = "btn_ToZero";
|
||||
this.btn_ToZero.Size = new System.Drawing.Size(161, 23);
|
||||
this.btn_ToZero.TabIndex = 0;
|
||||
@@ -492,6 +507,42 @@
|
||||
this.btn_ToZero.UseVisualStyleBackColor = true;
|
||||
this.btn_ToZero.Click += new System.EventHandler(this.btn_ToZero_Click);
|
||||
//
|
||||
// textBox2
|
||||
//
|
||||
this.textBox2.Location = new System.Drawing.Point(534, 22);
|
||||
this.textBox2.Name = "textBox2";
|
||||
this.textBox2.Size = new System.Drawing.Size(55, 21);
|
||||
this.textBox2.TabIndex = 33;
|
||||
this.textBox2.Text = "82";
|
||||
this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(532, 7);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(53, 12);
|
||||
this.label1.TabIndex = 34;
|
||||
this.label1.Text = "相机计数";
|
||||
//
|
||||
// textBox3
|
||||
//
|
||||
this.textBox3.Location = new System.Drawing.Point(595, 22);
|
||||
this.textBox3.Name = "textBox3";
|
||||
this.textBox3.Size = new System.Drawing.Size(55, 21);
|
||||
this.textBox3.TabIndex = 35;
|
||||
this.textBox3.Text = "4096";
|
||||
this.textBox3.TextChanged += new System.EventHandler(this.textBox3_TextChanged);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(593, 7);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(41, 12);
|
||||
this.label2.TabIndex = 36;
|
||||
this.label2.Text = "总计数";
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
@@ -556,7 +607,10 @@
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn Column4;
|
||||
private System.Windows.Forms.Label lbl_Time;
|
||||
private System.Windows.Forms.TextBox txt_Time;
|
||||
|
||||
private System.Windows.Forms.TextBox textBox2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox textBox3;
|
||||
private System.Windows.Forms.Label label2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ using System.Windows.Forms;
|
||||
using System.Xml.Serialization;
|
||||
using System.Diagnostics;
|
||||
using Cognex.VisionPro.PMAlign;
|
||||
using WaferAdjust;
|
||||
|
||||
|
||||
namespace WaferAlignment
|
||||
@@ -54,20 +55,12 @@ namespace WaferAlignment
|
||||
/// </summary>
|
||||
string arAngle = "DB7.DBD76";//设置触发拍照的偏转角度
|
||||
|
||||
GetCircleToolBlock getCircleMachineToolBlock;
|
||||
FitCircleToolBlock FitCircleMachineToolBlock;
|
||||
TranslateCirclePoint translateCirclePoint;
|
||||
CogGraphicCollection m_graphics;
|
||||
CogGraphicCollection m_graphics2;
|
||||
|
||||
|
||||
string vppPath;
|
||||
CogToolBlock mTB;
|
||||
CogToolBlock mTB_1;
|
||||
CogToolBlock mTB_2;
|
||||
|
||||
|
||||
float R = 11.25F;//1024->12
|
||||
//CogImage8Grey OutputImg;
|
||||
|
||||
//旋转中心的坐标应将标定的数据保存后获取
|
||||
double circleCenterX;
|
||||
double circleCenterY;
|
||||
//XML文件读取与写入
|
||||
ConfigStore _ConfigStore = new ConfigStore();
|
||||
CenterOfRotation _center = new CenterOfRotation();
|
||||
@@ -123,7 +116,6 @@ namespace WaferAlignment
|
||||
_s7.SetValue(arSizeX, (float)0);
|
||||
_s7.SetValue(arSizeY, (float)0);
|
||||
_s7.SetValue(arSizeR, (float)0);
|
||||
_s7.SetValue(arAngle, Convert.ToSingle(R));//角度为10
|
||||
lbl_CommunState.BackColor = Color.Lime;
|
||||
lbl_CommunState.Text = "已连接";
|
||||
}
|
||||
@@ -150,9 +142,16 @@ namespace WaferAlignment
|
||||
try
|
||||
{
|
||||
// 加载VPP文件
|
||||
vppPath = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "vpp", "ToolBlock.vpp");
|
||||
getCircleMachineToolBlock = new GetCircleToolBlock();
|
||||
getCircleMachineToolBlock.OnGetCircleResult += GetCircleMachineToolBlock_OnGetCircleResult;
|
||||
getCircleMachineToolBlock.OnGetNashResult += GetCircleMachineToolBlock_OnGetNashResult;
|
||||
getCircleMachineToolBlock.OnToolReady += GetCircleMachineToolBlock_OnToolReady;
|
||||
|
||||
mTB = CogSerializer.LoadObjectFromFile(vppPath) as CogToolBlock;
|
||||
FitCircleMachineToolBlock = new FitCircleToolBlock();
|
||||
FitCircleMachineToolBlock.OnFitCircleResult += FitCircleMachineToolBlock_OnFitCircleResult;
|
||||
FitCircleMachineToolBlock.OnToolReady += FitCircleMachineToolBlock_OnToolReady;
|
||||
translateCirclePoint = new TranslateCirclePoint();
|
||||
m_graphics2 = new CogGraphicCollection();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -171,15 +170,117 @@ namespace WaferAlignment
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void FitCircleMachineToolBlock_OnToolReady(bool ready)
|
||||
{
|
||||
LogHelper.LogInfo("FitCircleMachineToolBlock_OnToolReady");
|
||||
}
|
||||
|
||||
private void FitCircleMachineToolBlock_OnFitCircleResult(double x, double y, double r, double rms)
|
||||
{
|
||||
TCP_X = x.ToString("F4");
|
||||
TCP_Y = y.ToString("F4");
|
||||
TCP_RMS = rms.ToString("F4");
|
||||
TCP_R = r.ToString("F4");
|
||||
|
||||
deviationX = Math.Round((x - translateCirclePoint.GetRotateX()), 3);
|
||||
deviationY = Math.Round((y - translateCirclePoint.GetRotateY()), 3);
|
||||
|
||||
AddPointMarker(m_graphics2, x, y);
|
||||
AddPointMarker(m_graphics2, translateCirclePoint.GetRotateX(), translateCirclePoint.GetRotateY(), CogColorConstants.Red);
|
||||
|
||||
PointInfo nPoint = translateCirclePoint.GetNashPoint();
|
||||
if (nPoint != null)
|
||||
{
|
||||
AddPointMarker(m_graphics2, nPoint.X, nPoint.Y, CogColorConstants.Yellow);
|
||||
AddLineMarker(m_graphics2, x, y, x, y - r);
|
||||
AddLineMarker(m_graphics2, x, y, nPoint.X, nPoint.Y, CogColorConstants.Yellow);
|
||||
angle = GetCounterClockwiseAngle360(x, y, x, y - r, nPoint.X, nPoint.Y);
|
||||
AddLabelMarker(m_graphics2, angle.ToString(), x, y, CogColorConstants.Yellow);
|
||||
LogHelper.LogInfo($"nash degree:{angle}");
|
||||
}
|
||||
|
||||
// 指定XML文件路径
|
||||
string filePath = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "vpp", "CenterOfRotation.xml"); //@"D:\晶圆寻边机\XML文件\CenterOfRotation.xml";
|
||||
_center = _ConfigStore.ReadConfigFromFile(_center.GetType(), filePath) as CenterOfRotation;
|
||||
circleCenterX = _center.Center_X;
|
||||
circleCenterY = _center.Center_Y;
|
||||
LogHelper.LogInfo($"X:{x}, Y:{y}, RMS:{rms}");
|
||||
LogHelper.LogInfo($"DiffX:{deviationX}, DiffY:{deviationY}, RMS:{rms}{Environment.NewLine}");
|
||||
ImageDisplay(FitCircleMachineToolBlock.FitCircleImage);
|
||||
ImageDisplay(m_graphics);
|
||||
ImageDisplay(m_graphics2);
|
||||
ImageDisplayFit();
|
||||
}
|
||||
private void AddPointMarker(CogGraphicCollection graphicCollection, double x, double y, CogColorConstants color = CogColorConstants.Green)
|
||||
{
|
||||
CogPointMarker marker = new CogPointMarker();
|
||||
marker.X = x;
|
||||
marker.Y = y;
|
||||
marker.Color = color;
|
||||
marker.Interactive = false;
|
||||
graphicCollection.Add(marker);
|
||||
}
|
||||
private void AddLineMarker(CogGraphicCollection graphicCollection, double x1, double y1, double x2, double y2, CogColorConstants color = CogColorConstants.Green)
|
||||
{
|
||||
CogLineSegment line = new CogLineSegment();
|
||||
line.SetStartEnd((int)x1, (int)y1, (int)x2, (int)y2);
|
||||
line.Color = color;
|
||||
line.Interactive = false;
|
||||
graphicCollection.Add(line);
|
||||
}
|
||||
private void AddLabelMarker(CogGraphicCollection graphicCollection, string text, double x, double y, CogColorConstants color = CogColorConstants.Green)
|
||||
{
|
||||
CogGraphicLabel label = new CogGraphicLabel();
|
||||
label.Text = text;
|
||||
label.X = x;
|
||||
label.Y = y;
|
||||
label.Color = color;
|
||||
graphicCollection.Add(label);
|
||||
}
|
||||
/// <summary>
|
||||
/// 计算从 lineA 到 lineB 的逆时针有向角度(0-360度)
|
||||
/// 坐标系:向右为正,向下为正(标准屏幕坐标系)
|
||||
/// </summary>
|
||||
public double GetCounterClockwiseAngle360(double x, double y, double x1, double y1, double x2, double y2)
|
||||
{
|
||||
// 2. 获取方向向量(dy 向下为正)
|
||||
double dxA = x1 - x;
|
||||
double dyA = y1 - y;
|
||||
|
||||
double dxB = x2 - x;
|
||||
double dyB = y2 - y;
|
||||
|
||||
// 3. 将Y轴翻转,转换为标准数学坐标系(dy向上为正)
|
||||
// 这样 Math.Atan2 返回的就是标准数学角度(逆时针为正)
|
||||
double angleA = Math.Atan2(-dyA, dxA); // 注意:y取负号
|
||||
double angleB = Math.Atan2(-dyB, dxB); // 注意:y取负号
|
||||
|
||||
// 4. 计算逆时针角度差(弧度)
|
||||
double angleDiff = angleB - angleA;
|
||||
|
||||
// 5. 转换为角度并规范化为 [0, 360)
|
||||
double angleDegrees = angleDiff * 180.0 / Math.PI;
|
||||
angleDegrees = angleDegrees % 360.0;
|
||||
if (angleDegrees < 0) angleDegrees += 360.0;
|
||||
|
||||
return Math.Round(angleDegrees, 3);
|
||||
}
|
||||
private void GetCircleMachineToolBlock_OnToolReady(bool ready)
|
||||
{
|
||||
LogHelper.LogInfo("GetCircleMachineToolBlock_OnToolReady");
|
||||
}
|
||||
|
||||
private void GetCircleMachineToolBlock_OnGetNashResult(double x, double y)
|
||||
{
|
||||
translateCirclePoint.AddNashPoint(x, y);
|
||||
LogHelper.LogInfo($"Update Nash X:{x}, Y:{y}");
|
||||
}
|
||||
|
||||
private void GetCircleMachineToolBlock_OnGetCircleResult(double x, double y, double r)
|
||||
{
|
||||
translateCirclePoint.AddCircleCenter(x, y, r);
|
||||
translateCirclePoint.AddCirclePoint(getCircleMachineToolBlock.PointInfos);
|
||||
LogHelper.LogInfo($"X:{x}, Y:{y}, R:{r}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收到TCP数据时,根据接收到的数据,进行不同操作
|
||||
/// </summary>
|
||||
@@ -217,17 +318,11 @@ namespace WaferAlignment
|
||||
_tcp.SendData(e.ClientIp, "DetectionTime:" + TCP_time + " " + "X:" + TCP_X + " " + "Y:" + TCP_Y + " " + "Angle:" + TCP_R + " " + "RMS:" + TCP_RMS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void _cam_OutputImageEvent(Bitmap obj)
|
||||
{
|
||||
lstNasR.Add((acqNum + 1) * R);
|
||||
acqNum++;
|
||||
//lstNasR.Add((testNum) * R);
|
||||
//保存图像
|
||||
//SaveImage(new CogImage8Grey(obj));
|
||||
ImageData.Mailing(new CogImage8Grey(obj));
|
||||
Images.Add(new CogImage8Grey(obj));
|
||||
|
||||
@@ -235,10 +330,9 @@ namespace WaferAlignment
|
||||
|
||||
void ImageData_ErrorEvent(string obj)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -300,7 +394,6 @@ namespace WaferAlignment
|
||||
this.splitContainer1.Invoke(new Action(() => this.splitContainer1.Panel2.Enabled = true));
|
||||
});
|
||||
}
|
||||
|
||||
public string ToZero()
|
||||
{
|
||||
if (_s7 != null)
|
||||
@@ -393,15 +486,7 @@ namespace WaferAlignment
|
||||
}
|
||||
}
|
||||
|
||||
List<double> lstRotation;
|
||||
List<double> lstX;
|
||||
List<double> lstY;
|
||||
List<double> lstRadius;
|
||||
List<double> lstNasX;
|
||||
List<double> lstNasY;
|
||||
List<double> lstNasR;
|
||||
List<CogImage8Grey> Images;
|
||||
|
||||
int acqNum = 0;
|
||||
int testNum = 0;
|
||||
double angle = 0;
|
||||
@@ -411,9 +496,11 @@ namespace WaferAlignment
|
||||
private void btn_RunTest_Click(object sender, EventArgs e)
|
||||
{
|
||||
SavePath = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "SaveImage", DateTime.Now.ToString("yyyyMMdd_HHmmss"));
|
||||
|
||||
m_cameraCount = Convert.ToDouble(textBox2.Text);
|
||||
m_codeCount = Convert.ToDouble(textBox3.Text);
|
||||
m_roateX = Convert.ToDouble(nud_SizeX.Value);
|
||||
m_roateY = Convert.ToDouble(nud_SizeY.Value);
|
||||
ClearDisplay();
|
||||
////---------------------------------------
|
||||
Task.Run(() =>
|
||||
{
|
||||
this.splitContainer1.Invoke(new Action(() => this.splitContainer1.Panel2.Enabled = false));
|
||||
@@ -423,8 +510,6 @@ namespace WaferAlignment
|
||||
|
||||
this.splitContainer1.Invoke(new Action(() => this.splitContainer1.Panel2.Enabled = true));
|
||||
});
|
||||
|
||||
//---------------------------------------
|
||||
}
|
||||
|
||||
public string RunTest()
|
||||
@@ -436,7 +521,6 @@ namespace WaferAlignment
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//R轴回0
|
||||
if (_s7 != null)
|
||||
{
|
||||
@@ -480,13 +564,6 @@ namespace WaferAlignment
|
||||
angle = 0;
|
||||
acqNum = 0;
|
||||
testNum = 0;
|
||||
lstRotation = new List<double>();
|
||||
lstX = new List<double>();
|
||||
lstY = new List<double>();
|
||||
lstRadius = new List<double>();
|
||||
lstNasX = new List<double>();
|
||||
lstNasY = new List<double>();
|
||||
lstNasR = new List<double>();
|
||||
Images = new List<CogImage8Grey>();
|
||||
|
||||
sw_1 = new Stopwatch();//检测时间
|
||||
@@ -495,6 +572,7 @@ namespace WaferAlignment
|
||||
deviationY = 0;
|
||||
times = 0;
|
||||
//启动拍照
|
||||
translateCirclePoint.SetRotateXY(m_roateX, m_roateY, 360 * m_cameraCount / m_codeCount);
|
||||
|
||||
if (_s7 != null)
|
||||
{
|
||||
@@ -529,9 +607,7 @@ namespace WaferAlignment
|
||||
}
|
||||
}
|
||||
//Thread.Sleep(100);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_cam.SoftwareGrab();
|
||||
@@ -644,327 +720,62 @@ namespace WaferAlignment
|
||||
return "NG_RUN";
|
||||
}
|
||||
}
|
||||
|
||||
private CogImage8Grey m_lastImage;
|
||||
//所有点
|
||||
// 调整vpp中CogCaliperTool工具数据需要同时调整Y值与 for (double i = Y; i < 12; i = i + 0.5)中12的值
|
||||
private void MonitorSpot(CogImage8Grey outputImg)
|
||||
{
|
||||
sw_1 = new Stopwatch();//检测时间
|
||||
sw_1.Start();
|
||||
//double Y = -17;
|
||||
//double X = 0;
|
||||
double X = -15;
|
||||
double Y = 0;
|
||||
CogImage8Grey inputImg = new CogImage8Grey();
|
||||
CogGraphicCollection graphics = new CogGraphicCollection();
|
||||
CogImage8Grey _OutputImg = new CogImage8Grey();
|
||||
|
||||
inputImg = outputImg;
|
||||
mTB_1 = mTB.Tools["CogToolBlock1"] as CogToolBlock;
|
||||
mTB_2 = mTB.Tools["CogToolBlock2"] as CogToolBlock;
|
||||
mTB_1.Inputs["InputImage"].Value = inputImg;
|
||||
mTB_1.Run();
|
||||
_OutputImg = mTB_1.Outputs["OutputImage"].Value as CogImage8Grey;
|
||||
translateCirclePoint.AddCircleIndex();
|
||||
m_lastImage = outputImg;
|
||||
getCircleMachineToolBlock.Run(outputImg);
|
||||
|
||||
CogCaliperTool mCT = mTB_1.Tools["CogCaliperTool1"] as CogCaliperTool;
|
||||
|
||||
|
||||
|
||||
//x′= cx + (x−cx)⋅cos(r)−(y−cy)⋅sin(r)
|
||||
//y′= cy + (x−cx)⋅sin(r) + (y−cy)⋅cos(r)
|
||||
|
||||
int _count = 0;
|
||||
|
||||
for (double i = X; i < 14; i = i + 0.5)
|
||||
{
|
||||
mCT.InputImage = _OutputImg;
|
||||
mCT.Region.CenterX = i;
|
||||
mCT.Run();
|
||||
_count = mCT.Results.Count;
|
||||
|
||||
if (_count != 0)
|
||||
{
|
||||
Y = mCT.Results[0].Edge0.PositionY;
|
||||
//旋转角度
|
||||
double r = lstNasR[testNum] / 180 * Math.PI;
|
||||
//旋转移动到实际位置
|
||||
lstNasX.Add(i * Math.Cos(r) - Y * Math.Sin(r) + circleCenterX * (1 - Math.Cos(r)) + circleCenterY * Math.Sin(r));
|
||||
lstNasY.Add(i * Math.Sin(r) + Y * Math.Cos(r) - circleCenterX * Math.Sin(r) + circleCenterY * (1 - Math.Cos(r)));
|
||||
|
||||
CogPointMarker marker_1 = new CogPointMarker();//圆
|
||||
|
||||
marker_1.X = i;
|
||||
marker_1.Y = Y;
|
||||
marker_1.Color = CogColorConstants.Blue;
|
||||
marker_1.Interactive = false;
|
||||
graphics.Add(marker_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
OKorNG = false;
|
||||
testNum++;
|
||||
return;
|
||||
}
|
||||
if (i == X)
|
||||
{
|
||||
double r = lstNasR[testNum] / 180 * Math.PI;
|
||||
lstX.Add(i * Math.Cos(r) - Y * Math.Sin(r) + circleCenterX * (1 - Math.Cos(r)) + circleCenterY * Math.Sin(r));
|
||||
lstY.Add(i * Math.Sin(r) + Y * Math.Cos(r) - circleCenterX * Math.Sin(r) + circleCenterY * (1 - Math.Cos(r)));
|
||||
}
|
||||
|
||||
}
|
||||
sw_1.Stop();
|
||||
TimeSpan ts = sw_1.Elapsed;
|
||||
ImageDisplay(_OutputImg, graphics);
|
||||
DataDisplay(lstNasR[testNum], lstNasX[0], lstNasY[0], ts.TotalMilliseconds);
|
||||
PointInfo pp = translateCirclePoint.GetFirstPoint();
|
||||
if (pp != null)
|
||||
DataDisplay(translateCirclePoint.GetCurrentDegree(), pp.X, pp.Y, ts.TotalMilliseconds);
|
||||
else
|
||||
DataDisplay(translateCirclePoint.GetCurrentDegree(), 0, 0, ts.TotalMilliseconds);
|
||||
testNum++;
|
||||
times += ts.TotalMilliseconds;
|
||||
OKorNG = true;
|
||||
}
|
||||
|
||||
//比较半径和点间距,拟合圆
|
||||
private void FitCircle()
|
||||
{
|
||||
if (OKorNG)
|
||||
{
|
||||
sw_2 = new Stopwatch();//检测时间
|
||||
sw_2.Start();
|
||||
int Image_i = -1;
|
||||
// 调整vpp中CogCaliperTool工具数据需要同时调整step为x点数*2
|
||||
int step = 58;
|
||||
CogPMAlignTool mPM = mTB_2.Tools["CogPMAlignTool2"] as CogPMAlignTool;
|
||||
|
||||
LogHelper.LogInfo("转换机械坐标系下圆弧各点的原始坐标:\n");
|
||||
var points = translateCirclePoint.DoTranslatePoint();
|
||||
translateCirclePoint.DoTranslateNashPoint();
|
||||
|
||||
|
||||
CogImage8Grey outputImg = mTB_1.Outputs["OutputImage"].Value as CogImage8Grey;
|
||||
//添加找圆工具的 忽略点数 和 RMS偏差量
|
||||
CogFitCircleTool fitCircle_1 = new CogFitCircleTool();
|
||||
CogFitCircleTool fitCircle_2 = new CogFitCircleTool();
|
||||
|
||||
|
||||
CogGraphicCollection graphics = new CogGraphicCollection();
|
||||
|
||||
fitCircle_1.InputImage = outputImg;
|
||||
for (int i = 0; i < lstX.Count; i++)
|
||||
LogHelper.LogInfo("拟合机械坐标系下的圆中心:\n");
|
||||
m_graphics = new CogGraphicCollection();
|
||||
m_graphics2 = new CogGraphicCollection();
|
||||
foreach (PointInfo pointInfo in points)
|
||||
{
|
||||
fitCircle_1.RunParams.AddPoint(lstX[i], lstY[i]);
|
||||
|
||||
//CogPointMarker marker_1 = new CogPointMarker();//圆
|
||||
|
||||
//marker_1.X = lstNasX[i];
|
||||
//marker_1.Y = lstNasY[i];
|
||||
//marker_1.Color = CogColorConstants.White;
|
||||
//marker_1.Interactive = false;
|
||||
//graphics.Add(marker_1);
|
||||
|
||||
AddPointMarker(m_graphics, pointInfo.X, pointInfo.Y);
|
||||
}
|
||||
|
||||
//fitCircle_1.RunParams.NumToIgnore = 0;
|
||||
fitCircle_1.Run();
|
||||
if (fitCircle_1.Result != null)
|
||||
{
|
||||
double _RMS = fitCircle_1.Result.RMSError;
|
||||
CogCircle circle_1 = new CogCircle(fitCircle_1.Result.GetCircle());
|
||||
circle_1.Color = CogColorConstants.Cyan;
|
||||
circle_1.Interactive = false;
|
||||
FitCircleMachineToolBlock.Run(m_lastImage, points);
|
||||
|
||||
CogFitLineTool fitLine = new CogFitLineTool();
|
||||
sw_2.Stop();
|
||||
TimeSpan ts = sw_2.Elapsed;
|
||||
|
||||
//晶圆圆心位置
|
||||
double _centerX = circle_1.CenterX;
|
||||
double _centerY = circle_1.CenterY;
|
||||
double _radius = circle_1.Radius;
|
||||
times += ts.TotalMilliseconds;
|
||||
TCP_time = ts.TotalMilliseconds.ToString();
|
||||
|
||||
|
||||
fitCircle_2.InputImage = outputImg;
|
||||
|
||||
CogDistancePointPointTool pTp = new CogDistancePointPointTool();
|
||||
pTp.InputImage = outputImg;
|
||||
pTp.StartX = _centerX;
|
||||
pTp.StartY = _centerY;
|
||||
//double[] _DistanceMin = new double[lstNasX.Count];
|
||||
//int _distanceMin_i = 0;
|
||||
for (int i = 0; i < lstNasX.Count; i += step)
|
||||
{
|
||||
|
||||
for (int j = i; j < i + step && j < lstNasX.Count; j++)
|
||||
{
|
||||
if (j < (i + step - 15))//忽略重合数据的末尾的15个点
|
||||
{
|
||||
pTp.EndX = lstNasX[j];
|
||||
pTp.EndY = lstNasY[j];
|
||||
pTp.Run();
|
||||
double Distance = pTp.Distance;
|
||||
if (Distance - _radius < 0.1 && Distance - _radius > -0.1)
|
||||
{
|
||||
fitCircle_2.RunParams.AddPoint(lstNasX[j], lstNasY[j]);
|
||||
CogPointMarker marker_1 = new CogPointMarker();//圆
|
||||
|
||||
marker_1.X = lstNasX[j];
|
||||
marker_1.Y = lstNasY[j];
|
||||
marker_1.Color = CogColorConstants.Green;
|
||||
marker_1.Interactive = false;
|
||||
graphics.Add(marker_1);
|
||||
}
|
||||
else//忽略的点数
|
||||
{
|
||||
if (!(Distance - _radius < 1 && Distance - _radius > -1))
|
||||
{
|
||||
if (Image_i == -1)
|
||||
{
|
||||
Image_i = (int)(j / step);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CogPointMarker marker_1 = new CogPointMarker();//圆
|
||||
|
||||
marker_1.X = lstNasX[j];
|
||||
marker_1.Y = lstNasY[j];
|
||||
marker_1.Color = CogColorConstants.Yellow;
|
||||
marker_1.Interactive = false;
|
||||
graphics.Add(marker_1);
|
||||
}
|
||||
//_DistanceMin[i] = Distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
CogPointMarker marker_1 = new CogPointMarker();//圆
|
||||
|
||||
marker_1.X = lstNasX[j];
|
||||
marker_1.Y = lstNasY[j];
|
||||
marker_1.Color = CogColorConstants.Red;
|
||||
marker_1.Interactive = false;
|
||||
//graphics.Add(marker_1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//忽略的拟合点数
|
||||
fitCircle_2.RunParams.NumToIgnore = 0;
|
||||
fitCircle_2.Run();
|
||||
|
||||
double RMS = fitCircle_2.Result.RMSError;
|
||||
CogCircle circle_2 = new CogCircle(fitCircle_2.Result.GetCircle());
|
||||
circle_2.Color = CogColorConstants.Cyan;
|
||||
circle_2.Interactive = false;
|
||||
//晶圆圆心位置
|
||||
double centerX = circle_2.CenterX;
|
||||
double centerY = circle_2.CenterY;
|
||||
double radius = circle_2.Radius;
|
||||
|
||||
|
||||
double PM_X = 0;
|
||||
double PM_Y = 0;
|
||||
int _count = 0;
|
||||
if (Image_i != -1)
|
||||
{
|
||||
mTB_2.Inputs["InputImage"].Value = Images[Image_i];
|
||||
mTB_2.Run();
|
||||
_count = mPM.Results.Count;
|
||||
|
||||
if (_count != 0)
|
||||
{
|
||||
|
||||
double r = lstNasR[Image_i] / 180 * Math.PI;
|
||||
PM_X = mPM.Results[0].GetPose().TranslationX * Math.Cos(r) - mPM.Results[0].GetPose().TranslationY * Math.Sin(r) + circleCenterX * (1 - Math.Cos(r)) + circleCenterY * Math.Sin(r);
|
||||
PM_Y = mPM.Results[0].GetPose().TranslationX * Math.Sin(r) + mPM.Results[0].GetPose().TranslationY * Math.Cos(r) - circleCenterX * Math.Sin(r) + circleCenterY * (1 - Math.Cos(r));
|
||||
|
||||
}
|
||||
}
|
||||
//_distanceMin_i = DistanceMin(_DistanceMin);
|
||||
|
||||
////纳什口
|
||||
//CogLine line_ = new CogLine();
|
||||
//line_.SetFromStartXYEndXY(centerX, centerY, lstNasX[_distanceMin_i], lstNasY[_distanceMin_i]);
|
||||
//line_.Color = CogColorConstants.Green;
|
||||
//line_.Interactive = false;
|
||||
//graphics.Add(line_);
|
||||
//纳什口
|
||||
CogLine line_ = new CogLine();
|
||||
line_.SetFromStartXYEndXY(centerX, centerY, PM_X, PM_Y);
|
||||
line_.Color = CogColorConstants.Green;
|
||||
line_.Interactive = false;
|
||||
graphics.Add(line_);
|
||||
//角度值为0
|
||||
CogLine line_0 = new CogLine();
|
||||
line_0.SetXYRotation(centerX, centerY, 0);
|
||||
line_0.Color = CogColorConstants.Blue;
|
||||
line_0.Interactive = false;
|
||||
graphics.Add(line_0);
|
||||
CogAngleLineLineTool llTool = new CogAngleLineLineTool();
|
||||
llTool.InputImage = outputImg;
|
||||
llTool.LineA = line_0;
|
||||
llTool.LineB = line_;
|
||||
llTool.Run();
|
||||
angle = CogMisc.RadToDeg(llTool.Angle);
|
||||
|
||||
CogPointMarker marker_2 = new CogPointMarker();//圆心
|
||||
|
||||
marker_2.X = centerX;
|
||||
marker_2.Y = centerY;
|
||||
marker_2.Color = CogColorConstants.Green;
|
||||
marker_2.Interactive = false;
|
||||
graphics.Add(marker_2);
|
||||
|
||||
CogPointMarker marker_3 = new CogPointMarker();//旋转圆心
|
||||
|
||||
marker_3.X = circleCenterX;
|
||||
marker_3.Y = circleCenterY;
|
||||
marker_3.Color = CogColorConstants.Orange;
|
||||
marker_3.Interactive = false;
|
||||
graphics.Add(marker_3);
|
||||
graphics.Add(circle_2);
|
||||
|
||||
|
||||
deviationX = centerX - circleCenterX;
|
||||
deviationY = centerY - circleCenterY;
|
||||
|
||||
sw_2.Stop();
|
||||
TimeSpan ts = sw_2.Elapsed;
|
||||
|
||||
times += ts.TotalMilliseconds;
|
||||
|
||||
|
||||
ImageDisplay(outputImg, graphics);
|
||||
TCP_time = ts.TotalMilliseconds.ToString();
|
||||
TCP_X = centerX.ToString("F4");
|
||||
TCP_Y = centerY.ToString("F4");
|
||||
TCP_RMS = RMS.ToString("F4");
|
||||
TCP_R = angle.ToString("F4");
|
||||
ResultDisplay(times, ts.TotalMilliseconds, centerX, centerY, radius, RMS, deviationX, deviationY, angle);
|
||||
|
||||
OKorNG = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//MessageBox.Show("检测结果为空。");
|
||||
OKorNG = false;
|
||||
}
|
||||
ResultDisplay(times, ts.TotalMilliseconds, TCP_X, TCP_Y, TCP_R, TCP_RMS, deviationX, deviationY, angle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
//private int DistanceMin(double[] numbers)
|
||||
//{
|
||||
// double number = numbers[0];
|
||||
// int num1 = 0;
|
||||
// double num2 = ((IEnumerable<double>)numbers).Sum() / (double)((IEnumerable<double>)numbers).Count<double>();
|
||||
// for (int index = 1; index < numbers.Length; ++index)
|
||||
// {
|
||||
// if (numbers[index] < number)
|
||||
// {
|
||||
// number = numbers[index];
|
||||
// num1 = index;
|
||||
// }
|
||||
// }
|
||||
// //return Math.Abs(number - num2) > 0.0 ? num1 : -1;
|
||||
// return num1;
|
||||
//}
|
||||
|
||||
|
||||
private void ResultDisplay(double Times,double Time, double X, double Y, double R, double RMS, double dX, double dY, double dR)
|
||||
private void ResultDisplay(double Times,double Time, string X, string Y, string R, string RMS, double dX, double dY, double dR)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
@@ -1013,7 +824,6 @@ namespace WaferAlignment
|
||||
return;
|
||||
}
|
||||
this.cogRecordDisplay1.StaticGraphics.AddList(graphics, "");
|
||||
this.cogRecordDisplay1.Fit(true);
|
||||
}
|
||||
private void ImageDisplay(CogImage8Grey img)
|
||||
{
|
||||
@@ -1023,9 +833,17 @@ namespace WaferAlignment
|
||||
return;
|
||||
}
|
||||
this.cogRecordDisplay1.Image = img;
|
||||
this.cogRecordDisplay1.Fit(true);
|
||||
cogRecordDisplay1.StaticGraphics.Clear();
|
||||
}
|
||||
private void ImageDisplayFit()
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
BeginInvoke(new Action(() => ImageDisplayFit()));
|
||||
return;
|
||||
}
|
||||
cogRecordDisplay1.Fit(true);
|
||||
}
|
||||
|
||||
private void DataDisplay(double Rotation, double X, double Y, double Radius)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
@@ -1041,18 +859,6 @@ namespace WaferAlignment
|
||||
|
||||
}
|
||||
string SavePath;
|
||||
private void SaveImage(ICogImage img)
|
||||
{
|
||||
if (!Directory.Exists(SavePath))
|
||||
{
|
||||
Directory.CreateDirectory(SavePath);
|
||||
}
|
||||
using (CogImageFile imgFile = new CogImageFile())
|
||||
{
|
||||
imgFile.Open(Path.Combine(SavePath, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".bmp"), CogImageFileModeConstants.Write);
|
||||
imgFile.Append(img);
|
||||
}
|
||||
}
|
||||
private void Save()
|
||||
{
|
||||
if (!Directory.Exists(SavePath))
|
||||
@@ -1068,5 +874,27 @@ namespace WaferAlignment
|
||||
}
|
||||
}
|
||||
}
|
||||
private double m_cameraCount = 82;
|
||||
private double m_codeCount = 4096;
|
||||
private void textBox2_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
m_cameraCount = Convert.ToDouble(textBox2.Text);
|
||||
}
|
||||
|
||||
private void textBox3_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
m_codeCount = Convert.ToDouble(textBox3.Text);
|
||||
}
|
||||
private double m_roateX = 1;
|
||||
private double m_roateY = -1;
|
||||
private void nud_SizeX_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
m_roateX = Convert.ToDouble(nud_SizeX.Value);
|
||||
}
|
||||
|
||||
private void nud_SizeY_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
m_roateY = Convert.ToDouble(nud_SizeY.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,4 +140,16 @@
|
||||
<metadata name="Column4.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="Column1.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="Column2.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="Column3.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="Column4.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
</root>
|
||||
117
WaferAlignment/GetCircleToolBlock.cs
Normal file
117
WaferAlignment/GetCircleToolBlock.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using Cognex.VisionPro;
|
||||
using Cognex.VisionPro.Caliper;
|
||||
using Cognex.VisionPro.ToolBlock;
|
||||
using QWhale.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WaferAdjust
|
||||
{
|
||||
public delegate void OnGetCircleResult(double x, double y, double r);
|
||||
public delegate void OnToolReady(bool ready);
|
||||
public delegate void OnGetNashResult(double x, double y);
|
||||
internal class GetCircleToolBlock
|
||||
{
|
||||
private CogToolBlock cogToolBlock;
|
||||
private bool initialized = false;
|
||||
public event OnToolReady OnToolReady;
|
||||
public event OnGetCircleResult OnGetCircleResult;
|
||||
public event OnGetNashResult OnGetNashResult;
|
||||
public List<PointInfo> PointInfos;
|
||||
public void Initialize(string vpp)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cogToolBlock != null)
|
||||
{
|
||||
cogToolBlock.Ran -= CogToolBlock_Ran;
|
||||
cogToolBlock.Dispose();
|
||||
cogToolBlock = null;
|
||||
}
|
||||
initialized = false;
|
||||
PointInfos = new List<PointInfo>();
|
||||
cogToolBlock = CogSerializer.LoadObjectFromFile(vpp) as CogToolBlock;
|
||||
cogToolBlock.Ran += CogToolBlock_Ran;
|
||||
initialized = true;
|
||||
OnToolReady?.Invoke(initialized);
|
||||
LogHelper.LogInfo($"{vpp} initialized successfully: " + vpp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError(ex.Message);
|
||||
}
|
||||
}
|
||||
private void CogToolBlock_Ran(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
CogFindCircleTool cogFindCircleTool = cogToolBlock.Tools["CogFindCircleTool1"] as CogFindCircleTool;
|
||||
PointInfos.Clear();
|
||||
|
||||
if (cogFindCircleTool.Results != null)
|
||||
{
|
||||
foreach (CogFindCircleResult item in cogFindCircleTool.Results)
|
||||
{
|
||||
if (item.Found && item.Used)
|
||||
PointInfos.Add(new PointInfo(item.X, item.Y, item.DistanceToCircle));
|
||||
}
|
||||
}
|
||||
|
||||
OnGetCircleResult?.Invoke(Math.Round((double)cogToolBlock.Outputs["CenterX"].Value, 3),
|
||||
Math.Round((double)cogToolBlock.Outputs["CenterY"].Value, 3),
|
||||
Math.Round((double)cogToolBlock.Outputs["Radius"].Value, 3));
|
||||
|
||||
if ((int)cogToolBlock.Outputs["Results_Count"].Value == 1)
|
||||
{
|
||||
OnGetNashResult?.Invoke(Math.Round((double)cogToolBlock.Outputs["TranslationX"].Value, 3),
|
||||
Math.Round((double)cogToolBlock.Outputs["TranslationY"].Value, 3));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError(ex.Message + ex.StackTrace);
|
||||
}
|
||||
}
|
||||
public void Run(Bitmap bmp)
|
||||
{
|
||||
try
|
||||
{
|
||||
CogImage8Grey image8Grey = new CogImage8Grey(bmp);
|
||||
Run(image8Grey);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message);
|
||||
}
|
||||
}
|
||||
public void Run(CogImage8Grey image8Grey)
|
||||
{
|
||||
try
|
||||
{
|
||||
cogToolBlock.Inputs["OutputImage"].Value = image8Grey;
|
||||
cogToolBlock.Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message);
|
||||
}
|
||||
}
|
||||
public bool Ready()
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
if (cogToolBlock != null)
|
||||
{
|
||||
cogToolBlock.Ran -= CogToolBlock_Ran;
|
||||
cogToolBlock.Dispose();
|
||||
cogToolBlock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
WaferAlignment/LogHelper.cs
Normal file
22
WaferAlignment/LogHelper.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
|
||||
namespace WaferAdjust
|
||||
{
|
||||
public class LogHelper
|
||||
{
|
||||
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
|
||||
public static void LogInfo(string message)
|
||||
{
|
||||
Logger.Info(message);
|
||||
}
|
||||
public static void LogError(string message)
|
||||
{
|
||||
Logger.Error(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
WaferAlignment/Nlog.config
Normal file
14
WaferAlignment/Nlog.config
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
autoReload="true"
|
||||
throwConfigExceptions="true">
|
||||
<variable name="generic" value="${time} | ${level} | ${message} | ${all-event-properties} ${exception:format=tostring}"/>
|
||||
<targets async="true">
|
||||
<target xsi:type="File" name="logfile" fileName="${basedir}/logs/${shortdate}.log"
|
||||
layout="${generic}" encoding="utf-8"/>
|
||||
</targets>
|
||||
<rules>
|
||||
<logger name="*" minlevel="Info" writeTo="logfile" />
|
||||
</rules>
|
||||
</nlog>
|
||||
21
WaferAlignment/PointInfo.cs
Normal file
21
WaferAlignment/PointInfo.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WaferAdjust
|
||||
{
|
||||
internal class PointInfo
|
||||
{
|
||||
public double X;
|
||||
public double Y;
|
||||
public double Radius;
|
||||
public PointInfo(double x, double y, double radius)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Radius = radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
176
WaferAlignment/Rotation2D.cs
Normal file
176
WaferAlignment/Rotation2D.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WaferAdjust
|
||||
{
|
||||
/// <summary>
|
||||
/// 二维坐标旋转计算器(支持自定义坐标系方向)
|
||||
/// </summary>
|
||||
public class Rotation2D
|
||||
{
|
||||
#region 正向旋转:求旋转后的坐标
|
||||
|
||||
/// <summary>
|
||||
/// 点A绕点B逆时针旋转指定角度(角度制)
|
||||
/// </summary>
|
||||
/// <param name="ax">点A的X坐标</param>
|
||||
/// <param name="ay">点A的Y坐标</param>
|
||||
/// <param name="bx">旋转中心B的X坐标</param>
|
||||
/// <param name="by">旋转中心B的Y坐标</param>
|
||||
/// <param name="angleDegrees">旋转角度(角度制,逆时针)</param>
|
||||
/// <param name="isRight">X轴正方向是否向右(默认true)</param>
|
||||
/// <param name="isUp">Y轴正方向是否向上(默认true)</param>
|
||||
/// <returns>旋转后的点A'坐标 (x', y')</returns>
|
||||
public static (double x, double y) RotatePointDegrees(
|
||||
double ax, double ay,
|
||||
double bx, double by,
|
||||
double angleDegrees,
|
||||
bool isRight = true,
|
||||
bool isUp = true)
|
||||
{
|
||||
return RotatePointRadians(ax, ay, bx, by,
|
||||
DegreesToRadians(angleDegrees), isRight, isUp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点A绕点B逆时针旋转指定角度(弧度制)
|
||||
/// </summary>
|
||||
/// <param name="ax">点A的X坐标</param>
|
||||
/// <param name="ay">点A的Y坐标</param>
|
||||
/// <param name="bx">旋转中心B的X坐标</param>
|
||||
/// <param name="by">旋转中心B的Y坐标</param>
|
||||
/// <param name="angleRadians">旋转角度(弧度制,逆时针)</param>
|
||||
/// <param name="isRight">X轴正方向是否向右(默认true)</param>
|
||||
/// <param name="isUp">Y轴正方向是否向上(默认true)</param>
|
||||
/// <returns>旋转后的点A'坐标 (x', y')</returns>
|
||||
public static (double x, double y) RotatePointRadians(
|
||||
double ax, double ay,
|
||||
double bx, double by,
|
||||
double angleRadians,
|
||||
bool isRight = true,
|
||||
bool isUp = true)
|
||||
{
|
||||
// 1. 转换为标准数学坐标系(向右为正,向上为正)
|
||||
double mathAx = isRight ? ax : -ax;
|
||||
double mathAy = isUp ? ay : -ay;
|
||||
double mathBx = isRight ? bx : -bx;
|
||||
double mathBy = isUp ? by : -by;
|
||||
|
||||
// 2. 在标准坐标系中执行旋转
|
||||
double cosR = Math.Cos(angleRadians);
|
||||
double sinR = Math.Sin(angleRadians);
|
||||
|
||||
double dx = mathAx - mathBx;
|
||||
double dy = mathAy - mathBy;
|
||||
|
||||
double rotatedDx = dx * cosR - dy * sinR;
|
||||
double rotatedDy = dx * sinR + dy * cosR;
|
||||
|
||||
double mathNewX = mathBx + rotatedDx;
|
||||
double mathNewY = mathBy + rotatedDy;
|
||||
|
||||
// 3. 转换回用户指定的坐标系
|
||||
double outputX = isRight ? mathNewX : -mathNewX;
|
||||
double outputY = isUp ? mathNewY : -mathNewY;
|
||||
|
||||
return (outputX, outputY);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 反向旋转:求旋转前的原始坐标
|
||||
|
||||
/// <summary>
|
||||
/// 已知旋转后的点A',求绕点B逆时针旋转前的原始点A(角度制)
|
||||
/// </summary>
|
||||
/// <param name="rotatedX">旋转后的点A'的X坐标</param>
|
||||
/// <param name="rotatedY">旋转后的点A'的Y坐标</param>
|
||||
/// <param name="bx">旋转中心B的X坐标</param>
|
||||
/// <param name="by">旋转中心B的Y坐标</param>
|
||||
/// <param name="angleDegrees">旋转角度(角度制,逆时针)</param>
|
||||
/// <param name="isRight">X轴正方向是否向右(默认true)</param>
|
||||
/// <param name="isUp">Y轴正方向是否向上(默认true)</param>
|
||||
/// <returns>原始的未旋转点A坐标 (x, y)</returns>
|
||||
public static (double x, double y) GetOriginalPointDegrees(
|
||||
double rotatedX, double rotatedY,
|
||||
double bx, double by,
|
||||
double angleDegrees,
|
||||
bool isRight = true,
|
||||
bool isUp = true)
|
||||
{
|
||||
return GetOriginalPointRadians(rotatedX, rotatedY, bx, by,
|
||||
DegreesToRadians(angleDegrees), isRight, isUp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 已知旋转后的点A',求绕点B逆时针旋转前的原始点A(弧度制)
|
||||
/// </summary>
|
||||
/// <param name="rotatedX">旋转后的点A'的X坐标</param>
|
||||
/// <param name="rotatedY">旋转后的点A'的Y坐标</param>
|
||||
/// <param name="bx">旋转中心B的X坐标</param>
|
||||
/// <param name="by">旋转中心B的Y坐标</param>
|
||||
/// <param name="angleRadians">旋转角度(弧度制,逆时针)</param>
|
||||
/// <param name="isRight">X轴正方向是否向右(默认true)</param>
|
||||
/// <param name="isUp">Y轴正方向是否向上(默认true)</param>
|
||||
/// <returns>原始的未旋转点A坐标 (x, y)</returns>
|
||||
public static (double x, double y) GetOriginalPointRadians(
|
||||
double rotatedX, double rotatedY,
|
||||
double bx, double by,
|
||||
double angleRadians,
|
||||
bool isRight = true,
|
||||
bool isUp = true)
|
||||
{
|
||||
// 1. 转换为标准数学坐标系
|
||||
double mathRotatedX = isRight ? rotatedX : -rotatedX;
|
||||
double mathRotatedY = isUp ? rotatedY : -rotatedY;
|
||||
double mathBx = isRight ? bx : -bx;
|
||||
double mathBy = isUp ? by : -by;
|
||||
|
||||
// 2. 在标准坐标系中执行反向旋转
|
||||
double cosR = Math.Cos(angleRadians);
|
||||
double sinR = Math.Sin(angleRadians);
|
||||
|
||||
double dx = mathRotatedX - mathBx;
|
||||
double dy = mathRotatedY - mathBy;
|
||||
|
||||
// 反向旋转(相当于顺时针旋转)
|
||||
double originalDx = dx * cosR + dy * sinR;
|
||||
double originalDy = -dx * sinR + dy * cosR;
|
||||
|
||||
double mathOriginalX = mathBx + originalDx;
|
||||
double mathOriginalY = mathBy + originalDy;
|
||||
|
||||
// 3. 转换回用户指定的坐标系
|
||||
double outputX = isRight ? mathOriginalX : -mathOriginalX;
|
||||
double outputY = isUp ? mathOriginalY : -mathOriginalY;
|
||||
|
||||
return (outputX, outputY);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助方法
|
||||
|
||||
/// <summary>
|
||||
/// 角度转弧度
|
||||
/// </summary>
|
||||
private static double DegreesToRadians(double degrees)
|
||||
{
|
||||
return degrees * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 弧度转角度(公共方法,供外部使用)
|
||||
/// </summary>
|
||||
public static double RadiansToDegrees(double radians)
|
||||
{
|
||||
return radians * 180.0 / Math.PI;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
92
WaferAlignment/TranslateCirclePoint.cs
Normal file
92
WaferAlignment/TranslateCirclePoint.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WaferAdjust
|
||||
{
|
||||
internal class TranslateCirclePoint
|
||||
{
|
||||
private double rotateX;
|
||||
private double rotateY;
|
||||
List<PointInfo> totalPoints;
|
||||
List<PointInfo> totalCenters;
|
||||
private int circleIndex;
|
||||
private double perAngle;
|
||||
PointInfo nashPoint;
|
||||
PointInfo firstPoint;
|
||||
public void SetRotateXY(double x, double y, double angle)
|
||||
{
|
||||
rotateX = x; rotateY = y;
|
||||
totalPoints = new List<PointInfo>();
|
||||
totalCenters = new List<PointInfo>();
|
||||
circleIndex = 0;
|
||||
perAngle = angle;
|
||||
nashPoint = null;
|
||||
firstPoint = null;
|
||||
}
|
||||
public double GetRotateX()
|
||||
{
|
||||
return rotateX;
|
||||
}
|
||||
public double GetRotateY()
|
||||
{
|
||||
return rotateY;
|
||||
}
|
||||
public void AddCirclePoint(List<PointInfo> pointInfos)
|
||||
{
|
||||
if (pointInfos == null || pointInfos.Count == 0) return;
|
||||
foreach (var item in pointInfos)
|
||||
{
|
||||
totalPoints.Add(new PointInfo(item.X, item.Y, circleIndex * perAngle));
|
||||
}
|
||||
firstPoint = pointInfos[0];
|
||||
}
|
||||
public PointInfo GetFirstPoint()
|
||||
{
|
||||
return firstPoint;
|
||||
}
|
||||
public void AddCircleIndex()
|
||||
{
|
||||
circleIndex++;
|
||||
}
|
||||
public double GetCurrentDegree()
|
||||
{
|
||||
return circleIndex * perAngle;
|
||||
}
|
||||
public void AddNashPoint(double x, double y)
|
||||
{
|
||||
nashPoint = new PointInfo(x, y, circleIndex * perAngle);
|
||||
}
|
||||
public void AddCircleCenter(double x, double y, double r)
|
||||
{
|
||||
totalCenters.Add(new PointInfo(x, y, r));
|
||||
}
|
||||
public List<PointInfo> DoTranslatePoint()
|
||||
{
|
||||
List<PointInfo> trans = new List<PointInfo>();
|
||||
foreach (var item in totalPoints)
|
||||
{
|
||||
var res = Rotation2D.GetOriginalPointDegrees(item.X, item.Y,
|
||||
rotateX, rotateY, item.Radius, true, false);
|
||||
trans.Add(new PointInfo(res.x, res.y, item.Radius));
|
||||
}
|
||||
return trans;
|
||||
}
|
||||
public void DoTranslateNashPoint()
|
||||
{
|
||||
if (nashPoint == null)
|
||||
return;
|
||||
|
||||
var res = Rotation2D.GetOriginalPointDegrees(nashPoint.X, nashPoint.Y,
|
||||
rotateX, rotateY, nashPoint.Radius, true, false);
|
||||
|
||||
nashPoint = new PointInfo(res.x, res.y, nashPoint.Radius);
|
||||
}
|
||||
public PointInfo GetNashPoint()
|
||||
{
|
||||
return nashPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,9 @@
|
||||
<Reference Include="MvCameraControl.Net">
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\MVS\Development\DotNet\win64\net40\MvCameraControl.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=6.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.6.0.6\lib\net46\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="QWhale.Common, Version=1.62.4104.36375, Culture=neutral, PublicKeyToken=da632fd1713dff10" />
|
||||
@@ -86,6 +89,7 @@
|
||||
<Reference Include="QWhale.Syntax, Version=1.62.4104.36376, Culture=neutral, PublicKeyToken=da632fd1713dff10" />
|
||||
<Reference Include="QWhale.Syntax.Parsers, Version=1.62.4104.36376, Culture=neutral, PublicKeyToken=da632fd1713dff10" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
@@ -104,15 +108,21 @@
|
||||
<Compile Include="CenterOfRotation.cs" />
|
||||
<Compile Include="ConfigStore.cs" />
|
||||
<Compile Include="DataPostbox.cs" />
|
||||
<Compile Include="FitCircleToolBlock.cs" />
|
||||
<Compile Include="Form1.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Form1.Designer.cs">
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GetCircleToolBlock.cs" />
|
||||
<Compile Include="LogHelper.cs" />
|
||||
<Compile Include="PointInfo.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Rotation2D.cs" />
|
||||
<Compile Include="TCP.cs" />
|
||||
<Compile Include="TranslateCirclePoint.cs" />
|
||||
<EmbeddedResource Include="Form1.resx">
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -126,6 +136,10 @@
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<None Include="Nlog.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
|
||||
4
WaferAlignment/packages.config
Normal file
4
WaferAlignment/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="6.0.6" targetFramework="net48" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user