geboshi_V1/LeatherProject/LeatherApp/Page/FHome.cs
2024-04-28 14:05:46 +08:00

2066 lines
110 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using IKapC.NET;
using LeatherApp.Device;
using LeatherApp.Device.CamerUtil;
using LeatherApp.Interface;
using LeatherApp.Utils;
using Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using S7.Net;
using SqlSugar;
using Sunny.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LeatherApp.Page
{
public partial class FHome : UIPage
{
private WarningEnum warningLevel;//警告等级
private CurrentStateEnum currentState;//当前状态
private DevContainer devContainer = new DevContainer();
private Service.ProductService svcProduct = new Service.ProductService();
private Service.RecordsService svcRecord = new Service.RecordsService();
private bool defectPauseForUser = false;
//private Models.Product currProductModel = null;//当前产品
//private Models.Records record = null;
private Stopwatch pStopWatch=new Stopwatch();//计算速度用,暂停时停止计数
private object lockScanPhoto = new object();
private object lockCurrKey = new object();
private int currKey=0;
private Hashtable htTask = new Hashtable();//默认单线程写入不用lock, 多线程安全同步读取用Synchronized
//无产品编码时加载
FProductInfo frmProduct;
//云端
private CloudMgr cloudMgr = new CloudMgr();
private bool init_Cloud;
public FHome(FProductInfo frm)
{
InitializeComponent();
frmProduct = frm;
if(Config.Camer_Name == CamerDevNameEnum.)
IKapCLib.ItkManInitialize();
#region dataGridView设置
uiDataGridView1.AllowUserToAddRows = uiDataGridView1.AllowUserToDeleteRows = false;//用户添加删除行
uiDataGridView1.AllowUserToResizeRows = false;//用户调整行大小
uiDataGridView1.AllowUserToResizeColumns = false;//用户调整列大小
uiDataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;//只可选中整行,不是单元格
//显示行号与列宽度自动调整
uiDataGridView1.RowHeadersVisible = true;
uiDataGridView1.RowHeadersWidth = 60;
uiDataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
uiDataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;//数据量过百绑定太变
uiDataGridView1.RowPostPaint += (sender, e) =>//序号列头
{
Utils.Util.showRowNum_onDataGrid_RowPostPaint(this.uiDataGridView1, sender, e);
//Rectangle rectangle = new Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, uiDataGridView1.RowHeadersWidth - 4, e.RowBounds.Height);
//TextRenderer.DrawText(e.Graphics, (e.RowIndex).ToString(), uiDataGridView1.RowHeadersDefaultCellStyle.Font, rectangle, uiDataGridView1.RowHeadersDefaultCellStyle.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Right);
};
for (int i = 0; i < uiDataGridView1.Columns.Count; i++)//禁止点击列头排序
uiDataGridView1.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
////行列交叉处标题
//if (dataGridView1.RowHeadersVisible) dataGridView1.TopLeftHeaderCell.Value = "SPH/CYL";
//事件
//this.uiDataGridView1.DataBindingComplete += this.uiDataGridView1_DataBindingComplete;//bing data时发生可修改单元格内容
//this.uiDataGridView1.SelectIndexChange += uiDataGridView1_SelectIndexChange;//选择行时发行
this.uiDataGridView1.CellClick += uiDataGridView1_CellClick; ;
#endregion
this.ucColorListDefect.ColorChanged = (xcode, xcolor) =>
{
try
{
var item=Config.getDefectItem(xcode);
if(item != null)
{
item["color"] = xcolor;
Config.SaveDefectItemList(Config.defectItemList);
}
}
catch (Exception ex)
{
this.AddTextEvent(DateTime.Now,"事件", "缺陷颜色修改后保存失败!");
}
};
}
private void uiDataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0 || currKey == 0)
return;
Records record = Hashtable.Synchronized(htTask)[currKey] as Records;
//var defectInfo = record.DefectInfoList[record.DefectInfoList.Count - e.RowIndex-1];//按顺序索引引用
var defectInfo = record.DefectInfoList.FirstOrDefault(m => m.uid == (long)this.uiDataGridView1.CurrentRow.Cells["colUid"].Value);
if(defectInfo == null)
{
UIMessageTip.ShowError("此记录已不存在!", 1000);
return;
}
this.picDefectImage.loadImage(defectInfo.image);
//选中
this.Invoke(new System.Action(() =>
{
if (lineChartDefect.Option.Series != null && lineChartDefect.Option.Series.ContainsKey("SELECT"))
{
lineChartDefect.Option.Series["SELECT"].Clear();
lineChartDefect.Option.Series["SELECT"].Add( defectInfo.CentreX, defectInfo.CentreY / 100);
lineChartDefect.Refresh();
}
}));
}
private void lineChartDefect_Click(object sender, EventArgs e)
{
if (lineChartDefect.Option.Series != null && lineChartDefect.Option.Series.ContainsKey("SELECT") && lineChartDefect.Option.Series["SELECT"].DataCount > 0)
{
lineChartDefect.Option.Series["SELECT"].Clear();
lineChartDefect.Refresh();
}
}
#region
private void resetUIValue(bool resetCurrKey=true)
{
firstTest = true;
if(resetCurrKey)
currKey = 0;
pStopWatch.Reset();
this.Invoke(new System.Action(() =>
{
lblLen.Text = "0米";
lblSpeed.Text = "速度0米/分";
txtBarCodeName.Text = txtBatchId.Text = txtReelId.Text = "";
numErpLen.Text = "0";
this.lineChartDefect.SetOption(new UILineOption());
this.lineChartFaceWidth.SetOption(new UILineOption());
this.uiDataGridView1.DataSource = null;
this.uiDataGridView1.Rows.Clear();
this.lstboxLog.Items.Clear();
this.picDefectImage.clear();
this.picScanner1.Image = this.picScanner2.Image = null;
picScanner1.Refresh();
picScanner2.Refresh();
}));
}
/// <summary>
/// 全局中断
/// </summary>
private void globalBreakEvent(int portIndex, byte data)
{
AddTextEvent(DateTime.Now,"I/0状态", $"{portIndex}{Convert.ToString(data, 2)}");
if (compareIOInput(CMDName.) && this.btnStart.Enabled)
{
this.devContainer.devIOCard.writeBitState(0, 0, true);
this.startCommand();
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 0, false);
});
}
else if (compareIOInput(CMDName.) && this.btnPause.Enabled)
{
this.devContainer.devIOCard.writeBitState(0, 1, true);
this.pauseCommand();//true 输出暂停不会触发输入暂停
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 1, false);
});
}
//else if (compareIOInput(CMDName.复位按钮) && this.tsbtnReset.Enabled)
// resetCommand();
//else if (!this.disableBuzzer && compareIOInput(CMDName.门磁告警输入))
// warning(WarningEnum.Low, true);
//else if (!this.disableBuzzer && compareIOInput(CMDName.喷墨告警输入))
// warning(WarningEnum.Low, true);
}
private bool compareIOInput(CMDName key)
{
JObject joJson = Config.CMDProcess[key];
IODirectionEnum direction = (IODirectionEnum)joJson.Value<int>("Direction");
if (direction == IODirectionEnum. || direction == IODirectionEnum.)
{
return Util.compareIOInput(
joJson.Value<JArray>("IN_OP_SHOW").ToObject<List<string>>().ToArray(),
devContainer.devIOCard.DIData);
}
return false;
}
/// <summary>
/// 报警,只响应low,high
/// </summary>
private void warning(WarningEnum level, bool buzzer = true)
{
if (level == WarningEnum.Normal)
return;
//lock (myLock)
warningLevel = level;
//if ((int)level >= (int)WarningEnum.Low)//暂停
{
//currentState = CurrentStateEnum.暂停;
if (!Config.StopPLC)
this.devContainer.devPlc.pauseDev();
else if (!Config.StopIO && devContainer.devIOCard.IsInit)
{
this.devContainer.devIOCard.writeBitState(0, 1, true);
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 1, false);
});
}
pauseCommand(buzzer);
}
//else if (level == WarningEnum.High)//急停
//{
// currentState = CurrentStateEnum.急停;
// devContainer.devAxis.stopNow();
// stopNowCommand();
//}
//启用报警消除按钮
//this.Invoke(new System.Action(() =>
//{
// tsbtnWarning.Enabled = true;
//}));
}
/// <summary>
/// 重新生成缺陷分布(cm2M在内部转换)
/// </summary>
/// <param name="lstDefectInfo">Records.DefectInfoList</param>
/// <param name="XSizeRange">幅宽</param>
/// <param name="YSizeRange">卷长度</param>
private void reDrawDefectPoints(List<DefectInfo> lstDefectInfo, double[] XSizeRange=null, double[] YSizeRange=null,bool addSelRect=true)
{
UILineOption option;
//AddTextEvent(DateTime.Now,$"绘图", $"缺陷分布, W={string.Join(", ", XSizeRange)},H={string.Join(", ", YSizeRange)}, LastData={JsonConvert.SerializeObject(lstDefectInfo[lstDefectInfo.Count - 1])}");
var lstData = lstDefectInfo.OrderBy(m => m.Code).ThenBy(m => m.Code).ToList();
if (XSizeRange == null || YSizeRange == null)
option = this.lineChartDefect.Option;
else
{
if (YSizeRange[0] == YSizeRange[1])
{
YSizeRange[0] -= YSizeRange[0] / 10f;
YSizeRange[1] += YSizeRange[1] / 10f;
}
YSizeRange[0] /= 100;
YSizeRange[1] /= 100;
option = new UILineOption();
option.XAxis.Name = "面宽(cm)";
option.YAxis.Name = "长度(米)";
//option.Grid.Top = 20;//边距
option.Grid.Right = 20;//边距
//X轴数据类型
option.XAxisType = UIAxisType.Value;
//设置X/Y轴显示范围
option.XAxis.SetRange(XSizeRange[0], XSizeRange[1]);
option.YAxis.SetRange(YSizeRange[0], YSizeRange[1]);
//坐标轴显示小数位数
option.XAxis.AxisLabel.DecimalPlaces = option.YAxis.AxisLabel.DecimalPlaces = 1;
//X/Y轴画参考线
//option.YAxisScaleLines.Add(new UIScaleLine("上限", 3.5, Color.Red));
//option.YAxisScaleLines.Add(new UIScaleLine("下限", 2.2, Color.Gold));
//option.XAxisScaleLines.Add(new UIScaleLine(dt.AddHours(3).DateTimeString(), dt.AddHours(3), Color.Red));
//option.XAxisScaleLines.Add(new UIScaleLine(dt.AddHours(6).DateTimeString(), dt.AddHours(6), Color.Red));
option.ToolTip.Visible = true;
//option.ToolTip.Formatter = "怎么自定义X,Y显示名称{X}";
option.Title = new UITitle();
option.Title.Text = "";
option.Title.SubText = "";
}
option.Series.Clear();
string preCode = "";
UILineSeries series=null;
foreach (var item in lstData)
{
if (preCode != item.Code)//加一组新类型及样式
{
preCode = item.Code;
var one = Config.getDefectItem(item.Code);
if (one == null)
{
AddTextEvent(DateTime.Now,$"绘图", $"getDefectItem({item.Code}) is null!");
continue;
}
JObject objItem= one as JObject;
Color color = ColorTranslator.FromHtml(objItem.Value<string>("color"));
series = option.AddSeries(new UILineSeries(objItem.Value<string>("name"), color));//加一组
series.Symbol = UILinePointSymbol.Star;
series.SymbolSize = 4;
series.SymbolLineWidth = 2;
series.ShowLine = false;
series.SymbolColor = color;
//数据点显示小数位数针对当前UILineSeries
series.XAxisDecimalPlaces = 1;
series.YAxisDecimalPlaces = 2;
//series.Smooth = false;
}
series.Add( item.CentreX, item.CentreY / 100); //cm -> m
}
////加一组框选
if (addSelRect && !option.Series.ContainsKey("SELECT"))
{
series=option.AddSeries(new UILineSeries("SELECT", Color.Red));
series.Symbol = UILinePointSymbol.Circle;
series.SymbolSize = 6;
series.SymbolLineWidth = 3;
series.ShowLine = false;
series.SymbolColor = Color.Red;
//数据点显示小数位数针对当前UILineSeries
series.XAxisDecimalPlaces = 1;
series.YAxisDecimalPlaces = 2;
//series.Add(1, 1);
}
//====
//option.GreaterWarningArea = new UILineWarningArea(3.5);
//option.LessWarningArea = new UILineWarningArea(2.2, Color.Gold);
this.BeginInvoke(new System.Action(() =>
{
this.lineChartDefect.SetOption(option);
//series.UpdateYData();//按序号更新Y轴值(可设置值超出范围用于闪烁)
}));
}
/// <summary>
/// 重新门幅宽度
/// </summary>
/// <param name="points"></param>
/// <param name="XSizeRange">卷长度</param>
/// <param name="YSizeRange">幅宽</param>
private void reDrawFaceWidth(List<float[]> points, double[] XSizeRange, double[] YSizeRange)
{
//AddTextEvent(DateTime.Now,$"绘图", $"门幅宽度, W={string.Join(", ", XSizeRange)},H={string.Join(", ", YSizeRange)}, LastData={JsonConvert.SerializeObject(points[points.Count-1])}");
if(YSizeRange[0]== YSizeRange[1])
{
YSizeRange[0] -= YSizeRange[0] / 10f;
YSizeRange[1] += YSizeRange[1] / 10f;
}
XSizeRange[0] /= 100;
XSizeRange[1] /= 100;
//防止超限
XSizeRange[1] += 0.01;
YSizeRange[1] += 0.1;
UILineOption option = new UILineOption();
option.XAxis.Name = "长度(米)";
option.YAxis.Name = "面宽(cm)";
option.Grid.Top = 20;
option.Grid.Right = 20;
//X轴数据类型
option.XAxisType = UIAxisType.Value;
//设置X/Y轴显示范围
option.XAxis.SetRange(XSizeRange[0], XSizeRange[1]);
option.YAxis.SetRange(YSizeRange[0], YSizeRange[1]);
//坐标轴显示小数位数
option.XAxis.AxisLabel.DecimalPlaces = option.YAxis.AxisLabel.DecimalPlaces = 1;
//X/Y轴画参考线
//option.YAxisScaleLines.Add(new UIScaleLine("上限", 3.5, Color.Red));
//option.YAxisScaleLines.Add(new UIScaleLine("下限", 2.2, Color.Gold));
//option.XAxisScaleLines.Add(new UIScaleLine(dt.AddHours(3).DateTimeString(), dt.AddHours(3), Color.Red));
//option.XAxisScaleLines.Add(new UIScaleLine(dt.AddHours(6).DateTimeString(), dt.AddHours(6), Color.Red));
option.ToolTip.Visible = true;
//option.ToolTip.Formatter = "怎么自定义X,Y显示名称{X}";
option.Title = new UITitle();
option.Title.Text = "";
option.Title.SubText = "";
Color color = Color.Blue;
UILineSeries series = null;
series = option.AddSeries(new UILineSeries("面宽", color));
series.Symbol = UILinePointSymbol.Circle;
series.ShowLine = true;
series.SymbolSize = 1;//4
series.SymbolLineWidth = 1;//2
series.SymbolColor = color;
//数据点显示小数位数针对当前UILineSeries
series.XAxisDecimalPlaces = 2;
series.YAxisDecimalPlaces = 1;
float x;
foreach (var item in points)
{
x = item[0] / 100; //cm -> m
series.Add(x, item[1]);
if (x < XSizeRange[0]) AddTextEvent(DateTime.Now,$"绘图", $"门幅宽度超限 1 {x}<{XSizeRange[0]}",WarningEnum.High);
if (x > XSizeRange[1]) AddTextEvent(DateTime.Now,$"绘图", $"门幅宽度超限 2 {x}>{XSizeRange[1]}", WarningEnum.High);
if (item[1] < YSizeRange[0]) AddTextEvent(DateTime.Now,$"绘图", $"门幅宽度超限 3 {item[1]}<{YSizeRange[0]}", WarningEnum.High);
if (item[1] > YSizeRange[1]) AddTextEvent(DateTime.Now,$"绘图", $"门幅宽度超限 4 {item[1]}>{YSizeRange[1]}", WarningEnum.High);
}
//====
//option.GreaterWarningArea = new UILineWarningArea(3.5);
//option.LessWarningArea = new UILineWarningArea(2.2, Color.Gold);
this.BeginInvoke(new System.Action(() =>
{
this.lineChartFaceWidth.SetOption(option);
}));
}
private delegate void AddTextDelegate(DateTime time,string tag, string msg, WarningEnum level);
private void AddTextEvent(DateTime now, string tag, string msg, WarningEnum level = WarningEnum.Normal)
{
try
{
if (InvokeRequired)
{
Invoke(new AddTextDelegate(AddTextEvent), new object[]
{
now,
tag,
msg,
level
});
}
else
{
if (tag != null && tag != "")
tag = $" - [{tag}]";
//var now = DateTime.Now;
msg = now.ToString("HH:mm:ss fff") + tag + " - " + msg;
//cont = MyHelper.subString(cont, 300);
//写日志warn和error日志直接写
writeLog(now, level, msg);
//
//if (type > 0)
// cont = $"<color=\"{(type == 1 ? "Yellow" : "Red")}\">{cont}</color>";
//msg = (level == WarningEnum.Normal ? "B" : level == WarningEnum.Low ? "Y" : "R") + msg;
msg = (level == WarningEnum.Normal ? "" : level == WarningEnum.Low ? "Y" : "R") + msg;
//this.Invoke(new System.Action(() =>
//{
if (this.lstboxLog.Items.Count > 1000)
this.lstboxLog.Items.Clear();
lstboxLog.Items.Insert(0, msg);
//}));
//日志滚动
//lstLog.SelectedIndex = lstLog.Items.Count - 1;
//开启云端
if ((init_Cloud) && (level != WarningEnum.Normal))
{
//上传报警状态和信息
string statusStr = level == WarningEnum.Normal ? "正常" : level == WarningEnum.Low ? "警告" : "系统报警";
cloudMgr.SendTopic("device/attributes", $"{{\"status\": \"{statusStr}\", \"alm\": \"{tag}-{msg}\", " +
$"\"name\": \"{Config.CloudThisName}\"}}");
}
}
}
catch (Exception ex)
{
//MessageBox.Show("AddTextEvent ex=(" + ex.Message + ")", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
}
}
private void writeLog(DateTime now, WarningEnum level, string text)
{
string directory = Config.LogPath + "\\" + DateTime.Now.ToString("yyyyMM") + "\\";
//if (type == 0) directory = Application.StartupPath + "\\Log\\Info\\";
//else if (type == 1) directory = Application.StartupPath + "\\Log\\Warn\\";
//else directory = Application.StartupPath + "\\Log\\Error\\";
if (!System.IO.Directory.Exists(directory))
System.IO.Directory.CreateDirectory(directory);
File.AppendAllText(directory + now.ToString("yyyyMMdd") + ".log", text + "\r\n");
}
#endregion
private void FHome_Load(object sender, EventArgs e)
{
ucColorListDefect.initData(Config.defectItemList);
this.lineChartDefect.SetOption(new UILineOption());
this.lineChartFaceWidth.SetOption(new UILineOption());
//判断是否连接云端
if(Config.cloud_open >0)
{
AddTextEvent(DateTime.Now, "设备启动", $"连接云端");
if (cloudMgr.ConnectCloud(Config.cloud_ip, Config.cloud_port,
Config.cloud_username, Config.cloud_password))
{
init_Cloud = true;
AddTextEvent(DateTime.Now, "云端数据", $"开启云端连接");
//开启云端
if (init_Cloud)
{
//上传报警状态和信息
string statusStr = "正常" ;
cloudMgr.SendTopic("device/attributes", $"{{\"status\": \"{statusStr}\", \"alm\": \"系统运行-正常启动软件\", " +
$"\"name\": \"{Config.CloudThisName}\"}}");
}
}
else
AddTextEvent(DateTime.Now, "云端数据", "云端连接失败!", WarningEnum.Low);
}
}
private void FHome_Shown(object sender, EventArgs e)
{
//picScanner1.BackColor = Color.Red;
//picScanner2.BackColor = Color.Green;
picScanner1.Width = picScanner2.Width = pnlScannerImg.ClientSize.Width / 2 - 5;
picScanner2.Left = picScanner1.Width + 5;
}
//开机
private void btnOpen_Click(object sender, EventArgs e)
{
//this.txtNote.Text = (currProductModel == null ? "NO" : currProductModel.Name);
Config.LoadAllConfig();
//设置程序最小/大线程池
// Get the current settings.
int minWorker, minIOC;
ThreadPool.GetMinThreads(out minWorker, out minIOC);
ThreadPool.SetMinThreads(25, minIOC);
//ThreadPool.SetMaxThreads(256, 256);
this.btnOpen.Enabled = false;
this.resetUIValue();
AddTextEvent(DateTime.Now,"设备启动", $"正在启动硬件设备(版本:v{ Assembly.GetExecutingAssembly().GetName().Version.ToString()})。。。");
warningLevel = WarningEnum.Normal;
this.btnStart.Enabled = this.btnEnd.Enabled = this.btnPause.Enabled = false;
//后台线程回调事件
devContainer = new DevContainer();
devContainer.StateChange = (state, msg) =>
{
if (state)
{
currentState = CurrentStateEnum.;
AddTextEvent(DateTime.Now,"设备启动", $"启动成功,请点开始验布按钮!");
//全局中断
devContainer.devIOCard.INEvent = globalBreakEvent;
// I/O reset后输出默认状态
if (devContainer.devIOCard.IsInit)
{
AddTextEvent(DateTime.Now,"复位", $"I/O复位...");
if (!devContainer.devIOCard.reset())
{
AddTextEvent(DateTime.Now,"复位", "I/O板卡复位失败", WarningEnum.High);
return;
}
if (!devContainer.io_output(CMDName.IO默认输出))
{
//AddTextEvent(DateTime.Now,"复位", "I/O板卡复位默认值失败", WarningEnum.High);
//return;
}
int portIndex = 0;
foreach(var data in devContainer.devIOCard.DIData)
AddTextEvent(DateTime.Now,"I/0状态", $"DIData: {portIndex++}-{Convert.ToString(data, 2)}");
}
devContainer.OutDebugEvent = (tag, debugInfo) =>
{
AddTextEvent(DateTime.Now,tag, debugInfo);
};
//
this.Invoke(new System.Action(() =>
{
this.btnOpen.Enabled = false;
this.btnClose.Enabled = true;
this.btnStart.Enabled = true;
this.tcbarLightValue.Enabled = true;
tcbarLightValue.Value=devContainer.devLight.getDigitalValue(1);
}));
devContainer.libPhoto.QueueCountEvent = (count) =>
{
this.BeginInvoke(new System.Action(() =>
{
this.lblWaitImageCount.Text = count.ToString();
}));
};
devContainer.libDefect.QueueCountEvent = (type, count) =>
{
this.BeginInvoke(new System.Action(() =>
{
switch (type)
{
case 0: this.lblDefectQueue0.Text = count.ToString(); break;
case 1: this.lblDefectQueue1.Text = count.ToString(); break;
case 2: this.lblDefectQueue2.Text = count.ToString(); break;
}
}));
};
//在【暂停】和【运行中】时都可以扫码,扫码后即开始即结束上一卷(如存在),自动开始下一卷,等待相机照片回调
devContainer.devCodeScanner.ScanerEvent = (barCode) =>
{
int errCode = 0;
try
{
//AddTextEvent(DateTime.Now,"扫码", $"{code}{currentState.ToString()}");
if (!devContainer.state || string.IsNullOrWhiteSpace(barCode)
|| (currentState != CurrentStateEnum. && currentState != CurrentStateEnum.))
return;
string barCodeName="",len = "0", batchId = "", reelId = "";
if (!string.IsNullOrWhiteSpace(Config.ErpDBConStr) && !string.IsNullOrWhiteSpace(Config.ErpSql) && !string.IsNullOrWhiteSpace(barCode))
{
AddTextEvent(DateTime.Now,"扫码", $"产品条码({barCode})到ERP查询对应数据...", WarningEnum.Normal);
var rowData = this.loadErpData(barCode);
if (rowData == null)
{
AddTextEvent(DateTime.Now,"扫码", $"产品条码({barCode})无对应ERP数据不做响应", WarningEnum.Low);
return;
}
barCodeName = rowData[0].ToString();
if (rowData.ItemArray.Length > 1) len = rowData[1].ToString();
if (rowData.ItemArray.Length > 2) batchId = rowData[2].ToString();
if (rowData.ItemArray.Length > 3) reelId = rowData[3].ToString();
}
else
barCodeName = barCode;//没有ERP对应关系时直接使用条码做为品名
errCode = 1;
//SHNY-PX-6-***
string[] codes = barCodeName.Split(new char[] { '-' });
if (codes.Length < 4)
{
AddTextEvent(DateTime.Now,"扫码", $"产品品名({barCodeName})格式错误,不做响应!", WarningEnum.Low);
return;
}
//新开始
this.resetUIValue(false);
errCode = 2;
//加载新产品
string pcode = "1-" + codes[2];
if (codes[1] == "0" || Config.SuedeList.Contains(codes[1]))
pcode = "0-" + codes[2];
var productInfo = svcProduct.GetModelNav(pcode); //frmProduct.loadProduct(code);
Records record;
lock (lockCurrKey)
{
errCode = 3;
//保存,这里队列图片可能还未检测完
if (currKey > 0)
{
string szBatchId, szReelId;
double ldErpLen;
szBatchId = txtBatchId.Text.Trim();
szReelId = txtReelId.Text.Trim();
ldErpLen = Convert.ToDouble(numErpLen.Text.Trim());
//BatchId = code,//code[2]
//ReelId = "1",//code[3]
int mykey = currKey;
Task.Run(() => { saveCurrRecord(mykey, szBatchId, szReelId, ldErpLen); });
currKey = 0;
}
if (productInfo == null)
{
AddTextEvent(DateTime.Now,"扫码", $"编码({pcode})对应配方不存在,请先添加产品配方设置,暂停设备!", WarningEnum.High);
warning(WarningEnum.Low);//暂停
this.BeginInvoke(new System.Action(() =>
{
frmProduct.loadProduct(pcode);//转到新建编码
}));
return;
}
errCode = 4;
var now = DateTime.Now;
currKey = now.Hour * 10000 + now.Minute * 100 + now.Second;
//var materialItem = codes[0]+"-"+ codes[1];
var colorItem = Config.getColorItem(int.Parse(codes[2]));
record = new Records()
{
currKey = currKey,
ProductId = productInfo.Id,
ProductInfo = productInfo,//后面计算合格时用
Color = (colorItem == null ? "未知" : colorItem["name"].ToString()),
Material = codes[0] + "-" + codes[1],// (materialItem == null ? "未知" : materialItem["name"].ToString()),
BarCode = barCode,
BarCodeName = barCodeName,
ErpLen=double.Parse(len),
BatchId=batchId,
ReelId=reelId,
ModifyUserCode = Config.loginUser.Code,
CreateUserCode = Config.loginUser.Code,
};
htTask.Add(currKey, record);
}
errCode = 8;
//
errCode = 9;
AddTextEvent(DateTime.Now,"扫码", $"品名({barCodeName}),加载产品信息({productInfo.Code})完成,加载配方(光源={productInfo.LightValue},曝光={productInfo.ExposureTime},增益={productInfo.Gain})...");
errCode = 10;
if (productInfo.LightValue > 0)//光源 - 通道0
devContainer.devLight.setDigitalValue(1, productInfo.LightValue);
errCode = 11;
if (productInfo.ExposureTime > 0 || productInfo.Gain > 0)//相机曝光 增益
{
devContainer.devCamer1.setParam((float)(productInfo.ExposureTime > 0 ? productInfo.ExposureTime : -1), (float)(productInfo.Gain > 0 ? productInfo.Gain : -1));
devContainer.devCamer2.setParam((float)(productInfo.ExposureTime > 0 ? productInfo.ExposureTime : -1), (float)(productInfo.Gain > 0 ? productInfo.Gain : -1));
}
errCode = 15;
AddTextEvent(DateTime.Now,"扫码", $"品名({barCodeName}),配方设置完成:光源={productInfo.LightValue},曝光={productInfo.ExposureTime}");
//注意,这里和修改页共享操作(UI操作),注意冲突
this.Invoke(new System.Action(() =>
{
this.txtBarCode.Text = "";
this.txtBarCodeName.Text= barCodeName;
//txtBatchId.Text = record.BatchId;
//txtReelId.Text = record.ReelId;
this.numErpLen.Text = len;
this.txtBatchId.Text = batchId;
this.txtReelId.Text = reelId;
//暂时全部放开
//this.btnStart.Enabled = true;
//this.btnEnd.Enabled = true;
this.btnPause.Enabled = true;
//
this.swcDefectPauseForUser.Active = this.defectPauseForUser = productInfo.DefectPauseForUser;
}));
//
pStopWatch.Restart();
errCode = 19;
}
catch (Exception ex)
{
AddTextEvent(DateTime.Now,"扫码", $"异常({errCode}):{ex.Message}", WarningEnum.High);
}
};
//相机回调出照片
devContainer.devCamer1.ScanEvent = callBackScanMatEvent;
devContainer.devCamer2.ScanEvent = callBackScanMatEvent;
//devContainer.devScannerGentl1.ScanEventPath = callBackScanPathEvent;
//devContainer.devScannerGentl2.ScanEventPath = callBackScanPathEvent;
devContainer.devCamer1.PhotoNumCacheEvent = (num) =>
{
this.BeginInvoke(new System.Action(() =>
{
this.lblScanner1Cache.Text =num.ToString();
}));
};
devContainer.devCamer2.PhotoNumCacheEvent = (num) =>
{
this.BeginInvoke(new System.Action(() =>
{
this.lblScanner2Cache.Text = num.ToString();
}));
};
devContainer.devPlc.RuningStateChangeEvent = (runningState) =>
{
AddTextEvent(DateTime.Now,"PLC", $"当前状态为:{(runningState ? "" : "")}");
if (runningState)
this.startCommand();
else
this.pauseCommand();
};
//devContainer.devIOCard.INEvent = (i,value) =>
//{
// AddTextEvent(DateTime.Now,"I/O", $"INEvent 当前值:{i}-{value}");
// if (compareIOInput(CMDName.启动按钮))
// {
// this.startCommand();
// }
// else if (compareIOInput(CMDName.暂停按钮))
// {
// this.pauseCommand(true);
// }
//};
}
else
{
AddTextEvent(DateTime.Now,"设备启动", $"启动失败,{msg}", WarningEnum.High);
this.Invoke(new System.Action(() =>
{
this.btnOpen.Enabled = true;
this.btnClose.Enabled = false;
}));
}
};
devContainer.WarningEvent = (now,level, msg) =>
{
AddTextEvent(DateTime.Now,$"设备事件{Thread.CurrentThread.ManagedThreadId}", msg, level);
if (level == WarningEnum.High)
Task.Run(() => warning(level, true));
};
devContainer.start(this.picScanner1, this.picScanner2);
//devContainer.start(IntPtr.Zero,IntPtr.Zero);
}
private DataRow loadErpData(string barCode)
{
var paramList = new List<SugarParameter>() {
new SugarParameter("@code", barCode)
};
Stopwatch stopwatch = Stopwatch.StartNew();
var data = Utils.DBUtils.execSql(Config.ErpSql, paramList);
if (data != null && data.Rows.Count < 1)
{
AddTextEvent(DateTime.Now,"Erp查询结果", $"{barCode}: 时长={stopwatch.ElapsedMilliseconds}ms, 无数据!", WarningEnum.Normal);
return null;
}
AddTextEvent(DateTime.Now,"Erp查询结果", $"{barCode}: 时长={stopwatch.ElapsedMilliseconds}ms, {JsonConvert.SerializeObject(data.Rows[0])}", WarningEnum.Normal);
return data.Rows[0];
//Task.Run(() =>
//{
// try
// {
// var paramList = new List<SugarParameter>() {
// new SugarParameter("@code", code)
// };
// Stopwatch stopwatch = Stopwatch.StartNew();
// var data = Utils.DBUtils.execSql(Config.ErpSql, paramList);
// AddTextEvent(DateTime.Now,"Erp查询结果", $"{code}: 时长={stopwatch.ElapsedMilliseconds}ms, {JsonConvert.SerializeObject(data.Rows[0])}", WarningEnum.Normal);
// if (data != null && data.Rows.Count > 0)
// {
// this.Invoke(new System.Action(() =>
// {
// this.numErpLen.Text = data.Rows[0][0].ToString();
// if (data.Columns.Count > 1) this.txtBatchId.Text = data.Rows[0][1].ToString();
// if (data.Columns.Count > 2) this.txtReelId.Text = data.Rows[0][2].ToString();
// }));
// }
// }
// catch (Exception ex)
// {
// AddTextEvent(DateTime.Now,"Erp查询异常", $"{code}:{ex.Message}", WarningEnum.Low);
// }
//});
}
private class ScanPhotoInfo
{
/// <summary>
///
/// </summary>
/// <param name="_devIndex"></param>
/// <param name="_photoIndex">1-n 第1张会把1改为0</param>
/// <param name="_path"></param>
public ScanPhotoInfo(int _devIndex,int _photoIndex,string _path)
{
devIndex = _devIndex;
photoIndex = _photoIndex;
path = _path;
}
public ScanPhotoInfo(int _devIndex, int _photoIndex, Mat _mat)
{
devIndex = _devIndex;
photoIndex = _photoIndex;
mat = _mat;
}
public int devIndex { get; set; }
/// <summary>
/// 0-n
/// </summary>
public int photoIndex { get; set; }
public string path { get; set; }
public Mat mat { get; set; }
}
//private List<Queue<ScanPhotoInfo>> scanPhotoQueue1 = new List<Queue<ScanPhotoInfo>>();
/// <summary>
/// 存放相机1/2的实时图像3-多容错1帧
/// </summary>
private ScanPhotoInfo[] scanPhotos=new ScanPhotoInfo[3];
private void callBackScanPathEvent(int num, string path, int devIndex) //ScanEvent
{
AddTextEvent(DateTime.Now,"拍照", $"相机({devIndex})采集图索到图像({num}):{path}");
}
bool firstTest = true;
/// <summary>
///
/// </summary>
/// <param name="num">1-n</param>
/// <param name="matone"></param>
/// <param name="devIndex"></param>
private void callBackScanMatEvent(int num, Mat matone, int devIndex) //ScanEvent
{
int errStep = 0;
try
{
if (Config.Camer_Name == CamerDevNameEnum.)
{
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"采集卡({devIndex}),图像({num})");
Cv2.Flip(matone, matone, FlipMode.XY);//翻转
Bitmap bitmap = BitmapConverter.ToBitmap(matone);
this.BeginInvoke(new Action(() =>
{
//bitmap.Save($"d:\\{devIndex}_{num}.bmp", ImageFormat.Bmp);
//显示图片
if (devIndex == 0)
{
picScanner2.Image = bitmap;
picScanner2.Refresh();
}
else
{
picScanner1.Image = bitmap;
picScanner1.Refresh();
}
}));
}
errStep = 1;
if (!devContainer.state || (currentState != CurrentStateEnum. && currentState != CurrentStateEnum.))
{
matone.Dispose();
return;
}
errStep = 2;
lock (lockCurrKey)
{
if (currKey == 0 || !htTask.ContainsKey(currKey))
{
lock (lockScanPhoto)
{
if (scanPhotos[0] != null || scanPhotos[1] != null)
scanPhotos[0] = scanPhotos[1] = scanPhotos[2] = null;
}
matone.Dispose();
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"(图像{num})-未扫码,采集卡({devIndex}),图像丢弃!", WarningEnum.Low);
return;
}
}
errStep = 3;
Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
Device.PhotoLib.PhotoTask task;
Mat myMat = matone;//.Clone();
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"(图像{num})-采集卡({devIndex}),size:({myMat.Width}*{myMat.Height})({(myMat == null ? "A" : "B")})");
//AddTextEvent(DateTime.Now,"拍照", $"Dev={devIndex},图像{num}-2");
lock (lockScanPhoto)//多线程操作
{
if (scanPhotos[2] != null && scanPhotos[2].photoIndex == num)
{
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"相机图像不同步,急停中止(需停机重新开始,不可继续)!!!", WarningEnum.High);
warning(WarningEnum.High);
//重置...
}
if (scanPhotos[devIndex] != null) //添加一张容错
{
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"(图像{num})-采集卡({devIndex}) 容错一张图到队列!", WarningEnum.Low);
scanPhotos[2] = new ScanPhotoInfo(devIndex, num, myMat);
return;
}
errStep = 4;
//--
scanPhotos[devIndex] = new ScanPhotoInfo(devIndex, num, myMat);
if (scanPhotos[0] == null || scanPhotos[1] == null)
return;
//
//if (scanPhotos[0].photoIndex != scanPhotos[1].photoIndex)
//{
// if (scanPhotos[0].photoIndex > scanPhotos[1].photoIndex)
// {
// AddTextEvent(DateTime.Now,$"拍照{Thread.CurrentThread.ManagedThreadId}", $"(图像{num})-索引不一致),丢弃采集卡({scanPhotos[1].devIndex})中较小索引图像({scanPhotos[1].photoIndex}", WarningEnum.High);
// scanPhotos[1] = null;
// }
// else
// {
// AddTextEvent(DateTime.Now,$"拍照{Thread.CurrentThread.ManagedThreadId}", $"(图像{num})-索引不一致),丢弃采集卡({scanPhotos[0].devIndex})中较小索引图像({scanPhotos[0].photoIndex}", WarningEnum.High);
// scanPhotos[0] = null;
// }
// if (num > 1)
// {
// AddTextEvent(DateTime.Now,$"拍照{Thread.CurrentThread.ManagedThreadId}", $"相机图像不同步,急停中止(需停机重新开始,不可继续)!!!", WarningEnum.High);
// warning(WarningEnum.High);
// //重置...
// }
// return;
//}
//curRecord置新时相机里最后一张图还是上次的计数器devIndex累计
if (curRecord.ScannerPhotoCount == 0 && num >= 1)
{
devContainer.devCamer1.resetScanIndex();
devContainer.devCamer2.resetScanIndex();
scanPhotos[0].photoIndex = scanPhotos[1].photoIndex = 0;
if (scanPhotos[2] != null)
scanPhotos[2].photoIndex = 1;
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"新任务开始Dev={devIndex},图像({num})重置为图像(0)");
}
task = new Device.PhotoLib.PhotoTask()
{
scanPhotos0 = scanPhotos[0],
scanPhotos1 = scanPhotos[1],
};
scanPhotos[0] = scanPhotos[1] = null;
if (scanPhotos[2] != null)//容错图前移到正常位置
{
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"(图像{scanPhotos[2].photoIndex})-采集卡({scanPhotos[2].devIndex}) 容错队列图前移。");
scanPhotos[scanPhotos[2].devIndex] = scanPhotos[2];
scanPhotos[2] = null;
}
curRecord.ScannerPhotoCount++;
errStep = 5;
}
//长度剩余提醒
if (Config.residueWarnningLen > 0 && curRecord.ErpLen > 0 && Config.residueWarnningLen >= curRecord.ErpLen - curRecord.Len)
{
AddTextEvent(DateTime.Now, $"告警{Thread.CurrentThread.ManagedThreadId}", $"已达剩余长度不足提醒!({curRecord.ErpLen - curRecord.Len}<={Config.residueWarnningLen})", WarningEnum.High);
//warning(WarningEnum.Low, true);//暂停
}
errStep = 6;
//
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"待处理图像队列:{curRecord.ScannerPhotoCount - curRecord.ScannerPhotoFinishCount}张");
if (task.scanPhotos0 != null && task.scanPhotos1 != null)
{
var scanPhoto = task.scanPhotos0 as ScanPhotoInfo;
curRecord.dicPhoto_Defect.TryAdd(scanPhoto.photoIndex, false);//加入索引,默认无瑕疵
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"图像索引:{scanPhoto.photoIndex},标识数:{curRecord.dicPhoto_Defect.Count}");
errStep = 7;
//暂停:瑕疵二次判断
if (this.defectPauseForUser)
{
int liPhotoIndex = scanPhoto.photoIndex - Config.defectPauseSkipPhotoCount;
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"Dev={devIndex},图像{scanPhoto.photoIndex} {liPhotoIndex}={scanPhoto.photoIndex}-{Config.defectPauseSkipPhotoCount}{JsonConvert.SerializeObject(curRecord.dicPhoto_Defect)}");
if (liPhotoIndex >= 0 && curRecord.dicPhoto_Defect[liPhotoIndex])
{
List<DefectInfo> lstEditDefect = curRecord.DefectInfoList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
AddTextEvent(DateTime.Now, $"暂停{Thread.CurrentThread.ManagedThreadId}", $"(图像{liPhotoIndex})已达观察台,瑕疵二次判断=》({string.Join(",", lstEditDefect.Select(m => m.Code).ToArray())})是否包含在({string.Join(",", curRecord.ProductInfo.DefectPauseOption.ToArray())})中。");
//瑕疵选项过滤
if (curRecord.ProductInfo.DefectPauseOption.Count == 0 || lstEditDefect.Where(x => curRecord.ProductInfo.DefectPauseOption.Contains(x.Code)).Count() > 0)
{
AddTextEvent(DateTime.Now, $"暂停{Thread.CurrentThread.ManagedThreadId}", $"(图像{liPhotoIndex})需瑕疵二次判断,已达观察台,进入暂停。");
if (!Config.StopPLC)
this.devContainer.devPlc.pauseDev();
else if (!Config.StopIO && devContainer.devIOCard.IsInit)
{
//只是设备暂停APP没暂停
devContainer.io_output(CMDName.绿, false, true, 0);
devContainer.io_output(CMDName.);
devContainer.devIOCard.writeBitState(0, 1, true);
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 1, false);
});
}
errStep = 8;
//不能使用同步Invoke方式会使相机超时丢帧
this.BeginInvoke(new System.Action(() =>
{
int liDefectCount = lstEditDefect.Count;
FHome_Defect frmDefect = new FHome_Defect(lstEditDefect);
if (frmDefect.ShowDialog() == DialogResult.OK)
{
string oldCode;
for (int i = 0; i < this.uiDataGridView1.Rows.Count; i++)
{
if ((int)this.uiDataGridView1.Rows[i].Cells["colIndex"].Value != liPhotoIndex)
continue;
long uid = (long)this.uiDataGridView1.Rows[i].Cells["colUid"].Value;
foreach (var row in lstEditDefect)
{
AddTextEvent(DateTime.Now, $"暂停{Thread.CurrentThread.ManagedThreadId}", $"修改第({i + 1})行瑕疵名称,{uid} {row.uid}");
if (row.uid == uid)
{
oldCode = this.uiDataGridView1.Rows[i].Cells["colCode"].Value.ToString();
AddTextEvent(DateTime.Now, $"暂停{Thread.CurrentThread.ManagedThreadId}", $"修改第({i + 1})行瑕疵名称 ({this.uiDataGridView1.Rows[i].Cells["colDefectName"].Value})->({row.Name})");
this.uiDataGridView1.Rows[i].Cells["colCode"].Value = row.Code;
this.uiDataGridView1.Rows[i].Cells["colDefectName"].Value = row.Name;
//this.uiDataGridView1.Refresh();
if (!string.IsNullOrWhiteSpace(row.TagFilePath))
File.Move(row.TagFilePath, row.TagFilePath.Replace($"_类别{oldCode}", $"_类别{row.Code}"));//
break;
}
}
foreach (var item in frmDefect.lstDel)
{
if (item.uid == uid)
{
this.uiDataGridView1.Rows.RemoveAt(i);
i--;
break;
}
}
}
foreach (var item in frmDefect.lstDel)
{
curRecord.DefectInfoList.Remove(item);
//删除忽略瑕疵小图
//if (!string.IsNullOrWhiteSpace(item.TagFilePath))
// File.Delete(item.TagFilePath);
}
//double len = (double)this.lblLen.Tag;
//this.reDrawDefectPoints(curRecord.DefectInfoList, new double[] { 0, Math.Round(curRecord.FaceWidthMax + 0.005f, 2) }, new double[] { 0, len });
AddTextEvent(DateTime.Now, $"二次检测{Thread.CurrentThread.ManagedThreadId}", $"本次忽略{frmDefect.lstDel.Count}个瑕疵,本张图由{liDefectCount} -> {lstEditDefect.Count},总数{curRecord.DefectInfoList.Count}");
}
this.uiMiniPagination1.TotalCount = curRecord.DefectTotalCount = curRecord.DefectInfoList.Count;
//
//double len = Math.Round((res.photoIndex + 1) * bmpHeight * 1.0d / Config.cm2px_y + 0.005f, 2);
this.reDrawDefectPoints(curRecord.DefectInfoList);
errStep = 9;
//自动继续运行设备(这里临时暂停后不能再急停,否则无法继续)
if (!Config.StopPLC)
this.devContainer.devPlc.runDev();
else if (!Config.StopIO && devContainer.devIOCard.IsInit)
{
if (!compareIOInput(CMDName.))
{
devContainer.io_output(CMDName.绿);
devContainer.io_output(CMDName., false, true, 0);
this.devContainer.devIOCard.writeBitState(0, 0, true);
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 0, false);
});
}
}
}));
}
}
}
errStep = 10;
task.record = curRecord;
task.finishEvent = callBackPhotoEvent;
devContainer.libPhoto.add(task);
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"Dev={devIndex},图像{scanPhoto.photoIndex},已加入图像处理队列");
errStep = 11;
}
}
catch (Exception e)
{
AddTextEvent(DateTime.Now, $"拍照{Thread.CurrentThread.ManagedThreadId}", $"errStep:{errStep}-{e.Message}", WarningEnum.High);
}
}
private void callBackPhotoEvent(Device.PhotoLib.PhotoTask task)
{
int errStep = 0;
Records curRecord = task.record;
ScanPhotoInfo scanPhotos0 = task.scanPhotos0 as ScanPhotoInfo;
ScanPhotoInfo scanPhotos1 = task.scanPhotos1 as ScanPhotoInfo;
Stopwatch stopWatch = new Stopwatch();
AddTextEvent(DateTime.Now,$"图像处理{Thread.CurrentThread.ManagedThreadId}", $"图像{scanPhotos0.photoIndex}ThreadId={Thread.CurrentThread.ManagedThreadId}");
string time = "";
stopWatch.Start();
try
{
if (scanPhotos0.mat.Height != scanPhotos1.mat.Height)
{
AddTextEvent(DateTime.Now,$"警告{Thread.CurrentThread.ManagedThreadId}", $"两相机采集图高度不一致({scanPhotos0.photoIndex}),dev1.Height={scanPhotos0.mat.Height},dev2.Height={scanPhotos1.mat.Height},重新resize...", WarningEnum.Low);
if (scanPhotos0.mat.Height > scanPhotos1.mat.Height)
scanPhotos1.mat = OpenCVUtil.resize(scanPhotos1.mat, scanPhotos0.mat.Width, scanPhotos0.mat.Height);
else
scanPhotos0.mat = OpenCVUtil.resize(scanPhotos0.mat, scanPhotos1.mat.Width, scanPhotos1.mat.Height);
}
//saveMatTest(scanPhotos0.mat, 1);
//saveMatTest(scanPhotos1.mat, 2);
//反转+相机索引调换
Mat mat0 = scanPhotos1.mat;
Mat mat1 = scanPhotos0.mat;
if (Config.ScannerReversalX)
{
Cv2.Flip(mat0, mat0, FlipMode.X);
errStep = 1;
Cv2.Flip(mat1, mat1, FlipMode.X);
time += $"X翻转({stopWatch.ElapsedMilliseconds})";
}
if (Config.ScannerReversalY)
{
Cv2.Flip(mat0, mat0, FlipMode.Y);
errStep = 2;
Cv2.Flip(mat1, mat1, FlipMode.Y);
time += $"Y翻转({stopWatch.ElapsedMilliseconds})";
}
firstTest = false;
//记录resize大小
//var resize = new System.Drawing.Size(mat0.Width * 2, mat0.Height);
int resizeWidth = devContainer.libDefect.GetWidthForResize(mat0.Width+ mat1.Width - Config.MiddleSuperposition);
if (resizeWidth == 0)
throw new Exception("GetWidthForResize result 0 失败!");
var resize = new System.Drawing.Size(resizeWidth, 4096);//固定8192*2张*4096
//裁边,两侧和中间重合部分
if (Config.MiddleSuperposition > 0)//中间重合部分
{
errStep = 3;
int width = mat0.Width - Config.MiddleSuperposition;
mat0 = OpenCVUtil.cutImage(mat0, 0, 0, width, mat0.Height);
time += $"->图1去重({stopWatch.ElapsedMilliseconds})";
}
AddTextEvent(DateTime.Now,$"裁边{Thread.CurrentThread.ManagedThreadId}",
$"(图像{scanPhotos0.photoIndex})-左图去重后:{mat0.Width}*{mat0.Height},右图:{mat1.Width}*{mat1.Height}" +
$"重复值:{Config.MiddleSuperposition},孔洞:{Config.MarginHoleWidth},cm2px{Config.cm2px_x},resizeWidth{resizeWidth}");
errStep = 4;
//mat0 = OpenCVUtil.getMaxInsetRect(mat0);
int marginWidth0, marginWidth1;
mat0 = OpenCVUtil.getMaxInsetRect2(mat0, true, Config.MarginHoleWidth,out marginWidth0);
//AddTextEvent(DateTime.Now,"裁边", $"(图像{scanPhotos0.photoIndex})-图0裁边后{mat0.Width}*{mat0.Height}");
errStep = 5;
time += $"->图1裁边({stopWatch.ElapsedMilliseconds})";
//mat1 = OpenCVUtil.getMaxInsetRect(mat1);
mat1 = OpenCVUtil.getMaxInsetRect2(mat1,false, Config.MarginHoleWidth, out marginWidth1);
//AddTextEvent(DateTime.Now,"裁边", $"(图像{scanPhotos0.photoIndex})-图1裁边后{mat1.Width}*{mat1.Height}");
errStep = 6;
time += $"->图2裁边({stopWatch.ElapsedMilliseconds})";
//水平合并l
Mat mat = OpenCVUtil.mergeImage_sameSize(new Mat[] { mat0, mat1 });//这里相机反装,左右反转下
AddTextEvent(DateTime.Now,$"裁边{Thread.CurrentThread.ManagedThreadId}", $"(图像{scanPhotos0.photoIndex})-边缘宽度:(左图)={marginWidth0},(右图)={marginWidth1}; 裁边去孔洞后:({mat0.Width}+{mat1.Width}={mat0.Width+ mat1.Width});合并后(去孔洞){mat.Width}*{mat.Height}");
float widthRatio = mat.Width * 1.0f / resize.Width;//宽度比例
time += $"->图1+2合并({stopWatch.ElapsedMilliseconds})";
//门幅更新含两侧孔洞x,y cm
float faceWidthX_cm = (float)Math.Round((scanPhotos0.photoIndex+1) * mat.Height * 1.0f / Config.cm2px_y,2);
float faceWidthY_cm = (float)Math.Round((mat.Width + Config.MarginHoleWidth * 2) * 1.0f / Config.cm2px_x, 2);
faceWidthX_cm = (float)Math.Round(faceWidthX_cm, 2);
faceWidthY_cm = (float)Math.Round(faceWidthY_cm, 2);
if (curRecord.FaceWidthMin==0 || curRecord.FaceWidthMin > faceWidthY_cm)
curRecord.FaceWidthMin = faceWidthY_cm;
if (curRecord.FaceWidthMax < faceWidthY_cm)
curRecord.FaceWidthMax = faceWidthY_cm;
var point = new float[] { faceWidthX_cm, faceWidthY_cm };// new System.Drawing.PointF(faceWidthX_cm, faceWidthY_cm);
AddTextEvent(DateTime.Now,$"门幅{Thread.CurrentThread.ManagedThreadId}", $"(图像{scanPhotos0.photoIndex})-({scanPhotos0.photoIndex})位置:{point[0]}; 幅宽:{point[1]}");
curRecord.FacePointList.Add(point);
reDrawFaceWidth(curRecord.FacePointList,
new double[] { 0, Math.Round(point[0] + 0.005f, 2) },
new double[] { curRecord.FaceWidthMin, Math.Round(curRecord.FaceWidthMax + 0.005f, 2) });
errStep = 7;
time += $"->门幅刷新({stopWatch.ElapsedMilliseconds})";
//去除两侧孔洞(门幅计算时不能去除)
//if (Config.MarginHoleWidth > 0)
// mat = OpenCVUtil.cutImage(mat, Config.MarginHoleWidth, 0, mat.Width - Config.MarginHoleWidth * 2, mat.Height);
//计算速度
double lenMi = Math.Round(faceWidthX_cm / 100, 2);
curRecord.Len = lenMi;
curRecord.TimeLen= pStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
this.BeginInvoke(new System.Action(() =>
{
this.lblLen.Text = $"{lenMi}米";
this.lblLen.Tag = faceWidthX_cm;
this.lblSpeed.Text = $"速度:{Math.Round(lenMi / curRecord.TimeLen, 2)}米/分";
}));
//
errStep = 9;
time += $"->速度刷新({stopWatch.ElapsedMilliseconds})";
//----缺陷队列
mat = OpenCVUtil.resize(mat, resize.Width, resize.Height);
AddTextEvent(DateTime.Now,$"图像处理{Thread.CurrentThread.ManagedThreadId}", $"(图像{scanPhotos0.photoIndex})-合成图resize后:{mat.Width}*{mat.Height}");
devContainer.libDefect.add(new Device.DefectLib.DefectTask()
{
modelName= curRecord.ProductInfo.ModelName,
record = curRecord,
bmp = mat,
bmpTag = mat.Clone(),
photoIndex = scanPhotos0.photoIndex,//0-n 首张必需为0因下面计算长度是从0开始
widthRatio = widthRatio,
qualifiedLimitList = curRecord.ProductInfo.QualifiedLimitList,
finishEvent = callBackDefectEvent,
});
errStep = 10;
time += $"->加入瑕疵待检队列({stopWatch.ElapsedMilliseconds})";
}
catch (Exception ex)
{
curRecord.ScannerPhotoFinishCount++;//失败时不能因数量不一致无法保存
AddTextEvent(DateTime.Now,$"图像处理{Thread.CurrentThread.ManagedThreadId}", $"异常({errStep})(图像{scanPhotos0.photoIndex})-{ex.Message}", WarningEnum.High);
string dirPath = FileUtil.initFolder($"{Config.ImagePath}{curRecord.BatchId}_{curRecord.ReelId}\\Err\\");
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos0.mat).Save($"{dirPath}{scanPhotos0.photoIndex}_0_Step{errStep}.bmp", ImageFormat.Bmp);
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos1.mat).Save($"{dirPath}{scanPhotos1.photoIndex}_1_Step{errStep}.bmp", ImageFormat.Bmp);
}
finally
{
AddTextEvent(DateTime.Now,$"图像处理{Thread.CurrentThread.ManagedThreadId}", $"(图像{scanPhotos0.photoIndex})-进度计时:{time}");
scanPhotos0.mat.Dispose();
scanPhotos1.mat.Dispose();
scanPhotos0 = scanPhotos1 = null;
task = null;
System.GC.Collect();
}
}
private void callBackDefectEvent(Device.DefectLib.DefectTask res)
{
{
int step = 0;
try
{
AddTextEvent(DateTime.Now,$"检测完成{Thread.CurrentThread.ManagedThreadId}", $"图像队列:{res.record.ScannerPhotoFinishCount+1}/{res.record.ScannerPhotoCount} (图像{res.photoIndex})检测结果:{res.isSucceed}");
string dirPath = FileUtil.initFolder($"{Config.ImagePath}{res.record.BatchId}_{res.record.ReelId}\\");
string dirSourcePath = FileUtil.initFolder($"{Config.ImagePath}{res.record.BatchId}_{res.record.ReelId}\\源图\\");
//Cv2.Flip(res.bmp, res.bmp, FlipMode.XY);//翻转
if (Config.IsSaveAllImage)//保存所有原图
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirSourcePath}{res.photoIndex}.bmp", ImageFormat.Bmp);
if (res.isSucceed)
{
step = 1;
AddTextEvent(DateTime.Now,$"检测完成{Thread.CurrentThread.ManagedThreadId}", $"(图像{res.photoIndex})-瑕疵检测完成,共{res.excelTable.Rows.Count}个瑕疵!各环节用时:{string.Join(",",res.stopwatch)}");
//AddTextEvent(DateTime.Now,$"打标完成", $"第 ({res.photoIndex}) 张照片,计算过程:{res.resultInfo}");
if (!Config.IsSaveAllImage && Config.IsSaveDefectSourceImage)
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirSourcePath}{res.photoIndex}.bmp", ImageFormat.Bmp);
step = 2;
if (res.excelTable.Rows.Count > 0)
{
res.record.dicPhoto_Defect[res.photoIndex] = true;//改为此图有瑕疵
//有瑕疵打标图必需保存 Jpeg
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmpTag).Save($"{dirPath}{res.photoIndex}_tag.jpg", ImageFormat.Jpeg);
step = 3;
res.record.DefectTotalCount += res.excelTable.Rows.Count;
if (res.record.DefectInfoList == null)
res.record.DefectInfoList = new List<DefectInfo>();
step = 4;
JObject defectNameInfo;
DefectInfo defectInfo=null;
List<object[]> dataRowlist=new List<object[]>();
long preTicks = pStopWatch.ElapsedMilliseconds;// DateTime.Now.Ticks;
for (int i = 0; i < res.lstDefectBmp.Count; i++)
{
step = 5 + i * 10;
defectNameInfo = Config.getDefectItem(int.Parse(res.excelTable.Rows[i]["类别"].ToString()));
defectInfo = new DefectInfo
{
PhotoIndex = res.photoIndex,
Code = defectNameInfo.Value<string>("code"),
Name = defectNameInfo.Value<string>("name"),
X = double.Parse(res.excelTable.Rows[i]["X"].ToString()),//cm
Y = Math.Round((res.photoIndex * res.bmp.Height * 1.0d / Config.cm2px_y + double.Parse(res.excelTable.Rows[i]["Y"].ToString())), 2),//cm
Width = double.Parse(res.excelTable.Rows[i]["W"].ToString()),//cm
Height = double.Parse(res.excelTable.Rows[i]["H"].ToString()),//cm
ZXD = double.Parse(res.excelTable.Rows[i]["置信度"].ToString()),
Contrast = double.Parse(res.excelTable.Rows[i]["对比度"].ToString()),
Target = int.Parse(res.excelTable.Rows[i]["目标"].ToString()),
image = BitmapConverter.ToBitmap(res.lstDefectBmp[i])
};
defectInfo.ModifyUserCode = defectInfo.CreateUserCode = res.record.CreateUserCode;
step = 6 + i * 10;
res.record.DefectInfoList.Add(defectInfo);
defectInfo.uid = preTicks++;// res.record.DefectInfoList.Count;//程序中的唯一索引,用于移除用索引
//AddTextEvent(DateTime.Now,$"打标完成", $"第{i}个缺陷:{ JsonConvert.SerializeObject(defectInfo)}; Y={res.photoIndex * res.bmp.Height * 1.0d / Config.cm2px_y}+{res.excelTable.Rows[i]["Y"].ToString()}");
step = 7 + i * 10;
//保存打标小图
if (Config.IsSaveDefectCutImage)
{
string filename = $"{dirPath}\\{res.photoIndex}_X{defectInfo.X}_Y{defectInfo.Y}_W{defectInfo.Width}_H{defectInfo.Height}_目标{defectInfo.Target}_类别{defectInfo.Code}_置信度{defectInfo.ZXD}.jpg";
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.lstDefectBmp[i]).Save(filename, ImageFormat.Jpeg);
defectInfo.TagFilePath = filename;
}
step = 8 + i * 10;
res.lstDefectBmp[i].Dispose();
dataRowlist.Add(new object[]{ defectInfo.uid,defectInfo.Code, defectInfo.PhotoIndex,defectInfo.Name,
defectInfo.CentreX, defectInfo.CentreY / 100,defectInfo.Width * 10,defectInfo.Height * 10, defectInfo.Area * 100, defectInfo.ZXD, defectInfo.Contrast});
//更新UI
//this.Invoke(new System.Action(() =>
//{
// this.uiDataGridView1.Rows.Insert(0, );
// this.uiMiniPagination1.TotalCount = res.record.DefectInfoList.Count;
// if (this.uiDataGridView1.Rows.Count == 1)
// this.picDefectImage.loadImage(defectInfo.image);
//}));
step = 9 + i * 10;
//告警判断???在此还是在收到新照片时触发???
if (res.record.ProductInfo.DefectAreaLimit > 0 && defectInfo.Area>=res.record.ProductInfo.DefectAreaLimit)
{
AddTextEvent(DateTime.Now,$"告警{Thread.CurrentThread.ManagedThreadId}", $"瑕疵面积达到阈值!({defectInfo.Area}>={res.record.ProductInfo.DefectAreaLimit})", WarningEnum.High);
}
}
AddTextEvent(DateTime.Now,$"检测完成{Thread.CurrentThread.ManagedThreadId}", "更新UI");
//更新UI
int bmpHeight = res.bmp.Height;
this.BeginInvoke(new System.Action(() =>
{
//这里显示了第1张图的最后一个缺陷
if (this.uiDataGridView1.Rows.Count == 0 && defectInfo!=null)
this.picDefectImage.loadImage(defectInfo.image);
foreach (var rowItem in dataRowlist)
this.uiDataGridView1.Rows.Insert(0, rowItem);
this.uiMiniPagination1.TotalCount = res.record.DefectInfoList.Count;
//
double len = Math.Round((res.photoIndex + 1) * bmpHeight * 1.0d / Config.cm2px_y+0.005f, 2);
this.reDrawDefectPoints(res.record.DefectInfoList, new double[] { 0, Math.Round(res.record.FaceWidthMax+ 0.005f, 2) }, new double[] { 0, len });
}));
step = 9;
AddTextEvent(DateTime.Now,$"检测完成{Thread.CurrentThread.ManagedThreadId}", "保存CSV");
//保存CSV
bool b = Utils.ExcelUtil.DataTable2CSV($"{dirPath}{res.photoIndex}.csv", res.excelTable);
//AddTextEvent(DateTime.Now,$"打标完成", $"{res.tag}.xlsx {(b ? "保存成功!" : "保存失败!")}");
step = 10;
//每百米告警判断???在此还是在收到新照片时触发???
if (res.record.ProductInfo.DefectCountLimit > 0 && res.record.DefectTotalCount >= res.record.ProductInfo.DefectCountLimit)
{
int compLen = 100 * 100;//每百米 to cm
int compCount = compLen * Config.cm2px_y / res.bmp.Height;
//从上次告警后重新开始计算长度及数量
int defectCount = res.record.DefectInfoList.Where(m => m.PhotoIndex >= res.record.preWarningPhotoIndex && m.PhotoIndex >= res.photoIndex+1 - compCount).Count();
if (defectCount >= res.record.ProductInfo.DefectCountLimit)
{
res.record.preWarningPhotoIndex = res.photoIndex + 1;
AddTextEvent(DateTime.Now,$"告警{Thread.CurrentThread.ManagedThreadId}", $"每百米瑕疵数量达到阈值!({defectCount}>={res.record.ProductInfo.DefectCountLimit})", WarningEnum.High);
}
}
}
}
else
{
AddTextEvent(DateTime.Now,$"打标失败{Thread.CurrentThread.ManagedThreadId}", $"(图像{res.photoIndex})-瑕疵检测失败TId={Thread.CurrentThread.ManagedThreadId}");
}
res.bmp.Dispose();
res.bmpTag.Dispose();
res.bmps_cut = null;
res.excelTable.Dispose();
}
catch (Exception ex)
{
AddTextEvent(DateTime.Now,$"打标失败{Thread.CurrentThread.ManagedThreadId}", $"(图像{res.photoIndex})-瑕疵检测异常({step}):{ex.Message}TId={Thread.CurrentThread.ManagedThreadId}");
}
finally
{
res.record.ScannerPhotoFinishCount++;
int liScannerPhotoFinishCount = res.record.ScannerPhotoFinishCount;
int liScannerPhotoCount = res.record.ScannerPhotoCount;
AddTextEvent(DateTime.Now,$"检测完成{Thread.CurrentThread.ManagedThreadId}", $"{liScannerPhotoFinishCount}/{liScannerPhotoCount}");
//this.BeginInvoke(new System.Action(() =>
//{
// this.lblWaitImageCount.Text = $"{liScannerPhotoCount - liScannerPhotoFinishCount}";
//}));
res = null;
System.GC.Collect();
}
}
}
private bool _isDefect = false;
private async void saveCurrRecord(int key, string batchId, string reelId, double erpLen)
{
Records model=null;
int step = 0;
try
{
_isDefect = true;
AddTextEvent(DateTime.Now,"入库", $"准备入库key={key}");
//foreach (int itemKey in htTask.Keys)
// AddTextEvent(DateTime.Now,"入库", $"htTask {itemKey}");
step = 1;
model = Hashtable.Synchronized(htTask)[key] as Records;
//model = htTask[key] as Records;
step = 2;
if (model.Len == 0)
{
_isDefect = false;
return;
}
model.BatchId = batchId;
model.ReelId = reelId;
model.ErpLen = erpLen;
while (model.ScannerPhotoCount > model.ScannerPhotoFinishCount)
await Task.Delay(100);
step = 3;
//计算等级标准
List<GradeLimit> gradeLimitList = model.ProductInfo.GradeLimitList;
if (gradeLimitList!=null && gradeLimitList.Count > 0)
{
step = 4;
int count;
foreach(GradeLimit item in gradeLimitList)
{
if((model.DefectInfoList != null)&&(model.DefectInfoList.Count >0))
count = model.DefectInfoList.Where(m => m.Code == item.Code).Count();
else
count = 0;
if (count <= item.A && model.Grade <= 1) model.Grade = 1;
else if (count <= item.B && item.B > 0 && model.Grade <= 2) model.Grade = 2;
else if (count <= item.C && item.C > 0 && model.Grade <= 3) model.Grade = 3;
else if (count <= item.D && item.D > 0 && model.Grade <= 4) model.Grade = 4;
else if (count <= item.E && item.E > 0 && model.Grade <= 5) model.Grade = 5;
else if (count>0) model.Grade = 6;//不合格
AddTextEvent(DateTime.Now,"标准判断", $"({key}) 批号({model.BatchId}),标准={(char)(model.Grade + 64)} [{item.Code}:{count};A<={item.A};B<={item.B};C<={item.C};D<={item.D};E<={item.E}]");
}
step = 5;
}
model.Qualified = (model.Grade < 6);//是否合格
if (!svcRecord.InsertNav(model))
throw new Exception("写库失败!");
AddTextEvent(DateTime.Now,"入库完成", $"({key}) 批号({model.BatchId})已完成检测。");
htTask.Remove(key);
_isDefect = false;
}
catch (Exception ex)
{
_isDefect = false;
if (model==null)
AddTextEvent(DateTime.Now,"入库失败", $"记录({key})不存在{step}" + ex.Message, WarningEnum.High);
else
AddTextEvent(DateTime.Now,"入库失败", $"({key}) 批号({model.BatchId})检测完成,但保存检测记录失败{step}:" + ex.Message, WarningEnum.High);
warning(WarningEnum.High, true);//暂停
}
}
//停机
private void btnClose_Click(object sender, EventArgs e)
{
if (currentState == CurrentStateEnum.)
{
UIMessageTip.ShowWarning("请先结束或暂停设备运行后再停机!", 2000);
return;
}
if(_isDefect)
{
UIMessageTip.ShowWarning("还在检测处理中,等待完成再停机!", 2000);
return;
}
AddTextEvent(DateTime.Now,"停机", "停机中...");
this.btnStart.Enabled = this.btnEnd.Enabled = this.btnPause.Enabled = false;
this.btnClose.Enabled = false;
this.btnOpen.Enabled = true;
tcbarLightValue.Enabled = false;
if (devContainer.state && devContainer.devIOCard.IsInit)
{
devContainer.devIOCard.reset();
devContainer.io_output(CMDName.IO默认输出);
}
devContainer.stop();
currentState = CurrentStateEnum.;//应该是待机
this.resetUIValue();
AddTextEvent(DateTime.Now,"停机", "停机完成。");
}
//启动
private void btnStart_Click(object sender, EventArgs e)
{
AddTextEvent(DateTime.Now,"启动", "下发启动指令...");
if (!Config.StopPLC)
this.devContainer.devPlc.runDev();
else if (!Config.StopIO && devContainer.devIOCard.IsInit)
{
if (!compareIOInput(CMDName.))//硬件急停
{
AddTextEvent(DateTime.Now, "启动", "下发IO指令...");
this.devContainer.devIOCard.writeBitState(0, 0, true);
this.startCommand();
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 0, false);
});
}
else
AddTextEvent(DateTime.Now, "启动", "设备急停!");
}
}
private void btnPause_Click(object sender, EventArgs e)
{
AddTextEvent(DateTime.Now,"暂停", "下发暂停指令...");
if (!Config.StopPLC)
this.devContainer.devPlc.pauseDev();
else if (!Config.StopIO && devContainer.devIOCard.IsInit)
{
//if (!compareIOInput(CMDName.暂停按钮))
this.devContainer.devIOCard.writeBitState(0, 1, true);
this.pauseCommand();//输出暂停不会触发输入暂停
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 1, false);
});
}
}
private void startCommand()
{
if (!devContainer.state || currentState == CurrentStateEnum.)
return;
if (devContainer.devIOCard.IsInit)
{
//devContainer.io_output(CMDName.启动按钮);
devContainer.io_output(CMDName.绿);
devContainer.io_output(CMDName., false, true, 0);
devContainer.io_output(CMDName., false, true, 0);
devContainer.io_output(CMDName., false, true, 0);
//devContainer.io_output(CMDName.暂停按钮, false, true, 0);
//devContainer.io_output(CMDName.黄灯输出, false, true, 0);
}
//运行中和暂停时都可正常接收扫描器触发新卷
//暂停-》继续
if (currentState == CurrentStateEnum.)
{
AddTextEvent(DateTime.Now,"启动", $"暂停 -> 继续");
currentState = CurrentStateEnum.;
Task.Run(() =>
{
if (currKey > 0)
pStopWatch.Start();
//写I/O启动。。。
//继续读取编译器和门幅等
//int nextStepId = currProcessIndex;
//do
//{
// currentState = CurrentStateEnum.运行中;
// nextStepId = nextProcess(currProductModel, nextStepId);
//} while (nextStepId >= 0 && !isBreakProcessRun());
});
}
else//首次开始/结束后重新开始
{
//校正从复位-》运行,不会新启动
resetUIValue();
AddTextEvent(DateTime.Now,"启动", "等待扫码...");
currentState = CurrentStateEnum.;
}
this.Invoke(new System.Action(() =>
{
this.btnStart.Enabled = false;
this.btnEnd.Enabled = this.btnPause.Enabled = true;
}));
}
private void pauseCommand(bool buzzer = false)
{
if(!devContainer.state || currentState != CurrentStateEnum.)
return;
//写IO
if (devContainer.devIOCard.IsInit)
{
devContainer.io_output(CMDName.绿, false, true, 0);
if (buzzer)
{
devContainer.io_output(CMDName.);
devContainer.io_output(CMDName.);
}
else
devContainer.io_output(CMDName.);
//devContainer.io_output(CMDName.暂停按钮, false, true, 0);
//devContainer.io_output(CMDName.黄灯输出, false, true, 0);
}
//停止读取
//AddTextEvent(DateTime.Now,"暂停", "暂停!");
pStopWatch.Stop();
currentState = CurrentStateEnum.;
this.Invoke(new System.Action(() =>
{
this.btnStart.Enabled = this.btnEnd.Enabled = true;
this.btnPause.Enabled = false;
}));
}
//完成
private void btnEnd_Click(object sender, EventArgs e)
{
AddTextEvent(DateTime.Now,"结束验布", "结束验布!");
if (!Config.StopPLC)
this.devContainer.devPlc.pauseDev();
else if (!Config.StopIO)
{
this.devContainer.devIOCard.writeBitState(0, 1, true);
Task.Run(async () =>
{
await Task.Delay(500);
this.devContainer.devIOCard.writeBitState(0, 1, false);
});
}
currentState = CurrentStateEnum.;
UILocalize.OK = "是";
UILocalize.Cancel = "否";
if (currKey > 0 && ShowAskDialog("提示", "是否保存当前检测结果?"))
{
string szBatchId, szReelId;
double ldErpLen;
szBatchId = txtBatchId.Text.Trim();
szReelId = txtReelId.Text.Trim();
ldErpLen = numErpLen.IsEmpty ? 0 : Convert.ToDouble(numErpLen.Text.Trim());
int myKey = currKey;
Task.Run(() => { saveCurrRecord(myKey, szBatchId, szReelId, ldErpLen); });
resetUIValue();
pStopWatch.Stop();
this.btnStart.Enabled = true;
this.btnEnd.Enabled = this.btnPause.Enabled = false;//这里有问题应该是devPlc回调设置
}
else
{
AddTextEvent(DateTime.Now, "结束验布", "无数据结束验布!");
_isDefect = false;
}
}
private void lstboxLog_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0) return;
string text = lstboxLog.GetItemText(e.Index);
//if (text.Contains("D"))
//{
// e.Graphics.FillRectangle(UIColor.Green, e.Bounds);
// e.Graphics.DrawString(text, e.Font, Color.Blue, e.Bounds, ContentAlignment.MiddleLeft);
//}
//e.Graphics.FillRectangle(UIColor.Green, e.Bounds);
switch (text[0])
{
case 'R':
e.DrawBackground();
e.Graphics.DrawString(text.Substring(1), e.Font, Color.Red, e.Bounds, ContentAlignment.MiddleLeft);
break;
case 'Y':
e.DrawBackground();
e.Graphics.DrawString(text.Substring(1), e.Font, Color.Orange, e.Bounds, ContentAlignment.MiddleLeft);
break;
//default: //B
// e.Graphics.DrawString(text.Substring(1), e.Font, Color.Black, e.Bounds, ContentAlignment.MiddleLeft);
// break;
}
}
private void txtBarCode_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Enter)
{
string barcode=txtBarCode.Text.Trim();
if (barcode == "")
return;
if (currentState != CurrentStateEnum. && currentState != CurrentStateEnum.)
return;
devContainer.devCodeScanner.ScanerEvent?.Invoke(barcode);
}
}
private void showImg( Mat mat)
{
//把Mat格式的图片转换成Bitmap
Bitmap bitmap = BitmapConverter.ToBitmap(mat);
this.Invoke(new System.Action(() =>
{
//显示图片
//picDefectImage.loadImage(bitmap);
this.picScanner1.Image = bitmap;
}));
}
private void uiSymbolButton1_Click(object sender, EventArgs e)
{
try
{
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
int mynum = 0;
private void uiSymbolButton1_Click_1(object sender, EventArgs e)
{
//UIMessageTip.ShowOk($"{record.Len},{record.ScannerPhotoCount-record.ScannerPhotoFinishCount}", 1500);
//return;
try
{
// mynum++;
// int FaceWidth = 200;
// float faceWidthX_cm = (float)(mynum * 100 * 1.0f / Config.cm2px_y );
// float faceWidthY_cm = (float)(200 * 1.0f / Config.cm2px_y );
// var point = new System.Drawing.PointF(faceWidthX_cm, faceWidthY_cm);
// AddTextEvent(DateTime.Now,"门幅", $"位置:{point.X}; 幅宽:{point.Y}");
// lstFaceWidth.Add(point);
// reDrawFaceWidth(lstFaceWidth, new double[] { 0, point.X }, new double[] { faceWidthY_cm, faceWidthY_cm });
// //Mat mat = new Mat(Application.StartupPath + "\\1.bmp");
// //devContainer.devScannerGentl1.ScanEvent(1, mat, 1);
// //---------------------
// if (record == null)
// {
// record = new Records();
// record.DefectInfoList = new List<DefectInfo>();
// record.DefectInfoList.Add(new DefectInfo() { Code = "jb", Name = "浆斑", X = 20, Y = 2, Width = 2, Height = 2 });
// record.DefectInfoList.Add(new DefectInfo() { Code = "jb", Name = "浆斑", X = 20, Y = 5, Width = 2, Height = 2 });
// record.DefectInfoList.Add(new DefectInfo() { Code = "wy", Name = "污印", X = 50, Y = 2, Width = 4, Height = 4 });
// record.DefectInfoList.Add(new DefectInfo() { Code = "lj", Name = "垃圾", X = 60, Y = 5, Width = 2, Height = 2 });
// reDrawDefectPoints(record.DefectInfoList, new double[2] { 0, 10 }, new double[2] { 0, 100 });
// foreach (DefectInfo info in record.DefectInfoList)
// {
// this.uiDataGridView1.Rows.Add(info.Code, info.Name,
// info.CentreX, info.CentreY, info.Area, info.ZXD, info.Target);
// }
// }
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void tcbarLightValue_ValueChanged(object sender, EventArgs e)
{
if (devContainer.state)
{
//bool b1 = devContainer.devScannerGentl1.setParam((float)tcbarExposureTime.Value);
//bool b2= devContainer.devScannerGentl2.setParam((float)tcbarExposureTime.Value);
// AddTextEvent(DateTime.Now,"setExposureTime", b1.ToString());
// AddTextEvent(DateTime.Now,"setExposureTime", b2.ToString());
var res=devContainer.devLight.setDigitalValue(1, (int)tcbarLightValue.Value);
//UIMessageTip.ShowOk($"{(int)tcbarLightValue.Value}/255 var={res} {Config.Light_Name}", 1000);
//tpnlLight.Text = this.tpnlLight.Tag + $" ({(int)tcbarLightValue.Value}/255)";
}
}
private void swcDefectPauseForUser_ValueChanged(object sender, bool value)
{
this.defectPauseForUser = this.swcDefectPauseForUser.Active;
}
private void button1_Click(object sender, EventArgs e)
{
List<DefectInfo> lstEditDefect = new List<DefectInfo>();
DefectInfo dt = new DefectInfo();
dt.Name = "123";
dt.Code = "jb";
dt.image = Image.FromFile("C:\\Users\\fang\\Desktop\\123.png");
lstEditDefect.Add(dt);
FHome_Defect frmDefect = new FHome_Defect(lstEditDefect);
frmDefect.ShowDialog();
return;
Config.LoadAllConfig();
DefectLib dl = new DefectLib();
dl.start();
string[] files = Directory.GetFiles("E:\\CPL\\个人\\gePic", $"*.bmp", SearchOption.TopDirectoryOnly);
List<QualifiedLimit> list = new List<QualifiedLimit>();
list.Add(new QualifiedLimit() { Code = "jb",ZXD = 0.6, Area = 0.04, ContrastLower = 0.98, ContrastTop = 1.02});
list.Add(new QualifiedLimit() { Code = "wy", ZXD = 0.6, Area = 0.09, ContrastLower = 0.93, ContrastTop = 1.07 });
list.Add(new QualifiedLimit() { Code = "mj", ZXD = 0.6, Area = 0.04, ContrastLower = 0.96, ContrastTop = 1.04 });
list.Add(new QualifiedLimit() { Code = "hy", ZXD = 0.67, Area = 0.09, ContrastLower = 0.94, ContrastTop = 1.06 });
list.Add(new QualifiedLimit() { Code = "lj", ZXD = 0.7, Area = 0.08, ContrastLower = 0.99, ContrastTop = 1.01 });
list.Add(new QualifiedLimit() { Code = "yss", ZXD = 0.5, Area = 0.04, ContrastLower = 0.99, ContrastTop = 1.01 });
list.Add(new QualifiedLimit() { Code = "zy", ZXD = 0.8, Area = 2, ContrastLower = 0.99, ContrastTop = 1.01 });
list.Add(new QualifiedLimit() { Code = "wc", ZXD = 0.6, Area = 0.05, ContrastLower = 0.99, ContrastTop = 1.01 });
list.Add(new QualifiedLimit() { Code = "cs", ZXD = 0.8, Area = 2, ContrastLower = 0.99, ContrastTop = 1.01 });
list.Add(new QualifiedLimit() { Code = "cy", ZXD = 1, Area = 0.0, ContrastLower = 0.0, ContrastTop = 0 });
list.Add(new QualifiedLimit() { Code = "tcy", ZXD = 0.5, Area = 0.0, ContrastLower = 0.99, ContrastTop = 1.01 });
list.Add(new QualifiedLimit() { Code = "jt", ZXD = 1, Area = 0.0, ContrastLower = 0.0, ContrastTop = 0 });
for (int i = 0; i < files.Count(); i++)
{
Mat mat = new Mat(files[i]);
dl.add(new Device.DefectLib.DefectTask()
{
modelName = "best_0116_bs14.fp16.trt",
//record = curRecord,
bmp = mat.Clone(),
bmpTag = mat.Clone(),
photoIndex = i,//0-n 首张必需为0因下面计算长度是从0开始
widthRatio = 1,
qualifiedLimitList = list,
finishEvent = callBackDefectTestEvent,
});
}
string s = DateTime.Now.Ticks.ToString() + "-";
Thread.Sleep(1);
s += DateTime.Now.Ticks.ToString() + "-";
MessageBox.Show(s);
// 创建SqlSugarClient实例并配置连接字符串
//var db = new SqlSugarClient(new ConnectionConfig()
//{
// // 设置数据库类型为SQLServer
// DbType = SqlSugar.DbType.SqlServer,
// // 设置服务器地址、数据库名称以及登录信息等
// ConnectionString = "Data Source=.;Initial Catalog=testDB;User ID=sa;Password=abc123!@#;"
//});
//// 可选:打开调试日志输出
//db.Ado.IsEnableLogEvent = true;
//// 查询操作示例
//if (!db.Ado.IsValidConnection())
// db.Ado.Open();
//string sql = "select * from t2";
//List<SugarParameter> parameters = new List<SugarParameter>();
//var res= db.Ado.GetDataTable(sql, parameters);
//loadErpData("20240107492");
return;
string code = "SHNY-PX-6-L-100";
string[] barCodes = code.Split(new char[] { '-' });
if (barCodes.Length < 4)
{
AddTextEvent(DateTime.Now,"扫码", $"产品编码({code})格式错误,不做响应!", WarningEnum.High);
return;
}
//新开始
//加载新产品
string pcode = barCodes[0] + "-" + barCodes[1] + "-" + barCodes[2];
var productInfo = svcProduct.GetModelNav(pcode); //frmProduct.loadProduct(code);
if (productInfo == null)
{
AddTextEvent(DateTime.Now,"扫码", $"编码({code})不存在,请先添加产品,暂停设备!", WarningEnum.High);
this.BeginInvoke(new System.Action(() =>
{
frmProduct.loadProduct(pcode);//转到新建编码
}));
return;
}
AddTextEvent(DateTime.Now,"扫码", $"编码({code}),加载产品信息({productInfo.Code})完成,加载配方(光源={productInfo.LightValue},曝光={productInfo.ExposureTime},增益={productInfo.Gain})...");
if (productInfo.LightValue > 0)//光源 - 通道0
devContainer.devLight.setDigitalValue(1, productInfo.LightValue);
if (productInfo.ExposureTime > 0 || productInfo.Gain > 0)//相机曝光 增益
{
devContainer.devCamer1.setParam((float)(productInfo.ExposureTime > 0 ? productInfo.ExposureTime : -1), (float)(productInfo.Gain > 0 ? productInfo.Gain : -1));
devContainer.devCamer2.setParam((float)(productInfo.ExposureTime > 0 ? productInfo.ExposureTime : -1), (float)(productInfo.Gain > 0 ? productInfo.Gain : -1));
}
AddTextEvent(DateTime.Now,"扫码", $"编码({code}),配方设置完成:光源={productInfo.LightValue},曝光={productInfo.ExposureTime}");
//ABSCamerCardDev pDev = new CamerCardDevIK();
//pDev.WarningEvent = (level, msg) =>
//{
// AddTextEvent(DateTime.Now,"设备事件", msg, level);
//};
//var b = pDev.open(0, 0);
//MessageBox.Show(b.ToString());
////b = pDev.loadConfiguration(@"D:\Debug\DevCfg\wcf.vlcf");
//b =pDev.start(this.picScanner1,"c:\\");
//MessageBox.Show(b.ToString());
//====
//Mat mat0= new Mat(@"f:\2.bmp");
//int marginWidth0;
//mat0 = OpenCVUtil.getMaxInsetRect2(mat0, true, 0, out marginWidth0);
//Mat mat1 = new Mat(@"f:\1.bmp");
//mat1 = OpenCVUtil.getMaxInsetRect2(mat1, false, 0, out marginWidth0);
//lblLen.Text = "0";
//Task.Run(async () => {
// for(int i = 0; i < 100; i++)
// {
// //选中
// this.Invoke(new System.Action(() =>
// {
// lblLen.Text = Convert.ToInt32(lblLen.Text) + 1 + "";
// }));
// await Task.Delay(1000);
// }
//});
//FHome_Defect frm = new FHome_Defect();
//frm.ShowDialog();
}
#region
private void callBackDefectTestEvent(Device.DefectLib.DefectTask res)
{
{
int step = 0;
try
{
if (res.isSucceed)
{
step = 1;
AddTextEvent(DateTime.Now, $"检测完成{Thread.CurrentThread.ManagedThreadId}", $"(图像{res.photoIndex})-瑕疵检测完成,共{res.excelTable.Rows.Count}个瑕疵!各环节用时:{string.Join(",", res.stopwatch)}");
//AddTextEvent(DateTime.Now,$"打标完成", $"第 ({res.photoIndex}) 张照片,计算过程:{res.resultInfo}");
}
else
{
AddTextEvent(DateTime.Now, $"打标失败{Thread.CurrentThread.ManagedThreadId}", $"(图像{res.photoIndex})-瑕疵检测失败TId={Thread.CurrentThread.ManagedThreadId}");
}
res.bmp.Dispose();
res.bmpTag.Dispose();
res.bmps_cut = null;
res.excelTable.Dispose();
}
catch (Exception ex)
{
AddTextEvent(DateTime.Now, $"打标失败{Thread.CurrentThread.ManagedThreadId}", $"(图像{res.photoIndex})-瑕疵检测异常({step}):{ex.Message}TId={Thread.CurrentThread.ManagedThreadId}");
}
finally
{
res.record.ScannerPhotoFinishCount++;
int liScannerPhotoFinishCount = res.record.ScannerPhotoFinishCount;
int liScannerPhotoCount = res.record.ScannerPhotoCount;
AddTextEvent(DateTime.Now, $"检测完成{Thread.CurrentThread.ManagedThreadId}", $"{liScannerPhotoFinishCount}/{liScannerPhotoCount}");
//this.BeginInvoke(new System.Action(() =>
//{
// this.lblWaitImageCount.Text = $"{liScannerPhotoCount - liScannerPhotoFinishCount}";
//}));
res = null;
System.GC.Collect();
}
}
}
#endregion
private void numErpLen_ValueChanged(object sender, string value)
{
//numErpLen_TextChanged(sender, null);
if (numErpLen.IsEmpty || currKey == 0) return;
var val = Convert.ToDouble(numErpLen.Text);
if (val <= 0) return;
Records record = Hashtable.Synchronized(htTask)[currKey] as Records;
if (record != null)
record.ErpLen = val;
}
private void numErpLen_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab)
{
if (numErpLen.IsEmpty || currKey == 0) return;
var val = Convert.ToDouble(numErpLen.Text);
if (val <= 0) return;
Records record = Hashtable.Synchronized(htTask)[currKey] as Records;
if (record != null)
record.ErpLen = val;
}
}
}
}