/************************
* 作者: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;
using LibDataBase;
using LibReadTetraExcel;
using LibComm;
namespace TetraPackOCR
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
LogInit();
}
#region 字段 委托
//创建字段log
ILog log = LogManager.GetLogger(typeof(Form1));
ICommPLC commPLC;
///
/// 声明一个PaddleOCR对象
///
PaddleOCREngine Engine;
///
/// 表格路径
///
string execlFileName = AppDomain.CurrentDomain.BaseDirectory + "Data\\Excle\\OCR文件0602.xlsx";
OrderConfig config = null;
///
/// 定位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文件加载完成");
InitializeComm();
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();
}
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()
{
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 = null;
//初始化OCR
Engine = new PaddleOCREngine(config, "");
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);
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("DistX,DistY未找到,请检查订单号是否正确");
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;
}
}
///
/// 手动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 - (config.NumberOfLanes - 5);
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;
///
/// 清空上次订单数据
///
void ClearData()
{
config = new OrderConfig();
}
///
/// 清空上次订单显示区
///
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 (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();
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 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 pointS = null;
List pointH = null;
List 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()
{
if (autorunFlag == false)
commPLC?.NoticeCamComplete(1, DataConverter.FloatToByte(0.0f, true));
}
private void NoticePLCCompleteDet(byte[] datax)
{
if (autorunFlag == false)
commPLC?.NoticeCamComplete(0, datax);
}
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 TextPoint(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(" ", "");
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 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(CommPLC_OnCameraStatus), index, enable);
return;
}
if (enable)
ttls_AcqEnableShow.Visible = true;
else
ttls_AcqEnableShow.Visible = false;
}
private void CommPLC_OnDataReceived(byte[] data)
{
if (InvokeRequired)
{
BeginInvoke(new Action(CommPLC_OnDataReceived), data);
return;
}
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 (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(CommPLC_OnTrigCamera), index);
return;
}
try
{
if (index == 1)
{
Ocr_picBox.BackgroundImage = null;
Thread.Sleep(1000);
OcrCamTriger();
}
}
catch (Exception ex)
{
log.Error($"Trigger AcqStart Error: {ex.Message}");
}
}
private void CommPLC_OnConnectStatus(bool connected)
{
if (InvokeRequired)
{
BeginInvoke(new Action(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)
{
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("零点坐标已发送");
}
}
#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 locationXY = new List();
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(DataConverter.FloatToByte(0.0f, true));
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(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 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
}
}