Files
TetraParkOCR/TetraPackOCR/Form1.cs
2025-12-26 14:54:32 +08:00

1572 lines
62 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using AVP.CRobot;
using Cognex.VisionPro;
using Cognex.VisionPro.Comm;
using Cognex.VisionPro.ImageProcessing;
using Cognex.VisionPro.PMAlign;
using Cognex.VisionPro.QuickBuild;
using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro.ToolGroup;
using log4net;
using LogShowLib;
using OfficeOpenXml;
using OpenCvSharp;
using PaddleOCRSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Forms;
using LibDataBase;
using LibReadTetraExcel;
using LibComm;
using LibCamera;
namespace TetraPackOCR
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
LogInit();
}
#region
//创建字段log
ILog log = LogManager.GetLogger(typeof(Form1));
ICommPLC commPLC;
ICameraDriver cameraOCR, cameraDET;
/// <summary>
/// 声明一个PaddleOCR对象
/// </summary>
PaddleOCREngine Engine;
/// <summary>
/// 表格路径
/// </summary>
string execlFileName = AppDomain.CurrentDomain.BaseDirectory + "Data\\Excle\\OCR文件0602.xlsx";
OrderConfig config = null;
/// <summary>
/// 定位Vpp文件
/// </summary>
string vppdetFile = AppDomain.CurrentDomain.BaseDirectory + "Data\\VPPFile\\liledet.vpp";
/// <summary>
/// 存图路径
/// </summary>
string SaveImageFileOCR = System.IO.Path.GetPathRoot(Application.ExecutablePath) + "SaveImage\\OCR";//ocr存图
string SaveImageFileDET = System.IO.Path.GetPathRoot(Application.ExecutablePath) + "SaveImage\\Det";//ocr存图
private CogJobManager myJobManagerDET;
private CogJob myJobDET;
bool PlcContinueFlag = false; //PLC状态旗帜
int mMatchingStr = 0;//接收当前OCR拍照位置
List<double> ocrAcc = new List<double>();
delegate void DetResultDelegate(Object Sender, CogJobManagerActionEventArgs e);
delegate void OcrResultDelegate(Bitmap bmp);
#endregion
#region
/// <summary>
/// 窗体加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
try
{
btn_StarDet_manual.Enabled = false;
btn_StarDet_manual.BackColor = Color.LightGray;
button1.BackColor = Color.LightGray;
button2.Enabled = false;
button2.BackColor = Color.LightGray;
btn_OrderNum.Enabled = false;
btn_OrderNum.BackColor = Color.LightGray;
log.Info("软件正在加载...");
Enabled = false;
Action action = (() =>
{
InitializeCamerOCR();
InitializeCamerDET();
InitializePaddleOCR();
log.Info("VPP文件加载中...");
try
{
myJobManagerDET = CogSerializer.LoadObjectFromFile(vppdetFile) as CogJobManager;
}
catch (Exception ex)
{
log.Error("定位VPP文件加载失败请检查文件路径是否正确" + ex.Message);
myJobManagerDET = null;
}
log.Info("定位VPP文件加载完成");
InitializeComm();
log.Info("模型文件加载完成");
ttls_SystemStatusShow.Visible = true;
ttls_CamStatusShow.Visible = true;
Invoke(new Action(() =>
{
Enabled = true;
btn_OrderNum.Enabled = true;
btn_OrderNum.BackColor = Color.DeepSkyBlue;
}));
});
Task myTask = new Task(action);
//实例化一个线程列表
List<Task> tsk = new List<Task>();
//将上面的加载vpp工作加入线程列表中
tsk.Add(myTask);
//读取线程列表内的工作让cpu为其开辟线程空间并执行程序
foreach (var iteam in tsk)
{
iteam.Start();
}
TaskFactory tskFactory = new TaskFactory();
tskFactory.ContinueWhenAll(tsk.ToArray(), FlashFormView =>
{
if (myJobManagerDET != null)
{
myJobDET = myJobManagerDET.Job(0);
// 注册结果队列事件
myJobManagerDET.UserResultAvailable += new CogJobManager.CogUserResultAvailableEventHandler(DetResult);
}
});
}
catch (Exception ex)
{
log.Error(ex.Message);
}
}
/// <summary>
/// 窗体关闭
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
ClossCam();
//// 注销结果队列事件
if (myJobManagerDET != null)
{
myJobManagerDET.UserResultAvailable -= new CogJobManager.CogUserResultAvailableEventHandler(DetResult);
myJobManagerDET.Shutdown();
}
StopComm();
if (myJobManagerDET == null)
System.Environment.Exit(0);
}
catch
{
Application.DoEvents();
System.Environment.Exit(0);
}
}
#endregion
#region
private void LogInit()
{
try
{
//实例化日志助手
LogShowLib.LogHelper lib = new LogShowLib.LogHelper();
//为log4net导入配置文件
//若传入目录未找到配置文件将创建一个LogConfig.xml
log4net.Config.XmlConfigurator.Configure(lib.GetXMLStream(AppDomain.CurrentDomain.BaseDirectory));
}
catch (Exception ex)
{
MessageBox.Show(string.Format("配置日志出错:{0}", ex.Message));
}
}
#endregion
#region
#region 1 OCR相机
private void InitializeCamerOCR()
{
cameraOCR = new CameraDriver();
cameraOCR.OnCameraImage += CameraOCR_OnCameraImage;
cameraOCR.Initialize("Machine Vision:CK21686DAK00001", "BayerRG8", 500000, 2.5);
if (cameraOCR.IsOpened())
log.Info("OCR相机加载完毕");
else
log.Error("OCR相机加载失败");
}
private void CameraOCR_OnCameraImage(Bitmap bmp)
{
if (bmp == null)
return;
try
{
OCRResult(bmp);
}
catch (Exception ex)
{
log.Error(ex.ToString());
}
}
#endregion
#region 2
private void InitializeCamerDET()
{
cameraDET = new CameraDriver();
cameraDET.OnCameraImage += CameraDET_OnCameraImage;
cameraDET.Initialize("Machine Vision:BK27185BAK00038", "Mono", 30000, 1.0);
if (cameraDET.IsOpened())
log.Info("定位相机相机加载完毕");
else
log.Error("定位相机相机加载失败");
}
private void CameraDET_OnCameraImage(Bitmap bmp)
{
try
{
if (bmp == null)
return;
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] bytes = ms.GetBuffer();
ms.Close();
//保存DET图像
if (!Directory.Exists(SaveImageFileDET))
{
Directory.CreateDirectory(SaveImageFileDET);
}
string strTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
FileStream fs = new FileStream(SaveImageFileDET + '\\' + strTime + ".bmp", FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes, 0, bytes.Length);
bw.Close();
fs.Close();
log.Info("定位存图已完成");
CogImage8Grey cogimage = new CogImage8Grey(bmp);
//把图像给job中convertImagetool
CogToolGroup myTG = myJobDET.VisionTool as CogToolGroup;
CogToolBlock myTB = myTG.Tools["CogToolBlock1"] as CogToolBlock;
CogImageConvertTool cogImageConvert = myTB.Tools["CogImageConvertTool1"] as CogImageConvertTool;
cogImageConvert.InputImage = cogimage;
//运行jobmanager
myJobManagerDET.Run();
}
catch (Exception ex)
{
EnableStartDetect();
log.Error(ex.ToString());
}
}
#endregion
private void EnableStartDetect()
{
if (InvokeRequired)
{
BeginInvoke(new Action(EnableStartDetect));
return;
}
btn_StarDet_manual.Enabled = true;
btn_StarDet_manual.BackColor = Color.LimeGreen;
button2.Enabled = true;
button2.BackColor = Color.LimeGreen;
button1.Enabled = false;
button1.BackColor = Color.LightGray;
}
#region
void ClossCam()
{
cameraDET?.Stop();
cameraOCR?.Stop();
}
#endregion
#endregion
#region OCR模型参数初始化
private void InitializePaddleOCR()
{
try
{
//模型初始化
OCRModelConfig config = null;
//初始化OCR
Engine = new PaddleOCREngine(config, "");
log.Info("OCR模型初始化完成");
}
catch (Exception ex)
{
log.Error(ex.Message + ex.StackTrace);
}
}
#endregion
#region
private bool orderLoaded = false;
private Dictionary<int, List<string>> ocrTextRequest = new Dictionary<int, List<string>>();
private Dictionary<int, string> ocrTextDesign = new Dictionary<int, string>();
private Dictionary<string, bool> ocrTextResult = new Dictionary<string, bool>();
/// <summary>
/// 此按钮事件主要是获取excel表格内的数据
/// 包括定位偏移量,需要验证的字符
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_OrderNum_Click(object sender, EventArgs e)
{
try
{
button1.Enabled = false;
orderLoaded = false;
btn_StarDet_manual.Enabled = false;
btn_StarDet_manual.BackColor = Color.LightGray;
button2.Enabled = false;
button2.BackColor = Color.LightGray;
listBox1.Items.Clear();
ocrTextRequest.Clear();
ocrTextDesign.Clear();
ClearData();
ClearDataShow();
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "未启用";
lbl_L1_verOcrRs.BackColor = Color.Gray;
lbl_L2_verOcrRs.Text = "未启用";
lbl_L2_verOcrRs.BackColor = Color.Gray;
lbl_L3_verOcrRs.Text = "未启用";
lbl_L3_verOcrRs.BackColor = Color.Gray;
lbl_L4_verOcrRs.Text = "未启用";
lbl_L4_verOcrRs.BackColor = Color.Gray;
lbl_L5_verOcrRs.Text = "未启用";
lbl_L5_verOcrRs.BackColor = Color.Gray;
lbl_L6_verOcrRs.Text = "未启用";
lbl_L6_verOcrRs.BackColor = Color.Gray;
lbl_L7_verOcrRs.Text = "未启用";
lbl_L7_verOcrRs.BackColor = Color.Gray;
lbl_L8_verOcrRs.Text = "未启用";
lbl_L8_verOcrRs.BackColor = Color.Gray;
lbl_L9_verOcrRs.Text = "未启用";
lbl_L9_verOcrRs.BackColor = Color.Gray;
}));
btn_OrderNum.Enabled = false;
btn_OrderNum.BackColor = Color.LightGray;
//通过订单号获取表格中需要的值
string order = txt_OrderNum.Text;
if (string.IsNullOrEmpty(order))
{
log.Warn("订单号为空,请输入订单号。");
btn_OrderNum.Enabled = true;
btn_OrderNum.BackColor = Color.DeepSkyBlue;
return;
}
log.Info("当前订单号为:" + order);
config = ExcelHelper.ReadOCROrder(execlFileName, order);
if (config.ParseQSV)
{
lbl_QSV.Text = config.QSV;
log.Info("当前订单QSV:" + config.QSV);
log.Info("当前订单Number Of Lanes:" + config.NumberOfLanes);
lbl_NO.Text = config.NumberOfLanes.ToString();
var result = config.OCRDesign
.GroupBy(kvp => kvp.Value, kvp => kvp.Key)
.ToDictionary(g => g.Key, g => g.ToList());
foreach (var kvp in result)
{
listBox1.Items.Add(string.Join(",", kvp.Value));
listBox1.Items.Add(string.Join(",", config.OCRRequest[kvp.Value[0]]));
}
}
else
{
log.Debug("QSV未找到请检查订单号是否正确");
btn_OrderNum.Enabled = true;
btn_OrderNum.BackColor = Color.DeepSkyBlue;
return;
}
if (config.ParseProduct)
{
lbl_ProductStandard.Text = config.ProductStandard;
log.Info("当前订单产品编号:" + config.ProductStandard);
lbl_width.Text = config.Width.ToString();
log.Info("当前订单幅宽:" + config.Width);
lbl_height.Text = config.Height.ToString();
log.Info("当前订单幅高:" + config.Height);
lbl_Gradient.Text = config.Gradient.ToString();
log.Info("当前订单梯度:" + config.Gradient);
}
else
{
log.Debug("ProductStandard未找到请检查订单号是否正确");
btn_OrderNum.Enabled = true;
btn_OrderNum.BackColor = Color.DeepSkyBlue;
return;
}
if (config.ParseArrange)
{
lbl_DistX.Text = config.DistX.ToString();
log.Info("当前订单X偏移:" + config.DistX);
lbl_DistY.Text = config.DistY.ToString();
log.Info("当前订单Y偏移:" + config.DistY);
log.Info("当前排布方式:" + config.ColorArray);
log.Info("单行最大数量:" + config.ColorMax.ToString());
}
else
{
log.Debug("DistXDistY未找到请检查订单号是否正确");
btn_OrderNum.Enabled = true;
btn_OrderNum.BackColor = Color.DeepSkyBlue;
return;
}
log.Info("相关数据已获取完成,且已显示在界面中,请查看。");
//判断当前Lans决定结果显示数量
InitLableColumn();
btn_OrderNum.Enabled = true;
btn_OrderNum.BackColor = Color.DeepSkyBlue;
orderLoaded = true;
btn_StarDet_manual.Enabled = true;
btn_StarDet_manual.BackColor = Color.LimeGreen;
button2.Enabled = true;
button2.BackColor = Color.LimeGreen;
}
catch (Exception ex)
{
log.Error("数据解析错误:" + ex.Message);
btn_OrderNum.Enabled = true;
btn_OrderNum.BackColor = Color.DeepSkyBlue;
}
}
private void InitLableColumn()
{
switch (config.NumberOfLanes)
{
case 1:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 2:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 3:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
lbl_L3_verOcrRs.Text = "启用";
lbl_L3_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 4:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
lbl_L3_verOcrRs.Text = "启用";
lbl_L3_verOcrRs.BackColor = Color.Yellow;
lbl_L4_verOcrRs.Text = "启用";
lbl_L4_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 5:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
lbl_L3_verOcrRs.Text = "启用";
lbl_L3_verOcrRs.BackColor = Color.Yellow;
lbl_L4_verOcrRs.Text = "启用";
lbl_L4_verOcrRs.BackColor = Color.Yellow;
lbl_L5_verOcrRs.Text = "启用";
lbl_L5_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 6:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
lbl_L3_verOcrRs.Text = "启用";
lbl_L3_verOcrRs.BackColor = Color.Yellow;
lbl_L4_verOcrRs.Text = "启用";
lbl_L4_verOcrRs.BackColor = Color.Yellow;
lbl_L5_verOcrRs.Text = "启用";
lbl_L5_verOcrRs.BackColor = Color.Yellow;
lbl_L6_verOcrRs.Text = "启用";
lbl_L6_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 7:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
lbl_L3_verOcrRs.Text = "启用";
lbl_L3_verOcrRs.BackColor = Color.Yellow;
lbl_L4_verOcrRs.Text = "启用";
lbl_L4_verOcrRs.BackColor = Color.Yellow;
lbl_L5_verOcrRs.Text = "启用";
lbl_L5_verOcrRs.BackColor = Color.Yellow;
lbl_L6_verOcrRs.Text = "启用";
lbl_L6_verOcrRs.BackColor = Color.Yellow;
lbl_L7_verOcrRs.Text = "启用";
lbl_L7_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 8:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
lbl_L3_verOcrRs.Text = "启用";
lbl_L3_verOcrRs.BackColor = Color.Yellow;
lbl_L4_verOcrRs.Text = "启用";
lbl_L4_verOcrRs.BackColor = Color.Yellow;
lbl_L5_verOcrRs.Text = "启用";
lbl_L5_verOcrRs.BackColor = Color.Yellow;
lbl_L6_verOcrRs.Text = "启用";
lbl_L6_verOcrRs.BackColor = Color.Yellow;
lbl_L7_verOcrRs.Text = "启用";
lbl_L7_verOcrRs.BackColor = Color.Yellow;
lbl_L8_verOcrRs.Text = "启用";
lbl_L8_verOcrRs.BackColor = Color.Yellow;
}));
break;
case 9:
Invoke(new Action(() =>
{
lbl_L1_verOcrRs.Text = "启用";
lbl_L1_verOcrRs.BackColor = Color.Yellow;
lbl_L2_verOcrRs.Text = "启用";
lbl_L2_verOcrRs.BackColor = Color.Yellow;
lbl_L3_verOcrRs.Text = "启用";
lbl_L3_verOcrRs.BackColor = Color.Yellow;
lbl_L4_verOcrRs.Text = "启用";
lbl_L4_verOcrRs.BackColor = Color.Yellow;
lbl_L5_verOcrRs.Text = "启用";
lbl_L5_verOcrRs.BackColor = Color.Yellow;
lbl_L6_verOcrRs.Text = "启用";
lbl_L6_verOcrRs.BackColor = Color.Yellow;
lbl_L7_verOcrRs.Text = "启用";
lbl_L7_verOcrRs.BackColor = Color.Yellow;
lbl_L8_verOcrRs.Text = "启用";
lbl_L8_verOcrRs.BackColor = Color.Yellow;
lbl_L9_verOcrRs.Text = "启用";
lbl_L9_verOcrRs.BackColor = Color.Yellow;
}));
break;
}
}
private double m_textWidth = 0;
private DateTime m_startTime = DateTime.Now;
private void btn_StarDet_manual_Click(object sender, EventArgs e)
{
if (cameraDET?.IsOpened() == false || cameraOCR?.IsOpened() == false)
{
MessageBox.Show("相机未打开,无法进行检测,请检查相机连接及状态!");
return;
}
if (PlcContinueFlag == false)
{
MessageBox.Show("PLC未处于运行状态无法进行检测请检查PLC连接及状态");
return;
}
if (MessageBox.Show("确认OCR相机处于零点位置", "提示", MessageBoxButtons.YesNo) == DialogResult.No)
{
return;
}
if (orderLoaded == false)
{
MessageBox.Show("未获取正确的订单编号!");
return;
}
InitLableColumn();
m_GotoZero = false;
m_startTime = DateTime.Now;
m_textWidth = 18 - (config.NumberOfLanes - 5);
ocrAcc.Clear();
btn_StarDet_manual.Enabled = false;
button2.Enabled = false;
button1.Enabled = true;
btn_StarDet_manual.BackColor = Color.LightGray;
button2.BackColor = Color.LightGray;
button1.BackColor = Color.LimeGreen;
cameraDET.GrabImage();
list_Log.Clear();
log.Info("手动触发开始");
m_BeginOCR = true;
}
private bool m_BeginOCR = false;
/// <summary>
/// 清空上次订单数据
/// </summary>
void ClearData()
{
config = new OrderConfig();
}
/// <summary>
/// 清空上次订单显示区
/// </summary>
void ClearDataShow()
{
lbl_QSV.Text = "";
lbl_NO.Text = "";
lbl_ProductStandard.Text = "";
lbl_width.Text = "";
lbl_Gradient.Text = "";
lbl_DistX.Text = "";
lbl_DistY.Text = "";
}
private void txt_OrderNum_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
btn_OrderNum_Click(sender, e);
}
}
#endregion
#region
#region
public void DetResult(object sender, CogJobManagerActionEventArgs e)
{
try
{
if (InvokeRequired)
{
Invoke(new DetResultDelegate(DetResult), new object[] { sender, e });
return;
}
//清除上次的结果显示
lbl_XShow.Text = "";
lbl_YShow.Text = "";
lbl_RShow.Text = "";
CogToolGroup myTG = myJobDET.VisionTool as CogToolGroup;
CogToolBlock myTB = myTG.Tools["CogToolBlock1"] as CogToolBlock;
CogPMAlignTool myPMA = myTB.Tools["CogPMAlignTool2"] as CogPMAlignTool;
CogImageConvertTool myImage = myTB.Tools["CogImageConvertTool1"] as CogImageConvertTool;
Location_Display.Image = myPMA.InputImage;
Location_Display.StaticGraphics.Clear();
Location_Display.InteractiveGraphics.Clear();
Location_Display.Fit();
if (myPMA.Results != null)
{
int i = GetXYRonRightDown(myPMA.Results);//获取视野中最右下边的K标志坐标的索引
double xx = myPMA.Results[i].GetPose().TranslationX;
double yy = myPMA.Results[i].GetPose().TranslationY;
double rr = CogMisc.RadToDeg(myPMA.Results[i].GetPose().Rotation);
lbl_XShow.Text = xx.ToString();
lbl_YShow.Text = yy.ToString();
lbl_RShow.Text = rr.ToString();
log.Info($"x:{xx} y:{yy} degree:{rr}");
//画模型轮廓
CogCompositeShape shape = myPMA.Results[i].CreateResultGraphics(CogPMAlignResultGraphicConstants.MatchFeatures);
CogCompositeShape shape1 = myPMA.Results[i].CreateResultGraphics(CogPMAlignResultGraphicConstants.CoordinateAxes);
Location_Display.InteractiveGraphics.Add(shape, "", false);
Location_Display.InteractiveGraphics.Add(shape1, "", false);
//画定位的十字点
CPMARunStatus.DrawPointMarker(xx, yy, CogMisc.DegToRad(rr), CogColorConstants.Orange, Location_Display, ".");
log.Info("定位计算已完成。");
if (xx > 350)
{
log.Error("定位横向轴偏左,疑似倒数第二张图,请重新摆放后识别");
NoticePLCCompleteDet(0.0f);
}
else
SendToPLC(xx, yy, rr);
}
else
{
EnableStartDetect();
log.Info("没有定位到K标志,请查看图像或相机是否正常");
}
}
catch (Exception ex)
{
EnableStartDetect();
log.Error(ex.Message + "未检测到K标志");
NoticePLCCompleteDet(0.0f);
}
}
/// <summary>
/// 获取右下角定位标志坐标
/// </summary>
/// <param name="Results">PatMAX结果</param>
/// <returns></returns>
private int GetXYRonRightDown(CogPMAlignResults Results)
{
int i = 0;
double[] xx = new double[Results.Count], yy = new double[Results.Count], rr = new double[Results.Count];
//第一次循环将所有坐标取出
for (int j = 0; j < Results.Count; j++)
{
xx[j] = Results[j].GetPose().TranslationX;
yy[j] = Results[j].GetPose().TranslationY;
rr[j] = CogMisc.RadToDeg(Results[j].GetPose().Rotation);
}
if (Results.Count == 1)
{
i = 0;
}
else if (Results.Count == 2)
{
double Xdist, Ydist;
Xdist = Math.Abs(xx[0] - xx[1]);
Ydist = Math.Abs(yy[0] - yy[1]);
if (Xdist > Ydist)
{
i = Array.IndexOf(xx, xx.Min());
}
else if (Xdist < Ydist)
{
i = Array.IndexOf(yy, yy.Max());
}
}
else
{
double averageX = xx.Average();
//第二次循环保留x比平均x值小的元素
for (int j = 0; j < Results.Count; j++)
{
if (averageX < xx[j])
{
xx[j] = -9999;
yy[j] = -9999;
}
}
//找出保留元素中Y值最大的
i = Array.IndexOf(yy, yy.Max());
}
return i;
}
#endregion
#region
List<TextPoint> paixu(List<TextPoint> points)
{
int rowDistance = 50;
List<List<TextPoint>> rows = new List<List<TextPoint>>();
for (int i = 0; i < points.Count; i++)
{
List<TextPoint> row = new List<TextPoint>();
row.Add(points[i]);
for (int j = i + 1; j < points.Count; j++)
{
if (Math.Abs(points[j].y - points[i].y) < rowDistance)
{
row.Add(points[j]);
}
}
rows.Add(row);
}
List<TextPoint> sortedPoints = new List<TextPoint>();
foreach (List<TextPoint> row in rows)
{
row.Sort((x, y) => x.x - y.x);
foreach (TextPoint point in row)
{
if (!sortedPoints.Contains(point))
{
sortedPoints.Add(point);
}
}
}
return sortedPoints;
}
#endregion
#region OCR结果处理
private void OCRResult(Bitmap bmp)
{
try
{
if (InvokeRequired)
{
Invoke(new OcrResultDelegate(OCRResult), new object[] { bmp });
return;
}
if (m_GotoZero)
{
log.Info("零点拍照");
NoticePLCCompleteOCR();
return;
}
ocrTextResult = new Dictionary<string, bool>();
if (!ocrTextRequest.ContainsKey(mMatchingStr))
{
log.Error($"未知列{mMatchingStr},舍弃图片");
NoticePLCCompleteOCR();
return;
}
foreach (var item in ocrTextRequest[mMatchingStr])
{
ocrTextResult[item] = false;
}
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] bytes = ms.GetBuffer();
ms.Close();
string strtimef = DateTime.Now.ToString("yyyy-MM-dd");
//保存ocr图像
if (!Directory.Exists(SaveImageFileOCR + '\\' + strtimef))
{
Directory.CreateDirectory(SaveImageFileOCR + '\\' + strtimef);
}
string savePath = Path.Combine(SaveImageFileOCR + '\\' + strtimef, m_startTime.ToString("HHmmss"));
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
string strTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
FileStream fs = new FileStream(savePath + '\\' + strTime + ".bmp", FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes, 0, bytes.Length);
bw.Close();
fs.Close();
log.Info("OCR存图已完成");
CutPicture(savePath + '\\' + strTime + ".bmp", 400 + 200 * (6 - config.ColorMax), 2000, 3400 + 200 * config.ColorMax, 1600);
if (Engine == null)
{
log.Error("Engine未初始化");
NoticePLCCompleteOCR();
return;
}
GetOCRImage getOCRImage = new GetOCRImage();
GetOCRImage.FileTimeInfo file = getOCRImage.GetLatesFileImageName(savePath, ".bmp");
if (file != null)
{
Mat bgr = Cv2.ImRead(file.FileName, ImreadModes.Color); // 读入 BGR
if (bgr.Empty())
{
log.Error("OCR图片转换失败");
NoticePLCCompleteOCR();
return;
}
bool matchOK = false;
OCRTextResult rgbResult = null;
List<PointF[]> pointRGB = null;
rgbResult = OCRBytes(bgr.ToBytes());
if (rgbResult == null)
{
log.Error("彩色通道OCR字符识别失败");
NoticePLCCompleteOCR();
return;
}
txt_readOcrResultShow.Text = rgbResult.text;
log.Info("彩色通道字符读取结果:" + rgbResult.text);
matchOK = rgbResult.match;
pointRGB = rgbResult.points;
Mat hsv = null;
OCRTextResult hResult = null;
OCRTextResult sResult = null;
OCRTextResult vResult = null;
List<PointF[]> pointS = null;
List<PointF[]> pointH = null;
List<PointF[]> pointV = null;
if (!matchOK)
{
hsv = new Mat();
Cv2.CvtColor(bgr, hsv, ColorConversionCodes.BGR2HSV); // 1. 转 HSV
Mat[] channels = Cv2.Split(hsv); // 2. 拆通道
Mat h = channels[0]; // Hue 0-180
Mat s = channels[1]; // Saturation 0-255
Mat v = channels[2]; // Value 0-255
sResult = OCRBytes(s.ImEncode(".png"));
if (sResult == null)
{
log.Error("s通道OCR字符识别失败");
NoticePLCCompleteOCR();
return;
}
txt_readOcrResultShow.Text = "\n" + sResult.text;
log.Info("s通道字符读取结果" + sResult.text);
matchOK = sResult.match;
pointS = sResult.points;
if (!matchOK)
{
hResult = OCRBytes(h.ImEncode(".png"));
if (hResult == null)
{
log.Error("h通道OCR字符识别失败");
NoticePLCCompleteOCR();
return;
}
txt_readOcrResultShow.Text += "\n" + hResult.text;
log.Info("h通道字符读取结果" + hResult.text);
matchOK = hResult.match;
pointH = hResult.points;
}
if (!matchOK)
{
vResult = OCRBytes(v.ImEncode(".png"));
if (vResult == null)
{
log.Error("v通道OCR字符识别失败");
NoticePLCCompleteOCR();
return;
}
txt_readOcrResultShow.Text += "\n" + vResult.text;
log.Info("v通道字符读取结果" + vResult.text);
matchOK = vResult.match;
pointV = vResult.points;
}
}
byte[] ocrimagebyte = File.ReadAllBytes(file.FileName);
Bitmap Bmp = new Bitmap(new MemoryStream(ocrimagebyte));
if ((pointRGB != null && pointRGB.Count > 0) || (pointS != null && pointS.Count > 0) || (pointH != null && pointH.Count > 0) || (pointV != null && pointV.Count > 0))
{
using (Graphics g = Graphics.FromImage(Bmp))
{
if (pointRGB != null && pointRGB.Count > 0)
{
foreach (var item in pointRGB)
g.DrawPolygon(new Pen(Brushes.Red, 2), item.Select(x => new PointF() { X = x.X, Y = x.Y }).ToArray());
}
if (pointS != null && pointS.Count > 0)
{
foreach (var item in pointS)
g.DrawPolygon(new Pen(Brushes.Red, 2), item.Select(x => new PointF() { X = x.X, Y = x.Y }).ToArray());
}
if (pointH != null && pointH.Count > 0)
{
foreach (var item in pointH)
g.DrawPolygon(new Pen(Brushes.Red, 2), item.Select(x => new PointF() { X = x.X, Y = x.Y }).ToArray());
}
if (pointV != null && pointV.Count > 0)
{
foreach (var item in pointV)
g.DrawPolygon(new Pen(Brushes.Red, 2), item.Select(x => new PointF() { X = x.X, Y = x.Y }).ToArray());
}
}
int m1 = ocrTextResult.Count(x => x.Value);
log.Info($"OCR识别完成匹配成功{m1}个字符,匹配失败{ocrTextResult.Count - m1}个字符");
ShowTheLansRs(mMatchingStr, (double)m1 / (double)ocrTextResult.Count);
}
else
{
ShowTheLansRs(mMatchingStr, 0);
log.Info("OCR识别完成匹配失败");
}
Ocr_picBox.BackgroundImage = Bmp;
NoticePLCCompleteOCR();
}
}
catch (Exception ex)
{
log.Error(ex.Message + "未检测到字符");
NoticePLCCompleteOCR();
}
}
private void NoticePLCCompleteOCR()
{
commPLC?.NoticeCamComplete(1, 0.0f);
}
private void NoticePLCCompleteDet(float data)
{
commPLC?.NoticeCamComplete(0, data);
}
private void NoticePLCCompleteDet(List<float> data)
{
commPLC?.NoticeCamComplete(0, data);
}
private OCRTextResult OCRBytes(byte[] ocrimagebyte)
{
try
{
OCRTextResult result = new OCRTextResult();
List<string> lastocr = new List<string>();
OCRResult ocrResult = Engine.DetectText(ocrimagebyte);
List<TextPoint> pointsList = new List<TextPoint>();
foreach (var item in ocrResult.TextBlocks)
{
if (item.Text.Contains(ocrTextDesign[mMatchingStr]))
{
result.points.Add(item.BoxPoints.Select(x => new PointF() { X = x.X, Y = x.Y }).ToArray());
pointsList.Add(new TextPoint(item.BoxPoints[0].X, item.BoxPoints[0].Y, item.Text));
}
}
List<TextPoint> paixujeguo = paixu(pointsList);
foreach (var it in paixujeguo)
{
lastocr.Add(it.txt);
}
result.text = GETOCR(lastocr, ocrTextDesign[mMatchingStr]);
var keysToUpdate = new List<string>();
foreach (var item in ocrTextResult)
{
if (result.text.Contains(item.Key))
keysToUpdate.Add(item.Key);
}
foreach (var item in keysToUpdate)
{
ocrTextResult[item] = true;
}
result.match = true;
foreach (var item in ocrTextResult)
{
if (!item.Value)
result.match = false;
}
return result;
}
catch (Exception ex)
{
log.Error(ex.Message + ex.StackTrace);
return null;
}
}
#region
private void CutPicture(String picPath, int x, int y, int width, int height)
{
//图片路径
String oldPath = picPath;
//新图片路径
String newPath = System.IO.Path.GetExtension(oldPath);
//计算新的文件名在新文件名后加_new
newPath = oldPath.Substring(0, oldPath.Length - newPath.Length) + "_new" + mMatchingStr + newPath;
//定义截取矩形
System.Drawing.Rectangle cropArea = new System.Drawing.Rectangle(x, y, width, height);
//要截取的区域大小
//加载图片
System.Drawing.Image img = System.Drawing.Image.FromStream(new System.IO.MemoryStream(System.IO.File.ReadAllBytes(oldPath)));
//判断超出的位置否
if ((img.Width < x + width) || img.Height < y + height)
{
MessageBox.Show("裁剪尺寸超出原有尺寸!");
img.Dispose();
return;
}
//定义Bitmap对象
System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(img);
//进行裁剪
System.Drawing.Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
//保存成新文件
bmpCrop.Save(newPath);
//释放对象
img.Dispose();
bmpCrop.Dispose();
}
#endregion
/// <summary>
/// 使用正则表达式提取结果
/// </summary>
/// <param name="readOCR">读到的所有字符</param>
/// <param name="design">设计</param>
/// <param name="colours"></param>
/// <returns></returns>
private string GETOCR(List<string> readOCR, string design)
{
string ocrresult = "";
string pattern = @"" + design + "[A-Z0-9]{8}";
for (int i = 0; i < readOCR.Count; i++)
{
readOCR[i] = readOCR[i].Replace("_", "");
readOCR[i] = readOCR[i].Replace(" ", "");
readOCR[i] = readOCR[i].Replace(".", "");
}
MatchCollection matchResults;
try
{
foreach (var item in readOCR)
{
matchResults = Regex.Matches(item, pattern);
for (int i = 0; i < matchResults.Count; i++)
{
ocrresult = ocrresult + matchResults[i];
}
}
}
catch
{
ocrresult = null;
}
if (ocrresult != null)
{
return ocrresult;
}
else
{
return "未能匹配到对应字符请查看产品是否超标,或订单号是否正确";
}
}
private void button1_Click(object sender, EventArgs e)
{
btn_StarDet_manual.Enabled = true;
button1.Enabled = false;
button2.Enabled = true;
btn_StarDet_manual.BackColor = Color.LimeGreen;
button1.BackColor = Color.LightGray;
button2.BackColor = Color.LimeGreen;
NoticePLCCompleteOCR();
}
/// <summary>
/// 将结果显示在对应状态栏
/// </summary>
/// <param name="mM">PLC给的当前在第几道拍照</param>
/// <param name="s">OCR字符相似度结果</param>
void ShowTheLansRs(int mM, double s)
{
int mMnum = Convert.ToInt32(mM);
switch (mMnum)
{
case 1:
lbl_L1_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L1_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L1_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L1_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 2:
lbl_L2_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L2_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L2_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L2_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 3:
lbl_L3_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L3_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L3_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L3_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 4:
lbl_L4_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L4_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L4_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L4_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 5:
lbl_L5_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L5_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L5_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L5_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 6:
lbl_L6_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L6_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L6_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L6_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 7:
lbl_L7_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L7_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L7_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L7_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 8:
lbl_L8_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L8_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L8_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L8_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
case 9:
lbl_L9_verOcrRs.BackColor = Color.Lime;
if (s < 0.9)
{
lbl_L9_verOcrRs.BackColor = Color.Red;
}
else if (s > 0.9 & s < 1)
{
lbl_L9_verOcrRs.BackColor = Color.Lime;
s = 1;
}
ocrAcc.Add(s);
lbl_L9_verOcrRs.Text = s * 100 + "%";
log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%");
break;
}
}
#endregion
#endregion
#region
#region
void InitializeComm()
{
try
{
commPLC = new CommWithCC24();
commPLC.OnConnectStatus += CommPLC_OnConnectStatus;
commPLC.OnTrigCamera += CommPLC_OnTrigCamera;
commPLC.OnDataReceived += CommPLC_OnDataReceived;
commPLC.OnCameraStatus += CommPLC_OnCameraStatus;
commPLC.Start();
}
catch (Exception ex)
{
log.Error($"CommCard Initialize Error: {ex.Message}");
}
}
private void CommPLC_OnCameraStatus(int index, bool enable)
{
if (InvokeRequired)
{
BeginInvoke(new Action<int, bool>(CommPLC_OnCameraStatus), index, enable);
return;
}
if (enable)
ttls_AcqEnableShow.Visible = true;
else
ttls_AcqEnableShow.Visible = false;
}
private void CommPLC_OnDataReceived(float data)
{
if (InvokeRequired)
{
BeginInvoke(new Action<float>(CommPLC_OnDataReceived), data);
return;
}
mMatchingStr = Convert.ToInt32(data);
log.Info("PC接收PLC数据数据内容" + mMatchingStr);
if (m_BeginOCR == false && m_GotoZero == false)
{
NoticePLCCompleteOCR();
return;
}
if (m_GotoZero)
{
if (mMatchingStr == 2)
{
Thread.Sleep(3000);
EnableStartDetect();
return;
}
return;
}
if (config.NumberOfLanes + 1 == mMatchingStr)
{
Thread.Sleep(3000);
EnableStartDetect();
if (ocrAcc.Count == 0)
return;
if (ocrAcc.Min() < 0.95)
{
MessageBox.Show("当前检测中出现严重错误请注意!", Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ocrAcc.Min() > 0.95 & ocrAcc.Min() < 1)
{
MessageBox.Show("当前检测中出现可允许误差请注意!", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
log.Info("当前检测合格,正常结束");
}
}
private void CommPLC_OnTrigCamera(int index)
{
if (InvokeRequired)
{
BeginInvoke(new Action<int>(CommPLC_OnTrigCamera), index);
return;
}
try
{
if (index == 1)
{
Ocr_picBox.BackgroundImage = null;
Thread.Sleep(1000);
log.Info("PLC触发OCR相机正在拍照计算...");
cameraOCR?.GrabImage();
}
}
catch (Exception ex)
{
log.Error($"Trigger AcqStart Error: {ex.Message}");
}
}
private void CommPLC_OnConnectStatus(bool connected)
{
if (InvokeRequired)
{
BeginInvoke(new Action<bool>(CommPLC_OnConnectStatus), connected);
return;
}
if (connected)
{
PlcContinueFlag = true;
log.Info("PLC已连接PC,可以进行相关操作");
ttls_PCLStatusShow.Visible = true;
button2.Enabled = true;
button2.BackColor = Color.LimeGreen;
}
else
{
PlcContinueFlag = false;
log.Info("PLC已断开PC请查看相关设备是否连接");
ttls_PCLStatusShow.Visible = false;
button2.Enabled = false;
button2.BackColor = Color.LightGray;
}
}
#endregion
private bool m_GotoZero = false;
private void button2_Click(object sender, EventArgs e)
{
button1.Enabled = true;
button1.BackColor = Color.LimeGreen;
btn_StarDet_manual.Enabled = false;
btn_StarDet_manual.BackColor = Color.LightGray;
m_GotoZero = true;
List<float> plcXY = new List<float>();
plcXY.Add(1);
plcXY.Add(0);
plcXY.Add(0);
NoticePLCCompleteDet(plcXY);
log.Info("零点坐标已发送");
}
#region
private void SendToPLC(double x, double y, double r)
{
try
{
if (ocrTextRequest[1].Count == 0)
return;
double xx = x - (m_textWidth * config.ColorMax) / 2.0;
double yy = y;
double rr = r;
List<float> locationXY = new List<float>();
double ocrx = 0, ocry = 0;
locationXY.Add((float)config.NumberOfLanes);
int nol = Convert.ToInt32(config.NumberOfLanes);
log.Info("当前订单OCR区域共" + nol + "组:");
double degree = (rr * Math.PI) / 180;
for (int item = 0; item < nol; item++)
{
if (item == 0)
{
ocrx = xx - config.DistX * Math.Cos(degree) - config.DistY * Math.Sin(degree);
ocry = yy + config.DistY * Math.Cos(degree) - config.DistX * Math.Sin(degree);
}
else
{
ocrx = ocrx + config.Width * Math.Cos(degree) + config.Gradient * Math.Sin(degree);
ocry = ocry - config.Gradient * Math.Cos(degree) + config.Width * Math.Sin(degree);
}
log.Info("第" + (item + 1) + "组坐标为X" + ocrx + ",Y:" + ocry + "。");
if (ocrx < 0 || ocrx > 1600)
{
EnableStartDetect();
if (ocrx < 0)
log.Error("横向范围 0,1600纸张向左移动一点");
else
log.Error("横向范围 0,1600纸张向右移动一点");
NoticePLCCompleteDet(0.0f);
return;
}
if (ocry < - 50)
{
ocrx = ocrx - config.Height * Math.Sin(degree);
ocry = ocry + config.Height * Math.Cos(degree);
log.Info("更新第" + (item + 1) + "组坐标为X" + ocrx + ",Y:" + ocry + "。");
}
else if (ocry > 400)
{
ocrx = ocrx + config.Height * Math.Sin(degree);
ocry = ocry - config.Height * Math.Cos(degree);
log.Info("更新第" + (item + 1) + "组坐标为X" + ocrx + ",Y:" + ocry + "。");
}
if (ocry < -50 || ocry > 400)
{
EnableStartDetect();
if (ocry < -50)
log.Error("纵向范围 -50,400纸张向下移动一点");
else
log.Error("纵向范围 -50,400纸张向上移动一点");
NoticePLCCompleteDet(0.0f);
return;
}
locationXY.Add((float)ocrx);
locationXY.Add((float)ocry);
}
List<float> plcXY = new List<float>();
for (int i = 0; i < locationXY.Count; i++)
{
if (i == 0)
{
plcXY.Add(locationXY[i]);
}
else if (i % 2 == 1)
{
plcXY.Add(locationXY[locationXY.Count - i - 1]);
plcXY.Add(locationXY[locationXY.Count - i]);
}
}
NoticePLCCompleteDet(plcXY);
log.Info("坐标已发送完成。");
}
catch (Exception ex)
{
EnableStartDetect();
log.Error(ex.Message + "未检测到K标志");
NoticePLCCompleteDet(0.0f);
}
}
#endregion
#region
private void StopComm()
{
try
{
if (commPLC == null)
return;
commPLC.OnConnectStatus -= CommPLC_OnConnectStatus;
commPLC.OnTrigCamera -= CommPLC_OnTrigCamera;
commPLC.OnDataReceived -= CommPLC_OnDataReceived;
commPLC.OnCameraStatus -= CommPLC_OnCameraStatus;
commPLC.Stop();
}
catch (Exception ex)
{
log.Error($"CommCard Closing Error: {ex.Message}");
}
}
#endregion
#endregion
}
}