/************************ * 作者:CVE-安翀岚 * * Vision:1.0.23.1007 (发布使用) * Windows10 X64(PaddleOCR不能部署在32位操作系统上) * PaddleOCR 3.10 * Vpro: 9.5 SR2 * ***********************/ using System; using System.IO; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Windows.Forms; using OfficeOpenXml; using Cognex.VisionPro; using Cognex.VisionPro.Comm; using Cognex.VisionPro.QuickBuild; using Cognex.VisionPro.ToolBlock; using Cognex.VisionPro.PMAlign; using Cognex.VisionPro.ToolGroup; using Cognex.VisionPro.ImageProcessing; using PaddleOCRSharp; using AVP.CRobot; using log4net; using LogShowLib; using System.Text.RegularExpressions; using TetraParkOCR; using Bjcve.Comm.FFP; using ThridLibray; using CLIDelegate; namespace TetraPackOCR { public partial class Form1 : Form { public Form1() { InitializeComponent(); LogInit(); } #region 字段 委托 //创建字段log ILog log = LogManager.GetLogger(typeof(Form1)); /// /// 声明一个cc24通讯对象 /// CC24 cc24; /// /// 声明一个PaddleOCR对象 /// PaddleOCREngine Engine; /// ///对应表格"P2生成数据"这一页 /// ExcelWorksheet sheet1; /// /// 对应表格"QSV对应产品规格和梯度"这一页 /// ExcelWorksheet sheet2; /// /// 对应"产品规格对应排布方式"这一页 /// ExcelWorksheet sheet3; /// /// 表格路径 /// string execlFileName = AppDomain.CurrentDomain.BaseDirectory + "Data\\Excle\\OCR文件0602.xlsx"; /// /// 共印依据 QSV Design, Layers, Colours,产品规格 /// string Sequence, QSV, Design, Layers, Colours, ProductStandard, ord; /// /// 幅数 包材宽 梯度 X距离 Y距离 /// double NumberOfLanes, width, Gradient, DistX, DistY; /// /// 定位Vpp文件 /// string vppdetFile = AppDomain.CurrentDomain.BaseDirectory + "Data\\VPPFile\\liledet.vpp"; /// /// OCRVpp文件 /// string vppocrFile = AppDomain.CurrentDomain.BaseDirectory + "Data\\VPPFile\\lileOCR.vpp"; /// /// 存图路径 /// string SaveImageFileOCR = AppDomain.CurrentDomain.BaseDirectory + "SaveImage\\OCR";//ocr存图 string SaveImageFileDET = AppDomain.CurrentDomain.BaseDirectory + "SaveImage\\Det";//ocr存图 private CogJobManager myJobManager1, myJobManager2; private CogJob myJob1, myJob2; private string[] verocr = new string[20]; bool Coprinted_ordeFlag = false; //是否为共印订单旗帜 bool PlcContinueFlag = false; //PLC状态旗帜 int mMatchingStr = 0;//接收当前OCR拍照位置 List ocrAcc = new List(); /// /// 相机对象 1和2 /// IDevice m_dev_cam0, m_dev_cam1; List DeviceList; public string ImagePixelFormat = ""; //图像格式设置 delegate void DetResultDelegate(Object Sender, CogJobManagerActionEventArgs e); delegate void OcrResultDelegate(Bitmap bmp); #endregion #region 窗体加载和关闭 //private void MainPage_SizeChanged(object sender, EventArgs e) //{ // asf.controlAutoSize(this); //} /// /// 窗体加载 /// /// /// private void Form1_Load(object sender, EventArgs e) { try { btn_manualDet.Enabled = false; btn_manualOcr.Enabled = false; check_Autorun.Enabled = false; btn_StarDet_manual.Enabled = false; //asf.controllInitializeSize(this); log.Info("软件正在加载..."); Action action = (() => { InitializeCamer1(); InitializeCamer2(); InitializePaddleOCR(); myJobManager1 = CogSerializer.LoadObjectFromFile(vppdetFile) as CogJobManager; myJobManager2 = CogSerializer.LoadObjectFromFile(vppocrFile) as CogJobManager; InitializeCC24(); log.Info("模型文件加载完成"); this.check_Autorun.BackgroundImage = Image.FromFile(Application.StartupPath + "\\logo_image\\ON.png"); this.ttls_SystemStatusShow.Visible = true; this.ttls_CamStatusShow.Visible = true; this.Invoke(new Action(() => { this.btn_manualOcr.Enabled = true; this.btn_manualDet.Enabled = true; check_Autorun.Enabled = true; btn_StarDet_manual.Enabled = true; })); }); Task myTask = new Task(action); //实例化一个线程列表 List tsk = new List(); //将上面的加载vpp工作加入线程列表中 tsk.Add(myTask); //读取线程列表内的工作让cpu为其开辟线程空间并执行程序 foreach (var iteam in tsk) { iteam.Start(); } TaskFactory tskFactory = new TaskFactory(); tskFactory.ContinueWhenAll(tsk.ToArray(), FlashFormView => { myJob1 = myJobManager1.Job(0); myJob2 = myJobManager2.Job(0); // 注册结果队列事件 myJobManager1.UserResultAvailable += new CogJobManager.CogUserResultAvailableEventHandler(DetResult); // myJobManager2.UserResultAvailable += new CogJobManager.CogUserResultAvailableEventHandler(OCRResult); }); } catch (Exception ex) { log.Error(ex.Message); } } /// /// 窗体关闭 /// /// /// private void Form1_FormClosing(object sender, FormClosingEventArgs e) { try { if (myJob1.AcqFifo.FrameGrabber != null) { myJob1.AcqFifo.FrameGrabber.Disconnect(true); } if (myJob2.AcqFifo.FrameGrabber != null) { myJob2.AcqFifo.FrameGrabber.Disconnect(true); } ClossCam(); // 注销结果队列事件 myJobManager1.UserResultAvailable -= new CogJobManager.CogUserResultAvailableEventHandler(DetResult); //myJobManager2.UserResultAvailable -= new CogJobManager.CogUserResultAvailableEventHandler(OCRResult); myJobManager1.Shutdown(); //myJobManager2.Shutdown(); CloseCC24(); Application.DoEvents(); System.Environment.Exit(0); } catch { ClossCam(); // 注销结果队列事件 myJobManager1.UserResultAvailable -= new CogJobManager.CogUserResultAvailableEventHandler(DetResult); //myJobManager2.UserResultAvailable -= new CogJobManager.CogUserResultAvailableEventHandler(OCRResult); myJobManager1.Shutdown(); //myJobManager2.Shutdown(); CloseCC24(); 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 InitializeCamer1() { DeviceList = Enumerator.EnumerateDevices(); //发现设备,搜索所有大华相机 // m_dev_cam0 = Enumerator.GetDeviceByIndex(0);//通过索引获取 m_dev_cam0 = Enumerator.GetDeviceByKey("Machine Vision:CK21686DAK00001");//通过"设备厂商名:设备序列号"获取 //m_dev_cam0 = Enumerator.GetDeviceByGigeIP("192.168.20.2");//通过IP地址获取 m_dev_cam0.CameraOpened += m_dev0_CameraOpened; m_dev_cam0.CameraClosed += m_dev0_CameraClosed; m_dev_cam0.ConnectionLost += m_dev0_ConnectionLost; if(!m_dev_cam0.Open()) { MessageBox.Show("OCR相机打开失败"); } // 设置图像格式 // set PixelFormat using (IEnumParameter p = m_dev_cam0.ParameterCollection[ParametrizeNameSet.ImagePixelFormat]) { ImagePixelFormat = "BayerRG8"; //ImagePixelFormat = "Mono8"; p.SetValue(ImagePixelFormat); } // 设置曝光 using (IFloatParameter p = m_dev_cam0.ParameterCollection[ParametrizeNameSet.ExposureTime]) { p.SetValue(80000); } // 设置增益 using (IFloatParameter p = m_dev_cam0.ParameterCollection[ParametrizeNameSet.GainRaw]) { p.SetValue(2.5); } using (IEnumParameter p = m_dev_cam0.ParameterCollection[ParametrizeNameSet.AcquisitionMode]) { p.SetValue("Continuous"); } using (IEnumParameter p = m_dev_cam0.ParameterCollection[ParametrizeNameSet.TriggerMode]) { p.SetValue("On"); } //if (!m_dev_cam0.Open()) //{ // MessageBox.Show(@"OCR相机连接失败"); // return; //} m_dev_cam0.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed_0; m_dev_cam0.StreamGrabber.GrabStarted += StreamGrabber_GrabStarted_0; // 打开Software Trigger // Set Software Trigger m_dev_cam0.TriggerSet.Open(TriggerSourceEnum.Software); if (!m_dev_cam0.GrabUsingGrabLoopThread()) { // 开启采集失败 log.Error("开启采集失败"); } log.Info("OCR相机加载完毕"); } #endregion #region 相机1事件响应 void m_dev0_ConnectionLost(object sender, EventArgs e) { MessageBox.Show(m_dev_cam0.DeviceInfo.Key + "OCR相机断线"); } void m_dev0_CameraClosed(object sender, EventArgs e) { MessageBox.Show(m_dev_cam0.DeviceInfo.Key + "OCR相机关闭"); } void m_dev0_CameraOpened(object sender, EventArgs e) { // MessageBox.Show(m_dev_cam0.DeviceInfo.Key + "启动"); } void StreamGrabber_GrabStarted_0(object sender, EventArgs e) { log.Info("OCR相机启动码流"); } /// /// 拍照完成后触发 /// /// /// private void StreamGrabber_ImageGrabbed_0(object sender, GrabbedEventArgs e) { try { Bitmap bmp = null; bmp = e.GrabResult.ToBitmap(true); OCRResult(bmp); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } #endregion #region 相机2 定义为定位相机 private void InitializeCamer2() { DeviceList = Enumerator.EnumerateDevices(); //发现设备,搜索所有大华相机 //m_dev_cam1 = Enumerator.GetDeviceByIndex(1);//通过索引获取 m_dev_cam1 = Enumerator.GetDeviceByKey("Machine Vision:BK27185BAK00038");//通过"设备厂商名:设备序列号"获取 //m_dev_cam1 = Enumerator.GetDeviceByGigeIP("192.168.10.1");//通过IP地址获取 m_dev_cam1.CameraOpened += m_dev1_CameraOpened; m_dev_cam1.CameraClosed += m_dev1_CameraClosed; m_dev_cam1.ConnectionLost += m_dev1_ConnectionLost; if (!m_dev_cam1.Open()) { MessageBox.Show("定位相机打开失败"); } // 设置图像格式 // set PixelFormat using (IEnumParameter p = m_dev_cam1.ParameterCollection[ParametrizeNameSet.ImagePixelFormat]) { ImagePixelFormat = "Mono"; p.SetValue(ImagePixelFormat); } // 设置曝光 using (IFloatParameter p = m_dev_cam1.ParameterCollection[ParametrizeNameSet.ExposureTime]) { p.SetValue(80000); } // 设置增益 using (IFloatParameter p = m_dev_cam1.ParameterCollection[ParametrizeNameSet.GainRaw]) { p.SetValue(1.0); } using (IEnumParameter p = m_dev_cam1.ParameterCollection[ParametrizeNameSet.AcquisitionMode]) { p.SetValue("Continuous"); } using (IEnumParameter p = m_dev_cam1.ParameterCollection[ParametrizeNameSet.TriggerMode]) { p.SetValue("On"); } //if (!m_dev_cam1.Open()) //{ // MessageBox.Show(@"定位相机连接失败"); // return; //} m_dev_cam1.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed_1; m_dev_cam1.StreamGrabber.GrabStarted += StreamGrabber_GrabStarted_1; // 打开Software Trigger // Set Software Trigger m_dev_cam1.TriggerSet.Open(TriggerSourceEnum.Software); if (!m_dev_cam1.GrabUsingGrabLoopThread()) { // 开启采集失败 log.Error("开启采集失败"); } log.Info("定位相机加载完毕"); } #endregion #region 相机2事件响应 void m_dev1_ConnectionLost(object sender, EventArgs e) { MessageBox.Show(m_dev_cam1.DeviceInfo.Key + "定位相机断线"); } void m_dev1_CameraClosed(object sender, EventArgs e) { MessageBox.Show(m_dev_cam1.DeviceInfo.Key + "定位相机关闭"); } void m_dev1_CameraOpened(object sender, EventArgs e) { // MessageBox.Show(m_dev_cam0.DeviceInfo.Key + "启动"); } void StreamGrabber_GrabStarted_1(object sender, EventArgs e) { log.Info("定位相机启动码流"); } /// /// 拍照完成后触发 /// /// /// private void StreamGrabber_ImageGrabbed_1(object sender, GrabbedEventArgs e) { try { Bitmap bmp = null; bmp = e.GrabResult.ToBitmap(true); //Bitmap bmp = new Bitmap(cogimg.ToBitmap()); 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 = myJob1.VisionTool as CogToolGroup; CogToolBlock myTB = myTG.Tools["CogToolBlock1"] as CogToolBlock; CogImageConvertTool cogImageConvert = myTB.Tools["CogImageConvertTool1"] as CogImageConvertTool; cogImageConvert.InputImage = cogimage; //运行jobmanager myJobManager1.Run(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } #endregion #region 相机关闭 void ClossCam() { //注销相机事件 m_dev_cam0.CameraOpened -= m_dev0_CameraOpened; m_dev_cam0.CameraClosed -= m_dev0_CameraClosed; m_dev_cam0.ConnectionLost -= m_dev0_ConnectionLost; m_dev_cam1.CameraOpened -= m_dev1_CameraOpened; m_dev_cam1.CameraClosed -= m_dev1_CameraClosed; m_dev_cam1.ConnectionLost -= m_dev1_ConnectionLost; m_dev_cam0.ShutdownGrab(); m_dev_cam0.Dispose(); m_dev_cam0 = null; m_dev_cam1.ShutdownGrab(); m_dev_cam1.Dispose(); m_dev_cam1 = null; } #endregion #endregion #region OCR模型参数初始化 private void InitializePaddleOCR() { //模型初始化 OCRModelConfig config = new OCRModelConfig(); //创建一个模型参数设置对象 string rootPath = System.IO.Path.GetDirectoryName(typeof(OCRModelConfig).Assembly.Location); //程序的根目录 config.det_infer = rootPath + @"\Data\OCRModel\det_infer"; //文字检测模型路径 config.cls_infer = rootPath + @"\Data\OCRModel\cls_infer"; //文本角度模型路径 config.rec_infer = rootPath + @"\Data\OCRModel\rec_infer"; //文字内容识别模型路径 //以上三个模型参数的文件路径只需要写到存放的文件夹名称 //对于字典来说需要写全加上后缀 config.keys = rootPath + @"\Data\OCRModel\keys\ppocr_keys.txt"; //词典路径 //OCR参数设置 OCRParameter OcrParameter = new OCRParameter(); //创建一个检测参数设置对象 OcrParameter.cpu_math_library_num_threads = 8;//预测并发线程数 OcrParameter.enable_mkldnn = true;//web部署该值建议设置为0,否则出错,内存如果使用很大,建议该值也设置为0. OcrParameter.cls = true; //是否执行文字方向分类;默认false OcrParameter.det = true;//是否开启方向检测,用于检测识别180旋转 OcrParameter.rec = true; OcrParameter.use_angle_cls = true;//是否开启方向检测,用于检测识别180旋转 OcrParameter.det_db_score_mode = true;//是否使用多段线,即文字区域是用多段线还是用矩形, OcrParameter.det_db_unclip_ratio = 1.5f; OcrParameter.max_side_len = 1280; //初始化OCR Engine = new PaddleOCREngine(config, OcrParameter); } #endregion #region 按钮事件 /// /// 自动运行状态改变按钮 /// /// /// private void check_Autorun_CheckedChanged(object sender, EventArgs e) { if (check_Autorun.Checked) { //CloseCC24(); log.Info("PC断开PLC连接,只可进行本地操作。"); this.check_Autorun.BackgroundImage = Image.FromFile(Application.StartupPath + "\\logo_image\\OFF.png"); this.panel_Manual.Visible = true; this.btn_StarDet_manual.Enabled = false; this.ttls_PCLStatusShow.Visible = false; } else if (!check_Autorun.Checked) { //InitializeCC24(); log.Info("PC加载PLC已完成"); this.check_Autorun.BackgroundImage = Image.FromFile(Application.StartupPath + "\\logo_image\\ON.png"); this.panel_Manual.Visible = false; this.btn_StarDet_manual.Enabled = true; this.ttls_PCLStatusShow.Visible = true; } } /// /// 此按钮事件主要是获取excel表格内的数据 /// 包括定位偏移量,需要验证的字符 /// /// /// private void btn_OrderNum_Click(object sender, EventArgs e) { try { ClearData(); ClearDataShow(); this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "未启用"; this.lbl_L1_verOcrRs.BackColor = Color.Gray; this.lbl_L2_verOcrRs.Text = "未启用"; this.lbl_L2_verOcrRs.BackColor = Color.Gray; this.lbl_L3_verOcrRs.Text = "未启用"; this.lbl_L3_verOcrRs.BackColor = Color.Gray; this.lbl_L4_verOcrRs.Text = "未启用"; this.lbl_L4_verOcrRs.BackColor = Color.Gray; this.lbl_L5_verOcrRs.Text = "未启用"; this.lbl_L5_verOcrRs.BackColor = Color.Gray; this.lbl_L6_verOcrRs.Text = "未启用"; this.lbl_L6_verOcrRs.BackColor = Color.Gray; this.lbl_L7_verOcrRs.Text = "未启用"; this.lbl_L7_verOcrRs.BackColor = Color.Gray; this.lbl_L8_verOcrRs.Text = "未启用"; this.lbl_L8_verOcrRs.BackColor = Color.Gray; this.lbl_L9_verOcrRs.Text = "未启用"; this.lbl_L9_verOcrRs.BackColor = Color.Gray; })); this.btn_OrderNum.Enabled = false; //通过订单号获取表格中需要的值 string order = txt_OrderNum.Text; string laststr = order.Substring(order.Length - 1); if (laststr == "C") { Coprinted_ordeFlag = true; if (order == null) { log.Warn("订单号为空,请输入订单号。"); //MessageBox.Show("请输入订单号"); } else { log.Info("当前订单号为:" + order); //读取表格内容 ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; using (ExcelPackage package = new ExcelPackage(execlFileName)) { sheet1 = package.Workbook.Worksheets["P2生成数据"]; sheet2 = package.Workbook.Worksheets["QSV对应产品规格和梯度"]; sheet3 = package.Workbook.Worksheets["产品规格对应排布方式"]; //根据订单遍历sheet1 找Sequence QSV NumOFLanes 字符 for (int i = 1; i < sheet1.Dimension.Rows; i++) { if (sheet1.GetValue(i, 3) != null) { ord = sheet1.Cells[i, 3].Value.ToString(); } else { ord = null; } if (ord == order) { Sequence = sheet1.Cells[i, 2].Value.ToString(); QSV = sheet1.Cells[i, 4].Value.ToString(); this.lbl_QSVShow.Text = QSV; log.Info("当前订单QSV:" + QSV); NumberOfLanes = Convert.ToInt32(sheet1.Cells[i, 5].Value.ToString()); log.Info("当前订单Number Of Lanes:" + NumberOfLanes); this.lbl_NOFShow.Text = sheet1.Cells[i, 5].Value.ToString(); ////获取字符 并显示在界面还需处理先预留在这 共印订单不在这取字符 //Design = sheet1.Cells[i, 7].Value.ToString(); //Layers = sheet1.Cells[i, 8].Value.ToString(); //Colours = sheet1.Cells[i, 9].Value.ToString(); //lbl_verOcrShow.Text = ExecelGetOcrDealWithForShow(Design, Layers, Colours); break; } } if (Sequence != null) { for (int i = 1; i < sheet1.Dimension.Rows; i++) { string seq; if (sheet1.GetValue(i, 2) != null) { seq = sheet1.Cells[i, 2].Value.ToString(); } else { seq = null; } if (seq == Sequence) { Design = sheet1.Cells[i, 7].Value.ToString(); Layers = sheet1.Cells[i, 8].Value.ToString(); Colours = sheet1.Cells[i, 9].Value.ToString(); string Lane = sheet1.Cells[i, 6].Value.ToString(); Lane = Lane.Replace("[", ""); Lane = Lane.Replace("]", ""); string[] lans = Lane.Split(','); for (int j = 0; j < lans.Length; j++) { verocr[Convert.ToInt32(lans[j])] = ExecelGetOcrDealWithForShow(Design, Layers); } } } } if (QSV != null) { string qsv; //根据得到的QSV遍历sheet2 找产品规格和宽度梯度 for (int j = 1; j <= sheet2.Dimension.Rows; j++) { qsv = sheet2.Cells[j, 1].Value.ToString(); if (qsv == QSV) { ProductStandard = sheet2.Cells[j, 2].Value.ToString(); this.lbl_ProductStandardShow.Text = ProductStandard; log.Info("当前订单产品编号:" + ProductStandard); width = Convert.ToDouble(sheet2.Cells[j, 3].Value.ToString()); this.lbl_widthShow.Text = sheet2.Cells[j, 3].Value.ToString(); log.Info("当前订单幅宽:" + width); Gradient = Convert.ToDouble(sheet2.Cells[j, 4].Value.ToString()); this.lbl_GradientShow.Text = sheet2.Cells[j, 4].Value.ToString(); log.Info("当前订单梯度:" + Gradient); } } string str, ps; //根据产品规格获取距离坐标 for (int n = 1; n < sheet3.Dimension.Rows; n++) { if (sheet3.GetValue(n, 1) != null) { ps = sheet3.Cells[n, 1].Value.ToString(); } else { ps = null; } if (ps == null) { continue; } else if (ps == ProductStandard)//应该有另一个条件一同决定 { str = sheet3.Cells[n, 4].Value.ToString(); string[] x_y = str.Split(','); string[] X = x_y[0].Split(':'); string[] Y = x_y[1].Split(':'); DistX = Convert.ToDouble(X[1].Replace("mm", "")); this.lbl_DistXShow.Text = X[1].Replace("mm", ""); log.Info("当前订单X偏移:" + DistX); DistY = Convert.ToDouble(Y[1].Replace("mm", "")); this.lbl_DistYShow.Text = Y[1].Replace("mm", ""); log.Info("当前订单Y偏移:" + DistY); } } log.Info("相关数据已获取完成,且已显示在界面中,请查看。"); } else { log.Debug("请检查订单号是否正确"); } } } } else { Coprinted_ordeFlag = false; if (order == null) { log.Warn("订单号为空,请输入订单号。"); //MessageBox.Show("请输入订单号"); } else { log.Info("当前订单号为:" + order); //读取表格内容 ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; using (ExcelPackage package = new ExcelPackage(execlFileName)) { sheet1 = package.Workbook.Worksheets["P2生成数据"]; sheet2 = package.Workbook.Worksheets["QSV对应产品规格和梯度"]; sheet3 = package.Workbook.Worksheets["产品规格对应排布方式"]; //根据订单遍历sheet1 找QSV NumOFLanes 字符 for (int i = 1; i < sheet1.Dimension.Rows; i++) { if (sheet1.GetValue(i, 3) != null) { ord = sheet1.Cells[i, 3].Value.ToString(); } else { ord = null; } if (ord == order) { QSV = sheet1.Cells[i, 4].Value.ToString(); this.lbl_QSVShow.Text = QSV; log.Info("当前订单QSV:" + QSV); NumberOfLanes = Convert.ToInt32(sheet1.Cells[i, 5].Value.ToString()); log.Info("当前订单Number Of Lanes:" + NumberOfLanes); this.lbl_NOFShow.Text = sheet1.Cells[i, 5].Value.ToString(); //获取字符 并显示在界面还需处理先预留在这 Design = sheet1.Cells[i, 7].Value.ToString(); Layers = sheet1.Cells[i, 8].Value.ToString(); Colours = sheet1.Cells[i, 9].Value.ToString(); lbl_verOcrShow.Text = ExecelGetOcrDealWithForShow(Design, Layers); } } if (QSV != null) { string qsv; //根据得到的QSV遍历sheet2 找产品规格和宽度梯度 for (int j = 1; j <= sheet2.Dimension.Rows; j++) { qsv = sheet2.Cells[j, 1].Value.ToString(); if (qsv == QSV) { ProductStandard = sheet2.Cells[j, 2].Value.ToString(); this.lbl_ProductStandardShow.Text = ProductStandard; log.Info("当前订单产品编号:" + ProductStandard); width = Convert.ToDouble(sheet2.Cells[j, 3].Value.ToString()); this.lbl_widthShow.Text = sheet2.Cells[j, 3].Value.ToString(); log.Info("当前订单幅宽:" + width); Gradient = Convert.ToDouble(sheet2.Cells[j, 4].Value.ToString()); this.lbl_GradientShow.Text = sheet2.Cells[j, 4].Value.ToString(); log.Info("当前订单梯度:" + Gradient); } } string str, ps; //根据产品规格获取距离坐标 for (int n = 1; n < sheet3.Dimension.Rows; n++) { if (sheet3.GetValue(n, 1) != null) { ps = sheet3.Cells[n, 1].Value.ToString(); } else { ps = null; } if (ps == null) { continue; } else if (ps == ProductStandard)//应该有另一个条件一同决定 { str = sheet3.Cells[n, 4].Value.ToString(); string[] x_y = str.Split(','); string[] X = x_y[0].Split(':'); string[] Y = x_y[1].Split(':'); DistX = Convert.ToDouble(X[1].Replace("mm", "")); this.lbl_DistXShow.Text = X[1].Replace("mm", ""); log.Info("当前订单X偏移:" + DistX); DistY = Convert.ToDouble(Y[1].Replace("mm", "")); this.lbl_DistYShow.Text = Y[1].Replace("mm", ""); log.Info("当前订单Y偏移:" + DistY); } } log.Info("相关数据已获取完成,且已显示在界面中,请查看。"); } else { log.Debug("请检查订单号是否正确"); } } } } ///判断当前Lans决定结果显示数量 switch (NumberOfLanes) { case 1: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; })); break; case 2: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; })); break; case 3: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; this.lbl_L3_verOcrRs.Text = "启用"; this.lbl_L3_verOcrRs.BackColor = Color.Yellow; })); break; case 4: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; this.lbl_L3_verOcrRs.Text = "启用"; this.lbl_L3_verOcrRs.BackColor = Color.Yellow; this.lbl_L4_verOcrRs.Text = "启用"; this.lbl_L4_verOcrRs.BackColor = Color.Yellow; })); break; case 5: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; this.lbl_L3_verOcrRs.Text = "启用"; this.lbl_L3_verOcrRs.BackColor = Color.Yellow; this.lbl_L4_verOcrRs.Text = "启用"; this.lbl_L4_verOcrRs.BackColor = Color.Yellow; this.lbl_L5_verOcrRs.Text = "启用"; this.lbl_L5_verOcrRs.BackColor = Color.Yellow; })); break; case 6: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; this.lbl_L3_verOcrRs.Text = "启用"; this.lbl_L3_verOcrRs.BackColor = Color.Yellow; this.lbl_L4_verOcrRs.Text = "启用"; this.lbl_L4_verOcrRs.BackColor = Color.Yellow; this.lbl_L5_verOcrRs.Text = "启用"; this.lbl_L5_verOcrRs.BackColor = Color.Yellow; this.lbl_L6_verOcrRs.Text = "启用"; this.lbl_L6_verOcrRs.BackColor = Color.Yellow; })); break; case 7: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; this.lbl_L3_verOcrRs.Text = "启用"; this.lbl_L3_verOcrRs.BackColor = Color.Yellow; this.lbl_L4_verOcrRs.Text = "启用"; this.lbl_L4_verOcrRs.BackColor = Color.Yellow; this.lbl_L5_verOcrRs.Text = "启用"; this.lbl_L5_verOcrRs.BackColor = Color.Yellow; this.lbl_L6_verOcrRs.Text = "启用"; this.lbl_L6_verOcrRs.BackColor = Color.Yellow; this.lbl_L7_verOcrRs.Text = "启用"; this.lbl_L7_verOcrRs.BackColor = Color.Yellow; })); break; case 8: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; this.lbl_L3_verOcrRs.Text = "启用"; this.lbl_L3_verOcrRs.BackColor = Color.Yellow; this.lbl_L4_verOcrRs.Text = "启用"; this.lbl_L4_verOcrRs.BackColor = Color.Yellow; this.lbl_L5_verOcrRs.Text = "启用"; this.lbl_L5_verOcrRs.BackColor = Color.Yellow; this.lbl_L6_verOcrRs.Text = "启用"; this.lbl_L6_verOcrRs.BackColor = Color.Yellow; this.lbl_L7_verOcrRs.Text = "启用"; this.lbl_L7_verOcrRs.BackColor = Color.Yellow; this.lbl_L8_verOcrRs.Text = "启用"; this.lbl_L8_verOcrRs.BackColor = Color.Yellow; })); break; case 9: this.Invoke(new Action(() => { this.lbl_L1_verOcrRs.Text = "启用"; this.lbl_L1_verOcrRs.BackColor = Color.Yellow; this.lbl_L2_verOcrRs.Text = "启用"; this.lbl_L2_verOcrRs.BackColor = Color.Yellow; this.lbl_L3_verOcrRs.Text = "启用"; this.lbl_L3_verOcrRs.BackColor = Color.Yellow; this.lbl_L4_verOcrRs.Text = "启用"; this.lbl_L4_verOcrRs.BackColor = Color.Yellow; this.lbl_L5_verOcrRs.Text = "启用"; this.lbl_L5_verOcrRs.BackColor = Color.Yellow; this.lbl_L6_verOcrRs.Text = "启用"; this.lbl_L6_verOcrRs.BackColor = Color.Yellow; this.lbl_L7_verOcrRs.Text = "启用"; this.lbl_L7_verOcrRs.BackColor = Color.Yellow; this.lbl_L8_verOcrRs.Text = "启用"; this.lbl_L8_verOcrRs.BackColor = Color.Yellow; this.lbl_L9_verOcrRs.Text = "启用"; this.lbl_L9_verOcrRs.BackColor = Color.Yellow; })); break; } this.btn_OrderNum.Enabled = true; } catch (Exception ex) { log.Error(ex.Message + "请检查订单号是否正确,数据表中并无此订单号"); this.btn_OrderNum.Enabled = true; } } /// /// 手动ocr /// /// /// private void btn_manualOcr_Click(object sender, EventArgs e) { m_dev_cam0.ExecuteSoftwareTrigger();//相机1触发 = OCR拍照 log.Info("手动触发OCR"); } /// /// 手动定位 /// /// /// private void btn_manualDet_Click(object sender, EventArgs e) { m_dev_cam1.ExecuteSoftwareTrigger(); log.Info("手动触发定位"); } private void btn_StarDet_manual_Click(object sender, EventArgs e) { m_dev_cam1.ExecuteSoftwareTrigger(); log.Info("手动触发开始"); } /// /// 字符排序 /// /// 设计 /// /// /// private string ExecelGetOcrDealWithForShow(string d, string l) { string rescult = ""; string[] dd = d.Split('-'); //for (int i = 0; i < dd.Length-1; i++) //{ // rescult = rescult + dd[0]; //} //rescult = dd[0].Remove(0, 1); string[] ll = l.Split(','); for (int i = 0; i < ll.Length; i++) { ll[i] = ll[i].Replace(" ", ""); ll[i] = ll[i].Replace("[", ""); ll[i] = ll[i].Replace("]", ""); string[] str = ll[i].Split('-'); rescult = rescult + dd[1]+ str[1] + str[0]; } return rescult; } /// /// 清空上次订单数据 /// void ClearData() { QSV = null; Design = null; Layers = null; Colours = null; ProductStandard = null; ord = null; NumberOfLanes = 0; width = 0; Gradient = 0; DistX = 0; DistY = 0; } /// /// 清空上次订单显示区 /// void ClearDataShow() { lbl_QSVShow.Text = ""; lbl_NOFShow.Text = ""; lbl_ProductStandardShow.Text = ""; lbl_widthShow.Text = ""; lbl_GradientShow.Text = ""; lbl_DistXShow.Text = ""; lbl_DistYShow.Text = ""; lbl_verOcrShow.Text = ""; } private void txt_OrderNum_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { this.btn_OrderNum_Click(sender, e); } } #endregion #region PLC触发相机 #region 定位相机拍照触发处理函数 /// /// 定位相机拍照信号过来程序需要进行的操作 /// /// /// /// private void DetCamTriger() { log.Info("PLC触发定位相机,正在拍照计算..."); try { m_dev_cam1.ExecuteSoftwareTrigger(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } #endregion #region OCR相机拍照触发处理函数 /// /// OCR相机拍照信号过来需要进行的操作 /// /// /// private void OcrCamTriger() { log.Info("PLC触发OCR相机,正在拍照计算..."); try { m_dev_cam0.ExecuteSoftwareTrigger(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } #endregion #endregion #region 结果处理 #region 定位结果处理 public void DetResult(object sender, CogJobManagerActionEventArgs e) { try { if (InvokeRequired) { Invoke(new DetResultDelegate(DetResult), new object[] { sender, e }); return; } //清除上次的结果显示 this.lbl_XShow.Text = ""; this.lbl_YShow.Text = ""; this.lbl_RShow.Text = ""; CogToolGroup myTG = myJob1.VisionTool as CogToolGroup; CogToolBlock myTB = myTG.Tools["CogToolBlock1"] as CogToolBlock; CogPMAlignTool myPMA = myTB.Tools["CogPMAlignTool2"] as CogPMAlignTool; CogImageConvertTool myImage = myTB.Tools["CogImageConvertTool1"] as CogImageConvertTool; ////把vpro图像转为bitmap //ICogImage cogimg = myImage.OutputImage; //Bitmap bmp = new Bitmap(cogimg.ToBitmap()); //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("定位存图已完成"); 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); this.lbl_XShow.Text = xx.ToString(); this.lbl_YShow.Text = yy.ToString(); this.lbl_RShow.Text = rr.ToString(); //画模型轮廓 CogCompositeShape shape = myPMA.Results[i].CreateResultGraphics(CogPMAlignResultGraphicConstants.MatchFeatures); CogCompositeShape shape1 = myPMA.Results[i].CreateResultGraphics(CogPMAlignResultGraphicConstants.CoordinateAxes); this.Location_Display.InteractiveGraphics.Add(shape, "", false); this.Location_Display.InteractiveGraphics.Add(shape1, "", false); //画定位的十字点 CPMARunStatus.DrawPointMarker(xx, yy, CogMisc.DegToRad(rr), CogColorConstants.Orange, Location_Display, "."); log.Info("定位计算已完成。"); sendToPLC(xx, yy, rr); } else { log.Info("没有定位到K标志,请查看图像或相机是否正常"); } } catch (Exception ex) { log.Error(ex.Message + "未检测到K标志"); if (this.check_Autorun.Checked == false) { byte[] datax = DataConverter.FloatToByte(0.0f, true); cc24?.NotifyCamInspectionComplete(0, datax); cc24?.NotifyCamAcqComplete(0); } } } /// /// 获取右下角定位标志坐标 /// /// PatMAX结果 /// 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 paixu(List points) { int rowDistance = 50; List> rows = new List>(); for (int i = 0; i < points.Count; i++) { List row = new List(); 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 sortedPoints = new List(); foreach (List row in rows) { row.Sort((x, y) => x.x - y.x); foreach (Point point in row) { if (!sortedPoints.Contains(point)) { sortedPoints.Add(point); } } } return sortedPoints; } //ai suggest① 先按 y 排序 → ② 一次扫描把相邻且 Δy<50 的点归并成同一行 → ③ 每行内部按 x 排序 → ④ 按行收集。 //List paixu(List points) //{ // const int rowDistance = 50; // if (points.Count == 0) return new List(); // // 1. 先按纵坐标排序 // var src = points.OrderBy(p => p.y).ThenBy(p => p.x).ToList(); // var rows = new List>(); // List curRow = new List { src[0] }; // float baseY = src[0].y; // // 2. 一次扫描分好行 // for (int i = 1; i < src.Count; i++) // { // if (Math.Abs(src[i].y - baseY) < rowDistance) // { // curRow.Add(src[i]); // } // else // { // rows.Add(curRow); // curRow = new List { src[i] }; // baseY = src[i].y; // } // } // rows.Add(curRow); // 别忘了最后一行 // // 3. 行内再按 x 排一次(虽然 OrderBy 已做过,保险) // foreach (var row in rows) // row.Sort((a, b) => a.x.CompareTo(b.x)); // // 4. 按行先后汇总 // var sorted = new List(); // foreach (var row in rows) // sorted.AddRange(row); // return sorted; //} #endregion #region OCR结果处理 private void OCRResult(Bitmap bmp) { try { if (InvokeRequired) { Invoke(new OcrResultDelegate(OCRResult), new object[] { bmp }); return; } //CogToolGroup myTG = myJob2.VisionTool as CogToolGroup; //CogAcqFifoTool myImage = myTG.Tools["CogAcqFifoTool1"] as CogAcqFifoTool; //把vpro图像先转为bitmap //ICogImage cogimg = myImage.OutputImage; //Bitmap bmp = new Bitmap(cogimg.ToBitmap()); //有时会丢图cogimg为空,改为SDK取图 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 strTime = System.DateTime.Now.ToString("yyyyMMddHHmmss"); //string strtimef = DateTime.Now.ToString("yyyy-MM-dd"); FileStream fs = new FileStream(SaveImageFileOCR + '\\' + strtimef + '\\' + strTime + ".bmp", FileMode.Create); BinaryWriter bw = new BinaryWriter(fs); bw.Write(bytes, 0, bytes.Length); bw.Close(); fs.Close(); log.Info("OCR存图已完成"); CutPicture(SaveImageFileOCR + '\\' + strtimef + '\\' + strTime + ".bmp", 200, 1400, 5052, 1600); //List temps = new List(); GetOCRImage getOCRImage = new GetOCRImage(); GetOCRImage.FileTimeInfo file = getOCRImage.GetLatesFileImageName(SaveImageFileOCR + '\\' + strtimef, ".bmp"); if (file != null) { byte[] ocrimagebyte = File.ReadAllBytes(file.FileName); Bitmap Bmp = new Bitmap(new MemoryStream(ocrimagebyte)); List lastocr = new List(); OCRResult ocrResult = Engine.DetectText(ocrimagebyte); // log.Debug("读取原始数据1:" + ocrResult.JsonText); List pointsList = new List(); string[] sd = Design.Split('-'); foreach (var item in ocrResult.TextBlocks) //将检测框绘制在图片上 { if (item.Text.Contains(sd[1])) { using (Graphics g = Graphics.FromImage(Bmp)) { g.DrawPolygon(new Pen(Brushes.Red, 2), item.BoxPoints.Select(x => new PointF() { X = x.X, Y = x.Y }).ToArray()); } //lastocr.Add(item.Text); pointsList.Add(new Point(item.BoxPoints[0].X, item.BoxPoints[0].Y,item.Text)); } } List paixujeguo = paixu(pointsList); foreach (var it in paixujeguo) { lastocr.Add(it.txt); } //对图像显示区更新 Ocr_picBox.BackgroundImage = null; Ocr_picBox.BackgroundImage = Bmp; txt_readOcrResultShow.Clear(); if (!Coprinted_ordeFlag) //判断是否为共印订单 { txt_readOcrResultShow.Text = GETOCR(lastocr, Design); log.Info("字符读取结果:" + GETOCR(lastocr, Design)); int distance = CalculateAcc(ExecelGetOcrDealWithForShow(Design, Layers), GETOCR(lastocr, Design)); float maxLength = Math.Max(ExecelGetOcrDealWithForShow(Design, Layers).Length, GETOCR(lastocr, Design).Length); float strSimilarity = (maxLength - distance) / maxLength; ShowTheLansRs(mMatchingStr, strSimilarity); } else { txt_readOcrResultShow.Text = GETOCR(lastocr, Design); log.Info("字符读取结果:" + GETOCR(lastocr, Design)); int distance = CalculateAcc(verocr[mMatchingStr], GETOCR(lastocr, Design)); float maxLength = Math.Max(verocr[mMatchingStr].Length, GETOCR(lastocr, Design).Length); float strSimilarity = (maxLength - distance) / maxLength; ShowTheLansRs(mMatchingStr, strSimilarity); } if (this.check_Autorun.Checked == false) { byte[] datas = DataConverter.FloatToByte(0.0f); cc24?.NotifyCamAcqComplete(1); //通知PLC OCR相机已完成采集 cc24?.NotifyCamInspectionComplete(1, datas); } } } catch (Exception ex) { log.Error(ex.Message + "未检测到字符"); if (this.check_Autorun.Checked == false) { byte[] datax = DataConverter.FloatToByte(0.0f, true); cc24?.NotifyCamInspectionComplete(1, datax); cc24?.NotifyCamAcqComplete(1); } } } #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 /// /// 使用正则表达式提取结果 /// /// 读到的所有字符 /// 设计 /// /// private string GETOCR(List readOCR, string design) { string ocrresult=""; string[] d = design.Split('-'); string pattern = @""+d[1]+"[A-Z0-9]{8}"; for (int i = 0; i < readOCR.Count; i++) { 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 "未能匹配到对应字符请查看产品是否超标,或订单号是否正确"; } } /// /// 使用Levenshtein Distance计算字符串相似度 /// /// excel取到的验证字符 /// 读取到的字符 int CalculateAcc(string readocr, string getocr) { int columnSize = getocr.Length; int rowSize = readocr.Length; if (columnSize == 0) { return rowSize; } if (rowSize == 0) { return columnSize; } int[,] matrix = new int[rowSize + 1, columnSize + 1]; for (int i = 0; i <= columnSize; i++) { matrix[0, 1] = i;//ai提示此处应为matrix[0,i]=i; } for (int j = 1; j <= rowSize; j++)//ai提示此处应为j=0 { matrix[j, 0] = j; } for (int i = 0; i < rowSize; i++) { for (int j = 0; j < columnSize; j++) { int sign; if (getocr[j].Equals(readocr[i])) sign = 0; else sign = 1; matrix[i + 1, j + 1] = Math.Min(Math.Min(matrix[i, j] + sign, matrix[i + 1, j] + 1), matrix[i, j + 1] + 1); } } return matrix[rowSize, columnSize]; } /// /// 将结果显示在对应状态栏 /// /// PLC给的当前在第几道拍照 /// OCR字符相似度结果 void ShowTheLansRs(float mM, float s) { int mMnum = Convert.ToInt32(mM); //s = 1;//**************************************************************************************************注意 switch (mMnum) { case 1: this.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); this.lbl_L1_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 2: this.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); this.lbl_L2_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 3: this.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); this.lbl_L3_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 4: this.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); this.lbl_L4_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 5: this.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); this.lbl_L5_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 6: this.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); this.lbl_L6_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 7: this.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); this.lbl_L7_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 8: this.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); this.lbl_L8_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; case 9: this.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); this.lbl_L9_verOcrRs.Text = s * 100 + "%"; log.Info("字符对比结果:当前第" + mMnum + "道的读取字符与验证字符相似度为" + s * 100 + "%"); break; } } #endregion #endregion #region 通讯相关 #region 通讯初始化 void InitializeCC24() { try { cc24 = new CC24(); cc24.VisionReceivedNewUserData += CC24_NewUserDataReceived; cc24.PlcConnectionStatusChanged += CC24_PlcConnectionStatusChanged; cc24.PlcTriggerCamAcqStart += CC24_PlcTriggerCamAcqStart; cc24.PlcTriggerCamAcqStop += CC24_PlcTriggerCamAcqStop; cc24.NotifyCamAcqEnabled += CC24_NotifyCamAcqEnabled; cc24.NotifyCamAcqDisabled += CC24_NotifyCamAcqDisabled; cc24.Initialize(); cc24.NotifyCamAcqEnable(0); cc24.NotifyCamAcqEnable(1); this.Invoke(new Action(() => { if (cc24.SignalState.PlcConnectionStatus) { ttls_PCLStatusShow.Visible = true; } else { ttls_PCLStatusShow.Visible = false; } })); } catch (Exception ex) { log.Error($"CommCard Initialize Error: {ex.Message}"); } } #endregion #region 相机采集使能状态 private void CC24_NotifyCamAcqEnabled(int cameraIndex, bool isEnabled) { this.Invoke(new Action(() => { if (isEnabled) { this.ttls_AcqEnableShow.Visible = true; } else { this.ttls_AcqEnableShow.Visible = false; } })); } private void CC24_NotifyCamAcqDisabled(int cameraIndex, bool isEnabled) { this.Invoke(new Action(() => { if (isEnabled) { this.ttls_AcqEnableShow.Visible = true; } else { this.ttls_AcqEnableShow.Visible = false; } })); } #endregion #region 接收PLC数据 void CC24_NewUserDataReceived(object sender, CogNdmNewUserDataEventArgs e) { if (InvokeRequired) { Invoke(new CogNdmNewUserDataEventHandler(CC24_NewUserDataReceived), new object[] { sender, e }); return; } byte[] data = cc24.ReadBytesFromPLC(0, 4); float mMatchingStrf = DataConverter.ByteToFloat(data, true); mMatchingStr = Convert.ToInt32(mMatchingStrf); log.Info("PC接收PLC数据:数据内容:" + mMatchingStr); if (NumberOfLanes+1 == mMatchingStr) { if(ocrAcc.Min()<0.95) { MessageBox.Show("当前检测中出现严重错误请注意!",this.Text, MessageBoxButtons.OK,MessageBoxIcon.Error); } else if(ocrAcc.Min()>0.95 & ocrAcc.Min()<1) { MessageBox.Show("当前检测中出现可允许误差请注意!", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); } ocrAcc.Clear(); } } #endregion #region 接收触发相机信号 void CC24_PlcTriggerCamAcqStart(object sender, CogNdmTriggerAcquisitionEventArgs e) { if (InvokeRequired) { Invoke(new CogNdmTriggerAcquisitionEventHandler(CC24_PlcTriggerCamAcqStart), new object[] { sender, e }); return; } try { #region 接收到定位拍照信号 if (e.CameraIndex == 0) { DetCamTriger(); } #endregion #region 接收到OCR拍照信号 if (e.CameraIndex == 1) { Thread.Sleep(100); OcrCamTriger(); } #endregion } catch (Exception ex) { log.Error($"Trigger AcqStart Error: {ex.Message}"); } } #endregion #region 相机停止 private void CC24_PlcTriggerCamAcqStop(object sender, CogNdmTriggerAcquisitionStopEventArgs e) { if (InvokeRequired) { Invoke(new CogNdmTriggerAcquisitionStopEventHandler(CC24_PlcTriggerCamAcqStop), new object[] { sender, e }); return; } if (e.CameraIndex == 0) { log.Info("PLC中断定位相机拍照。"); } if (e.CameraIndex == 1) { log.Info("PLC中断OCR相机拍照。"); } } #endregion #region 通讯状态发生改变 private void CC24_PlcConnectionStatusChanged(object sender, CogNdmProtocolStatusChangedEventArgs e) { // The event is raised from a non-GUI thread. // Invoke this function on the GUI thread. if (InvokeRequired) { Invoke(new CogNdmProtocolStatusChangedEventHandler(CC24_PlcConnectionStatusChanged), new object[] { sender, e }); return; } if (e.ProtocolStatus == CogNdmConnectionStatusConstants.Connected) { PlcContinueFlag = true; log.Info("PLC已连接PC,可以进行相关操作"); ttls_PCLStatusShow.Visible = true; } else if (e.ProtocolStatus != CogNdmConnectionStatusConstants.Connecting) { PlcContinueFlag = false; log.Info("PLC已断开PC,请查看相关设备是否连接"); ttls_PCLStatusShow.Visible = false; } } #endregion #region 通讯发送坐标 private void sendToPLC(double x, double y, double r) { try { string[] col = Colours.Split(','); float xx = (float)x; float yy = (float)y; float rr = (float)r; List ocrxx = new List(); List ocryy = new List(); switch (ProductStandard) { case "TBA1000Slim": switch (col.Length) { case 1: xx = (float)x - 9.5f; break; case 2: xx = (float)x - 19f; break; case 3: xx = (float)x - 28.5f; break; case 4: xx = (float)x - 38f; break; case 5: xx = (float)x - 47.5f; break; case 6: xx = (float)x - 57f; break; } break; case "TBA250B": switch (col.Length) { case 1: xx = (float)x - 9.5f; break; case 2: xx = (float)x - 19f; break; case 3: xx = (float)x - 28.5f; break; case 4: xx = (float)x - 38f; break; case 5: xx = (float)x - 38f; break; case 6: xx = (float)x - 38f; break; } break; case "TBA125Slim": switch (col.Length) { case 1: xx = (float)x - 9.5f; break; case 2: xx = (float)x - 19f; break; case 3: xx = (float)x - 28.5f; break; case 4: xx = (float)x - 28.5f; break; case 5: xx = (float)x - 28.5f; break; case 6: xx = (float)x - 28.5f; break; } break; case "TPA250SQ": switch (col.Length) { case 1: xx = (float)x - 9.5f; break; case 2: xx = (float)x - 19f; break; case 3: xx = (float)x - 19f; break; case 4: xx = (float)x - 19f; break; case 5: xx = (float)x - 19f; break; case 6: xx = (float)x - 19f; break; } break; } float ocrx = 0, ocry = 0; List l = new List(); l.Add((float)NumberOfLanes); int nol = Convert.ToInt32(NumberOfLanes); log.Info("当前订单OCR区域共" + nol + "组:"); for (int item = 0; item < nol; item++) { if (item == 0) { ocrx = xx - ((float)DistX) * ((float)Math.Cos((rr * Math.PI) / 180)); l.Add(ocrx); ocry = yy - ((float)DistY) * ((float)Math.Sin((rr * Math.PI) / 180)); l.Add(ocry); ocrxx.Add(ocrx); ocryy.Add(ocry); } else { ocrx = ocrx + ((float)width * ((float)Math.Cos((rr * Math.PI) / 180))); l.Add(ocrx); ocry = ocry - ((float)Gradient * ((float)Math.Cos((rr * Math.PI) / 180))); l.Add(ocry); ocrxx.Add(ocrx); ocryy.Add(ocry); } log.Info("第" + (item + 1) + "组坐标为:X:" + ocrxx[item] + ",Y:" + ocryy[item] + "。"); } if (this.check_Autorun.Checked == false) { List d = new List(); for (int i=0;i