geboshi_V1/LeatherProject/LeatherApp/Page/FHome.cs

3585 lines
199 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.

#define OnLine
#define JM
//#define Oracle //禾欣使用oracle数据库
#define NT //新流程
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 Service;
using SqlSugar;
using Sunny.UI;
using Sunny.UI.Win32;
using System;
using System.Collections;
using System.Collections.Concurrent;
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;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock;
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 Stopwatch ptStopWatch = new Stopwatch();//计算速度用,暂停时停止计数
private double ptTime = 0;
private double ptLen = 0;
private object lockScanPhoto = new object();
private object lockCurrKey = new object();
private int currKey=0;
private Hashtable htTask = new Hashtable();//默认单线程写入不用lock, 多线程安全同步读取用Synchronized
//无产品编码时加载
FProductInfo frmProduct;
private double ThnDieLen = 0;
private Dictionary<int, Mat> defectTag = new Dictionary<int, Mat>();
//裁切偏移
private double OffsetCut = 0.2;
//云端
private CloudMgr cloudMgr = new CloudMgr();
private bool init_Cloud;
//
private bool _residueWarnningLenStop;
//判断是否已经扫码获取erp信息
private bool _IsGetErpCode = false;
#region
private class tScanPhotoInfo
{
/// <summary>
///
/// </summary>
/// <param name="_devIndex"></param>
/// <param name="_photoIndex">1-n 第1张会把1改为0</param>
/// <param name="_path"></param>
public tScanPhotoInfo(int _devIndex, int _photoIndex, string _path)
{
devIndex = _devIndex;
photoIndex = _photoIndex;
path = _path;
}
public tScanPhotoInfo(int _devIndex, int _photoIndex, Mat _mat, double dis = 0)
{
devIndex = _devIndex;
photoIndex = _photoIndex;
mat = _mat;
CurrDis = dis;
}
public int devIndex { get; set; }
/// <summary>
/// 0-n
/// </summary>
public int photoIndex { get; set; }
public string path { get; set; }
public Mat mat { get; set; }
public double CurrDis { get; set; }
}
#endregion
//主流程
private CancellationTokenSource _cts;
private ConcurrentQueue<tScanPhotoInfo> _matList1 = new ConcurrentQueue<tScanPhotoInfo>();
private ConcurrentQueue<tScanPhotoInfo> _matList2 = new ConcurrentQueue<tScanPhotoInfo>();
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)
{
AddTextEvent(DateTime.Now, "表格查询", $"Row:{e.RowIndex} currKey={currKey}", WarningEnum.Normal,false);
if (e.RowIndex < 0 || currKey == 0)
{
UIMessageTip.ShowError($"无记录{e.RowIndex}-{currKey}", 1000);
return;
}
try
{
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);
var defectInfo = record.DefectInfoList.FirstOrDefault(m => m.CentreX == (double)this.uiDataGridView1.CurrentRow.Cells["colX"].Value
&& (m.CentreY/100) == (double)this.uiDataGridView1.CurrentRow.Cells["colY"].Value);
if (defectInfo == null)
{
UIMessageTip.ShowError("此记录已不存在!", 1000);
return;
}
if (defectInfo.image != null)
{
this.picDefectImage.loadImage(defectInfo.image);
this.picDefectImage.Refresh();
}
else
UIMessageTip.ShowError("此记录图片已不存在!", 1000);
//选中
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();
}
}));
AddTextEvent(DateTime.Now, "表格查询", $"查询完成 Row:{this.uiDataGridView1.CurrentRow.Index} Uid={this.uiDataGridView1.CurrentRow.Cells["colUid"].Value} X={(double)this.uiDataGridView1.CurrentRow.Cells["colX"].Value} Y={(double)this.uiDataGridView1.CurrentRow.Cells["colY"].Value}", WarningEnum.Normal, false);
}
catch (Exception ex)
{
UIMessageTip.ShowError($"记录出错{ex.Message}", 2000);
return;
}
}
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();
ptStopWatch.Reset();
this.Invoke(new System.Action(() =>
{
lblLen.Text = "0米";
lblSpeed.Text = "速度0米/分";
this.uilbKF.Text = $"当前幅宽0cm";
//txtBarCodeName.Text = txtBatchId.Text = txtReelId.Text = "";
if(string.IsNullOrEmpty(numErpLen.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)
{
if (!_IsGetErpCode)
{
AddTextEvent(DateTime.Now, "启动", "还未扫码获取检测信息!", WarningEnum.Low);
return;
}
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>
object fklock=new object();
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]) break;// AddTextEvent(DateTime.Now,$"绘图", $"门幅宽度超限 1 {x}<{XSizeRange[0]}",WarningEnum.High);
if (x > XSizeRange[1]) break;// 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(() =>
{
lock (fklock)
{
this.lineChartFaceWidth.SetOption(option);
}
}));
}
private delegate void AddTextDelegate(DateTime time,string tag, string msg, WarningEnum level, bool Show);
private void AddTextEvent(DateTime now, string tag, string msg, WarningEnum level = WarningEnum.Normal, bool Show = true)
{
try
{
if (InvokeRequired)
{
Invoke(new AddTextDelegate(AddTextEvent), new object[]
{
now,
tag,
msg,
level,
Show
});
}
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>";
if (Show)
{
//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;
uilbKF.Top = 8;
}
//开机
private Thread t_test1;
private Thread t_test2;
private Thread t_test3;
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);
//DefectLib dl = new DefectLib();
//dl.start();
//加载寻边模型
OpenCVUtil.LoadEdgeMode();
this.btnOpen.Enabled = false;
_cts = new CancellationTokenSource();
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;
if (!devContainer.state || string.IsNullOrWhiteSpace(barCode)
|| (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.SuedeList1.Contains(codes[1]))
pcode = "0-" + codes[2];
#if false
else
pcode = codes[1] + "-" + codes[2];
#elif HX_LOD
else
pcode = "1-" + codes[2];
#else
else if (codes[1] == "1" || Config.SuedeList2.Contains(codes[1]))
pcode = "1-" + codes[2];
else if (codes[1] == "2" || Config.SuedeList3.Contains(codes[1]))
pcode = "2-" + codes[2];
else if (codes[1] == "3" || Config.SuedeList4.Contains(codes[1]))
pcode = "3-" + codes[2];
else if (codes[1] == "4" || Config.SuedeList5.Contains(codes[1]))
pcode = "4-" + codes[2];
else if (codes[1] == "5" || Config.SuedeList6.Contains(codes[1]))
pcode = "5-" + codes[2];
else
pcode = "1-" + codes[2];
#endif
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;
_residueWarnningLenStop = false;
//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}");
//加载模型
if(!devContainer.libDefect.LoadModel(productInfo.ModelName))
{
AddTextEvent(DateTime.Now, "模型预加载", $"模型加载异常({errCode})请检测模型路径:{productInfo.ModelName}", WarningEnum.High);
return;
}
//注意,这里和修改页共享操作(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();
ptStopWatch.Reset();
errCode = 19;
//扫码成功
_IsGetErpCode = true;
}
catch (Exception ex)
{
AddTextEvent(DateTime.Now,"扫码", $"异常({errCode}):{ex.Message}", WarningEnum.High);
}
};
//相机回调出照片
#if NT
#else
devContainer.devCamer1.ScanEvent = callBackScanMatEvent;
devContainer.devCamer2.ScanEvent = callBackScanMatEvent;
#endif
//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,$"设备事件", msg, level, false);
if (level == WarningEnum.High)
Task.Run(() => warning(level, true));
};
devContainer.start(this.picScanner1, this.picScanner2);
//devContainer.start(IntPtr.Zero,IntPtr.Zero);
#if NT
t_test1 = new System.Threading.Thread(Cam1ThreadFunction);
t_test1.IsBackground = true;
t_test1.Start();
t_test2 = new System.Threading.Thread(Cam2ThreadFunction);
t_test2.IsBackground = true;
t_test2.Start();
t_test1 = new System.Threading.Thread(MainThreadFunction);
t_test1.IsBackground = true;
t_test1.Start();
#endif
}
private DataRow loadErpData(string barCode)
{
var paramList = new List<SugarParameter>() {
new SugarParameter("@code", barCode)
};
Stopwatch stopwatch = Stopwatch.StartNew();
#if Oracle
var data = Utils.DBUtils.execSql(Config.ErpSql, paramList, SqlSugar.DbType.Oracle);
#else
var data = Utils.DBUtils.execSql(Config.ErpSql, paramList);
#endif
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;
#region
/// <summary>
/// 中断工序运行
/// </summary>
/// <returns></returns>
private bool isBreakProcessRun()
{
//if (!devContainer.state || (currentState != CurrentStateEnum.运行中 && currentState != CurrentStateEnum.暂停))
return (!devContainer.state || (currentState != CurrentStateEnum. && currentState != CurrentStateEnum.));
}
#endregion
#region 线1 &&
/// <summary>
/// 相机1采图预处理
/// </summary>
private void Cam1ThreadFunction()
{
int errStep = 0;
AddTextEvent(DateTime.Now, "相机流程1", $"流程启动!");
#if OnLine
#else
string imgfilePath = "D:\\CPL\\img\\L1.bmp";
Mat timg = new Mat(imgfilePath);
timg = timg.Flip(FlipMode.XY);
#endif
while (true)
{
try
{
if (_cts.IsCancellationRequested)
break;
if (true)
{
////暂停开始
//stopWatch.Start();
do
{
#region
#if OnLine
int index;
Mat Image;
int devNo;
//采集图片
if(devContainer.devCamer1 == null)
{
Thread.Sleep(50);
continue;
}
bool gsts = devContainer.devCamer1.readDataImage(out index, out Image, out devNo);
//AcquisitionMat acq = _LinecamDev1.GetFrames(100);
if (gsts)
{
//double stLen = devContainer.GetLength();
Cv2.Flip(Image, Image, FlipMode.XY);//翻转
AddTextEvent(DateTime.Now, $"拍照", $"采集卡({devNo}),图像({index})", WarningEnum.Normal, false);
this.BeginInvoke(new Action(() =>
{
Bitmap bitmap = Image.ToBitmap();
//Bitmap bitmap = BitmapConverter.ToBitmap(Image);
//bitmap.Save($"d:\\{devIndex}_{num}.bmp", ImageFormat.Bmp);
//显示图片
if (devNo == 0)
{
picScanner2.Image = bitmap;
//picScanner2.Refresh();
}
else
{
picScanner1.Image = bitmap;
//picScanner1.Refresh();
}
}));
//裁边
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int marginWidth;
Image = OpenCVUtil.getMaxInsetRect2(Image, devNo == 1 ? true : false, Config.MarginHoleWidth, out marginWidth);
//AddTextEvent(DateTime.Now,"裁边", $"(图像{scanPhotos0.photoIndex})-图0裁边后{mat0.Width}*{mat0.Height}");
errStep = 55;
string time = $"dev{devNo}-图{index}裁边({stopWatch.ElapsedMilliseconds})";
AddTextEvent(DateTime.Now, $"拍照", time, WarningEnum.Normal, false);
errStep = 1;
if (!devContainer.state || (currentState != CurrentStateEnum. && currentState != CurrentStateEnum.))
{
Image.Dispose();
continue;
}
if (currKey != 0 || htTask.ContainsKey(currKey))
{
Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
//长度剩余提醒
if (Config.residueWarnningLen > 0 && curRecord.ErpLen > 0 && Config.residueWarnningLen >= Math.Abs(curRecord.ErpLen - curRecord.Len))
{
AddTextEvent(DateTime.Now, $"告警", $"已达剩余长度不足提醒!(({curRecord.ErpLen} -{ curRecord.Len})<={Config.residueWarnningLen})", WarningEnum.High);
#region
if (!_residueWarnningLenStop)
{
_residueWarnningLenStop = true;
AddTextEvent(DateTime.Now, $"暂停", $"已达剩余长度不足提醒!(({curRecord.ErpLen} - {curRecord.Len})<={Config.residueWarnningLen}),进入暂停。");
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);
Thread.Sleep(500);
this.devContainer.devIOCard.writeBitState(0, 1, false);
//});
}
this.BeginInvoke(new System.Action(() =>
{
//warning(WarningEnum.Low, true);//暂停
MessageBox.Show($"已达剩余长度不足提醒!({Math.Abs(curRecord.ErpLen - curRecord.Len)}<={Config.residueWarnningLen}),进入暂停。", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}));
}
#endregion
}
errStep = 6;
//厚度检测提示
if (curRecord.ProductInfo.OpenThicknessDetection)
{
if ((curRecord.Len - ThnDieLen) > curRecord.ProductInfo.ThicknessDetectionStopDis)
{
ThnDieLen = curRecord.Len;
AddTextEvent(DateTime.Now, $"厚度检测", $"位置:{curRecord.Len}; 上次位置:{ThnDieLen}");
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);
//Thread.Sleep(500);
this.devContainer.devIOCard.writeBitState(0, 1, false);
});
}
}
}
//二次判断
curRecord.dicPhoto_Defect.TryAdd(index, false);//加入索引,默认无瑕疵
errStep = 7;
//暂停:瑕疵二次判断
if (this.defectPauseForUser)
{
AddTextEvent(DateTime.Now, $"拍照", $"图像索引:{index},标识数:{curRecord.dicPhoto_Defect.Count}", WarningEnum.Normal, false);
int liPhotoIndex = index - Config.defectPauseSkipPhotoCount;
AddTextEvent(DateTime.Now, $"拍照", $"Dev={devNo},图像{index} {liPhotoIndex}={index}-{Config.defectPauseSkipPhotoCount}", WarningEnum.Normal, false);
if (liPhotoIndex >= 0 && curRecord.dicPhoto_Defect.ContainsKey(liPhotoIndex) && curRecord.dicPhoto_Defect[liPhotoIndex])
{
errStep = 8;
for (int fi = 0; fi < 3; fi++)
{
//循环等待数据后期处理完成
Thread.Sleep(500);
List<DefectInfo> lstEditDefect = curRecord.DefectInfoList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
AddTextEvent(DateTime.Now, $"暂停", $"(图像{liPhotoIndex})已达观察台,瑕疵二次判断=》({string.Join(",", lstEditDefect.Select(m => m.Code).ToArray())})是否包含在({string.Join(",", curRecord.ProductInfo.DefectPauseOption.ToArray())})中。");
//瑕疵选项过滤
if (Config.OpenHalconDefect || curRecord.ProductInfo.DefectPauseOption.Count == 0 || lstEditDefect.Where(x => curRecord.ProductInfo.DefectPauseOption.Contains(x.Code)).Count() > 0)
{
//暂停
AddTextEvent(DateTime.Now, $"暂停", $"(图像{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);
});
if (Config.OpenBeep)
{
Task.Run(async () =>
{
devContainer.io_output(CMDName., false, true, Config.BeepTime);
await Task.Delay(5);
});
}
}
errStep = 9;
//不能使用同步Invoke方式会使相机超时丢帧
this.BeginInvoke(new System.Action(() =>
{
int liDefectCount = lstEditDefect.Count;
FHome_Defect frmDefect = new FHome_Defect(lstEditDefect, defectTag[liPhotoIndex]);
if (frmDefect.ShowDialog() == DialogResult.OK)
{
defectTag.Remove(liPhotoIndex);
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, $"暂停", $"修改第({i + 1})行瑕疵名称,{uid} {row.uid}", WarningEnum.Low, false);
if (row.uid == uid)
{
oldCode = this.uiDataGridView1.Rows[i].Cells["colCode"].Value.ToString();
AddTextEvent(DateTime.Now, $"暂停", $"修改第({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, $"二次检测", $"本次忽略{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 = 10;
//自动继续运行设备(这里临时暂停后不能再急停,否则无法继续)
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);
Thread.Sleep(200);
this.devContainer.devIOCard.writeBitState(0, 0, false);
//Task.Run(async () =>
//{
// await Task.Delay(500);
// this.devContainer.devIOCard.writeBitState(0, 0, false);
//});
}
}
}));
break;
}
}
}
}
errStep = 10;
//以下判定放置于二次判定之后,因为二次判定可能会忽略部分检测项!!
//暂停:缺陷超标
//每百米告警判断???在此还是在收到新照片时触发???
if (curRecord.ProductInfo.DefectCountLimit > 0 && curRecord.DefectTotalCount >= curRecord.ProductInfo.DefectCountLimit && curRecord.DefectInfoList != null)
{
int liPhotoIndex =index - Config.defectPauseSkipPhotoCount; //二次判定完的图片index
int compLen = 100 * 100;//每百米 to cm
int compCount = compLen * Config.cm2px_y / Image.Height; //100m图像张数
//从上次告警后重新开始计算长度及数量
int defectCount = curRecord.DefectInfoList.Where(m => m.PhotoIndex >= curRecord.preWarningPhotoIndex && m.PhotoIndex >= (liPhotoIndex + 1 - compCount) && m.PhotoIndex <= liPhotoIndex).Count();
if (defectCount >= curRecord.ProductInfo.DefectCountLimit)
{
curRecord.preWarningPhotoIndex = liPhotoIndex + 1;
AddTextEvent(DateTime.Now, $"告警", $"每百米瑕疵数量达到阈值!({defectCount}>={curRecord.ProductInfo.DefectCountLimit})", WarningEnum.High);
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);
});
if (Config.OpenBeep)
{
Task.Run(async () =>
{
devContainer.io_output(CMDName., false, true, Config.BeepTime);
await Task.Delay(5);
});
}
}
}
errStep = 11;
}
//暂停:每个缺陷项不同长度检测数量报警
if (curRecord.DefectTotalCount > 0 && curRecord.DefectInfoList != null)
{
#if true
//按缺陷计算没X米多少缺陷报警
for (int i = 0; i < curRecord.ProductInfo.QualifiedLimitList.Count; i++)
{
var defectWarn = curRecord.ProductInfo.QualifiedLimitList[i];
if (defectWarn.DefectWarnLength > 0 || defectWarn.DefectWarnCnt > 0)
{
errStep = 12;
int liPhotoIndex = index - Config.defectPauseSkipPhotoCount; //二次判定完的图片index
int warnLen = defectWarn.DefectWarnLength * 100;//每米 to cm
int warnCount = warnLen * Config.cm2px_y / Image.Height; //计算图像张数
//从上次告警后重新开始计算长度及数量
int warnDefectCount = curRecord.DefectInfoList.Where(m => m.PhotoIndex >= curRecord.preWarningPhotoIndexByLabel[i] && m.PhotoIndex >= (liPhotoIndex + 1 - warnCount) && m.PhotoIndex <= liPhotoIndex).Count();
if (warnDefectCount >= defectWarn.DefectWarnCnt)
{
curRecord.preWarningPhotoIndexByLabel[i] = liPhotoIndex + 1;
AddTextEvent(DateTime.Now, $"告警", $"每{defectWarn.DefectWarnLength}米{Config.getDefectName(defectWarn.Code)}瑕疵数量达到阈值!({warnDefectCount}>={defectWarn.DefectWarnCnt})", WarningEnum.High);
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);
});
if (Config.OpenBeep)
{
Task.Run(async () =>
{
devContainer.io_output(CMDName., false, true, Config.BeepTime);
await Task.Delay(5);
});
}
}
}
}
}
#endif
}
errStep = 21;
//Application.DoEvents();
}
_matList1.Enqueue(new tScanPhotoInfo(1, index, Image.Clone(), 0));
}
#else
Thread.Sleep(2500);
AcquisitionMat acq = new AcquisitionMat();
{
acq.GrabStatus = "GrabPass";
acq.Image = timg.Clone();
Log($"图像预处理", $"模拟相机1-{Cam1Cnt}", WarningEnum.Normal, true);
}
if (acq.GrabStatus == "GrabPass")
{
#endif
#endregion
//System.GC.Collect();
Thread.Sleep(50);
} while (!isBreakProcessRun());
//暂停中断
//stopWatch.Stop();
pStopWatch.Stop();
//_isRuning = false;
}
else
{
//防止内存爆满
//AcquisitionMat acq = _LinecamDev1.GetFrames(10);
}
Thread.Sleep(50);
}
catch (Exception e)
{
//_isRuning = false;
AddTextEvent(DateTime.Now, $"运行报警", $"相机1流程运行出错{errStep}" + e.Message + "\n", WarningEnum.High, true);
//Log("运行报警", $"相机1流程运行出错{errStep}" + e.Message + "\n", WarningEnum.High);
}
}
}
#endregion
#region 线2 &&
/// <summary>
/// 相机2采图预处理
/// </summary>
private void Cam2ThreadFunction()
{
int errStep = 0;
AddTextEvent(DateTime.Now, "相机流程2", $"流程启动!");
#if OnLine
#else
string imgfilePath = "D:\\CPL\\img\\L1.bmp";
Mat timg = new Mat(imgfilePath);
timg = timg.Flip(FlipMode.XY);
#endif
while (true)
{
try
{
if (_cts.IsCancellationRequested)
break;
if (true)
{
////暂停开始
//stopWatch.Start();
do
{
#region
#if OnLine
int index;
Mat Image;
int devNo;
//采集图片
if (devContainer.devCamer2 == null)
{
Thread.Sleep(50);
continue;
}
bool gsts = devContainer.devCamer2.readDataImage(out index, out Image, out devNo);
//AcquisitionMat acq = _LinecamDev1.GetFrames(100);
if (gsts)
{
Cv2.Flip(Image, Image, FlipMode.XY);//翻转
AddTextEvent(DateTime.Now, $"拍照", $"采集卡({devNo}),图像({index})", WarningEnum.Normal, false);
this.BeginInvoke(new Action(() =>
{
Bitmap bitmap = Image.ToBitmap();
//Bitmap bitmap = BitmapConverter.ToBitmap(Image);
//bitmap.Save($"d:\\{devIndex}_{num}.bmp", ImageFormat.Bmp);
//显示图片
if (devNo == 0)
{
picScanner2.Image = bitmap;
//picScanner2.Refresh();
}
else
{
picScanner1.Image = bitmap;
//picScanner1.Refresh();
}
}));
//裁边
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int marginWidth;
Image = OpenCVUtil.getMaxInsetRect2(Image, devNo == 1 ? true : false, Config.MarginHoleWidth, out marginWidth);
//AddTextEvent(DateTime.Now,"裁边", $"(图像{scanPhotos0.photoIndex})-图0裁边后{mat0.Width}*{mat0.Height}");
errStep = 55;
string time = $"dev{devNo}-图{index}裁边({stopWatch.ElapsedMilliseconds})";
AddTextEvent(DateTime.Now, $"拍照", time, WarningEnum.Normal, false);
errStep = 1;
if (!devContainer.state || (currentState != CurrentStateEnum. && currentState != CurrentStateEnum.))
{
Image.Dispose();
continue;
}
_matList2.Enqueue(new tScanPhotoInfo(1, index, Image.Clone(), 0));
}
#else
Thread.Sleep(2500);
AcquisitionMat acq = new AcquisitionMat();
{
acq.GrabStatus = "GrabPass";
acq.Image = timg.Clone();
Log($"图像预处理", $"模拟相机1-{Cam1Cnt}", WarningEnum.Normal, true);
}
if (acq.GrabStatus == "GrabPass")
{
#endif
#endregion
//System.GC.Collect();
Thread.Sleep(50);
} while (!isBreakProcessRun());
//暂停中断
//stopWatch.Stop();
pStopWatch.Stop();
//_isRuning = false;
}
else
{
//防止内存爆满
//AcquisitionMat acq = _LinecamDev1.GetFrames(10);
}
Thread.Sleep(50);
}
catch (Exception e)
{
//_isRuning = false;
AddTextEvent(DateTime.Now, $"运行报警", $"相机1流程运行出错{errStep}" + e.Message + "\n", WarningEnum.High, true);
//Log("运行报警", $"相机1流程运行出错{errStep}" + e.Message + "\n", WarningEnum.High);
}
}
}
#endregion
#region 线
int testCnt = 0;
/// <summary>
/// 后台运行主线程
/// </summary>
private void MainThreadFunction()
{
AddTextEvent(DateTime.Now, "处理流程流程", $"流程启动!");
Mat acq1 = new Mat();
Mat acq2 = new Mat();
#if OnLine
#else
string imgfilePath1 = "D:\\CPL\\img\\L1.bmp";
string imgfilePath2 = "D:\\CPL\\img\\R1.bmp";
Mat timg1 = new Mat(imgfilePath1);
timg1 = timg1.Flip(FlipMode.XY);
Mat timg2 = new Mat(imgfilePath2);
timg2 = timg1.Flip(FlipMode.XY);
#endif
while (true)
{
int errStep = 0;
try
{
if (_cts.IsCancellationRequested)
break;
if (true)
{
////暂停开始
//stopWatch.Start();
do
{
tScanPhotoInfo peek1;
tScanPhotoInfo peek2;
if (_matList1.Count > 0 && _matList2.Count > 0)
{
_matList1.TryPeek(out peek1);
_matList2.TryPeek(out peek2);
if (peek1 != null && peek2 != null && peek1.photoIndex != peek2.photoIndex)
continue;
tScanPhotoInfo tscanPhotos0;
if (!_matList1.TryDequeue(out tscanPhotos0))
AddTextEvent(DateTime.Now, $"图像出队列", $"图像{tscanPhotos0.photoIndex},异常相机1队列出队失败", WarningEnum.High, true);
tScanPhotoInfo tscanPhotos1;
if (!_matList2.TryDequeue(out tscanPhotos1))
AddTextEvent(DateTime.Now, $"图像出队列", $"图像{tscanPhotos0.photoIndex},异常相机2队列出队失败", WarningEnum.High, true);
Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
ScanPhotoInfo scanPhotos0 = new ScanPhotoInfo(tscanPhotos0.devIndex, tscanPhotos0.photoIndex, tscanPhotos0.mat);
ScanPhotoInfo scanPhotos1 = new ScanPhotoInfo(tscanPhotos1.devIndex, tscanPhotos1.photoIndex, tscanPhotos1.mat);
Stopwatch stopWatch = new Stopwatch();
AddTextEvent(DateTime.Now, $"图像处理", $"图像{scanPhotos0.photoIndex}", WarningEnum.Low, false);
string time = "";
stopWatch.Start();
try
{
if (scanPhotos0.mat.Height != scanPhotos1.mat.Height)
{
int xw, xh;
AddTextEvent(DateTime.Now, $"警告", $"两相机采集图高度不一致({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, out xw, out xh);
else
scanPhotos0.mat = OpenCVUtil.resize(scanPhotos0.mat, scanPhotos1.mat.Width, scanPhotos1.mat.Height, out xw, out xh);
}
//saveMatTest(scanPhotos0.mat, 1);
//saveMatTest(scanPhotos1.mat, 2);
//反转+相机索引调换
Mat mat0 = scanPhotos1.mat;
Mat mat1 = scanPhotos0.mat;
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 / 2;
mat0 = OpenCVUtil.cutImage(mat0, 0, 0, width, mat0.Height);
time += $"->图1去重({stopWatch.ElapsedMilliseconds})";
width = mat1.Width - Config.MiddleSuperposition / 2;
mat1 = OpenCVUtil.cutImage(mat1, Config.MiddleSuperposition / 2, 0, width, mat1.Height);
time += $"->图2去重({stopWatch.ElapsedMilliseconds})";
}
AddTextEvent(DateTime.Now, $"裁边",
$"(图像{scanPhotos0.photoIndex})-左图去重后:{mat0.Width}*{mat0.Height},右图:{mat1.Width}*{mat1.Height}" +
$"重复值:{Config.MiddleSuperposition},孔洞:{Config.MarginHoleWidth},cm2px{Config.cm2px_x},resizeWidth{resizeWidth}", WarningEnum.Low, false);
errStep = 4;
//水平合并l
Mat mat = OpenCVUtil.mergeImage_sameSize(new Mat[] { mat0, mat1 });//这里相机反装,左右反转下
//AddTextEvent(DateTime.Now, $"裁边", $"(图像{scanPhotos0.photoIndex})-边缘宽度:(左图)={marginWidth0},(右图)={marginWidth1}; 裁边去孔洞后:({mat0.Width}+{mat1.Width}={mat0.Width + mat1.Width});合并后(去孔洞){mat.Width}*{mat.Height}", WarningEnum.Low, false);
AddTextEvent(DateTime.Now, $"裁边", $"(图像{scanPhotos0.photoIndex}); 裁边去孔洞后:({mat0.Width}+{mat1.Width}={mat0.Width + mat1.Width});合并后(去孔洞){mat.Width}*{mat.Height}", WarningEnum.Normal, false);
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, $"门幅", $"(图像{scanPhotos0.photoIndex})-({scanPhotos0.photoIndex})位置:{point[0]}; 幅宽:{point[1]}", WarningEnum.Normal, false);
curRecord.FacePointList.Add(point);
List<float[]> mfdata = new List<float[]>();
for (int i = 0; i < curRecord.FacePointList.Count; i++)
//foreach (var item in curRecord.FacePointList)
mfdata.Add(curRecord.FacePointList[i]);
reDrawFaceWidth(mfdata,
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);
//计算速度
//
//
curRecord.TimeLen = pStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
#if JM
double stLen = devContainer.GetLength();
if (stLen < 9999)
{
curRecord.Len = stLen;
#else
double lenMi = Math.Round(faceWidthX_cm / 100, 2);
double stLen = lenMi;
curRecord.Len = lenMi;
#endif
//ptTime = ptStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
this.BeginInvoke(new System.Action(() =>
{
//double sstLen = devContainer.GetLength();
ptTime = ptStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
AddTextEvent(DateTime.Now, $"记录", $"(计米{stLen}米),时间:{ptTime}分; 速度:{Math.Round((stLen - ptLen) / ptTime, 2)}米/分", WarningEnum.Normal, false);
this.lblLen.Text = $"{stLen}米";//$"{lenMi}米";
this.lblLen.Tag = faceWidthX_cm;
#if JM
this.lblSpeed.Text = $"速度:{Math.Round((stLen - ptLen) / ptTime, 2)}米/分";//$"速度:{Math.Round(lenMi / curRecord.TimeLen, 2)}米/分";
#else
this.lblSpeed.Text = $"速度:{Math.Round(lenMi / curRecord.TimeLen, 2)}米/分";
#endif
this.uilbKF.Text = $"当前幅宽:{faceWidthY_cm}cm";
ptLen = stLen;
ptStopWatch.Restart();//重新计时
}));
#if JM
}
#endif
//
errStep = 9;
time += $"->速度刷新({stopWatch.ElapsedMilliseconds})";
//----缺陷队列
int oxw, oxh;
mat = OpenCVUtil.resize(mat, resize.Width, resize.Height, out oxw, out oxh);
AddTextEvent(DateTime.Now, $"图像处理", $"(图像{scanPhotos0.photoIndex})-合成图resize后:{mat.Width}*{mat.Height}-{oxw}*{oxh}", WarningEnum.Normal, false);
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,
xw = oxw,
//PicDis = picLoc,
});
errStep = 10;
time += $"->加入瑕疵待检队列({stopWatch.ElapsedMilliseconds})";
}
catch (Exception ex)
{
curRecord.ScannerPhotoFinishCount++;//失败时不能因数量不一致无法保存
AddTextEvent(DateTime.Now, $"图像处理", $"异常({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, $"图像处理", $"(图像{scanPhotos0.photoIndex})-进度计时:{time}", WarningEnum.Normal, false);
scanPhotos0.mat.Dispose();
scanPhotos1.mat.Dispose();
scanPhotos0 = scanPhotos1 = null;
//System.GC.Collect();
}
}
Thread.Sleep(20);
} while (!isBreakProcessRun());
//暂停中断
//stopWatch.Stop();
pStopWatch.Stop();
//_isRuning = false;
}
#if Online_One
else
{
//防止内存爆满
AcquisitionMat tacq1 = _LinecamDev1.GetFrames(10);
AcquisitionMat tacq2 = _LinecamDev2.GetFrames(10);
}
#endif
Thread.Sleep(20);
}
catch (Exception e)
{
//_isRuning = false;
AddTextEvent(DateTime.Now, $"运行报警", $"流程运行出错{errStep}" + e.Message , WarningEnum.High, true);
//Log("运行报警", $"流程运行出错{errStep}" + e.Message + "\n", WarningEnum.High);
}
}
}
#endregion
#if NT
#else
/// <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, $"拍照", $"采集卡({devIndex}),图像({num})", WarningEnum.Normal, false);
Cv2.Flip(matone, matone, FlipMode.XY);//翻转
this.BeginInvoke(new Action(() =>
{
Bitmap bitmap = BitmapConverter.ToBitmap(matone);
//bitmap.Save($"d:\\{devIndex}_{num}.bmp", ImageFormat.Bmp);
//显示图片
if (devIndex == 0)
{
picScanner2.Image = bitmap;
picScanner2.Refresh();
}
else
{
picScanner1.Image = bitmap;
picScanner1.Refresh();
}
}));
//裁边
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
int marginWidth;
matone = OpenCVUtil.getMaxInsetRect2(matone, devIndex == 1?true:false, Config.MarginHoleWidth, out marginWidth);
//AddTextEvent(DateTime.Now,"裁边", $"(图像{scanPhotos0.photoIndex})-图0裁边后{mat0.Width}*{mat0.Height}");
errStep = 55;
string time = $"dev{devIndex}-图{num}裁边({stopWatch.ElapsedMilliseconds})";
AddTextEvent(DateTime.Now, $"拍照", time, WarningEnum.Normal, false);
}
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, $"拍照", $"(图像{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, $"拍照", $"(图像{num})-采集卡({devIndex}),size:({myMat.Width}*{myMat.Height})({(myMat == null ? "A" : "B")})", WarningEnum.Low, false);
//AddTextEvent(DateTime.Now,"拍照", $"Dev={devIndex},图像{num}-2");
lock (lockScanPhoto)//多线程操作
{
if (scanPhotos[2] != null && scanPhotos[2].photoIndex == num)
{
AddTextEvent(DateTime.Now, $"拍照", $"相机图像不同步,急停中止(需停机重新开始,不可继续)!!!", WarningEnum.High);
warning(WarningEnum.High);
//重置...
}
if (scanPhotos[devIndex] != null) //添加一张容错
{
//AddTextEvent(DateTime.Now, $"拍照", $"(图像{num})-采集卡({devIndex}) 容错一张图到队列!", WarningEnum.Low);
AddTextEvent(DateTime.Now, $"拍照", $"(图像{num})-采集卡({devIndex}) 容错一张图到队列!");
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;
//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, $"拍照", $"新任务开始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, $"拍照", $"(图像{scanPhotos[2].photoIndex})-采集卡({scanPhotos[2].devIndex}) 容错队列图前移。");
scanPhotos[scanPhotos[2].devIndex] = scanPhotos[2];
scanPhotos[2] = null;
}
curRecord.ScannerPhotoCount++;
errStep = 5;
}
if (task.scanPhotos0 != null && task.scanPhotos1 != null)
{
var scanPhoto = task.scanPhotos0 as ScanPhotoInfo;
AddTextEvent(DateTime.Now, $"拍照", $"待处理图像队列:{curRecord.ScannerPhotoCount - curRecord.ScannerPhotoFinishCount}张", WarningEnum.Normal, false);
task.record = curRecord;
task.finishEvent = callBackPhotoEvent;
devContainer.libPhoto.add(task);
AddTextEvent(DateTime.Now, $"拍照", $"Dev={devIndex},图像{scanPhoto.photoIndex},已加入图像处理队列", WarningEnum.Normal, false);
}
//长度剩余提醒
if (Config.residueWarnningLen > 0 && curRecord.ErpLen > 0 && Config.residueWarnningLen >= curRecord.ErpLen - curRecord.Len)
{
AddTextEvent(DateTime.Now, $"告警", $"已达剩余长度不足提醒!({curRecord.ErpLen - curRecord.Len}<={Config.residueWarnningLen})", WarningEnum.High);
#region
if (!_residueWarnningLenStop)
{
_residueWarnningLenStop = true;
AddTextEvent(DateTime.Now, $"暂停", $"已达剩余长度不足提醒!({curRecord.ErpLen - curRecord.Len}<={Config.residueWarnningLen}),进入暂停。");
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);
});
}
this.BeginInvoke(new System.Action(() =>
{
//warning(WarningEnum.Low, true);//暂停
MessageBox.Show($"已达剩余长度不足提醒!({curRecord.ErpLen - curRecord.Len}<={Config.residueWarnningLen}),进入暂停。", "警告",MessageBoxButtons.OK, MessageBoxIcon.Warning);
}));
}
#endregion
}
errStep = 6;
//厚度检测提示
if (curRecord.ProductInfo.OpenThicknessDetection)
{
if ((curRecord.Len - ThnDieLen) > curRecord.ProductInfo.ThicknessDetectionStopDis)
{
ThnDieLen = curRecord.Len;
AddTextEvent(DateTime.Now, $"厚度检测", $"位置:{curRecord.Len}; 上次位置:{ThnDieLen}");
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);
});
}
}
}
//
if (task.scanPhotos0 != null && task.scanPhotos1 != null)
{
var scanPhoto = task.scanPhotos0 as ScanPhotoInfo;
curRecord.dicPhoto_Defect.TryAdd(scanPhoto.photoIndex, false);//加入索引,默认无瑕疵
AddTextEvent(DateTime.Now, $"拍照", $"图像索引:{scanPhoto.photoIndex},标识数:{curRecord.dicPhoto_Defect.Count}", WarningEnum.Normal, false);
errStep = 7;
//暂停:瑕疵二次判断
if (this.defectPauseForUser)
{
int liPhotoIndex = scanPhoto.photoIndex - Config.defectPauseSkipPhotoCount;
AddTextEvent(DateTime.Now, $"拍照", $"Dev={devIndex},图像{scanPhoto.photoIndex} {liPhotoIndex}={scanPhoto.photoIndex}-{Config.defectPauseSkipPhotoCount}", WarningEnum.Normal, false);
if (liPhotoIndex >= 0 && curRecord.dicPhoto_Defect[liPhotoIndex])
{
errStep = 8;
for (int fi = 0; fi < 3; fi++)
{
//循环等待数据后期处理完成
Thread.Sleep(500);
List<DefectInfo> lstEditDefect = curRecord.DefectInfoList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
AddTextEvent(DateTime.Now, $"暂停", $"(图像{liPhotoIndex})已达观察台,瑕疵二次判断=》({string.Join(",", lstEditDefect.Select(m => m.Code).ToArray())})是否包含在({string.Join(",", curRecord.ProductInfo.DefectPauseOption.ToArray())})中。");
//瑕疵选项过滤
if (Config.OpenHalconDefect || curRecord.ProductInfo.DefectPauseOption.Count == 0 || lstEditDefect.Where(x => curRecord.ProductInfo.DefectPauseOption.Contains(x.Code)).Count() > 0)
{
//暂停
AddTextEvent(DateTime.Now, $"暂停", $"(图像{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);
});
if (Config.OpenBeep)
{
Task.Run(async () =>
{
devContainer.io_output(CMDName., false, true, Config.BeepTime);
await Task.Delay(5);
});
}
}
errStep = 9;
//不能使用同步Invoke方式会使相机超时丢帧
this.BeginInvoke(new System.Action(() =>
{
int liDefectCount = lstEditDefect.Count;
FHome_Defect frmDefect = new FHome_Defect(lstEditDefect, defectTag[liPhotoIndex]);
if (frmDefect.ShowDialog() == DialogResult.OK)
{
defectTag.Remove(liPhotoIndex);
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, $"暂停", $"修改第({i + 1})行瑕疵名称,{uid} {row.uid}", WarningEnum.Low, false);
if (row.uid == uid)
{
oldCode = this.uiDataGridView1.Rows[i].Cells["colCode"].Value.ToString();
AddTextEvent(DateTime.Now, $"暂停", $"修改第({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, $"二次检测", $"本次忽略{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 = 10;
//自动继续运行设备(这里临时暂停后不能再急停,否则无法继续)
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);
});
}
}
}));
break;
}
}
}
}
errStep = 10;
//以下判定放置于二次判定之后,因为二次判定可能会忽略部分检测项!!
//暂停:缺陷超标
//每百米告警判断???在此还是在收到新照片时触发???
if (curRecord.ProductInfo.DefectCountLimit > 0 && curRecord.DefectTotalCount >= curRecord.ProductInfo.DefectCountLimit && curRecord.DefectInfoList != null)
{
int liPhotoIndex = scanPhoto.photoIndex - Config.defectPauseSkipPhotoCount; //二次判定完的图片index
int compLen = 100 * 100;//每百米 to cm
int compCount = compLen * Config.cm2px_y / scanPhoto.mat.Height; //100m图像张数
//从上次告警后重新开始计算长度及数量
int defectCount = curRecord.DefectInfoList.Where(m => m.PhotoIndex >= curRecord.preWarningPhotoIndex && m.PhotoIndex >= (liPhotoIndex + 1 - compCount) && m.PhotoIndex <= liPhotoIndex).Count();
if (defectCount >= curRecord.ProductInfo.DefectCountLimit)
{
curRecord.preWarningPhotoIndex = liPhotoIndex + 1;
AddTextEvent(DateTime.Now, $"告警", $"每百米瑕疵数量达到阈值!({defectCount}>={curRecord.ProductInfo.DefectCountLimit})", WarningEnum.High);
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 = 11;
}
//暂停:每个缺陷项不同长度检测数量报警
if (curRecord.DefectTotalCount > 0 && curRecord.DefectInfoList != null)
{
#if true
//按缺陷计算没X米多少缺陷报警
for (int i = 0; i < curRecord.ProductInfo.QualifiedLimitList.Count; i++)
{
var defectWarn = curRecord.ProductInfo.QualifiedLimitList[i];
if (defectWarn.DefectWarnLength > 0 || defectWarn.DefectWarnCnt > 0)
{
errStep = 12;
int liPhotoIndex = scanPhoto.photoIndex - Config.defectPauseSkipPhotoCount; //二次判定完的图片index
int warnLen = defectWarn.DefectWarnLength * 100;//每米 to cm
int warnCount = warnLen * Config.cm2px_y / scanPhoto.mat.Height; //计算图像张数
//从上次告警后重新开始计算长度及数量
int warnDefectCount = curRecord.DefectInfoList.Where(m => m.PhotoIndex >= curRecord.preWarningPhotoIndexByLabel[i] && m.PhotoIndex >= (liPhotoIndex + 1 - warnCount) && m.PhotoIndex <= liPhotoIndex).Count();
if (warnDefectCount >= defectWarn.DefectWarnCnt)
{
curRecord.preWarningPhotoIndexByLabel[i] = liPhotoIndex + 1;
AddTextEvent(DateTime.Now, $"告警", $"每{defectWarn.DefectWarnLength}米{Config.getDefectName(defectWarn.Code)}瑕疵数量达到阈值!({warnDefectCount}>={defectWarn.DefectWarnCnt})", WarningEnum.High);
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);
});
}
}
}
}
#endif
}
#if false
//暂停:按等级分卷
if (curRecord.DefectTotalCount > 0 && curRecord.ProductInfo.GradeLimitList != null && curRecord.ProductInfo.GradeLimitList.Count > 0 && curRecord.DefectInfoList != null)
{
errStep = 13;
//按缺陷计算每X米多少缺陷分等级
for (int i = 0; i < curRecord.ProductInfo.GradeLimitList.Count; i++)
{
if (curRecord.ProductInfo.GradeLimitList[i].JudgeLength > 0)
{
errStep = 14;
int liPhotoIndex = scanPhoto.photoIndex - Config.defectPauseSkipPhotoCount; //二次判定完的图片index
double GrageLen = curRecord.ProductInfo.GradeLimitList[i].JudgeLength * 100;//每米 to cm
int warnCount = (int)(GrageLen * Config.cm2px_y) / scanPhoto.mat.Height; //计算图像张数
if (curRecord.GradeDifferentiateInfoList == null)
{
curRecord.GradeDifferentiateInfoList = new List<GradeDifferentiateInfo>();
}
GradeLimit item = curRecord.ProductInfo.GradeLimitList[i];
GradeDifferentiateInfo differentiateInfo = new GradeDifferentiateInfo();
//从上次告警后重新开始计算长度及数量
var allFind = curRecord.DefectInfoList.Where(m => m.PhotoIndex >= curRecord.preGradePhotoIndexByGradeIndex && m.PhotoIndex >= (liPhotoIndex + 1 - warnCount) && m.PhotoIndex <= liPhotoIndex).ToList();
int warnDefectCount = 0;
if (item.Code == "All")
warnDefectCount = allFind.Count();
else
{
warnDefectCount = allFind.Where(m => m.Code == item.Code).Count();
}
int GradeCount = 0;
if (item.E > 0 && warnDefectCount > item.E)
{
GradeCount = item.E;
differentiateInfo.GradeCode = "E";
}
else if (item.D > 0 && warnDefectCount > item.D)
{
GradeCount = item.D;
differentiateInfo.GradeCode = "D";
}
else if (item.C > 0 && warnDefectCount > item.C)
{
GradeCount = item.C;
differentiateInfo.GradeCode = "C";
}
else if (item.B > 0 && warnDefectCount > item.B)
{
GradeCount = item.B;
differentiateInfo.GradeCode = "B";
}
else if (item.A > 0 && warnDefectCount > item.A)
{
GradeCount = item.A;
differentiateInfo.GradeCode = "A";
}
else
{
//不需要分级,下一条
continue;
}
differentiateInfo.UseGradeLimit = item;
differentiateInfo.DefectCnt = warnDefectCount;
differentiateInfo.StartPhotoIndex = allFind.Min(x => x.PhotoIndex);
differentiateInfo.EndPhotoIndex = allFind.Max(x => x.PhotoIndex);
differentiateInfo.StartY = allFind.Min(x => x.CentreY) / 100 - OffsetCut;
differentiateInfo.EndY = allFind.Max(x => x.CentreY) / 100 + OffsetCut;
differentiateInfo.CutLen = differentiateInfo.EndY - differentiateInfo.StartY;
//记录新的判定开始位置
curRecord.preGradePhotoIndexByGradeIndex = liPhotoIndex + 1;
AddTextEvent(DateTime.Now, $"提示", $"每{curRecord.ProductInfo.GradeLimitList[i].JudgeLength}米,瑕疵数量达到分级阈值!({warnDefectCount}>={GradeCount})", WarningEnum.Low);
curRecord.GradeDifferentiateInfoList.Add(differentiateInfo);
//标记裁切位置
this.BeginInvoke(new System.Action(() =>
{
reDrawDefectPointsAndCut(differentiateInfo.StartY, differentiateInfo.EndY, differentiateInfo.GradeCode);
}));
//裁切暂停提示
if (curRecord.ProductInfo.IsHintCutting)
{
AddTextEvent(DateTime.Now, $"提示", $"裁切 起始{differentiateInfo.StartY}-终点{differentiateInfo.EndY}", WarningEnum.Low);
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);
});
}
}
}
}
}
#endif
errStep = 21;
Application.DoEvents();
}
}
catch (Exception e)
{
AddTextEvent(DateTime.Now, $"拍照", $"errStep:{errStep}-{e.Message}", WarningEnum.High);
}
}
/// <summary>
/// 相机图片合并预处理
/// </summary>
/// <param name="task"></param>
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,$"图像处理", $"图像{scanPhotos0.photoIndex}ThreadId={Thread.CurrentThread.ManagedThreadId}", WarningEnum.Low, false);
string time = "";
stopWatch.Start();
try
{
if (scanPhotos0.mat.Height != scanPhotos1.mat.Height)
{
int xw, xh;
AddTextEvent(DateTime.Now,$"警告", $"两相机采集图高度不一致({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,out xw, out xh);
else
scanPhotos0.mat = OpenCVUtil.resize(scanPhotos0.mat, scanPhotos1.mat.Width, scanPhotos1.mat.Height, out xw, out xh);
}
//saveMatTest(scanPhotos0.mat, 1);
//saveMatTest(scanPhotos1.mat, 2);
//反转+相机索引调换
Mat mat0 = scanPhotos1.mat;
Mat mat1 = scanPhotos0.mat;
#if false //去除不需要
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})";
}
#endif
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 /2 ;
mat0 = OpenCVUtil.cutImage(mat0, 0, 0, width, mat0.Height);
time += $"->图1去重({stopWatch.ElapsedMilliseconds})";
width = mat1.Width - Config.MiddleSuperposition / 2;
mat1 = OpenCVUtil.cutImage(mat1, Config.MiddleSuperposition / 2, 0, width, mat1.Height);
time += $"->图2去重({stopWatch.ElapsedMilliseconds})";
}
AddTextEvent(DateTime.Now,$"裁边",
$"(图像{scanPhotos0.photoIndex})-左图去重后:{mat0.Width}*{mat0.Height},右图:{mat1.Width}*{mat1.Height}" +
$"重复值:{Config.MiddleSuperposition},孔洞:{Config.MarginHoleWidth},cm2px{Config.cm2px_x},resizeWidth{resizeWidth}", WarningEnum.Low, false);
errStep = 4;
#if false
//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})";
#endif
//水平合并l
Mat mat = OpenCVUtil.mergeImage_sameSize(new Mat[] { mat0, mat1 });//这里相机反装,左右反转下
//AddTextEvent(DateTime.Now, $"裁边", $"(图像{scanPhotos0.photoIndex})-边缘宽度:(左图)={marginWidth0},(右图)={marginWidth1}; 裁边去孔洞后:({mat0.Width}+{mat1.Width}={mat0.Width + mat1.Width});合并后(去孔洞){mat.Width}*{mat.Height}", WarningEnum.Low, false);
AddTextEvent(DateTime.Now, $"裁边", $"(图像{scanPhotos0.photoIndex}); 裁边去孔洞后:({mat0.Width}+{mat1.Width}={mat0.Width + mat1.Width});合并后(去孔洞){mat.Width}*{mat.Height}", WarningEnum.Normal, false);
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,$"门幅", $"(图像{scanPhotos0.photoIndex})-({scanPhotos0.photoIndex})位置:{point[0]}; 幅宽:{point[1]}", WarningEnum.Normal, false);
curRecord.FacePointList.Add(point);
List<float[]> mfdata = new List<float[]>();
for (int i = 0;i< curRecord.FacePointList.Count;i++)
//foreach (var item in curRecord.FacePointList)
mfdata.Add(curRecord.FacePointList[i]);
reDrawFaceWidth(mfdata,
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;//总时间 分
#if JM
double stLen = devContainer.GetLength();
curRecord.Len = stLen;
#else
stLen = lenMi;
#endif
//ptTime = ptStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
this.BeginInvoke(new System.Action(() =>
{
//double sstLen = devContainer.GetLength();
ptTime = ptStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
AddTextEvent(DateTime.Now, $"记录", $"(计米{stLen}米),时间:{ptTime}分; 速度:{Math.Round((stLen - ptLen) / ptTime, 2)}米/分", WarningEnum.Normal, false);
this.lblLen.Text = $"{stLen}米";//$"{lenMi}米";
this.lblLen.Tag = faceWidthX_cm;
#if JM
this.lblSpeed.Text = $"速度:{Math.Round((stLen - ptLen) / ptTime, 2)}米/分";//$"速度:{Math.Round(lenMi / curRecord.TimeLen, 2)}米/分";
#else
this.lblSpeed.Text = $"速度:{Math.Round(lenMi / curRecord.TimeLen, 2)}米/分";
#endif
this.uilbKF.Text = $"当前幅宽:{faceWidthY_cm}cm";
ptLen = stLen;
ptStopWatch.Restart();//重新计时
}));
//
errStep = 9;
time += $"->速度刷新({stopWatch.ElapsedMilliseconds})";
//----缺陷队列
int oxw, oxh;
mat = OpenCVUtil.resize(mat, resize.Width, resize.Height, out oxw, out oxh);
AddTextEvent(DateTime.Now,$"图像处理", $"(图像{scanPhotos0.photoIndex})-合成图resize后:{mat.Width}*{mat.Height}-{oxw}*{oxh}", WarningEnum.Normal, false);
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,
xw = oxw,
});
errStep = 10;
time += $"->加入瑕疵待检队列({stopWatch.ElapsedMilliseconds})";
}
catch (Exception ex)
{
curRecord.ScannerPhotoFinishCount++;//失败时不能因数量不一致无法保存
AddTextEvent(DateTime.Now,$"图像处理", $"异常({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,$"图像处理", $"(图像{scanPhotos0.photoIndex})-进度计时:{time}", WarningEnum.Normal, false);
scanPhotos0.mat.Dispose();
scanPhotos1.mat.Dispose();
scanPhotos0 = scanPhotos1 = null;
task = null;
//System.GC.Collect();
}
}
#endif
/// <summary>
/// 处理完成回调
/// </summary>
/// <param name="res"></param>
private void callBackDefectEvent(Device.DefectLib.DefectTask res)
{
{
int step = 0;
try
{
AddTextEvent(DateTime.Now,$"检测完成", $"图像队列:{res.record.ScannerPhotoFinishCount+1}/{res.record.ScannerPhotoCount} (图像{res.photoIndex})检测结果:{res.isSucceed}", WarningEnum.Normal, false);
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,$"检测完成", $"(图像{res.photoIndex})-瑕疵检测完成,共{res.excelTable.Rows.Count}个瑕疵!各环节用时:{string.Join(",",res.stopwatch)}", WarningEnum.Normal, false);
//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);
if (!Config.IsSaveAllImage && Config.IsSaveDefectSourceImage)
OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirSourcePath}{res.photoIndex}.bmp", ImageFormat.Bmp);
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
//Y = Math.Round((res.PicDis * 100 - 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 (!defectTag.ContainsKey(res.photoIndex))
{
defectTag.Add(res.photoIndex, res.bmpTag.Clone());
}
//保存打标小图
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,$"告警", $"瑕疵面积达到阈值!({defectInfo.Area}>={res.record.ProductInfo.DefectAreaLimit})", WarningEnum.High);
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);
});
}
}
}
AddTextEvent(DateTime.Now,$"检测完成", "更新UI", WarningEnum.Low, false);
//更新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,$"检测完成", "保存CSV", WarningEnum.Low, false);
//保存CSV
bool b = Utils.ExcelUtil.DataTable2CSV($"{dirPath}{res.photoIndex}.csv", res.excelTable);
//AddTextEvent(DateTime.Now,$"打标完成", $"{res.tag}.xlsx {(b ? "保存成功!" : "保存失败!")}");
step = 10;
#if
//每百米告警判断???在此还是在收到新照片时触发???
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,$"告警", $"每百米瑕疵数量达到阈值!({defectCount}>={res.record.ProductInfo.DefectCountLimit})", WarningEnum.High);
}
step = 11;
#if false
//按缺陷计算没X米多少缺陷报警
for (int i = 0; i < res.record.ProductInfo.QualifiedLimitList.Count; i++)
{
var defectWarn = res.record.ProductInfo.QualifiedLimitList[i];
if (defectWarn.DefectWarnLength > 0 || defectWarn.DefectWarnCnt >0)
{
step = 12;
int warnLen = defectWarn.DefectWarnLength * 100;//每百米 to cm
int warnCount = warnLen * Config.cm2px_y / res.bmp.Height;
//从上次告警后重新开始计算长度及数量
int warnDefectCount = res.record.DefectInfoList.Where(m => m.PhotoIndex >= res.record.preWarningPhotoIndexByLabel[i] && m.PhotoIndex >= res.photoIndex + 1 - warnCount).Count();
if (warnDefectCount >= defectWarn.DefectWarnCnt)
{
res.record.preWarningPhotoIndexByLabel[i] = res.photoIndex + 1;
AddTextEvent(DateTime.Now, $"告警", $"每{defectWarn.DefectWarnLength}米{Config.getDefectName(defectWarn.Code)}瑕疵数量达到阈值!({warnDefectCount}>={defectWarn.DefectWarnCnt})", WarningEnum.High);
}
}
}
#endif
}
#endif
}
}
else
{
AddTextEvent(DateTime.Now,$"打标失败", $"(图像{res.photoIndex})-瑕疵检测失败TId={Thread.CurrentThread.ManagedThreadId}");
}
res.bmp.Dispose();
res.bmpTag.Dispose();
res.bmps_cut = null;
res.excelTable.Dispose();
if(Config.OpenHalconDefect)
{
res.ho_Img.Dispose();
res.ho_imgG.Dispose();
res.ho_ImageResult3.Dispose();
res.ho_ImageSub.Dispose();
res.hv_RES.Dispose();
res.hv_gauss_filter1.Dispose();
res.hv_gauss_filter2.Dispose();
res.hv_Energy_value.Dispose();
res.hv_Region_S_value.Dispose();
res.hv_class.Dispose();
res.hv_defectinfo.Dispose();
}
}
catch (Exception ex)
{
AddTextEvent(DateTime.Now,$"打标失败", $"(图像{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,$"检测完成", $"{liScannerPhotoFinishCount}/{liScannerPhotoCount}", WarningEnum.Low, false);
//this.BeginInvoke(new System.Action(() =>
//{
// this.lblWaitImageCount.Text = $"{liScannerPhotoCount - liScannerPhotoFinishCount}";
//}));
res = null;
System.GC.Collect();
}
}
}
/// <summary>
/// 数据保存状态
/// </summary>
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})已完成检测。");
if(!string.IsNullOrEmpty(Config.ServerDBConStr))
{
try
{
InitDB.SendServerDB(Config.ServerDBConStr, model);
AddTextEvent(DateTime.Now, "上传完成", $"({key}) 批号({model.BatchId})已完成检测。");
}
catch (Exception ex)
{
AddTextEvent(DateTime.Now, "上传失败", $"({key}) 批号({model.BatchId}):{ex.Message}", WarningEnum.High);
}
}
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();
#if NT
if (null != _cts)
{
_cts.Cancel();
}
#endif
AddTextEvent(DateTime.Now,"停机", "停机完成。");
//重置缓存
scanPhotos = new ScanPhotoInfo[3];
#if NT
if (t_test1 != null)
{
bool b = t_test1.Join(5000);
if (!b) t_test1.Abort();
t_test1 = null;
}
if (t_test2 != null)
{
bool b = t_test2.Join(5000);
if (!b) t_test2.Abort();
t_test2 = null;
}
if (t_test3 != null)
{
bool b = t_test3.Join(5000);
if (!b) t_test3.Abort();
t_test3 = null;
}
#endif
}
private Thread t_test;
//启动
private void btnStart_Click(object sender, EventArgs e)
{
if(!_IsGetErpCode)
{
AddTextEvent(DateTime.Now, "启动", "还未扫码获取检测信息!", WarningEnum.Low);
return;
}
AddTextEvent(DateTime.Now,"启动", "下发启动指令...");
this.btnPause.Enabled = true;
#if OnLine
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, "启动", "设备急停!");
}
#else
//暂停-》继续
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.;
defectTag.Clear();
ThnDieLen = 0;
}
this.Invoke(new System.Action(() =>
{
this.btnStart.Enabled = false;
this.btnEnd.Enabled = this.btnPause.Enabled = true;
}));
IsTest = true;
t_test = new System.Threading.Thread(run_Test);
t_test.IsBackground = true;
t_test.Start();
#endif
}
#region 线
private bool IsTest = false;
private void run_Test()
{
int num1 = 0;
int num2 = 0;
Mat mat1 = new Mat("E:\\CPL\\img\\L1.bmp");
Mat mat2 = new Mat("E:\\CPL\\img\\R1.bmp");
while (IsTest)
{
#if NT
#else
callBackScanMatEvent(num1++, mat1.Clone(), 0);
callBackScanMatEvent(num2++, mat2.Clone(), 1);
#endif
Thread.Sleep(1000);
}
}
#endregion
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();
ptStopWatch.Start();
}
//写I/O启动。。。
//继续读取编译器和门幅等
//int nextStepId = currProcessIndex;
//do
//{
// currentState = CurrentStateEnum.运行中;
// nextStepId = nextProcess(currProductModel, nextStepId);
//} while (nextStepId >= 0 && !isBreakProcessRun());
});
}
else//首次开始/结束后重新开始
{
#if JM
devContainer.ClearLengthCount();
#endif
devContainer.devCamer1.resetScanIndex();
devContainer.devCamer2.resetScanIndex();
#if JM
ptLen = Math.Round(devContainer.GetLength(), 2);
#endif
//校正从复位-》运行,不会新启动
resetUIValue();
AddTextEvent(DateTime.Now,"启动", "开始测试...");
currentState = CurrentStateEnum.;
defectTag.Clear();
ThnDieLen = 0;
}
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();
ptStopWatch.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)
{
if (!ShowAskDialog("提示", "是否保存当前检测结果?", UIStyle.Blue, false, UIMessageDialogButtons.Cancel))
return;
AddTextEvent(DateTime.Now,"结束验布", "结束验布!");
#if OnLine
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);
});
}
#else
IsTest = false;
if (t_test != null)
{
bool b = t_test.Join(5000);
if (!b) t_test.Abort();
t_test = null;
}
#endif
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();
if(_matList1.Count > 0)
{
tScanPhotoInfo dt;
for (int i = 0; i < _matList1.Count; i++)
{
_matList1.TryDequeue(out dt);
}
}
if (_matList2.Count > 0)
{
tScanPhotoInfo dt;
for (int i = 0; i < _matList2.Count; i++)
{
_matList2.TryDequeue(out dt);
}
}
currKey = 0;
txtBarCodeName.Text = txtBatchId.Text = txtReelId.Text = "";
pStopWatch.Stop();
ptStopWatch.Stop();
this.btnStart.Enabled = true;
this.btnEnd.Enabled = this.btnPause.Enabled = false;//这里有问题应该是devPlc回调设置
_IsGetErpCode = false;
}
else
{
AddTextEvent(DateTime.Now, "结束验布", "无数据结束验布!");
_isDefect = false;
_IsGetErpCode = 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;
if (currentState != CurrentStateEnum. )
return;
if(devContainer.devCodeScanner != null)
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 = "wuyin";
//dt.image = Image.FromFile("C:\\Users\\fang\\Desktop\\123.png");
//lstEditDefect.Add(dt);
//Mat mtt = new Mat("C:\\Users\\fang\\Desktop\\新建文件夹\\mx\\636.bmp");
//FHome_Defect frmDefect = new FHome_Defect(lstEditDefect, mtt);
//frmDefect.ShowDialog();
Config.LoadAllConfig();
//设置程序最小/大线程池
// Get the current settings.
int minWorker, minIOC;
ThreadPool.GetMinThreads(out minWorker, out minIOC);
ThreadPool.SetMinThreads(25, minIOC);
Mat matt = new Mat("C:\\Users\\fang\\Desktop\\新建文件夹\\433.bmp");
//OpenCVUtil.LoadEdgeMode();
//int tt = 0;
//var mty = OpenCVUtil.getMaxInsetRect2(matt, false, 0,out tt);
//mty.SaveImage("edge.bmp");
List<QualifiedLimit> qlist = new List<QualifiedLimit>();
//[ 'laji','liangdian', 'wuyin', 'jietou', 'bmss', 'qipi', 'tiaohen','yayin','zhouyin','yisesi','chongying']
qlist.Add(new QualifiedLimit() { Code = "laji", ZXD = 0.3, Area = 0.04, ContrastLower = 0.98, ContrastTop = 1.02 });
qlist.Add(new QualifiedLimit() { Code = "liangdian", ZXD = 0.3, Area = 0.09, ContrastLower = 0.93, ContrastTop = 1.07 });
qlist.Add(new QualifiedLimit() { Code = "wuyin", ZXD = 0.3, Area = 0.04, ContrastLower = 0.96, ContrastTop = 1.04 });
qlist.Add(new QualifiedLimit() { Code = "jietou", ZXD = 0.3, Area = 0.09, ContrastLower = 0.94, ContrastTop = 1.06 });
qlist.Add(new QualifiedLimit() { Code = "bmss", ZXD = 0.3, Area = 0.08, ContrastLower = 0.99, ContrastTop = 1.01 });
qlist.Add(new QualifiedLimit() { Code = "qipi", ZXD = 0.4, Area = 0.01, ContrastLower = 0.99, ContrastTop = 1.01 });
qlist.Add(new QualifiedLimit() { Code = "tiaohen", ZXD = 0.3, Area = 2, ContrastLower = 0.99, ContrastTop = 1.01 });
qlist.Add(new QualifiedLimit() { Code = "yayin", ZXD = 0.3, Area = 0.05, ContrastLower = 0.99, ContrastTop = 1.01 });
qlist.Add(new QualifiedLimit() { Code = "zhouyin", ZXD = 0.3, Area = 2, ContrastLower = 0.99, ContrastTop = 1.01 });
qlist.Add(new QualifiedLimit() { Code = "yisesi", ZXD = 0.3, Area = 0.05, ContrastLower = 0.99, ContrastTop = 1.01 });
qlist.Add(new QualifiedLimit() { Code = "chongying", ZXD = 0.3, Area = 2, ContrastLower = 0.99, ContrastTop = 1.01 });
DefectLib dlt = new DefectLib();
dlt.start();
dlt.add(new Device.DefectLib.DefectTask()
{
modelName = "BS_CYG_1003.trt",
record = null,
bmp = matt,
bmpTag = matt.Clone(),
photoIndex = 0,//0-n 首张必需为0因下面计算长度是从0开始
widthRatio = 1,
qualifiedLimitList = qlist,
finishEvent = callBackDefectEvent,
xw = 0,
});
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, $"检测完成", $"(图像{res.photoIndex})-瑕疵检测完成,共{res.excelTable.Rows.Count}个瑕疵!各环节用时:{string.Join(",", res.stopwatch)}");
//AddTextEvent(DateTime.Now,$"打标完成", $"第 ({res.photoIndex}) 张照片,计算过程:{res.resultInfo}");
}
else
{
AddTextEvent(DateTime.Now, $"打标失败", $"(图像{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, $"打标失败", $"(图像{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, $"检测完成", $"{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;
}
}
private void FHome_Resize(object sender, EventArgs e)
{
uilbKF.Top = 8;
}
private void FHome_Paint(object sender, PaintEventArgs e)
{
uilbKF.Top = 8;
}
private void button2_Click(object sender, EventArgs e)
{
double sstLen = devContainer.GetLength();
MessageBox.Show($"{sstLen}");
}
#region ERP测试
private void button3_Click(object sender, EventArgs e)
{
string code = "RSHX2410002536";
var dt = loadErpData(code);
MessageBox.Show($"{JsonConvert.SerializeObject(dt)}");
}
#endregion
}
}