415 lines
14 KiB
C#
415 lines
14 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Diagnostics;
|
|||
|
using System.Drawing;
|
|||
|
using System.Drawing.Imaging;
|
|||
|
using System.IO;
|
|||
|
using System.Reflection;
|
|||
|
using System.Threading;
|
|||
|
using Microsoft.ML.OnnxRuntime;
|
|||
|
using Microsoft.ML.OnnxRuntime.Tensors;
|
|||
|
using Yolo5;
|
|||
|
|
|||
|
namespace ProductionControl.Device
|
|||
|
{
|
|||
|
public class DefectLib : IDisposable
|
|||
|
{
|
|||
|
public Action<WarningEnum, string> WarningEvent;
|
|||
|
/// <summary>
|
|||
|
/// 检测结果JSON(原图,结果)
|
|||
|
/// </summary>
|
|||
|
public Action<DefectTask> finishEvent;
|
|||
|
/// <summary>
|
|||
|
/// 是否打开设备成功
|
|||
|
/// </summary>
|
|||
|
public bool IsInit { get; private set; } = false;
|
|||
|
//private System.Timers.Timer timer = new System.Timers.Timer();
|
|||
|
|
|||
|
private Thread t_task, t_task2, t_task3, t_task4, t_task_operation, t_task_operation2, t_task_tag;
|
|||
|
private Yolo_Class yolo1;
|
|||
|
private InferenceSession _onnxSession;
|
|||
|
public DefectLib()
|
|||
|
{
|
|||
|
}
|
|||
|
public bool start()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
yolo1 = new Yolo_Class();
|
|||
|
//加载模型(只加载一次即可)
|
|||
|
string modelFilePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\best.onnx";
|
|||
|
_onnxSession = yolo1.LoadModel(modelFilePath, true);//false-CPU true-显卡
|
|||
|
|
|||
|
IsInit = true;
|
|||
|
//timer.Elapsed += Timer_Elapsed;
|
|||
|
//timer.Interval = 100;
|
|||
|
//timer.Enabled = true;
|
|||
|
taskList.Clear();
|
|||
|
taskOperationList.Clear();
|
|||
|
taskTagList.Clear();
|
|||
|
|
|||
|
t_task = new System.Threading.Thread(run);
|
|||
|
t_task.IsBackground = true;
|
|||
|
t_task.Start();
|
|||
|
t_task2 = new System.Threading.Thread(run);
|
|||
|
t_task2.IsBackground = true;
|
|||
|
t_task2.Start();
|
|||
|
t_task3 = new System.Threading.Thread(run);
|
|||
|
t_task3.IsBackground = true;
|
|||
|
t_task3.Start();
|
|||
|
t_task4 = new System.Threading.Thread(run);
|
|||
|
t_task4.IsBackground = true;
|
|||
|
t_task4.Start();
|
|||
|
|
|||
|
t_task_operation = new System.Threading.Thread(run2);
|
|||
|
t_task_operation.IsBackground = true;
|
|||
|
t_task_operation.Start();
|
|||
|
|
|||
|
t_task_operation2 = new System.Threading.Thread(run2);
|
|||
|
t_task_operation2.IsBackground = true;
|
|||
|
t_task_operation2.Start();
|
|||
|
|
|||
|
t_task_tag = new System.Threading.Thread(run3);
|
|||
|
t_task_tag.IsBackground = true;
|
|||
|
t_task_tag.Start();
|
|||
|
return true;
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(WarningEnum.High, ex.Message);
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
public void stop()
|
|||
|
{
|
|||
|
if (!IsInit) return;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
IsInit = false;
|
|||
|
//timer.Elapsed -= Timer_Elapsed;
|
|||
|
//释放模型
|
|||
|
_onnxSession.Dispose();
|
|||
|
if (t_task != null)
|
|||
|
{
|
|||
|
bool b = t_task.Join(5000);
|
|||
|
if (!b) t_task.Abort();
|
|||
|
t_task = null;
|
|||
|
}
|
|||
|
if (t_task2 != null)
|
|||
|
{
|
|||
|
bool b = t_task2.Join(5000);
|
|||
|
if (!b) t_task2.Abort();
|
|||
|
t_task2 = null;
|
|||
|
}
|
|||
|
if (t_task3 != null)
|
|||
|
{
|
|||
|
bool b = t_task3.Join(5000);
|
|||
|
if (!b) t_task3.Abort();
|
|||
|
t_task3 = null;
|
|||
|
}
|
|||
|
if (t_task4 != null)
|
|||
|
{
|
|||
|
bool b = t_task4.Join(5000);
|
|||
|
if (!b) t_task4.Abort();
|
|||
|
t_task4 = null;
|
|||
|
}
|
|||
|
|
|||
|
if (t_task_operation != null)
|
|||
|
{
|
|||
|
bool b = t_task_operation.Join(5000);
|
|||
|
if (!b) t_task_operation.Abort();
|
|||
|
t_task_operation = null;
|
|||
|
}
|
|||
|
if (t_task_operation2 != null)
|
|||
|
{
|
|||
|
bool b = t_task_operation2.Join(5000);
|
|||
|
if (!b) t_task_operation2.Abort();
|
|||
|
t_task_operation2 = null;
|
|||
|
}
|
|||
|
if (t_task_tag != null)
|
|||
|
{
|
|||
|
bool b = t_task_tag.Join(5000);
|
|||
|
if (!b) t_task_tag.Abort();
|
|||
|
t_task_tag = null;
|
|||
|
}
|
|||
|
taskList.Clear();
|
|||
|
taskOperationList.Clear();
|
|||
|
taskTagList.Clear();
|
|||
|
}
|
|||
|
catch { }
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// 保存图片
|
|||
|
/// </summary>
|
|||
|
/// <param name="Img"></param>图片
|
|||
|
/// <param name="pictureUrl"></param>保存路径
|
|||
|
/// <param name="pictureName"></param>保存名称
|
|||
|
public void SaveImage(Bitmap Img, string pictureUrl, string pictureName)
|
|||
|
{
|
|||
|
if (!Directory.Exists(pictureUrl))
|
|||
|
{
|
|||
|
Directory.CreateDirectory(pictureUrl);
|
|||
|
}
|
|||
|
FileInfo FileUrl = new FileInfo(pictureUrl);//防止路径中有日期导致路径错误
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
using (Bitmap bitmap = new Bitmap(Img))
|
|||
|
{
|
|||
|
using (MemoryStream stream = new MemoryStream())
|
|||
|
{
|
|||
|
bitmap.Save(stream, ImageFormat.Bmp);
|
|||
|
System.Drawing.Image img = System.Drawing.Image.FromStream(stream);
|
|||
|
//img.Save(FileUrl +"\\"+ pictureName);
|
|||
|
//img.Dispose();
|
|||
|
string szURL = FileUrl + "\\" + pictureName;
|
|||
|
img.Save(szURL, ImageFormat.Bmp);
|
|||
|
img.Dispose();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch (Exception)
|
|||
|
{
|
|||
|
if (Img != null)
|
|||
|
{
|
|||
|
Img.Dispose();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
private void run()
|
|||
|
{
|
|||
|
while (IsInit)
|
|||
|
{
|
|||
|
if (taskList.Count < 1)
|
|||
|
{
|
|||
|
Thread.Sleep(0);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
var task = pop();
|
|||
|
try
|
|||
|
{
|
|||
|
if (task != null)
|
|||
|
{
|
|||
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
|||
|
//源图
|
|||
|
//Bitmap bmp = yolo1.Read2Bmp(file_path);
|
|||
|
//切割图像,输入图像格式14208*10640
|
|||
|
stopwatch.Restart();
|
|||
|
task.bmps_cut = yolo1.OpenCVToCuts(task.bmp, task.cut_size.Width, task.cut_size.Height);
|
|||
|
stopwatch.Stop();
|
|||
|
task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
|
|||
|
|
|||
|
//Resize图像
|
|||
|
stopwatch.Restart();
|
|||
|
task.bmps_resize = yolo1.OpenCVToResizes(task.bmps_cut, task.resize.Width, task.resize.Height);
|
|||
|
stopwatch.Stop();
|
|||
|
task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
|
|||
|
|
|||
|
//预处理模型
|
|||
|
stopwatch.Restart();
|
|||
|
task.tensors = yolo1.PreprocessImage(task.bmps_resize);
|
|||
|
stopwatch.Stop();
|
|||
|
task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
|
|||
|
lock (taskOperationList)
|
|||
|
taskOperationList.Add(task);
|
|||
|
}
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(WarningEnum.Low, "DefectLib task err:" + ex.Message);
|
|||
|
task.isSucceed = false;
|
|||
|
task.resultInfo = ex.Message;
|
|||
|
callback(task);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
private void run2()
|
|||
|
{
|
|||
|
while (IsInit)
|
|||
|
{
|
|||
|
if (taskOperationList.Count < 1)
|
|||
|
{
|
|||
|
Thread.Sleep(0);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
var task = pop2();
|
|||
|
try
|
|||
|
{
|
|||
|
if (task != null)
|
|||
|
{
|
|||
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
|||
|
//====运行推理(必需单队列)
|
|||
|
stopwatch.Restart();
|
|||
|
IDisposableReadOnlyCollection<DisposableNamedOnnxValue>[] results = yolo1.RunModlel(_onnxSession, task.tensors);
|
|||
|
task.informationList = yolo1.ScreeningResults(results, task.bmps_resize, task.thresholds);
|
|||
|
stopwatch.Stop();
|
|||
|
task.stopwatch[3] = stopwatch.ElapsedMilliseconds;
|
|||
|
if (task.informationList.Count > 0)
|
|||
|
{
|
|||
|
lock (taskTagList)
|
|||
|
taskTagList.Add(task);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
task.isSucceed = true;
|
|||
|
callback(task);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(WarningEnum.Low, "DefectLib task2 err:" + ex.Message);
|
|||
|
task.isSucceed = false;
|
|||
|
task.resultInfo = ex.Message;
|
|||
|
callback(task);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
private void run3()
|
|||
|
{
|
|||
|
while (IsInit)
|
|||
|
{
|
|||
|
if (taskTagList.Count < 1)
|
|||
|
{
|
|||
|
Thread.Sleep(0);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
var task = pop3();
|
|||
|
try
|
|||
|
{
|
|||
|
if (task != null)
|
|||
|
{
|
|||
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
|||
|
//====打标 null ,有缺陷返回缺陷图片数组,没缺陷返回所有图片数组
|
|||
|
stopwatch.Restart();
|
|||
|
task.bmps_tag = yolo1.DrawYoloPrediction2(task.bmps_cut, task.informationList, 27, SixLabors.ImageSharp.Color.OrangeRed, task.resize.Width);
|
|||
|
stopwatch.Stop();
|
|||
|
task.stopwatch[4] = stopwatch.ElapsedMilliseconds;
|
|||
|
task.isSucceed = true;
|
|||
|
callback(task);
|
|||
|
}
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
WarningEvent?.Invoke(WarningEnum.Low, "DefectLib task3 err:" + ex.Message);
|
|||
|
task.isSucceed = false;
|
|||
|
task.resultInfo = ex.Message;
|
|||
|
callback(task);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
private void callback(DefectTask task)
|
|||
|
{
|
|||
|
//返回成功/失败,异步调用
|
|||
|
if (task.finishEvent != null || (task.finishEvent = finishEvent) != null)
|
|||
|
//task.finishEvent.BeginInvoke(result, errInfo, res => task.finishEvent.EndInvoke(res), null);
|
|||
|
System.Threading.ThreadPool.QueueUserWorkItem(waitCallback, task);
|
|||
|
}
|
|||
|
//异步回调
|
|||
|
WaitCallback waitCallback = new WaitCallback(o =>
|
|||
|
{
|
|||
|
var task = (DefectTask)o;
|
|||
|
task.finishEvent(task);
|
|||
|
});
|
|||
|
//=======task list
|
|||
|
private List<DefectTask> taskList = new List<DefectTask>();
|
|||
|
private List<DefectTask> taskOperationList = new List<DefectTask>();
|
|||
|
private List<DefectTask> taskTagList = new List<DefectTask>();
|
|||
|
public class DefectTask
|
|||
|
{
|
|||
|
//图索引
|
|||
|
public int index = 0;
|
|||
|
/// <summary>
|
|||
|
/// 源文件
|
|||
|
/// </summary>
|
|||
|
public Bitmap bmp;
|
|||
|
public Size cut_size = new Size(592, 532);
|
|||
|
public Size resize = new Size(224, 224);
|
|||
|
/// <summary>
|
|||
|
/// 阈值
|
|||
|
/// </summary>
|
|||
|
public float thresholds = 0.4f;
|
|||
|
/// <summary>
|
|||
|
/// 完成后回调
|
|||
|
/// </summary>
|
|||
|
public Action<DefectTask> finishEvent;
|
|||
|
|
|||
|
//
|
|||
|
public long createTime = DateTime.Now.Ticks;
|
|||
|
public DateTime nowTime;
|
|||
|
//中间变量,供step2使用
|
|||
|
public Bitmap[] bmps_cut;
|
|||
|
public Bitmap[] bmps_resize;
|
|||
|
//预处理模型
|
|||
|
public Tensor<float>[] tensors;
|
|||
|
|
|||
|
//==结果返回
|
|||
|
public List<Dictionary<int, List<string>[]>> informationList;
|
|||
|
public Bitmap[] bmps_tag;
|
|||
|
public bool isSucceed;//转换是否成功
|
|||
|
public string resultInfo = "";//成功或失败信息
|
|||
|
public long[] stopwatch = new long[5];
|
|||
|
}
|
|||
|
|
|||
|
public void add(DefectTask task)
|
|||
|
{
|
|||
|
lock (taskList)
|
|||
|
taskList.Add(task);
|
|||
|
}
|
|||
|
private DefectTask pop()
|
|||
|
{
|
|||
|
lock (taskList)
|
|||
|
{
|
|||
|
if (taskList.Count < 1)
|
|||
|
return null;
|
|||
|
|
|||
|
int index = 0;// taskList.FindIndex(p => { return p.isSync; });
|
|||
|
//if (index < 0) index = 0;
|
|||
|
var task = taskList[0];
|
|||
|
taskList.RemoveAt(0);
|
|||
|
return task;
|
|||
|
}
|
|||
|
}
|
|||
|
private DefectTask pop2()
|
|||
|
{
|
|||
|
lock (taskOperationList)
|
|||
|
{
|
|||
|
if (taskOperationList.Count < 1)
|
|||
|
return null;
|
|||
|
|
|||
|
int index = 0;// taskList.FindIndex(p => { return p.isSync; });
|
|||
|
//if (index < 0) index = 0;
|
|||
|
var task = taskOperationList[0];
|
|||
|
taskOperationList.RemoveAt(0);
|
|||
|
return task;
|
|||
|
}
|
|||
|
}
|
|||
|
private DefectTask pop3()
|
|||
|
{
|
|||
|
lock (taskTagList)
|
|||
|
{
|
|||
|
if (taskTagList.Count < 1)
|
|||
|
return null;
|
|||
|
|
|||
|
int index = 0;// taskList.FindIndex(p => { return p.isSync; });
|
|||
|
//if (index < 0) index = 0;
|
|||
|
var task = taskTagList[0];
|
|||
|
taskTagList.RemoveAt(0);
|
|||
|
return task;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Dispose()
|
|||
|
{
|
|||
|
stop();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|