using Bro.Common.Base;
|
using Bro.Common.Helper;
|
using Bro.Common.Interface;
|
using Bro.Common.Model;
|
using Bro.Device.InsCamera;
|
using Bro.M135.Common;
|
using Bro.M135.DBManager;
|
using Bro.Process;
|
using Bro.Process.DataBase.Models;
|
using Bro.UI.Model.Winform;
|
using HalconDotNet;
|
using Newtonsoft.Json;
|
using Newtonsoft.Json.Linq;
|
using NPOI.SS.Formula.Functions;
|
using Org.BouncyCastle.Asn1.X509;
|
using Org.BouncyCastle.Ocsp;
|
using ScottPlot.Drawing.Colormaps;
|
using Sunny.UI;
|
using Sunny.UI.Win32;
|
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
using System.Drawing.Imaging;
|
using System.IO;
|
using System.Linq;
|
using System.Text;
|
using Windows.ApplicationModel.Appointments;
|
using Windows.Networking;
|
using static Org.BouncyCastle.Math.EC.ECCurve;
|
|
namespace Bro.M141.Process
|
{
|
public partial class M141Process : ProcessControl
|
{
|
#region constructor
|
public M141Process() { }
|
|
public M141Process(string productCode) : base(productCode) { }
|
#endregion
|
TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
|
protected M141Config M141Config => Config as M141Config;
|
|
public static object _productListLock = new object();
|
public List<ProductModel> ProductList = new List<ProductModel>();
|
MachineLearningBase ML = null;
|
|
public event Action<List<int>> RefreshUIplc;
|
public event Action<string> RefreshState;
|
|
List<ZipImage> ZipImages = new List<ZipImage>();
|
|
public override void InitialProcessMethods()
|
{
|
base.InitialProcessMethods();
|
|
|
|
|
if (ThHeartPlc == null)
|
{
|
ThHeartPlc = new Thread(Heartplc);
|
ThHeartPlc.IsBackground = true;
|
ThHeartPlc.Start();
|
}
|
}
|
|
public override void ProcessRunStateChanged()
|
{
|
base.ProcessRunStateChanged();
|
|
}
|
|
public PLCBase Plc1;
|
Thread ThHeartPlc;
|
Spec _errorSpec;
|
bool isstart = false;
|
public override void Open()
|
{
|
base.Open();
|
|
ML = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase) as MachineLearningBase;
|
if (ML == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Information, $"未设置ML实例");
|
}
|
Plc1 = DeviceCollection.FirstOrDefault(u => u is PLCBase) as PLCBase;
|
|
if (Plc1 == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未设置plc");
|
}
|
_errorSpec = M141Config.SpecCollection.FirstOrDefault(u => u.Code == M141Config.CheckErrorSpecCode) as Spec;
|
|
|
|
NetWarmUp();
|
|
_positionCheckTimeDict.Clear();
|
_positionSpecHeads.Clear();
|
|
|
InitialContinuousNGAlarm();
|
|
|
int vava = 0;
|
if (M141Config.channelva == 3)
|
{
|
vava = 0;
|
}
|
else if (M141Config.channelva == 2)
|
{
|
vava = 1;
|
}
|
|
Plc1.WriteSingleAddress(3006, vava, out _);
|
|
isstart = true;
|
|
}
|
|
|
public override void Close()
|
{
|
isstart = false;
|
base.Close();
|
}
|
|
public void Heartplc()
|
{
|
Thread.Sleep(1000);
|
|
string _statisticFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Statistic.json");
|
if (File.Exists(_statisticFilePath))
|
{
|
try
|
{
|
string dataStr = "";
|
using (StreamReader reader = new StreamReader(_statisticFilePath, System.Text.Encoding.UTF8))
|
{
|
dataStr = reader.ReadToEnd();
|
}
|
|
lock (StatisticRecordsFull)
|
{
|
var temRecords = JsonConvert.DeserializeObject<StatisticRecords_Full>(dataStr);
|
if (StatisticRecordsFull != null && temRecords != null)
|
{
|
StatisticRecordsFull.CurRecord = temRecords.CurRecord;
|
StatisticRecordsFull.HistoryRecord = temRecords.HistoryRecord;
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"产品统计信息反序列化异常");
|
StatisticRecordsFull = new StatisticRecords_Full();
|
}
|
}
|
int state = 0;
|
int state2 = 0;
|
int numsum = 0;
|
DateTime dtday = DateTime.Now;
|
while (true)
|
{
|
Thread.Sleep(1000);
|
|
|
if (!isstart)
|
{
|
continue;
|
}
|
numsum++;
|
|
try
|
{
|
Plc1.WriteSingleAddress(3009, 2, out _);
|
}
|
catch
|
{
|
|
}
|
|
|
|
try
|
{
|
if (M141Config.WorkShiftList != null && M141Config.WorkShiftList.Count > 0 && numsum >= 0)
|
{
|
for (int i = 0; i < M141Config.WorkShiftList.Count; i++)
|
{
|
|
double timeshap = (DateTime.Now - M141Config.WorkShiftList[i].ShiftTime_Start).TotalMinutes % 1440;
|
double timeshap2 = (DateTime.Now - M141Config.WorkShiftList[i].ShiftTime_End).TotalMinutes % 1440;
|
|
|
if (timeshap2 > 0 && timeshap2 < 1)
|
{
|
if (M141Config.WorkShiftList[i].IsRecordProductSummary)
|
{
|
string csvPathAll = Path.Combine(M141Config.LogPath, "Alldata.csv");
|
|
using (StreamWriter writer = new StreamWriter(csvPathAll, true, Encoding.UTF8))
|
{
|
try
|
{
|
int sum = StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.Where(u => u.IsStatistic).Sum(u => u.Amount);
|
int OKnum = 0;
|
string okpercent = "";
|
string headcsv = "日期,班次,总数,OK,OK占比";
|
string datacsv = "";
|
|
StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.ForEach(u =>
|
{
|
if (u.ClassDesc.ToUpper() == "OK")
|
{
|
OKnum = u.Amount;
|
okpercent = u.PercentStr;
|
}
|
else
|
{
|
headcsv += $",{u.ClassDesc},{u.ClassDesc}占比";
|
datacsv += $",{u.Amount},{u.PercentStr}";
|
}
|
|
});
|
|
string daystr = DateTime.Now.ToString("yyyyMMdd");
|
if (M141Config.WorkShiftList[i].ShiftTime_End.TimeOfDay < M141Config.WorkShiftList[i].ShiftTime_Start.TimeOfDay)
|
{
|
daystr = DateTime.Now.AddDays(-1).ToString("yyyyMMdd");
|
}
|
|
datacsv = $"{daystr}T,{M141Config.WorkShiftList[i].ShiftName},{sum},{OKnum},{OKnum}" + datacsv;
|
|
writer.WriteLine(headcsv);
|
writer.WriteLine(datacsv);
|
|
}
|
catch (Exception exx)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, exx.ToString());
|
}
|
}
|
|
}
|
numsum = -62;
|
}
|
|
if (timeshap > 0 && timeshap < 1)
|
{
|
|
if (M141Config.WorkShiftList[i].IsClearProductSummary)
|
{
|
StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.Clear();
|
StatisticRecordsFull.CurRecord.DefectSummary.RecordsList.Clear();
|
}
|
numsum = -62;
|
}
|
}
|
}
|
|
lock (StatisticRecordsFull)
|
{
|
if (numsum > 20)
|
{
|
numsum = 0;
|
using (FileStream fileStream = new FileStream(_statisticFilePath, FileMode.OpenOrCreate, FileAccess.Write))
|
{
|
fileStream.Seek(0L, SeekOrigin.Begin);
|
string s = JsonConvert.SerializeObject(StatisticRecordsFull);
|
byte[] bytes = Encoding.UTF8.GetBytes(s);
|
fileStream.Write(bytes, 0, bytes.Length);
|
fileStream.SetLength(bytes.Length);
|
fileStream.Flush();
|
fileStream.Close();
|
}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
|
}
|
|
|
|
try
|
{
|
var tem = Plc1.Read(3030, 18, out _);
|
if (tem != null && RefreshUIplc != null)
|
{
|
RefreshUIplc.Invoke(tem);
|
}
|
}
|
catch
|
{
|
|
}
|
|
try
|
{
|
var tem = Plc1.Read(3010, 8, out _);
|
if (tem != null && RefreshUIplc != null)
|
{
|
RefreshUIplc.Invoke(tem);
|
}
|
}
|
catch
|
{
|
|
}
|
|
try
|
{
|
var tem = Plc1.Read(3027, 1, out _)[0];
|
var tem2 = Plc1.Read(3028, 1, out _)[0];
|
if (state != tem || state2 != tem2)
|
{
|
state = tem;
|
state2 = tem2;
|
|
if (RefreshState != null)
|
{
|
if (state == 1)
|
{
|
RefreshState.Invoke("调试模式");
|
}
|
else if (state2 == 1)
|
{
|
RefreshState.Invoke("离线模式");
|
}
|
else
|
{
|
RefreshState.Invoke("正常模式");
|
}
|
}
|
}
|
}
|
catch
|
{
|
|
}
|
|
}
|
}
|
|
|
|
public void PlcWrite(int add, int va)
|
{
|
try
|
{
|
Plc1.WriteSingleAddress(add, va, out _);
|
var tem = Plc1.Read(3030, 18, out _);
|
if (tem != null && RefreshUIplc != null)
|
{
|
RefreshUIplc.Invoke(tem);
|
}
|
}
|
catch
|
{
|
|
}
|
}
|
|
|
/// <summary>
|
/// 网络预热
|
/// </summary>
|
/// <exception cref="NotImplementedException"></exception>
|
private void NetWarmUp()
|
{
|
|
string warmUpImageFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WarmUp");
|
if (!Directory.Exists(warmUpImageFolder))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"程序根目录下没有\"WarmUp\"预热图片文件夹");
|
return;
|
}
|
|
var ml = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase && u.CurrentState == EnumHelper.DeviceState.DSOpen) as MachineLearningBase;
|
if (ml == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"预热时未能获取开启的深度学习驱动");
|
return;
|
}
|
var netNames = ml.IConfig.NetCollections.Where(u => u.IsEnabled).Select(u => u.Name).ToList();
|
var imageFiles = new DirectoryInfo(warmUpImageFolder).GetFiles().Select(u => u.FullName).ToList();
|
|
Parallel.ForEach(netNames, n =>
|
{
|
Parallel.ForEach(imageFiles, i =>
|
{
|
HImage hImage = new HImage();
|
hImage.ReadImage(i);
|
|
ml.RunNetEvaluate(n, hImage);
|
|
hImage.Dispose();
|
hImage = null;
|
});
|
});
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "深度学习驱动预热完成");
|
|
|
if (M141Config.WarmUp && M141Config.WarmUpList.Count > 0)
|
{
|
M141Config.WarmUpList.AsParallel().ForAll(x =>
|
{
|
try
|
{
|
HImage im = new HImage(x.PicFilePath);
|
var tool = GetHalconTool(null, "", x.HalconFilePath);
|
if (tool != null)
|
{
|
//int num = 0;
|
//for (int i = 0; i < 10; i++)
|
//{
|
try
|
{
|
var res = tool.RunProcedure(null, new Dictionary<string, HalconDotNet.HObject>() { { "INPUT_Image", im } }, new List<string>() { "OUTPUT_Results_1", "OUTPUT_Results_2" }, null);
|
|
//if (res != null)
|
//{
|
// if (res.Item1&& res.Item2[$"OUTPUT_Results_{i}"].HTupleToDouble()[0]!=-1234)
|
// {
|
// num++;
|
// if (num >= 2)
|
// {
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"算法{x.HalconFilePath}预热完成{i}");
|
// break;
|
// }
|
// }
|
//}
|
}
|
catch
|
{
|
|
}
|
//if (i==9)
|
//{
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败{num}");
|
//}
|
//}
|
}
|
im.Dispose();
|
|
}
|
catch
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败");
|
}
|
});
|
}
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "算法预热完成");
|
}
|
|
static object _positionCheckTimeLock = new object();
|
Dictionary<string, List<int>> _positionCheckTimeDict = new Dictionary<string, List<int>>();
|
Dictionary<string, List<string>> _positionSpecHeads = new Dictionary<string, List<string>>();
|
|
|
volatile int uploadId = 0;
|
|
public void NewProductIntoList(ProductModel p, bool isSaveDB)
|
{
|
lock (_productListLock)
|
{
|
ProductList.RemoveAll(u => u.PID == p.PID || u.SEQUENCE == p.SEQUENCE);
|
ProductList.Insert(0, p);
|
while (ProductList.Count > 200)
|
{
|
ProductList.RemoveAt(ProductList.Count - 1);
|
}
|
}
|
|
//if (isSaveDB)
|
//{
|
// var isNewDone = _manager_P_Product.NewProduct(p, p.Details, out string msg);
|
// if (!isNewDone)
|
// {
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{p.PID}数据库新增异常,{msg}");
|
// }
|
//}
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"{p.PID}_{p.SEQUENCE}产品入列完成");
|
}
|
|
public virtual ProductModel FindProductBySequence(string sequence, bool isEnabelQueue)
|
{
|
ProductModel p = null;
|
if (isEnabelQueue)
|
{
|
lock (_productListLock)
|
{
|
p = ProductList.FirstOrDefault(u => u.SEQUENCE == sequence);
|
}
|
}
|
|
if (p != null)
|
{
|
return p;
|
}
|
else
|
{
|
//var pDB = _manager_P_Product.QueryProductBySequence(sequence);
|
//if (pDB != null)
|
//{
|
// p = new ProductModel(pDB);
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"从数据库获取产品对象{pDB.PID},序号{pDB.SEQUENCE},条码{pDB.SN}");
|
//}
|
|
if (p == null)
|
{
|
p = new ProductModel();
|
p.SEQUENCE = sequence;
|
p.PID = p.PID + "_" + sequence.Split('_')[sequence.Split('_').Length - 1];
|
|
p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Where(u => u.IsEnabled).Select(u => u.PositionName).ToList());
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"未能获取产品对象,使用临时新建产品对象");
|
}
|
|
NewProductIntoList(p, false);
|
}
|
|
return p;
|
}
|
|
public async Task RunImageCheckAsync(List<ProductModel> products, string triggerText, string triggerSource, IImageSet imgSet, MeasureBind measureBind)
|
{
|
await Task.Run(() =>
|
{
|
List<DetectResult> resultList = new List<DetectResult>();
|
if (products == null || products.Count == 0)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"工位{measureBind.WorkPosition}检测时产品信息为空");
|
imgSet.HImage?.Dispose();
|
imgSet.HImage = null;
|
return;
|
}
|
|
try
|
{
|
List<string> pidList = products.Select(u => u.PID).OrderBy(u => u).ToList();
|
if (imgSet == null || imgSet.HImage == null)
|
{
|
throw new Exception($"产品{string.Join(",", pidList)}检测{measureBind.GetDisplayText()}未能获取图片对象");
|
}
|
|
//检测顺序 ML->自定义检测
|
if (!string.IsNullOrWhiteSpace(measureBind.DetectionId))
|
{
|
string detectionName = (ML.InitialConfig as MLInitialConfigBase).DetectionConfigs.FirstOrDefault(u => u.Id == measureBind.DetectionId)?.Name;
|
|
|
//List<string> pidList2 = new List<string>();//pidList.Select(u => u.Split('_')[u.Split('_').Length - 1]).ToList();
|
//Dictionary<string, string> dicpid = new Dictionary<string, string>();
|
|
//for (int i = 0; i < pidList.Count; i++)
|
//{
|
// var tem = pidList[i].Split('_')[pidList[i].Split('_').Length - 1];
|
// pidList2.Add(tem);
|
// dicpid[tem] = pidList[i];
|
//}
|
|
|
List<DetectResult> detectResults = ML?.RunMLDetectionSync(imgSet, pidList, measureBind.DetectionId);
|
List<DetectResult> ngResults = new List<DetectResult>();
|
|
|
//for (int i = 0; i < detectResults.Count; i++)
|
//{
|
// detectResults[i].PID = dicpid[detectResults[i].PID];
|
//}
|
|
|
detectResults.GroupBy(u => u.PID).ToList().ForEach(u =>
|
{
|
if (u.ToList().Count > 0 && u.ToList().Any(m => m.ResultState != EnumHelper.ResultState.OK))
|
{
|
if (u.ToList().GetDefectDescList().Count == 0)
|
{
|
var errorSpec = _errorSpec.Copy();
|
errorSpec.Code = "检测TBD";
|
errorSpec.ActualValue = -999;
|
DetectResult ngResult = new DetectResult() { Specs = new List<ISpec>() { errorSpec }, PID = u.Key };
|
ngResults.Add(ngResult);
|
}
|
}
|
});
|
|
detectResults.AddRange(ngResults);
|
resultList.AddRange(detectResults);
|
|
//detectResults[0].ActionForAllNetResults(n =>
|
//{
|
// if (n.DetectDetails.Count == 0)
|
// {
|
// string data = $"{n.DetectTime.ToString("HH:mm:ss.fff")},{pid},,,,{detectResult.DetectionName},{n.IsAbandoned},{n.NetName},{set.ImageIndex},OK,OK,,,,,,,,";
|
// CSVHelper.CSVOutputAsync(csvpartfilename, data, Part_CSV_Head);
|
// }
|
// else
|
// {
|
// n.DetectDetails.ForEach(d =>
|
// {
|
// string data = $"{n.DetectTime.ToString("HH:mm:ss.fff")},{pid},{d.Id},{string.Join("|", d.ParentIds)},{d.Remark},{detectResult.DetectionName},{d.IsAbandoned},{n.NetName},{set.ImageIndex},{d.FinalResult},{d.DetectResult},{d.ClassName},{(d.Rect.Width * d.PixelSize).ToString("f4")},{(d.Rect.Height * d.PixelSize).ToString("f4")},{d.Probability},{d.Uncertainty},{d.Area},{d.AreaInCrop},{d.AreaInActual.ToString("f4")},{d.Rect.X.ToString("f4")},{d.Rect.Y.ToString("f4")}";
|
// CSVHelper.CSVOutputAsync(csvpartfilename, data, Part_CSV_Head);
|
// });
|
// }
|
//});
|
}
|
|
|
RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedMonitorId, resultList);
|
RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedCombineMethodId, resultList);
|
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBind.WorkPosition}检测过程异常,{ex.ToString()}");
|
|
var errorSpec = _errorSpec.Copy();
|
errorSpec.ActualValue = -999;
|
products.ForEach(p =>
|
{
|
p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, new List<DetectResult>()
|
{
|
new DetectResult()
|
{
|
Specs = new List<ISpec>()
|
{
|
errorSpec
|
},
|
PID = p.PID,
|
}
|
});
|
});
|
}
|
finally
|
{
|
|
try
|
{
|
if (resultList.Count > 0)
|
{
|
products.ForEach(p =>
|
{
|
var pResults = resultList.Where(u => u.PID == p.PID).ToList();
|
p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, pResults);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}添加工位{measureBind.WorkPosition}检测结果,数量{pResults.Count}");
|
});
|
}
|
|
products.ForEach(p =>
|
{
|
if (p.PositoinCheckDone(measureBind.WorkPosition, measureBind.CheckIndex, out string msg))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,该工位检测全部结束");
|
}
|
else
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,{msg}");
|
}
|
});
|
|
|
if (resultList.Any(u => u.ResultState != EnumHelper.ResultState.OK))
|
{
|
if (!products[0].SEQUENCE.ToLower().Contains("test"))
|
{
|
SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition);
|
}
|
if (measureBind.NGImageSwitch)
|
{
|
if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录");
|
}
|
else
|
{
|
string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "NG");
|
|
if (!Directory.Exists(folder))
|
{
|
Directory.CreateDirectory(folder);
|
}
|
|
string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}";
|
|
string post = "";
|
if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatNG))
|
{
|
post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatNG];
|
}
|
else
|
{
|
post = M141Config.ImageFormatNG.ToString().ToLower();
|
}
|
|
string ngImageFile = Path.Combine(folder, $"{id}.{post}");
|
var bitmap = imgSet.HImage.ConvertHImageToBitmap();
|
bitmap.Save(ngImageFile, M141Config.ImageFormatNG);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}NG图片已保存");
|
bitmap.Dispose();
|
}
|
}
|
}
|
else
|
{
|
if (!products[0].SEQUENCE.ToLower().Contains("test"))
|
{
|
SaveZipPreparation(string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}", imgSet, measureBind.WorkPosition);
|
}
|
if (measureBind.OKImageSwitch)
|
{
|
if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录");
|
}
|
else
|
{
|
string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "OK");
|
|
if (!Directory.Exists(folder))
|
{
|
Directory.CreateDirectory(folder);
|
}
|
|
string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}";
|
string post = "";
|
if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatOK))
|
{
|
post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatOK];
|
}
|
else
|
{
|
post = M141Config.ImageFormatOK.ToString().ToLower();
|
}
|
|
string ngImageFile = Path.Combine(folder, $"{id}.{post}");
|
var bitmap = imgSet.HImage.ConvertHImageToBitmap();
|
bitmap.Save(ngImageFile, M141Config.ImageFormatOK);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK图片已保存");
|
bitmap.Dispose();
|
}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{measureBind.WorkPosition},产品{string.Join(",", products.Select(u => u.PID))}的NG图片保存异常,{ex.GetExceptionMessage()}");
|
}
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片{imgSet.PID}开始释放");
|
imgSet.HImage?.Dispose();
|
imgSet.HImage = null;
|
imgSet.Dispose();
|
imgSet = null;
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片已释放");
|
|
|
}
|
});
|
}
|
|
private void RunCustomizedMethod(List<ProductModel> products, string triggerText, string triggerSource, IImageSet imgSet, string methodId, List<DetectResult> resultList)
|
{
|
try
|
{
|
if (!string.IsNullOrWhiteSpace(methodId))
|
{
|
|
var monitorSet = Config.GetAllMonitorSet().FirstOrDefault(u => u.Id == methodId);
|
|
if (monitorSet.OpConfig is IImageCheckOperationConfig iConfig)
|
{
|
var opConfig = iConfig.Clone();
|
|
opConfig.Products = new List<ProductModel>(products);
|
opConfig.ImageSet = imgSet;
|
|
opConfig.TriggerStr = triggerText;
|
opConfig.TriggerSource = triggerSource;
|
opConfig.ExecuteDevice = iConfig.ExecuteDevice;
|
|
|
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"图片id,{imgSet.id}");
|
var res = RunSelectedMonitorSetByManual(methodId, opConfig);
|
|
if (res.DataObj is List<DetectResult> dr)
|
{
|
dr.ForEach(r =>
|
{
|
r.IsPreTreatDone = r.IsNetCheckDone = r.IsAfterTreatDone = true;
|
r.SetResult();
|
});
|
resultList.AddRange(dr);
|
}
|
|
if (res.Result != 1)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{res.Message}");
|
}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{ex.GetExceptionMessage()}");
|
}
|
}
|
|
|
public void SaveZipPreparation(string id, IImageSet imgSet, string workstation)
|
{
|
try
|
{
|
if (M141Config.SaveStateZip)
|
{
|
if (M141Config.PositionZip.Any(u => u.WorkPosition == workstation))
|
{
|
if (M141Config.SaveTwoPathZip)
|
{
|
if (!string.IsNullOrEmpty(M141Config.SavePathZip) || !string.IsNullOrEmpty(M141Config.SavePathZip2))
|
{
|
if (string.IsNullOrEmpty(M141Config.CurrPathZip))
|
{
|
M141Config.CurrPathZip = M141Config.SavePathZip;
|
}
|
|
if (M141Config.CurrPathZip != M141Config.SavePathZip && M141Config.CurrPathZip != M141Config.SavePathZip2)
|
{
|
M141Config.CurrPathZip = M141Config.SavePathZip;
|
}
|
|
DriveInfo driveInfo3 = DriveInfo.GetDrives().First(d => M141Config.CurrPathZip.StartsWith(d.Name));
|
double freespace3 = (double)driveInfo3.AvailableFreeSpace / (double)driveInfo3.TotalSize * 100;
|
|
if (freespace3 < M141Config.SaveMinPercentZip)
|
{
|
DriveInfo driveInfo1 = DriveInfo.GetDrives().First(d => M141Config.SavePathZip.StartsWith(d.Name));
|
double freespace1 = (double)driveInfo1.AvailableFreeSpace / (double)driveInfo1.TotalSize * 100;
|
|
DriveInfo driveInfo2 = DriveInfo.GetDrives().First(d => M141Config.SavePathZip2.StartsWith(d.Name));
|
double freespace2 = (double)driveInfo2.AvailableFreeSpace / (double)driveInfo2.TotalSize * 100;
|
|
if (freespace1 > M141Config.SaveMinPercentZip)
|
{
|
M141Config.CurrPathZip = M141Config.SavePathZip;
|
SaveProcessConfig(M141Config);
|
}
|
else if (freespace2 > M141Config.SaveMinPercentZip)
|
{
|
M141Config.CurrPathZip = M141Config.SavePathZip2;
|
SaveProcessConfig(M141Config);
|
}
|
else
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"双磁盘都达到存储极限,不再保存压缩图片");
|
return;
|
}
|
}
|
|
string folder = Path.Combine(M141Config.CurrPathZip, DateTime.Now.ToString("yyyyMMdd"), workstation);
|
|
if (!Directory.Exists(folder))
|
{
|
Directory.CreateDirectory(folder);
|
}
|
|
string post = "";
|
if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatZip))
|
{
|
post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatZip];
|
}
|
else
|
{
|
post = M141Config.ImageFormatZip.ToString().ToLower();
|
}
|
|
|
HImage zoomimage;
|
if ((int)M141Config.SavezipZip != 10)
|
{
|
//// 调用zoom_image_factor算子
|
HOperatorSet.ZoomImageFactor(imgSet.HImage, out HObject zoomHob, ((double)M141Config.SavezipZip) / 10, ((double)M141Config.SavezipZip) / 10, "constant");
|
zoomimage = zoomHob.ConvertHObjectToHImage();
|
}
|
else
|
{
|
zoomimage = imgSet.HImage;
|
}
|
//string ngImageFile = Path.Combine(folder, $"{id}.{post}");
|
//var bitmap = zoomimage.ConvertHImageToBitmap();
|
//bitmap.Save(ngImageFile, M141Config.ImageFormatZip);
|
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}压缩图片已保存");
|
//zoomimage.Dispose();
|
//bitmap.Dispose();
|
|
lock (ZipImages)
|
{
|
ZipImages.Add(new ZipImage
|
{
|
path = folder,
|
name = id,
|
post = post,
|
image = zoomimage,
|
});
|
}
|
}
|
else
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"压缩图片保存双路径为空");
|
}
|
}
|
else
|
{
|
if (!string.IsNullOrEmpty(M141Config.SavePathZip))
|
{
|
|
string folder = Path.Combine(M141Config.SavePathZip, DateTime.Now.ToString("yyyyMMdd"), workstation);
|
if (!Directory.Exists(folder))
|
{
|
Directory.CreateDirectory(folder);
|
}
|
string post = "";
|
if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatZip))
|
{
|
post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatZip];
|
}
|
else
|
{
|
post = M141Config.ImageFormatZip.ToString().ToLower();
|
}
|
|
//// 调用zoom_image_factor算子
|
HOperatorSet.ZoomImageFactor(imgSet.HImage, out HObject zoomHob, ((double)M141Config.SavezipZip) / 10, ((double)M141Config.SavezipZip) / 10, "constant");
|
|
HImage zoomimage = zoomHob.ConvertHObjectToHImage();
|
//string ngImageFile = Path.Combine(folder, $"{id}_{Result}.{post}");
|
//var bitmap = zoomimage.ConvertHImageToBitmap();
|
//bitmap.Save(ngImageFile, M141Config.ImageFormatZip);
|
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}压缩图片已保存");
|
//zoomimage.Dispose();
|
|
lock (ZipImages)
|
{
|
ZipImages.Add(new ZipImage
|
{
|
path = folder,
|
name = id,
|
post = post,
|
image = zoomimage,
|
});
|
}
|
|
}
|
else
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"压缩图片保存路径为空");
|
}
|
}
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"压缩图片整理异常{e.ToString()}");
|
}
|
}
|
|
#region plc
|
public ResponseMessage RunImageCheck_plc(IOperationConfig config, int plcnum)
|
{
|
ResponseMessage msg = new ResponseMessage();
|
msg.Result = 1;
|
List<MeasureBind> measureBinds = new List<MeasureBind>();
|
string inputSequence = "";
|
var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
try
|
{
|
RunImageCheckPreTreat_plc(config, out measureBinds, out inputSequence);
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测预处理异常,{ex.GetExceptionMessage()}");
|
msg.Result = -1;
|
msg.Message = ex.Message;
|
return msg;
|
}
|
|
List<string> cameraIds = measureBinds.Select(u => u.CameraId).ToList();
|
try
|
{
|
ConcurrentDictionary<MeasureBind, IImageSet> imgSetDicts = new ConcurrentDictionary<MeasureBind, IImageSet>();
|
|
measureBinds.AsParallel().ForAll(b =>
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == b.CameraId) as CameraBase;
|
if (camera == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测配置{b.GetDisplayText()}未能获取相机设备");
|
imgSetDicts[b] = null;
|
return;
|
}
|
imgSetDicts[b] = null;
|
|
try
|
{
|
imgSetDicts[b] = CollectHImage(camera, b.SnapshotOpConfig);
|
}
|
catch (Exception ea)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息异常 {ea.ToString()}");
|
}
|
|
var pList = b.ProductIndices.Select(pi =>
|
{
|
string pid = $"{inputSequence}_{pi}";
|
return FindProductBySequence(pid, true);
|
}).ToList();
|
|
RunImageCheckAsync(pList, config.TriggerStr, config.TriggerSource, imgSetDicts[b], b);
|
});
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测处理异常,{ex.GetExceptionMessage()}");
|
msg.Result = -1;
|
msg.Message = ex.Message;
|
return msg;
|
}
|
|
CheckPositionDoneAsync_plc(measureBinds[0].WorkPosition, inputSequence, config, cameraIds, plcnum);
|
return msg;
|
}
|
|
public void RunImageCheckPreTreat_plc(IOperationConfig config, out List<MeasureBind> measureBinds, out string inputSequence)
|
{
|
Task.Run(() =>
|
{
|
SetProcessRunState(EnumHelper.RunState.Running);
|
});
|
|
measureBinds = new List<MeasureBind>();
|
inputSequence = "";
|
|
var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
if (triggerDatas.Length < 2)
|
{
|
throw new ProcessException($"触发文本{config.TriggerStr}解析失败,数据长度小于2");
|
}
|
|
string positionValue = triggerDatas[0];
|
int checkIndex = -1;
|
if (!int.TryParse(triggerDatas[1].Replace("Scan", ""), out checkIndex))
|
{
|
throw new ProcessException($"触发文本{config.TriggerStr}解析失败,未能获取检测序号");
|
}
|
|
|
var positionSet = M141Config.WorkPositionCollection.Where(u => u.IsEnabled).FirstOrDefault(u => u.TriggerValue == positionValue);
|
if (positionSet == null)
|
{
|
throw new ProcessException($"触发文本{config.TriggerStr}未能获取{positionValue}对应的可用工位信息");
|
}
|
|
measureBinds = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionSet.PositionName && u.CheckIndex == checkIndex).ToList();
|
if (measureBinds.Count == 0)
|
{
|
throw new ProcessException($"未能获取工位{positionSet.PositionName}的第{checkIndex}检测配置信息");
|
}
|
|
measureBinds.Select(u => u.CameraId).ToList().ForEach(c =>
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase;
|
if (camera != null)
|
{
|
camera.ClearImageBufferQueue();
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"相机{camera.Name}检测前清理缓存完成");
|
}
|
});
|
|
inputSequence = triggerDatas[triggerDatas.Length - 1];
|
|
string tempPID = inputSequence;
|
|
string pidstr = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
measureBinds.Where(b => b.IsFirstPosition).ToList().ForEach(b =>
|
{
|
b.ProductIndices.ForEach(i =>
|
{
|
ProductModel p = new ProductModel();
|
p.SEQUENCE = $"{tempPID}_{i}";
|
p.PID = $"{pidstr}T_{i}";
|
p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Select(u => u.PositionName).ToList());
|
NewProductIntoList(p, true);
|
});
|
});
|
|
|
int de = 0;
|
|
measureBinds.Where(b => (b.CheckIndex == de || b.CheckIndex == 1) && b.ImageIndex == 0).AsParallel().ForAll(b =>
|
{
|
List<int> temint = new List<int>();
|
|
temint = new List<int>() { 1, 2, 3 };
|
|
temint.ForEach(i =>
|
{
|
string sequence = $"{tempPID}_{i}";
|
var p = FindProductBySequence(sequence, b.IsEnabelQueryFromQueue);
|
|
//初始化产品的检测次数
|
var checkIndexList = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition && u.ProductIndices.Contains(i)).Select(u => u.CheckIndex).OrderBy(u => u).ToList();
|
p.InitialPositionCheckList(b.WorkPosition, checkIndexList);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{p.PID}_{p.SEQUENCE}已清理{b.WorkPosition}检测数据。当前已完成工位{string.Join(",", p.Details.Select(u => u.PositionName))}");
|
});
|
|
//初始化工位的检测次数
|
var positionCheckTimes = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition).Select(u => u.CheckIndex).ToList();
|
lock (_positionCheckTimeLock)
|
{
|
_positionCheckTimeDict[b.WorkPosition] = positionCheckTimes;
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}初始化检测次数:{string.Join(",", positionCheckTimes)}");
|
}
|
});
|
|
measureBinds.AsParallel().ForAll(b =>
|
{
|
lock (_positionCheckTimeLock)
|
{
|
_positionCheckTimeDict[b.WorkPosition].RemoveAll(u => u == b.CheckIndex);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}开始第{b.CheckIndex}次检测,待检测序号:{string.Join(",", _positionCheckTimeDict[b.WorkPosition])}");
|
}
|
});
|
}
|
|
public async Task<List<ProductModel>> CheckPositionDoneAsync_plc(string positionName, string inputSequence, IOperationConfig config, List<string> cameraIds, int plcnum)
|
{
|
string triggerSource = config.TriggerSource;
|
return await _taskFactory.StartNew(() =>
|
{
|
try
|
{
|
|
string index = config.TriggerStr.Split(',')[1];
|
var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName);
|
|
var checkRemains = _positionCheckTimeDict[positionName];
|
|
var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList();
|
pIndices = new List<int> { 1, 2, 3 };
|
|
|
var pList = pIndices.Select(u =>
|
{
|
string sequence = $"{inputSequence}_{u}";
|
return FindProductBySequence(sequence, true);
|
}).ToList();
|
List<bool> plcresult = new List<bool>();
|
if (pList.Any(u => u == null))
|
{
|
plcresult = new List<bool>() { false, false, false };
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空");
|
}
|
else
|
{
|
int waitInterval = 20;
|
int repeatTime = M141Config.DetectTimeout / waitInterval;
|
do
|
{
|
if (!pList.All(p =>
|
{
|
p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail);
|
return detail?.IsDone ?? false;
|
}))
|
{
|
Thread.Sleep(waitInterval);
|
repeatTime--;
|
}
|
else
|
{
|
//Thread.Sleep(50);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测");
|
break;
|
}
|
|
if (repeatTime < 0)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时");
|
break;
|
}
|
} while (true);
|
}
|
|
|
pList.ForEach(p =>
|
{
|
var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail);
|
plcresult.Add(isOK);
|
//List<string> specHeads = new List<string>();
|
//string head = p.GetCSVHead(ref specHeads, positionName);
|
//if (!_positionSpecHeads.ContainsKey(positionName))
|
//{
|
// _positionSpecHeads[positionName] = specHeads;
|
//}
|
|
//string data = p.GetCSVData(_positionSpecHeads[positionName], positionName);
|
//CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head);
|
|
////UpdatePositionResultToDB(detail);
|
//var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
//UpdatePositionResultDisplay(detail, isOK, positionName, seqData[seqData.Count - 1]);
|
//if (IsInspectionDoing)
|
//{
|
// OnSinglePostionDetectResultUpdate.Invoke(positionName, detail, seqData[seqData.Count - 1]);
|
//}
|
|
if (positionSet.IsLastPosition)
|
{
|
UpdateProductResultAsync(p);
|
//UpdateOverAllProductResultToUI(p, isOK);
|
//OnNewProductEnqueued?.Invoke(p);
|
//OnProductDequeued?.Invoke(p);
|
CheckContinuousNGAlarmAsync(p);
|
}
|
|
//SetSpecResult(p);
|
});
|
ReplyPlcData(plcresult, plcnum);
|
if (positionSet.IsLastPosition)
|
{
|
if (_ct != null)
|
{
|
UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds) / 3);
|
}
|
_ct = DateTime.Now;
|
}
|
|
//ReplyPlcData(positionName, config.TriggerValue);
|
|
//cameraIds.ForEach(c =>
|
//{
|
// var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase;
|
// if (camera != null)
|
// {
|
// camera.ClearImageBufferQueue();
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存");
|
// }
|
//});
|
|
return pList;
|
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, ex.ToString());
|
return null;
|
}
|
|
});
|
}
|
|
public virtual void ReplyPlcData(List<bool> result, int plcnum)
|
{
|
|
}
|
|
#endregion
|
|
|
public void wirtePLC(int add, int value)
|
{
|
Plc1?.WriteSingleAddress(add, value, out _);
|
}
|
|
|
}
|
|
|
|
public class ZipImage
|
{
|
public string path { set; get; }
|
|
public string name { set; get; }
|
|
public string post { set; get; }
|
|
public HImage image { set; get; }
|
|
}
|
public class OKNGImage
|
{
|
public string pid { set; get; }
|
public string path { set; get; }
|
|
public string name { set; get; }
|
|
public string post { set; get; }
|
public string result { set; get; }
|
|
public Bitmap bitmap { set; get; }
|
|
public ImageFormat ImageFormat { set; get; }
|
|
public bool issave { set; get; }
|
|
}
|
|
|
|
}
|