/************************ * 作者:CVE-安翀岚 * * Vision:1.0.23.1007 (发布使用) * Windows10 X64(PaddleOCR不能部署在32位操作系统上) * PaddleOCR 3.10 * Vpro: 9.5 SR2 * ***********************/ using AVP.CRobot; using Bjcve.Comm.FFP; using CLIDelegate; 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 ThridLibray; 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 m_ProductStandard; /// /// 幅数 包材宽 梯度 X距离 Y距离 /// int NumberOfLanes; double m_width, m_Gradient, m_DistX, m_DistY, m_height; int m_ColorMax = 0; /// /// 定位Vpp文件 /// string vppdetFile = AppDomain.CurrentDomain.BaseDirectory + "Data\\VPPFile\\liledet.vpp"; /// /// 存图路径 /// 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 ocrAcc = new List(); /// /// 相机对象 1和2 /// IDevice m_dev_cam_ocr, m_dev_cam_det; delegate void DetResultDelegate(Object Sender, CogJobManagerActionEventArgs e); delegate void OcrResultDelegate(Bitmap bmp); #endregion #region 窗体加载和关闭 /// /// 窗体加载 /// /// /// 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; 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文件加载完成"); InitializeCC24(); log.Info("模型文件加载完成"); check_Autorun.BackgroundImage = Image.FromFile(Application.StartupPath + "\\logo_image\\ON.png"); ttls_SystemStatusShow.Visible = true; ttls_CamStatusShow.Visible = true; Invoke(new Action(() => { btn_manualOcr.Enabled = true; btn_manualDet.Enabled = true; check_Autorun.Enabled = true; Enabled = true; btn_OrderNum.Enabled = true; btn_OrderNum.BackColor = Color.DeepSkyBlue; })); }); 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 => { if (myJobManagerDET != null) { myJobDET = myJobManagerDET.Job(0); // 注册结果队列事件 myJobManagerDET.UserResultAvailable += new CogJobManager.CogUserResultAvailableEventHandler(DetResult); } }); } catch (Exception ex) { log.Error(ex.Message); } } /// /// 窗体关闭 /// /// /// private void Form1_FormClosing(object sender, FormClosingEventArgs e) { try { ClossCam(); //// 注销结果队列事件 if (myJobManagerDET != null) { myJobManagerDET.UserResultAvailable -= new CogJobManager.CogUserResultAvailableEventHandler(DetResult); myJobManagerDET.Shutdown(); } CloseCC24(); 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() { try { camOCROpened = false; List deviceList = Enumerator.EnumerateDevices(); //发现设备,搜索所有大华相机 m_dev_cam_ocr = Enumerator.GetDeviceByKey("Machine Vision:CK21686DAK00001");//通过"设备厂商名:设备序列号"获取 if (m_dev_cam_ocr == null) { log.Error("未发现OCR相机,请检查相机连接"); return; } m_dev_cam_ocr.CameraOpened += m_dev_cam_ocr_CameraOpened; m_dev_cam_ocr.CameraClosed += m_dev_cam_ocr_CameraClosed; m_dev_cam_ocr.ConnectionLost += m_dev_cam_ocr_ConnectionLost; if (!m_dev_cam_ocr.Open()) { MessageBox.Show("OCR相机打开失败"); } // 设置图像格式 using (IEnumParameter p = m_dev_cam_ocr.ParameterCollection[ParametrizeNameSet.ImagePixelFormat]) { p.SetValue("BayerRG8"); } // 设置曝光 using (IFloatParameter p = m_dev_cam_ocr.ParameterCollection[ParametrizeNameSet.ExposureTime]) { p.SetValue(500000); } // 设置增益 using (IFloatParameter p = m_dev_cam_ocr.ParameterCollection[ParametrizeNameSet.GainRaw]) { p.SetValue(2.5); } using (IEnumParameter p = m_dev_cam_ocr.ParameterCollection[ParametrizeNameSet.AcquisitionMode]) { p.SetValue("Continuous"); } using (IEnumParameter p = m_dev_cam_ocr.ParameterCollection[ParametrizeNameSet.TriggerMode]) { p.SetValue("On"); } m_dev_cam_ocr.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed_OCR; m_dev_cam_ocr.StreamGrabber.GrabStarted += StreamGrabber_GrabStarted_OCR; // 打开Software Trigger m_dev_cam_ocr.TriggerSet.Open(TriggerSourceEnum.Software); if (!m_dev_cam_ocr.GrabUsingGrabLoopThread()) { // 开启采集失败 log.Error("开启采集失败"); return; } camOCROpened = true; log.Info("OCR相机加载完毕"); } catch (Exception ex) { camOCROpened = false; log.Error("OCR相机加载失败:" + ex.Message); m_dev_cam_ocr = null; } } private bool camOCROpened = false; private bool camDETOpened = false; #endregion #region 相机1事件响应 void m_dev_cam_ocr_ConnectionLost(object sender, EventArgs e) { log.Error(m_dev_cam_ocr.DeviceInfo.Key + "OCR相机断线"); } void m_dev_cam_ocr_CameraClosed(object sender, EventArgs e) { log.Error(m_dev_cam_ocr.DeviceInfo.Key + "OCR相机关闭"); } void m_dev_cam_ocr_CameraOpened(object sender, EventArgs e) { } void StreamGrabber_GrabStarted_OCR(object sender, EventArgs e) { log.Info("OCR相机启动码流"); } /// /// 拍照完成后触发 /// /// /// private void StreamGrabber_ImageGrabbed_OCR(object sender, GrabbedEventArgs e) { try { OCRResult(e.GrabResult.ToBitmap(true)); } catch (Exception ex) { log.Error(ex.ToString()); } } #endregion #region 相机2 定义为定位相机 private void InitializeCamerDET() { try { camDETOpened = false; List deviceList = Enumerator.EnumerateDevices(); //发现设备,搜索所有大华相机 m_dev_cam_det = Enumerator.GetDeviceByKey("Machine Vision:BK27185BAK00038");//通过"设备厂商名:设备序列号"获取 if (m_dev_cam_det == null) { log.Error("未发现OCR相机,请检查相机连接"); return; } m_dev_cam_det.CameraOpened += m_dev_cam_det_CameraOpened; m_dev_cam_det.CameraClosed += m_dev_cam_det_CameraClosed; m_dev_cam_det.ConnectionLost += m_dev_cam_det_ConnectionLost; if (!m_dev_cam_det.Open()) { MessageBox.Show("定位相机打开失败"); } // 设置图像格式 using (IEnumParameter p = m_dev_cam_det.ParameterCollection[ParametrizeNameSet.ImagePixelFormat]) { p.SetValue("Mono"); } // 设置曝光 using (IFloatParameter p = m_dev_cam_det.ParameterCollection[ParametrizeNameSet.ExposureTime]) { p.SetValue(30000); } // 设置增益 using (IFloatParameter p = m_dev_cam_det.ParameterCollection[ParametrizeNameSet.GainRaw]) { p.SetValue(1.0); } using (IEnumParameter p = m_dev_cam_det.ParameterCollection[ParametrizeNameSet.AcquisitionMode]) { p.SetValue("Continuous"); } using (IEnumParameter p = m_dev_cam_det.ParameterCollection[ParametrizeNameSet.TriggerMode]) { p.SetValue("On"); } m_dev_cam_det.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed_DET; m_dev_cam_det.StreamGrabber.GrabStarted += StreamGrabber_GrabStarted_DET; // 打开Software Trigger // Set Software Trigger m_dev_cam_det.TriggerSet.Open(TriggerSourceEnum.Software); if (!m_dev_cam_det.GrabUsingGrabLoopThread()) { // 开启采集失败 log.Error("开启采集失败"); return; } camDETOpened = true; log.Info("定位相机加载完毕"); } catch (Exception ex) { camDETOpened = false; log.Error("定位相机加载失败:" + ex.Message); m_dev_cam_det = null; } } #endregion #region 相机2事件响应 void m_dev_cam_det_ConnectionLost(object sender, EventArgs e) { log.Error(m_dev_cam_det.DeviceInfo.Key + "定位相机断线"); } void m_dev_cam_det_CameraClosed(object sender, EventArgs e) { log.Error(m_dev_cam_det.DeviceInfo.Key + "定位相机关闭"); } void m_dev_cam_det_CameraOpened(object sender, EventArgs e) { } void StreamGrabber_GrabStarted_DET(object sender, EventArgs e) { log.Info("定位相机启动码流"); } /// /// 拍照完成后触发 /// /// /// private void StreamGrabber_ImageGrabbed_DET(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 = 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() { //注销相机事件 if (m_dev_cam_ocr != null) { m_dev_cam_ocr.CameraOpened -= m_dev_cam_ocr_CameraOpened; m_dev_cam_ocr.CameraClosed -= m_dev_cam_ocr_CameraClosed; m_dev_cam_ocr.ConnectionLost -= m_dev_cam_ocr_ConnectionLost; m_dev_cam_ocr.ShutdownGrab(); m_dev_cam_ocr.Dispose(); m_dev_cam_ocr = null; } if (m_dev_cam_det != null) { m_dev_cam_det.CameraOpened -= m_dev_cam_det_CameraOpened; m_dev_cam_det.CameraClosed -= m_dev_cam_det_CameraClosed; m_dev_cam_det.ConnectionLost -= m_dev_cam_det_ConnectionLost; m_dev_cam_det.ShutdownGrab(); m_dev_cam_det.Dispose(); m_dev_cam_det = null; } } #endregion #endregion #region OCR模型参数初始化 private void InitializePaddleOCR() { try { //模型初始化 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.6f; OcrParameter.max_side_len = 4600; //初始化OCR Engine = new PaddleOCREngine(config, OcrParameter); log.Info("OCR模型初始化完成"); } catch (Exception ex) { log.Error(ex.Message + ex.StackTrace); } } #endregion #region 按钮事件 /// /// 自动运行状态改变按钮 /// /// /// private void check_Autorun_CheckedChanged(object sender, EventArgs e) { if (check_Autorun.Checked) { log.Info("PC断开PLC连接,只可进行本地操作。"); check_Autorun.BackgroundImage = Image.FromFile(Application.StartupPath + "\\logo_image\\OFF.png"); panel_Manual.Visible = true; btn_StarDet_manual.Enabled = false; btn_StarDet_manual.BackColor = Color.LightGray; ttls_PCLStatusShow.Visible = false; } else if (!check_Autorun.Checked) { log.Info("PC加载PLC已完成"); check_Autorun.BackgroundImage = Image.FromFile(Application.StartupPath + "\\logo_image\\ON.png"); panel_Manual.Visible = false; if (orderLoaded) { btn_StarDet_manual.Enabled = true; btn_StarDet_manual.BackColor = Color.LimeGreen; } ttls_PCLStatusShow.Visible = true; } } private bool orderLoaded = false; private Dictionary> ocrTextRequest = new Dictionary>(); private Dictionary ocrTextDesign = new Dictionary(); private Dictionary ocrTextResult = new Dictionary(); /// /// 此按钮事件主要是获取excel表格内的数据 /// 包括定位偏移量,需要验证的字符 /// /// /// 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); //读取表格内容 ExcelPackage.License.SetNonCommercialOrganization("My Noncommercial organization"); using (ExcelPackage package = new ExcelPackage(execlFileName)) { sheet1 = package.Workbook.Worksheets["P2生成数据"]; sheet2 = package.Workbook.Worksheets["QSV对应产品规格和梯度"]; sheet3 = package.Workbook.Worksheets["产品规格对应排布方式"]; //根据订单遍历sheet1 找Sequence QSV NumOFLanes 字符 string currentQSV = ""; for (int i = 1; i < sheet1.Dimension.Rows; i++) { if (sheet1.GetValue(i, 3) != null) { if (sheet1.Cells[i, 3].Value.ToString() == order) { currentQSV = sheet1.Cells[i, 4].Value.ToString(); lbl_QSV.Text = currentQSV; log.Info("当前订单QSV:" + currentQSV); NumberOfLanes = Convert.ToInt32(sheet1.Cells[i, 5].Value.ToString()); log.Info("当前订单Number Of Lanes:" + NumberOfLanes); lbl_NO.Text = sheet1.Cells[i, 5].Value.ToString(); int num = 0; for (int k = 0; k < 10; k++) { string lanes = sheet1.Cells[i + k, 6].Value.ToString(); string design = sheet1.Cells[i + k, 7].Value.ToString().Split('-')[1]; lanes = lanes.Substring(1, lanes.Length - 2); string[] tmp = lanes.Split(','); num += tmp.Length; List textOCR = ExecelGetOcrText(design, sheet1.Cells[i + k, 8].Value.ToString()); foreach (string lan in tmp) { int lanInt = Convert.ToInt32(lan); ocrTextRequest[lanInt] = textOCR; ocrTextDesign[lanInt] = design; } listBox1.Items.Add(sheet1.Cells[i + k, 6].Value.ToString()); listBox1.Items.Add(string.Join(",", textOCR)); if (num >= NumberOfLanes) break; } break; } } } if (!string.IsNullOrEmpty(currentQSV)) { string qsv; //根据得到的QSV遍历sheet2 找产品规格和宽度梯度 for (int j = 1; j <= sheet2.Dimension.Rows; j++) { qsv = sheet2.Cells[j, 1].Value.ToString(); if (qsv == currentQSV) { m_ProductStandard = sheet2.Cells[j, 2].Value.ToString(); lbl_ProductStandard.Text = m_ProductStandard; log.Info("当前订单产品编号:" + m_ProductStandard); m_width = Convert.ToDouble(sheet2.Cells[j, 3].Value.ToString()); lbl_width.Text = sheet2.Cells[j, 3].Value.ToString(); log.Info("当前订单幅宽:" + m_width); m_height = Convert.ToDouble(sheet2.Cells[j, 4].Value.ToString()); lbl_height.Text = sheet2.Cells[j, 4].Value.ToString(); log.Info("当前订单幅高:" + m_height); m_Gradient = Convert.ToDouble(sheet2.Cells[j, 5].Value.ToString()); lbl_Gradient.Text = sheet2.Cells[j, 5].Value.ToString(); log.Info("当前订单梯度:" + m_Gradient); break; } } if (string.IsNullOrEmpty(m_ProductStandard)) { log.Debug("ProductStandard未找到,请检查订单号是否正确"); btn_OrderNum.Enabled = true; btn_OrderNum.BackColor = Color.DeepSkyBlue; return; } //根据产品规格获取距离坐标 for (int n = 1; n < sheet3.Dimension.Rows; n++) { if (sheet3.GetValue(n, 1) != null) { if (sheet3.Cells[n, 1].Value.ToString() == m_ProductStandard) { string str = sheet3.Cells[n + ocrTextRequest[1].Count - 1, 4].Value.ToString(); string[] x_y = str.Split(','); string[] X = x_y[0].Split(':'); string[] Y = x_y[1].Split(':'); m_DistX = Convert.ToDouble(X[1].Replace("mm", "")); lbl_DistX.Text = X[1].Replace("mm", ""); log.Info("当前订单X偏移:" + m_DistX); m_DistY = Convert.ToDouble(Y[1].Replace("mm", "")); lbl_DistY.Text = Y[1].Replace("mm", ""); log.Info("当前订单Y偏移:" + m_DistY); string alignColor = sheet3.Cells[n + ocrTextRequest[1].Count - 1, 3].Value.ToString(); if (alignColor.Contains("单排")) m_ColorMax = ocrTextRequest.Values.Select(x => x.Count).Max();// ocrTextRequest[1].Count; else m_ColorMax = alignColor.Replace("排布", "").Split(',').ToList().Select(int.Parse).Max(); log.Info("当前排布方式:" + alignColor); log.Info("单行最大数量:" + m_ColorMax.ToString()); break; } } } if (m_DistX == 0 || m_DistY == 0) { log.Debug("DistX,DistY未找到,请检查订单号是否正确"); btn_OrderNum.Enabled = true; btn_OrderNum.BackColor = Color.DeepSkyBlue; return; } log.Info("相关数据已获取完成,且已显示在界面中,请查看。"); } else { log.Debug("QSV未找到,请检查订单号是否正确"); btn_OrderNum.Enabled = true; btn_OrderNum.BackColor = Color.DeepSkyBlue; return; } } //判断当前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 (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; } } /// /// 手动ocr /// /// /// private void btn_manualOcr_Click(object sender, EventArgs e) { m_dev_cam_ocr?.ExecuteSoftwareTrigger();//相机1触发 = OCR拍照 log.Info("手动触发OCR"); } /// /// 手动定位 /// /// /// private void btn_manualDet_Click(object sender, EventArgs e) { m_dev_cam_det?.ExecuteSoftwareTrigger(); log.Info("手动触发定位"); } private bool autorunFlag = false; private double m_textWidth = 0; private DateTime m_startTime = DateTime.Now; private void btn_StarDet_manual_Click(object sender, EventArgs e) { if (camOCROpened == false || camDETOpened == 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 - (NumberOfLanes - 5); //m_textWidth = Convert.ToDouble(textBox1.Text); ocrAcc.Clear(); autorunFlag = check_Autorun.Checked; 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; m_dev_cam_det?.ExecuteSoftwareTrigger(); list_Log.Clear(); log.Info("手动触发开始"); m_BeginOCR = true; } private bool m_BeginOCR = false; private List ExecelGetOcrText(string design, string layer) { List result = new List(); string[] ll = layer.Replace("[", "").Replace("]", "").Split(','); for (int i = 0; i < ll.Length; i++) { ll[i] = ll[i].Replace(" ", ""); string[] str = ll[i].Split('-'); if (str.Length < 2) continue; result.Add(design + str[1] + str[0]); } return result; } /// /// 清空上次订单数据 /// void ClearData() { m_ProductStandard = null; NumberOfLanes = 0; m_width = 0; m_Gradient = 0; m_DistX = 0; m_DistY = 0; m_height = 0; } /// /// 清空上次订单显示区 /// 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 OCR相机拍照触发处理函数 /// /// OCR相机拍照信号过来需要进行的操作 /// /// /// private void OcrCamTriger() { try { log.Info("PLC触发OCR相机,正在拍照计算..."); m_dev_cam_ocr?.ExecuteSoftwareTrigger(); } catch (Exception ex) { log.Error(ex.Message); } } #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(DataConverter.FloatToByte(0.0f, true)); } else SendToPLC(xx, yy, rr); } else { EnableStartDetect(); log.Info("没有定位到K标志,请查看图像或相机是否正常"); } } catch (Exception ex) { EnableStartDetect(); log.Error(ex.Message + "未检测到K标志"); NoticePLCCompleteDet(DataConverter.FloatToByte(0.0f, true)); } } /// /// 获取右下角定位标志坐标 /// /// 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 < 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 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; } #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(); 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 - m_ColorMax), 2000, 3400 + 200 * m_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; } Mat 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 OCRTextResult hResult = null; OCRTextResult sResult = null; OCRTextResult vResult = null; bool matchOK = false; List pointS = null; List pointH = null; List pointV = null; sResult = OCRBytes(s.ImEncode(".png")); if (sResult == null) { log.Error("s通道,OCR字符识别失败"); NoticePLCCompleteOCR(); return; } txt_readOcrResultShow.Text = 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 ((pointS != null && pointS.Count > 0) || (pointH != null && pointH.Count > 0) || (pointV != null && pointV.Count > 0)) { using (Graphics g = Graphics.FromImage(Bmp)) { 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() { if (autorunFlag == false) { byte[] datax = DataConverter.FloatToByte(0.0f, true); cc24?.NotifyCamInspectionComplete(1, datax); cc24?.NotifyCamAcqComplete(1); } } private void NoticePLCCompleteDet(byte[] datax) { if (autorunFlag == false) { cc24?.NotifyCamInspectionComplete(0, datax); cc24?.NotifyCamAcqComplete(0); } } private OCRTextResult OCRBytes(byte[] ocrimagebyte) { try { OCRTextResult result = new OCRTextResult(); List lastocr = new List(); OCRResult ocrResult = Engine.DetectText(ocrimagebyte); List pointsList = new List(); 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 Point(item.BoxPoints[0].X, item.BoxPoints[0].Y, item.Text)); } } List paixujeguo = paixu(pointsList); foreach (var it in paixujeguo) { lastocr.Add(it.txt); } result.text = GETOCR(lastocr, ocrTextDesign[mMatchingStr]); var keysToUpdate = new List(); 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 /// /// 使用正则表达式提取结果 /// /// 读到的所有字符 /// 设计 /// /// private string GETOCR(List 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(" ", ""); } 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(); } /// /// 将结果显示在对应状态栏 /// /// PLC给的当前在第几道拍照 /// OCR字符相似度结果 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 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); 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) { Invoke(new Action(() => { if (isEnabled) { ttls_AcqEnableShow.Visible = true; } else { ttls_AcqEnableShow.Visible = false; } })); } private void CC24_NotifyCamAcqDisabled(int cameraIndex, bool isEnabled) { Invoke(new Action(() => { if (isEnabled) { ttls_AcqEnableShow.Visible = true; } else { 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 (m_BeginOCR == false && m_GotoZero == false) { NoticePLCCompleteOCR(); return; } if (m_GotoZero) { if (mMatchingStr == 2) { Thread.Sleep(3000); EnableStartDetect(); return; } return; } if (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 bool m_GotoZero = false; private void button2_Click(object sender, EventArgs e) { autorunFlag = check_Autorun.Checked; if (check_Autorun.Checked == false) { button1.Enabled = true; button1.BackColor = Color.LimeGreen; btn_StarDet_manual.Enabled = false; btn_StarDet_manual.BackColor = Color.LightGray; m_GotoZero = true; List plcXY = new List(); plcXY.Add(1); plcXY.Add(0); plcXY.Add(0); NoticePLCCompleteDet(DataConverter.FloatToByte(plcXY, true)); log.Info("零点坐标已发送"); } } #endregion #region 接收触发相机信号 void CC24_PlcTriggerCamAcqStart(object sender, CogNdmTriggerAcquisitionEventArgs e) { if (InvokeRequired) { Invoke(new CogNdmTriggerAcquisitionEventHandler(CC24_PlcTriggerCamAcqStart), new object[] { sender, e }); return; } try { if (e.CameraIndex == 1) { Ocr_picBox.BackgroundImage = null; Thread.Sleep(1000); OcrCamTriger(); } } catch (Exception ex) { log.Error($"Trigger AcqStart Error: {ex.Message}"); } } #endregion #region 相机停止 private void CC24_PlcTriggerCamAcqStop(object sender, CogNdmTriggerAcquisitionStopEventArgs e) { } #endregion #region 通讯状态发生改变 private void CC24_PlcConnectionStatusChanged(object sender, CogNdmProtocolStatusChangedEventArgs e) { 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; button2.Enabled = true; button2.BackColor = Color.LimeGreen; } else if (e.ProtocolStatus != CogNdmConnectionStatusConstants.Connecting) { PlcContinueFlag = false; log.Info("PLC已断开PC,请查看相关设备是否连接"); ttls_PCLStatusShow.Visible = false; button2.Enabled = false; button2.BackColor = Color.LightGray; } } #endregion #region 通讯发送坐标 private void SendToPLC(double x, double y, double r) { try { if (ocrTextRequest[1].Count == 0) return; double xx = x - (m_textWidth * m_ColorMax) / 2.0; double yy = y; double rr = r; List locationXY = new List(); double ocrx = 0, ocry = 0; locationXY.Add((float)NumberOfLanes); int nol = Convert.ToInt32(NumberOfLanes); log.Info("当前订单OCR区域共" + nol + "组:"); double degree = (rr * Math.PI) / 180; for (int item = 0; item < nol; item++) { if (item == 0) { ocrx = xx - m_DistX * Math.Cos(degree) - m_DistY * Math.Sin(degree); ocry = yy + m_DistY * Math.Cos(degree) - m_DistX * Math.Sin(degree); } else { ocrx = ocrx + m_width * Math.Cos(degree) + m_Gradient * Math.Sin(degree); ocry = ocry - m_Gradient * Math.Cos(degree) + m_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(DataConverter.FloatToByte(0.0f, true)); return; } if (ocry < - 50) { ocrx = ocrx - m_height * Math.Sin(degree); ocry = ocry + m_height * Math.Cos(degree); log.Info("更新第" + (item + 1) + "组坐标为:X:" + ocrx + ",Y:" + ocry + "。"); } else if (ocry > 400) { ocrx = ocrx + m_height * Math.Sin(degree); ocry = ocry - m_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(DataConverter.FloatToByte(0.0f, true)); return; } locationXY.Add((float)ocrx); locationXY.Add((float)ocry); } if (check_Autorun.Checked == false) { List plcXY = new List(); 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(DataConverter.FloatToByte(plcXY, true)); log.Info("坐标已发送完成。"); } } catch (Exception ex) { EnableStartDetect(); log.Error(ex.Message + "未检测到K标志"); NoticePLCCompleteDet(DataConverter.FloatToByte(0.0f, true)); } } #endregion #region 通讯关闭 private void CloseCC24() { try { 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.Shutdown(); } catch (Exception ex) { log.Error($"CommCard Closing Error: {ex.Message}"); } } #endregion #endregion } }